1240116Smarcel//
2240116Smarcel// Automated Testing Framework (atf)
3240116Smarcel//
4240116Smarcel// Copyright (c) 2007 The NetBSD Foundation, Inc.
5240116Smarcel// All rights reserved.
6240116Smarcel//
7240116Smarcel// Redistribution and use in source and binary forms, with or without
8240116Smarcel// modification, are permitted provided that the following conditions
9240116Smarcel// are met:
10240116Smarcel// 1. Redistributions of source code must retain the above copyright
11240116Smarcel//    notice, this list of conditions and the following disclaimer.
12240116Smarcel// 2. Redistributions in binary form must reproduce the above copyright
13240116Smarcel//    notice, this list of conditions and the following disclaimer in the
14240116Smarcel//    documentation and/or other materials provided with the distribution.
15240116Smarcel//
16240116Smarcel// THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND
17240116Smarcel// CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
18240116Smarcel// INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
19240116Smarcel// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
20240116Smarcel// IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS BE LIABLE FOR ANY
21240116Smarcel// DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22240116Smarcel// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
23240116Smarcel// GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
24240116Smarcel// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
25240116Smarcel// IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
26240116Smarcel// OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
27240116Smarcel// IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28240116Smarcel//
29240116Smarcel
30240116Smarcelextern "C" {
31240116Smarcel#include <sys/types.h>
32240116Smarcel#include <sys/stat.h>
33240116Smarcel#include <sys/time.h>
34240116Smarcel#include <sys/wait.h>
35240116Smarcel#include <signal.h>
36240116Smarcel#include <unistd.h>
37240116Smarcel}
38240116Smarcel
39240116Smarcel#include <algorithm>
40240116Smarcel#include <cctype>
41240116Smarcel#include <cerrno>
42240116Smarcel#include <cstdlib>
43240116Smarcel#include <cstring>
44240116Smarcel#include <fstream>
45240116Smarcel#include <iostream>
46240116Smarcel#include <map>
47240116Smarcel#include <memory>
48240116Smarcel#include <sstream>
49240116Smarcel#include <stdexcept>
50240116Smarcel#include <vector>
51240116Smarcel
52240116Smarcelextern "C" {
53240116Smarcel#include "atf-c/error.h"
54240116Smarcel#include "atf-c/tc.h"
55240116Smarcel#include "atf-c/utils.h"
56240116Smarcel}
57240116Smarcel
58240116Smarcel#include "tests.hpp"
59240116Smarcel
60240116Smarcel#include "detail/application.hpp"
61260029Sjmmv#include "detail/auto_array.hpp"
62240116Smarcel#include "detail/env.hpp"
63240116Smarcel#include "detail/exceptions.hpp"
64240116Smarcel#include "detail/fs.hpp"
65240116Smarcel#include "detail/sanity.hpp"
66240116Smarcel#include "detail/text.hpp"
67240116Smarcel
68240116Smarcelnamespace impl = atf::tests;
69240116Smarcelnamespace detail = atf::tests::detail;
70240116Smarcel#define IMPL_NAME "atf::tests"
71240116Smarcel
72240116Smarcel// ------------------------------------------------------------------------
73240116Smarcel// The "atf_tp_writer" class.
74240116Smarcel// ------------------------------------------------------------------------
75240116Smarcel
76240116Smarceldetail::atf_tp_writer::atf_tp_writer(std::ostream& os) :
77240116Smarcel    m_os(os),
78240116Smarcel    m_is_first(true)
79240116Smarcel{
80262855Sjmmv    m_os << "Content-Type: application/X-atf-tp; version=\"1\"\n\n";
81240116Smarcel}
82240116Smarcel
83240116Smarcelvoid
84240116Smarceldetail::atf_tp_writer::start_tc(const std::string& ident)
85240116Smarcel{
86240116Smarcel    if (!m_is_first)
87240116Smarcel        m_os << "\n";
88240116Smarcel    m_os << "ident: " << ident << "\n";
89240116Smarcel    m_os.flush();
90240116Smarcel}
91240116Smarcel
92240116Smarcelvoid
93240116Smarceldetail::atf_tp_writer::end_tc(void)
94240116Smarcel{
95240116Smarcel    if (m_is_first)
96240116Smarcel        m_is_first = false;
97240116Smarcel}
98240116Smarcel
99240116Smarcelvoid
100240116Smarceldetail::atf_tp_writer::tc_meta_data(const std::string& name,
101240116Smarcel                                    const std::string& value)
102240116Smarcel{
103240116Smarcel    PRE(name != "ident");
104240116Smarcel    m_os << name << ": " << value << "\n";
105240116Smarcel    m_os.flush();
106240116Smarcel}
107240116Smarcel
108240116Smarcel// ------------------------------------------------------------------------
109240116Smarcel// Free helper functions.
110240116Smarcel// ------------------------------------------------------------------------
111240116Smarcel
112240116Smarcelbool
113240116Smarceldetail::match(const std::string& regexp, const std::string& str)
114240116Smarcel{
115240116Smarcel    return atf::text::match(str, regexp);
116240116Smarcel}
117240116Smarcel
118240116Smarcel// ------------------------------------------------------------------------
119240116Smarcel// The "tc" class.
120240116Smarcel// ------------------------------------------------------------------------
121240116Smarcel
122240116Smarcelstatic std::map< atf_tc_t*, impl::tc* > wraps;
123240116Smarcelstatic std::map< const atf_tc_t*, const impl::tc* > cwraps;
124240116Smarcel
125262855Sjmmvstruct impl::tc_impl {
126262855Sjmmvprivate:
127262855Sjmmv    // Non-copyable.
128262855Sjmmv    tc_impl(const tc_impl&);
129262855Sjmmv    tc_impl& operator=(const tc_impl&);
130262855Sjmmv
131262855Sjmmvpublic:
132240116Smarcel    std::string m_ident;
133240116Smarcel    atf_tc_t m_tc;
134240116Smarcel    bool m_has_cleanup;
135240116Smarcel
136240116Smarcel    tc_impl(const std::string& ident, const bool has_cleanup) :
137240116Smarcel        m_ident(ident),
138240116Smarcel        m_has_cleanup(has_cleanup)
139240116Smarcel    {
140240116Smarcel    }
141240116Smarcel
142240116Smarcel    static void
143240116Smarcel    wrap_head(atf_tc_t *tc)
144240116Smarcel    {
145240116Smarcel        std::map< atf_tc_t*, impl::tc* >::iterator iter = wraps.find(tc);
146240116Smarcel        INV(iter != wraps.end());
147240116Smarcel        (*iter).second->head();
148240116Smarcel    }
149240116Smarcel
150240116Smarcel    static void
151240116Smarcel    wrap_body(const atf_tc_t *tc)
152240116Smarcel    {
153240116Smarcel        std::map< const atf_tc_t*, const impl::tc* >::const_iterator iter =
154240116Smarcel            cwraps.find(tc);
155240116Smarcel        INV(iter != cwraps.end());
156240116Smarcel        try {
157240116Smarcel            (*iter).second->body();
158240116Smarcel        } catch (const std::exception& e) {
159240116Smarcel            (*iter).second->fail("Caught unhandled exception: " + std::string(
160240116Smarcel                                     e.what()));
161240116Smarcel        } catch (...) {
162240116Smarcel            (*iter).second->fail("Caught unknown exception");
163240116Smarcel        }
164240116Smarcel    }
165240116Smarcel
166240116Smarcel    static void
167240116Smarcel    wrap_cleanup(const atf_tc_t *tc)
168240116Smarcel    {
169240116Smarcel        std::map< const atf_tc_t*, const impl::tc* >::const_iterator iter =
170240116Smarcel            cwraps.find(tc);
171240116Smarcel        INV(iter != cwraps.end());
172240116Smarcel        (*iter).second->cleanup();
173240116Smarcel    }
174240116Smarcel};
175240116Smarcel
176240116Smarcelimpl::tc::tc(const std::string& ident, const bool has_cleanup) :
177240116Smarcel    pimpl(new tc_impl(ident, has_cleanup))
178240116Smarcel{
179240116Smarcel}
180240116Smarcel
181240116Smarcelimpl::tc::~tc(void)
182240116Smarcel{
183240116Smarcel    cwraps.erase(&pimpl->m_tc);
184240116Smarcel    wraps.erase(&pimpl->m_tc);
185240116Smarcel
186240116Smarcel    atf_tc_fini(&pimpl->m_tc);
187240116Smarcel}
188240116Smarcel
189240116Smarcelvoid
190240116Smarcelimpl::tc::init(const vars_map& config)
191240116Smarcel{
192240116Smarcel    atf_error_t err;
193240116Smarcel
194260029Sjmmv    auto_array< const char * > array(new const char*[(config.size() * 2) + 1]);
195240116Smarcel    const char **ptr = array.get();
196240116Smarcel    for (vars_map::const_iterator iter = config.begin();
197240116Smarcel         iter != config.end(); iter++) {
198240116Smarcel         *ptr = (*iter).first.c_str();
199240116Smarcel         *(ptr + 1) = (*iter).second.c_str();
200240116Smarcel         ptr += 2;
201240116Smarcel    }
202240116Smarcel    *ptr = NULL;
203240116Smarcel
204240116Smarcel    wraps[&pimpl->m_tc] = this;
205240116Smarcel    cwraps[&pimpl->m_tc] = this;
206240116Smarcel
207240116Smarcel    err = atf_tc_init(&pimpl->m_tc, pimpl->m_ident.c_str(), pimpl->wrap_head,
208240116Smarcel        pimpl->wrap_body, pimpl->m_has_cleanup ? pimpl->wrap_cleanup : NULL,
209240116Smarcel        array.get());
210240116Smarcel    if (atf_is_error(err))
211240116Smarcel        throw_atf_error(err);
212240116Smarcel}
213240116Smarcel
214240116Smarcelbool
215240116Smarcelimpl::tc::has_config_var(const std::string& var)
216240116Smarcel    const
217240116Smarcel{
218240116Smarcel    return atf_tc_has_config_var(&pimpl->m_tc, var.c_str());
219240116Smarcel}
220240116Smarcel
221240116Smarcelbool
222240116Smarcelimpl::tc::has_md_var(const std::string& var)
223240116Smarcel    const
224240116Smarcel{
225240116Smarcel    return atf_tc_has_md_var(&pimpl->m_tc, var.c_str());
226240116Smarcel}
227240116Smarcel
228240116Smarcelconst std::string
229240116Smarcelimpl::tc::get_config_var(const std::string& var)
230240116Smarcel    const
231240116Smarcel{
232240116Smarcel    return atf_tc_get_config_var(&pimpl->m_tc, var.c_str());
233240116Smarcel}
234240116Smarcel
235240116Smarcelconst std::string
236240116Smarcelimpl::tc::get_config_var(const std::string& var, const std::string& defval)
237240116Smarcel    const
238240116Smarcel{
239240116Smarcel    return atf_tc_get_config_var_wd(&pimpl->m_tc, var.c_str(), defval.c_str());
240240116Smarcel}
241240116Smarcel
242240116Smarcelconst std::string
243240116Smarcelimpl::tc::get_md_var(const std::string& var)
244240116Smarcel    const
245240116Smarcel{
246240116Smarcel    return atf_tc_get_md_var(&pimpl->m_tc, var.c_str());
247240116Smarcel}
248240116Smarcel
249240116Smarcelconst impl::vars_map
250240116Smarcelimpl::tc::get_md_vars(void)
251240116Smarcel    const
252240116Smarcel{
253240116Smarcel    vars_map vars;
254240116Smarcel
255240116Smarcel    char **array = atf_tc_get_md_vars(&pimpl->m_tc);
256240116Smarcel    try {
257240116Smarcel        char **ptr;
258240116Smarcel        for (ptr = array; *ptr != NULL; ptr += 2)
259240116Smarcel            vars[*ptr] = *(ptr + 1);
260240116Smarcel    } catch (...) {
261240116Smarcel        atf_utils_free_charpp(array);
262240116Smarcel        throw;
263240116Smarcel    }
264240116Smarcel
265240116Smarcel    return vars;
266240116Smarcel}
267240116Smarcel
268240116Smarcelvoid
269240116Smarcelimpl::tc::set_md_var(const std::string& var, const std::string& val)
270240116Smarcel{
271240116Smarcel    atf_error_t err = atf_tc_set_md_var(&pimpl->m_tc, var.c_str(), val.c_str());
272240116Smarcel    if (atf_is_error(err))
273240116Smarcel        throw_atf_error(err);
274240116Smarcel}
275240116Smarcel
276240116Smarcelvoid
277240116Smarcelimpl::tc::run(const std::string& resfile)
278240116Smarcel    const
279240116Smarcel{
280240116Smarcel    atf_error_t err = atf_tc_run(&pimpl->m_tc, resfile.c_str());
281240116Smarcel    if (atf_is_error(err))
282240116Smarcel        throw_atf_error(err);
283240116Smarcel}
284240116Smarcel
285240116Smarcelvoid
286240116Smarcelimpl::tc::run_cleanup(void)
287240116Smarcel    const
288240116Smarcel{
289240116Smarcel    atf_error_t err = atf_tc_cleanup(&pimpl->m_tc);
290240116Smarcel    if (atf_is_error(err))
291240116Smarcel        throw_atf_error(err);
292240116Smarcel}
293240116Smarcel
294240116Smarcelvoid
295240116Smarcelimpl::tc::head(void)
296240116Smarcel{
297240116Smarcel}
298240116Smarcel
299240116Smarcelvoid
300240116Smarcelimpl::tc::cleanup(void)
301240116Smarcel    const
302240116Smarcel{
303240116Smarcel}
304240116Smarcel
305240116Smarcelvoid
306240116Smarcelimpl::tc::require_prog(const std::string& prog)
307240116Smarcel    const
308240116Smarcel{
309240116Smarcel    atf_tc_require_prog(prog.c_str());
310240116Smarcel}
311240116Smarcel
312240116Smarcelvoid
313240116Smarcelimpl::tc::pass(void)
314240116Smarcel{
315240116Smarcel    atf_tc_pass();
316240116Smarcel}
317240116Smarcel
318240116Smarcelvoid
319240116Smarcelimpl::tc::fail(const std::string& reason)
320240116Smarcel{
321240116Smarcel    atf_tc_fail("%s", reason.c_str());
322240116Smarcel}
323240116Smarcel
324240116Smarcelvoid
325240116Smarcelimpl::tc::fail_nonfatal(const std::string& reason)
326240116Smarcel{
327240116Smarcel    atf_tc_fail_nonfatal("%s", reason.c_str());
328240116Smarcel}
329240116Smarcel
330240116Smarcelvoid
331240116Smarcelimpl::tc::skip(const std::string& reason)
332240116Smarcel{
333240116Smarcel    atf_tc_skip("%s", reason.c_str());
334240116Smarcel}
335240116Smarcel
336240116Smarcelvoid
337240116Smarcelimpl::tc::check_errno(const char* file, const int line, const int exp_errno,
338240116Smarcel                      const char* expr_str, const bool result)
339240116Smarcel{
340240116Smarcel    atf_tc_check_errno(file, line, exp_errno, expr_str, result);
341240116Smarcel}
342240116Smarcel
343240116Smarcelvoid
344240116Smarcelimpl::tc::require_errno(const char* file, const int line, const int exp_errno,
345240116Smarcel                        const char* expr_str, const bool result)
346240116Smarcel{
347240116Smarcel    atf_tc_require_errno(file, line, exp_errno, expr_str, result);
348240116Smarcel}
349240116Smarcel
350240116Smarcelvoid
351240116Smarcelimpl::tc::expect_pass(void)
352240116Smarcel{
353240116Smarcel    atf_tc_expect_pass();
354240116Smarcel}
355240116Smarcel
356240116Smarcelvoid
357240116Smarcelimpl::tc::expect_fail(const std::string& reason)
358240116Smarcel{
359240116Smarcel    atf_tc_expect_fail("%s", reason.c_str());
360240116Smarcel}
361240116Smarcel
362240116Smarcelvoid
363240116Smarcelimpl::tc::expect_exit(const int exitcode, const std::string& reason)
364240116Smarcel{
365240116Smarcel    atf_tc_expect_exit(exitcode, "%s", reason.c_str());
366240116Smarcel}
367240116Smarcel
368240116Smarcelvoid
369240116Smarcelimpl::tc::expect_signal(const int signo, const std::string& reason)
370240116Smarcel{
371240116Smarcel    atf_tc_expect_signal(signo, "%s", reason.c_str());
372240116Smarcel}
373240116Smarcel
374240116Smarcelvoid
375240116Smarcelimpl::tc::expect_death(const std::string& reason)
376240116Smarcel{
377240116Smarcel    atf_tc_expect_death("%s", reason.c_str());
378240116Smarcel}
379240116Smarcel
380240116Smarcelvoid
381240116Smarcelimpl::tc::expect_timeout(const std::string& reason)
382240116Smarcel{
383240116Smarcel    atf_tc_expect_timeout("%s", reason.c_str());
384240116Smarcel}
385240116Smarcel
386240116Smarcel// ------------------------------------------------------------------------
387240116Smarcel// The "tp" class.
388240116Smarcel// ------------------------------------------------------------------------
389240116Smarcel
390240116Smarcelclass tp : public atf::application::app {
391240116Smarcelpublic:
392240116Smarcel    typedef std::vector< impl::tc * > tc_vector;
393240116Smarcel
394240116Smarcelprivate:
395240116Smarcel    static const char* m_description;
396240116Smarcel
397240116Smarcel    bool m_lflag;
398240116Smarcel    atf::fs::path m_resfile;
399240116Smarcel    std::string m_srcdir_arg;
400240116Smarcel    atf::fs::path m_srcdir;
401240116Smarcel
402240116Smarcel    atf::tests::vars_map m_vars;
403240116Smarcel
404240116Smarcel    std::string specific_args(void) const;
405240116Smarcel    options_set specific_options(void) const;
406240116Smarcel    void process_option(int, const char*);
407240116Smarcel
408240116Smarcel    void (*m_add_tcs)(tc_vector&);
409240116Smarcel    tc_vector m_tcs;
410240116Smarcel
411240116Smarcel    void parse_vflag(const std::string&);
412240116Smarcel    void handle_srcdir(void);
413240116Smarcel
414240116Smarcel    tc_vector init_tcs(void);
415240116Smarcel
416240116Smarcel    enum tc_part {
417240116Smarcel        BODY,
418240116Smarcel        CLEANUP,
419240116Smarcel    };
420240116Smarcel
421240116Smarcel    void list_tcs(void);
422240116Smarcel    impl::tc* find_tc(tc_vector, const std::string&);
423240116Smarcel    static std::pair< std::string, tc_part > process_tcarg(const std::string&);
424240116Smarcel    int run_tc(const std::string&);
425240116Smarcel
426240116Smarcelpublic:
427240116Smarcel    tp(void (*)(tc_vector&));
428240116Smarcel    ~tp(void);
429240116Smarcel
430240116Smarcel    int main(void);
431240116Smarcel};
432240116Smarcel
433240116Smarcelconst char* tp::m_description =
434240116Smarcel    "This is an independent atf test program.";
435240116Smarcel
436240116Smarceltp::tp(void (*add_tcs)(tc_vector&)) :
437262855Sjmmv    app(m_description, "atf-test-program(1)"),
438240116Smarcel    m_lflag(false),
439240116Smarcel    m_resfile("/dev/stdout"),
440240116Smarcel    m_srcdir("."),
441240116Smarcel    m_add_tcs(add_tcs)
442240116Smarcel{
443240116Smarcel}
444240116Smarcel
445240116Smarceltp::~tp(void)
446240116Smarcel{
447240116Smarcel    for (tc_vector::iterator iter = m_tcs.begin();
448240116Smarcel         iter != m_tcs.end(); iter++) {
449240116Smarcel        impl::tc* tc = *iter;
450240116Smarcel
451240116Smarcel        delete tc;
452240116Smarcel    }
453240116Smarcel}
454240116Smarcel
455240116Smarcelstd::string
456240116Smarceltp::specific_args(void)
457240116Smarcel    const
458240116Smarcel{
459240116Smarcel    return "test_case";
460240116Smarcel}
461240116Smarcel
462240116Smarceltp::options_set
463240116Smarceltp::specific_options(void)
464240116Smarcel    const
465240116Smarcel{
466240116Smarcel    using atf::application::option;
467240116Smarcel    options_set opts;
468240116Smarcel    opts.insert(option('l', "", "List test cases and their purpose"));
469240116Smarcel    opts.insert(option('r', "resfile", "The file to which the test program "
470240116Smarcel                                       "will write the results of the "
471240116Smarcel                                       "executed test case"));
472240116Smarcel    opts.insert(option('s', "srcdir", "Directory where the test's data "
473240116Smarcel                                      "files are located"));
474240116Smarcel    opts.insert(option('v', "var=value", "Sets the configuration variable "
475240116Smarcel                                         "`var' to `value'"));
476240116Smarcel    return opts;
477240116Smarcel}
478240116Smarcel
479240116Smarcelvoid
480240116Smarceltp::process_option(int ch, const char* arg)
481240116Smarcel{
482240116Smarcel    switch (ch) {
483240116Smarcel    case 'l':
484240116Smarcel        m_lflag = true;
485240116Smarcel        break;
486240116Smarcel
487240116Smarcel    case 'r':
488240116Smarcel        m_resfile = atf::fs::path(arg);
489240116Smarcel        break;
490240116Smarcel
491240116Smarcel    case 's':
492240116Smarcel        m_srcdir_arg = arg;
493240116Smarcel        break;
494240116Smarcel
495240116Smarcel    case 'v':
496240116Smarcel        parse_vflag(arg);
497240116Smarcel        break;
498240116Smarcel
499240116Smarcel    default:
500240116Smarcel        UNREACHABLE;
501240116Smarcel    }
502240116Smarcel}
503240116Smarcel
504240116Smarcelvoid
505240116Smarceltp::parse_vflag(const std::string& str)
506240116Smarcel{
507240116Smarcel    if (str.empty())
508240116Smarcel        throw std::runtime_error("-v requires a non-empty argument");
509240116Smarcel
510240116Smarcel    std::vector< std::string > ws = atf::text::split(str, "=");
511240116Smarcel    if (ws.size() == 1 && str[str.length() - 1] == '=') {
512240116Smarcel        m_vars[ws[0]] = "";
513240116Smarcel    } else {
514240116Smarcel        if (ws.size() != 2)
515240116Smarcel            throw std::runtime_error("-v requires an argument of the form "
516240116Smarcel                                     "var=value");
517240116Smarcel
518240116Smarcel        m_vars[ws[0]] = ws[1];
519240116Smarcel    }
520240116Smarcel}
521240116Smarcel
522240116Smarcelvoid
523240116Smarceltp::handle_srcdir(void)
524240116Smarcel{
525240116Smarcel    if (m_srcdir_arg.empty()) {
526240116Smarcel        m_srcdir = atf::fs::path(m_argv0).branch_path();
527240116Smarcel        if (m_srcdir.leaf_name() == ".libs")
528240116Smarcel            m_srcdir = m_srcdir.branch_path();
529240116Smarcel    } else
530240116Smarcel        m_srcdir = atf::fs::path(m_srcdir_arg);
531240116Smarcel
532240116Smarcel    if (!atf::fs::exists(m_srcdir / m_prog_name))
533240116Smarcel        throw std::runtime_error("Cannot find the test program in the "
534240116Smarcel                                 "source directory `" + m_srcdir.str() + "'");
535240116Smarcel
536240116Smarcel    if (!m_srcdir.is_absolute())
537240116Smarcel        m_srcdir = m_srcdir.to_absolute();
538240116Smarcel
539240116Smarcel    m_vars["srcdir"] = m_srcdir.str();
540240116Smarcel}
541240116Smarcel
542240116Smarceltp::tc_vector
543240116Smarceltp::init_tcs(void)
544240116Smarcel{
545240116Smarcel    m_add_tcs(m_tcs);
546240116Smarcel    for (tc_vector::iterator iter = m_tcs.begin();
547240116Smarcel         iter != m_tcs.end(); iter++) {
548240116Smarcel        impl::tc* tc = *iter;
549240116Smarcel
550240116Smarcel        tc->init(m_vars);
551240116Smarcel    }
552240116Smarcel    return m_tcs;
553240116Smarcel}
554240116Smarcel
555240116Smarcel//
556240116Smarcel// An auxiliary unary predicate that compares the given test case's
557240116Smarcel// identifier to the identifier stored in it.
558240116Smarcel//
559240116Smarcelclass tc_equal_to_ident {
560240116Smarcel    const std::string& m_ident;
561240116Smarcel
562240116Smarcelpublic:
563240116Smarcel    tc_equal_to_ident(const std::string& i) :
564240116Smarcel        m_ident(i)
565240116Smarcel    {
566240116Smarcel    }
567240116Smarcel
568240116Smarcel    bool operator()(const impl::tc* tc)
569240116Smarcel    {
570240116Smarcel        return tc->get_md_var("ident") == m_ident;
571240116Smarcel    }
572240116Smarcel};
573240116Smarcel
574240116Smarcelvoid
575240116Smarceltp::list_tcs(void)
576240116Smarcel{
577240116Smarcel    tc_vector tcs = init_tcs();
578240116Smarcel    detail::atf_tp_writer writer(std::cout);
579240116Smarcel
580240116Smarcel    for (tc_vector::const_iterator iter = tcs.begin();
581240116Smarcel         iter != tcs.end(); iter++) {
582240116Smarcel        const impl::vars_map vars = (*iter)->get_md_vars();
583240116Smarcel
584240116Smarcel        {
585240116Smarcel            impl::vars_map::const_iterator iter2 = vars.find("ident");
586240116Smarcel            INV(iter2 != vars.end());
587240116Smarcel            writer.start_tc((*iter2).second);
588240116Smarcel        }
589240116Smarcel
590240116Smarcel        for (impl::vars_map::const_iterator iter2 = vars.begin();
591240116Smarcel             iter2 != vars.end(); iter2++) {
592240116Smarcel            const std::string& key = (*iter2).first;
593240116Smarcel            if (key != "ident")
594240116Smarcel                writer.tc_meta_data(key, (*iter2).second);
595240116Smarcel        }
596240116Smarcel
597240116Smarcel        writer.end_tc();
598240116Smarcel    }
599240116Smarcel}
600240116Smarcel
601240116Smarcelimpl::tc*
602240116Smarceltp::find_tc(tc_vector tcs, const std::string& name)
603240116Smarcel{
604240116Smarcel    std::vector< std::string > ids;
605240116Smarcel    for (tc_vector::iterator iter = tcs.begin();
606240116Smarcel         iter != tcs.end(); iter++) {
607240116Smarcel        impl::tc* tc = *iter;
608240116Smarcel
609240116Smarcel        if (tc->get_md_var("ident") == name)
610240116Smarcel            return tc;
611240116Smarcel    }
612240116Smarcel    throw atf::application::usage_error("Unknown test case `%s'",
613240116Smarcel                                        name.c_str());
614240116Smarcel}
615240116Smarcel
616240116Smarcelstd::pair< std::string, tp::tc_part >
617240116Smarceltp::process_tcarg(const std::string& tcarg)
618240116Smarcel{
619240116Smarcel    const std::string::size_type pos = tcarg.find(':');
620240116Smarcel    if (pos == std::string::npos) {
621240116Smarcel        return std::make_pair(tcarg, BODY);
622240116Smarcel    } else {
623240116Smarcel        const std::string tcname = tcarg.substr(0, pos);
624240116Smarcel
625240116Smarcel        const std::string partname = tcarg.substr(pos + 1);
626240116Smarcel        if (partname == "body")
627240116Smarcel            return std::make_pair(tcname, BODY);
628240116Smarcel        else if (partname == "cleanup")
629240116Smarcel            return std::make_pair(tcname, CLEANUP);
630240116Smarcel        else {
631240116Smarcel            using atf::application::usage_error;
632240116Smarcel            throw usage_error("Invalid test case part `%s'", partname.c_str());
633240116Smarcel        }
634240116Smarcel    }
635240116Smarcel}
636240116Smarcel
637240116Smarcelint
638240116Smarceltp::run_tc(const std::string& tcarg)
639240116Smarcel{
640240116Smarcel    const std::pair< std::string, tc_part > fields = process_tcarg(tcarg);
641240116Smarcel
642240116Smarcel    impl::tc* tc = find_tc(init_tcs(), fields.first);
643240116Smarcel
644240116Smarcel    if (!atf::env::has("__RUNNING_INSIDE_ATF_RUN") || atf::env::get(
645240116Smarcel        "__RUNNING_INSIDE_ATF_RUN") != "internal-yes-value")
646240116Smarcel    {
647240116Smarcel        std::cerr << m_prog_name << ": WARNING: Running test cases without "
648240116Smarcel            "atf-run(1) is unsupported\n";
649240116Smarcel        std::cerr << m_prog_name << ": WARNING: No isolation nor timeout "
650240116Smarcel            "control is being applied; you may get unexpected failures; see "
651240116Smarcel            "atf-test-case(4)\n";
652240116Smarcel    }
653240116Smarcel
654240116Smarcel    try {
655240116Smarcel        switch (fields.second) {
656240116Smarcel        case BODY:
657240116Smarcel            tc->run(m_resfile.str());
658240116Smarcel            break;
659240116Smarcel        case CLEANUP:
660240116Smarcel            tc->run_cleanup();
661240116Smarcel            break;
662240116Smarcel        default:
663240116Smarcel            UNREACHABLE;
664240116Smarcel        }
665240116Smarcel        return EXIT_SUCCESS;
666240116Smarcel    } catch (const std::runtime_error& e) {
667240116Smarcel        std::cerr << "ERROR: " << e.what() << "\n";
668240116Smarcel        return EXIT_FAILURE;
669240116Smarcel    }
670240116Smarcel}
671240116Smarcel
672240116Smarcelint
673240116Smarceltp::main(void)
674240116Smarcel{
675240116Smarcel    using atf::application::usage_error;
676240116Smarcel
677240116Smarcel    int errcode;
678240116Smarcel
679240116Smarcel    handle_srcdir();
680240116Smarcel
681240116Smarcel    if (m_lflag) {
682240116Smarcel        if (m_argc > 0)
683240116Smarcel            throw usage_error("Cannot provide test case names with -l");
684240116Smarcel
685240116Smarcel        list_tcs();
686240116Smarcel        errcode = EXIT_SUCCESS;
687240116Smarcel    } else {
688240116Smarcel        if (m_argc == 0)
689240116Smarcel            throw usage_error("Must provide a test case name");
690240116Smarcel        else if (m_argc > 1)
691240116Smarcel            throw usage_error("Cannot provide more than one test case name");
692240116Smarcel        INV(m_argc == 1);
693240116Smarcel
694240116Smarcel        errcode = run_tc(m_argv[0]);
695240116Smarcel    }
696240116Smarcel
697240116Smarcel    return errcode;
698240116Smarcel}
699240116Smarcel
700240116Smarcelnamespace atf {
701240116Smarcel    namespace tests {
702240116Smarcel        int run_tp(int, char* const*, void (*)(tp::tc_vector&));
703240116Smarcel    }
704240116Smarcel}
705240116Smarcel
706240116Smarcelint
707240116Smarcelimpl::run_tp(int argc, char* const* argv, void (*add_tcs)(tp::tc_vector&))
708240116Smarcel{
709240116Smarcel    return tp(add_tcs).run(argc, argv);
710240116Smarcel}
711