1*00b67f09SDavid van Moolenbroek //
2*00b67f09SDavid van Moolenbroek // Automated Testing Framework (atf)
3*00b67f09SDavid van Moolenbroek //
4*00b67f09SDavid van Moolenbroek // Copyright (c) 2007 The NetBSD Foundation, Inc.
5*00b67f09SDavid van Moolenbroek // All rights reserved.
6*00b67f09SDavid van Moolenbroek //
7*00b67f09SDavid van Moolenbroek // Redistribution and use in source and binary forms, with or without
8*00b67f09SDavid van Moolenbroek // modification, are permitted provided that the following conditions
9*00b67f09SDavid van Moolenbroek // are met:
10*00b67f09SDavid van Moolenbroek // 1. Redistributions of source code must retain the above copyright
11*00b67f09SDavid van Moolenbroek //    notice, this list of conditions and the following disclaimer.
12*00b67f09SDavid van Moolenbroek // 2. Redistributions in binary form must reproduce the above copyright
13*00b67f09SDavid van Moolenbroek //    notice, this list of conditions and the following disclaimer in the
14*00b67f09SDavid van Moolenbroek //    documentation and/or other materials provided with the distribution.
15*00b67f09SDavid van Moolenbroek //
16*00b67f09SDavid van Moolenbroek // THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND
17*00b67f09SDavid van Moolenbroek // CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
18*00b67f09SDavid van Moolenbroek // INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
19*00b67f09SDavid van Moolenbroek // MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
20*00b67f09SDavid van Moolenbroek // IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS BE LIABLE FOR ANY
21*00b67f09SDavid van Moolenbroek // DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22*00b67f09SDavid van Moolenbroek // DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
23*00b67f09SDavid van Moolenbroek // GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
24*00b67f09SDavid van Moolenbroek // INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
25*00b67f09SDavid van Moolenbroek // IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
26*00b67f09SDavid van Moolenbroek // OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
27*00b67f09SDavid van Moolenbroek // IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28*00b67f09SDavid van Moolenbroek //
29*00b67f09SDavid van Moolenbroek 
30*00b67f09SDavid van Moolenbroek extern "C" {
31*00b67f09SDavid van Moolenbroek #include <sys/types.h>
32*00b67f09SDavid van Moolenbroek #include <sys/stat.h>
33*00b67f09SDavid van Moolenbroek #include <sys/time.h>
34*00b67f09SDavid van Moolenbroek #include <sys/wait.h>
35*00b67f09SDavid van Moolenbroek #include <signal.h>
36*00b67f09SDavid van Moolenbroek #include <unistd.h>
37*00b67f09SDavid van Moolenbroek }
38*00b67f09SDavid van Moolenbroek 
39*00b67f09SDavid van Moolenbroek #include <algorithm>
40*00b67f09SDavid van Moolenbroek #include <cctype>
41*00b67f09SDavid van Moolenbroek #include <cerrno>
42*00b67f09SDavid van Moolenbroek #include <cstdlib>
43*00b67f09SDavid van Moolenbroek #include <cstring>
44*00b67f09SDavid van Moolenbroek #include <fstream>
45*00b67f09SDavid van Moolenbroek #include <iostream>
46*00b67f09SDavid van Moolenbroek #include <map>
47*00b67f09SDavid van Moolenbroek #include <memory>
48*00b67f09SDavid van Moolenbroek #include <sstream>
49*00b67f09SDavid van Moolenbroek #include <stdexcept>
50*00b67f09SDavid van Moolenbroek #include <vector>
51*00b67f09SDavid van Moolenbroek 
52*00b67f09SDavid van Moolenbroek extern "C" {
53*00b67f09SDavid van Moolenbroek #include "atf-c/error.h"
54*00b67f09SDavid van Moolenbroek #include "atf-c/tc.h"
55*00b67f09SDavid van Moolenbroek #include "atf-c/utils.h"
56*00b67f09SDavid van Moolenbroek }
57*00b67f09SDavid van Moolenbroek 
58*00b67f09SDavid van Moolenbroek #include "noncopyable.hpp"
59*00b67f09SDavid van Moolenbroek #include "tests.hpp"
60*00b67f09SDavid van Moolenbroek 
61*00b67f09SDavid van Moolenbroek #include "detail/application.hpp"
62*00b67f09SDavid van Moolenbroek #include "detail/auto_array.hpp"
63*00b67f09SDavid van Moolenbroek #include "detail/env.hpp"
64*00b67f09SDavid van Moolenbroek #include "detail/exceptions.hpp"
65*00b67f09SDavid van Moolenbroek #include "detail/fs.hpp"
66*00b67f09SDavid van Moolenbroek #include "detail/parser.hpp"
67*00b67f09SDavid van Moolenbroek #include "detail/sanity.hpp"
68*00b67f09SDavid van Moolenbroek #include "detail/text.hpp"
69*00b67f09SDavid van Moolenbroek 
70*00b67f09SDavid van Moolenbroek namespace impl = atf::tests;
71*00b67f09SDavid van Moolenbroek namespace detail = atf::tests::detail;
72*00b67f09SDavid van Moolenbroek #define IMPL_NAME "atf::tests"
73*00b67f09SDavid van Moolenbroek 
74*00b67f09SDavid van Moolenbroek // ------------------------------------------------------------------------
75*00b67f09SDavid van Moolenbroek // The "atf_tp_writer" class.
76*00b67f09SDavid van Moolenbroek // ------------------------------------------------------------------------
77*00b67f09SDavid van Moolenbroek 
atf_tp_writer(std::ostream & os)78*00b67f09SDavid van Moolenbroek detail::atf_tp_writer::atf_tp_writer(std::ostream& os) :
79*00b67f09SDavid van Moolenbroek     m_os(os),
80*00b67f09SDavid van Moolenbroek     m_is_first(true)
81*00b67f09SDavid van Moolenbroek {
82*00b67f09SDavid van Moolenbroek     atf::parser::headers_map hm;
83*00b67f09SDavid van Moolenbroek     atf::parser::attrs_map ct_attrs;
84*00b67f09SDavid van Moolenbroek     ct_attrs["version"] = "1";
85*00b67f09SDavid van Moolenbroek     hm["Content-Type"] = atf::parser::header_entry("Content-Type",
86*00b67f09SDavid van Moolenbroek         "application/X-atf-tp", ct_attrs);
87*00b67f09SDavid van Moolenbroek     atf::parser::write_headers(hm, m_os);
88*00b67f09SDavid van Moolenbroek }
89*00b67f09SDavid van Moolenbroek 
90*00b67f09SDavid van Moolenbroek void
start_tc(const std::string & ident)91*00b67f09SDavid van Moolenbroek detail::atf_tp_writer::start_tc(const std::string& ident)
92*00b67f09SDavid van Moolenbroek {
93*00b67f09SDavid van Moolenbroek     if (!m_is_first)
94*00b67f09SDavid van Moolenbroek         m_os << "\n";
95*00b67f09SDavid van Moolenbroek     m_os << "ident: " << ident << "\n";
96*00b67f09SDavid van Moolenbroek     m_os.flush();
97*00b67f09SDavid van Moolenbroek }
98*00b67f09SDavid van Moolenbroek 
99*00b67f09SDavid van Moolenbroek void
end_tc(void)100*00b67f09SDavid van Moolenbroek detail::atf_tp_writer::end_tc(void)
101*00b67f09SDavid van Moolenbroek {
102*00b67f09SDavid van Moolenbroek     if (m_is_first)
103*00b67f09SDavid van Moolenbroek         m_is_first = false;
104*00b67f09SDavid van Moolenbroek }
105*00b67f09SDavid van Moolenbroek 
106*00b67f09SDavid van Moolenbroek void
tc_meta_data(const std::string & name,const std::string & value)107*00b67f09SDavid van Moolenbroek detail::atf_tp_writer::tc_meta_data(const std::string& name,
108*00b67f09SDavid van Moolenbroek                                     const std::string& value)
109*00b67f09SDavid van Moolenbroek {
110*00b67f09SDavid van Moolenbroek     PRE(name != "ident");
111*00b67f09SDavid van Moolenbroek     m_os << name << ": " << value << "\n";
112*00b67f09SDavid van Moolenbroek     m_os.flush();
113*00b67f09SDavid van Moolenbroek }
114*00b67f09SDavid van Moolenbroek 
115*00b67f09SDavid van Moolenbroek // ------------------------------------------------------------------------
116*00b67f09SDavid van Moolenbroek // Free helper functions.
117*00b67f09SDavid van Moolenbroek // ------------------------------------------------------------------------
118*00b67f09SDavid van Moolenbroek 
119*00b67f09SDavid van Moolenbroek bool
match(const std::string & regexp,const std::string & str)120*00b67f09SDavid van Moolenbroek detail::match(const std::string& regexp, const std::string& str)
121*00b67f09SDavid van Moolenbroek {
122*00b67f09SDavid van Moolenbroek     return atf::text::match(str, regexp);
123*00b67f09SDavid van Moolenbroek }
124*00b67f09SDavid van Moolenbroek 
125*00b67f09SDavid van Moolenbroek // ------------------------------------------------------------------------
126*00b67f09SDavid van Moolenbroek // The "tc" class.
127*00b67f09SDavid van Moolenbroek // ------------------------------------------------------------------------
128*00b67f09SDavid van Moolenbroek 
129*00b67f09SDavid van Moolenbroek static std::map< atf_tc_t*, impl::tc* > wraps;
130*00b67f09SDavid van Moolenbroek static std::map< const atf_tc_t*, const impl::tc* > cwraps;
131*00b67f09SDavid van Moolenbroek 
132*00b67f09SDavid van Moolenbroek struct impl::tc_impl : atf::noncopyable {
133*00b67f09SDavid van Moolenbroek     std::string m_ident;
134*00b67f09SDavid van Moolenbroek     atf_tc_t m_tc;
135*00b67f09SDavid van Moolenbroek     bool m_has_cleanup;
136*00b67f09SDavid van Moolenbroek 
tc_implimpl::tc_impl137*00b67f09SDavid van Moolenbroek     tc_impl(const std::string& ident, const bool has_cleanup) :
138*00b67f09SDavid van Moolenbroek         m_ident(ident),
139*00b67f09SDavid van Moolenbroek         m_has_cleanup(has_cleanup)
140*00b67f09SDavid van Moolenbroek     {
141*00b67f09SDavid van Moolenbroek     }
142*00b67f09SDavid van Moolenbroek 
143*00b67f09SDavid van Moolenbroek     static void
wrap_headimpl::tc_impl144*00b67f09SDavid van Moolenbroek     wrap_head(atf_tc_t *tc)
145*00b67f09SDavid van Moolenbroek     {
146*00b67f09SDavid van Moolenbroek         std::map< atf_tc_t*, impl::tc* >::iterator iter = wraps.find(tc);
147*00b67f09SDavid van Moolenbroek         INV(iter != wraps.end());
148*00b67f09SDavid van Moolenbroek         (*iter).second->head();
149*00b67f09SDavid van Moolenbroek     }
150*00b67f09SDavid van Moolenbroek 
151*00b67f09SDavid van Moolenbroek     static void
wrap_bodyimpl::tc_impl152*00b67f09SDavid van Moolenbroek     wrap_body(const atf_tc_t *tc)
153*00b67f09SDavid van Moolenbroek     {
154*00b67f09SDavid van Moolenbroek         std::map< const atf_tc_t*, const impl::tc* >::const_iterator iter =
155*00b67f09SDavid van Moolenbroek             cwraps.find(tc);
156*00b67f09SDavid van Moolenbroek         INV(iter != cwraps.end());
157*00b67f09SDavid van Moolenbroek         try {
158*00b67f09SDavid van Moolenbroek             (*iter).second->body();
159*00b67f09SDavid van Moolenbroek         } catch (const std::exception& e) {
160*00b67f09SDavid van Moolenbroek             (*iter).second->fail("Caught unhandled exception: " + std::string(
161*00b67f09SDavid van Moolenbroek                                      e.what()));
162*00b67f09SDavid van Moolenbroek         } catch (...) {
163*00b67f09SDavid van Moolenbroek             (*iter).second->fail("Caught unknown exception");
164*00b67f09SDavid van Moolenbroek         }
165*00b67f09SDavid van Moolenbroek     }
166*00b67f09SDavid van Moolenbroek 
167*00b67f09SDavid van Moolenbroek     static void
wrap_cleanupimpl::tc_impl168*00b67f09SDavid van Moolenbroek     wrap_cleanup(const atf_tc_t *tc)
169*00b67f09SDavid van Moolenbroek     {
170*00b67f09SDavid van Moolenbroek         std::map< const atf_tc_t*, const impl::tc* >::const_iterator iter =
171*00b67f09SDavid van Moolenbroek             cwraps.find(tc);
172*00b67f09SDavid van Moolenbroek         INV(iter != cwraps.end());
173*00b67f09SDavid van Moolenbroek         (*iter).second->cleanup();
174*00b67f09SDavid van Moolenbroek     }
175*00b67f09SDavid van Moolenbroek };
176*00b67f09SDavid van Moolenbroek 
tc(const std::string & ident,const bool has_cleanup)177*00b67f09SDavid van Moolenbroek impl::tc::tc(const std::string& ident, const bool has_cleanup) :
178*00b67f09SDavid van Moolenbroek     pimpl(new tc_impl(ident, has_cleanup))
179*00b67f09SDavid van Moolenbroek {
180*00b67f09SDavid van Moolenbroek }
181*00b67f09SDavid van Moolenbroek 
~tc(void)182*00b67f09SDavid van Moolenbroek impl::tc::~tc(void)
183*00b67f09SDavid van Moolenbroek {
184*00b67f09SDavid van Moolenbroek     cwraps.erase(&pimpl->m_tc);
185*00b67f09SDavid van Moolenbroek     wraps.erase(&pimpl->m_tc);
186*00b67f09SDavid van Moolenbroek 
187*00b67f09SDavid van Moolenbroek     atf_tc_fini(&pimpl->m_tc);
188*00b67f09SDavid van Moolenbroek }
189*00b67f09SDavid van Moolenbroek 
190*00b67f09SDavid van Moolenbroek void
init(const vars_map & config)191*00b67f09SDavid van Moolenbroek impl::tc::init(const vars_map& config)
192*00b67f09SDavid van Moolenbroek {
193*00b67f09SDavid van Moolenbroek     atf_error_t err;
194*00b67f09SDavid van Moolenbroek 
195*00b67f09SDavid van Moolenbroek     auto_array< const char * > array(new const char*[(config.size() * 2) + 1]);
196*00b67f09SDavid van Moolenbroek     const char **ptr = array.get();
197*00b67f09SDavid van Moolenbroek     for (vars_map::const_iterator iter = config.begin();
198*00b67f09SDavid van Moolenbroek          iter != config.end(); iter++) {
199*00b67f09SDavid van Moolenbroek          *ptr = (*iter).first.c_str();
200*00b67f09SDavid van Moolenbroek          *(ptr + 1) = (*iter).second.c_str();
201*00b67f09SDavid van Moolenbroek          ptr += 2;
202*00b67f09SDavid van Moolenbroek     }
203*00b67f09SDavid van Moolenbroek     *ptr = NULL;
204*00b67f09SDavid van Moolenbroek 
205*00b67f09SDavid van Moolenbroek     wraps[&pimpl->m_tc] = this;
206*00b67f09SDavid van Moolenbroek     cwraps[&pimpl->m_tc] = this;
207*00b67f09SDavid van Moolenbroek 
208*00b67f09SDavid van Moolenbroek     err = atf_tc_init(&pimpl->m_tc, pimpl->m_ident.c_str(), pimpl->wrap_head,
209*00b67f09SDavid van Moolenbroek         pimpl->wrap_body, pimpl->m_has_cleanup ? pimpl->wrap_cleanup : NULL,
210*00b67f09SDavid van Moolenbroek         array.get());
211*00b67f09SDavid van Moolenbroek     if (atf_is_error(err))
212*00b67f09SDavid van Moolenbroek         throw_atf_error(err);
213*00b67f09SDavid van Moolenbroek }
214*00b67f09SDavid van Moolenbroek 
215*00b67f09SDavid van Moolenbroek bool
has_config_var(const std::string & var) const216*00b67f09SDavid van Moolenbroek impl::tc::has_config_var(const std::string& var)
217*00b67f09SDavid van Moolenbroek     const
218*00b67f09SDavid van Moolenbroek {
219*00b67f09SDavid van Moolenbroek     return atf_tc_has_config_var(&pimpl->m_tc, var.c_str());
220*00b67f09SDavid van Moolenbroek }
221*00b67f09SDavid van Moolenbroek 
222*00b67f09SDavid van Moolenbroek bool
has_md_var(const std::string & var) const223*00b67f09SDavid van Moolenbroek impl::tc::has_md_var(const std::string& var)
224*00b67f09SDavid van Moolenbroek     const
225*00b67f09SDavid van Moolenbroek {
226*00b67f09SDavid van Moolenbroek     return atf_tc_has_md_var(&pimpl->m_tc, var.c_str());
227*00b67f09SDavid van Moolenbroek }
228*00b67f09SDavid van Moolenbroek 
229*00b67f09SDavid van Moolenbroek const std::string
get_config_var(const std::string & var) const230*00b67f09SDavid van Moolenbroek impl::tc::get_config_var(const std::string& var)
231*00b67f09SDavid van Moolenbroek     const
232*00b67f09SDavid van Moolenbroek {
233*00b67f09SDavid van Moolenbroek     return atf_tc_get_config_var(&pimpl->m_tc, var.c_str());
234*00b67f09SDavid van Moolenbroek }
235*00b67f09SDavid van Moolenbroek 
236*00b67f09SDavid van Moolenbroek const std::string
get_config_var(const std::string & var,const std::string & defval) const237*00b67f09SDavid van Moolenbroek impl::tc::get_config_var(const std::string& var, const std::string& defval)
238*00b67f09SDavid van Moolenbroek     const
239*00b67f09SDavid van Moolenbroek {
240*00b67f09SDavid van Moolenbroek     return atf_tc_get_config_var_wd(&pimpl->m_tc, var.c_str(), defval.c_str());
241*00b67f09SDavid van Moolenbroek }
242*00b67f09SDavid van Moolenbroek 
243*00b67f09SDavid van Moolenbroek const std::string
get_md_var(const std::string & var) const244*00b67f09SDavid van Moolenbroek impl::tc::get_md_var(const std::string& var)
245*00b67f09SDavid van Moolenbroek     const
246*00b67f09SDavid van Moolenbroek {
247*00b67f09SDavid van Moolenbroek     return atf_tc_get_md_var(&pimpl->m_tc, var.c_str());
248*00b67f09SDavid van Moolenbroek }
249*00b67f09SDavid van Moolenbroek 
250*00b67f09SDavid van Moolenbroek const impl::vars_map
get_md_vars(void) const251*00b67f09SDavid van Moolenbroek impl::tc::get_md_vars(void)
252*00b67f09SDavid van Moolenbroek     const
253*00b67f09SDavid van Moolenbroek {
254*00b67f09SDavid van Moolenbroek     vars_map vars;
255*00b67f09SDavid van Moolenbroek 
256*00b67f09SDavid van Moolenbroek     char **array = atf_tc_get_md_vars(&pimpl->m_tc);
257*00b67f09SDavid van Moolenbroek     try {
258*00b67f09SDavid van Moolenbroek         char **ptr;
259*00b67f09SDavid van Moolenbroek         for (ptr = array; *ptr != NULL; ptr += 2)
260*00b67f09SDavid van Moolenbroek             vars[*ptr] = *(ptr + 1);
261*00b67f09SDavid van Moolenbroek     } catch (...) {
262*00b67f09SDavid van Moolenbroek         atf_utils_free_charpp(array);
263*00b67f09SDavid van Moolenbroek         throw;
264*00b67f09SDavid van Moolenbroek     }
265*00b67f09SDavid van Moolenbroek 
266*00b67f09SDavid van Moolenbroek     return vars;
267*00b67f09SDavid van Moolenbroek }
268*00b67f09SDavid van Moolenbroek 
269*00b67f09SDavid van Moolenbroek void
set_md_var(const std::string & var,const std::string & val)270*00b67f09SDavid van Moolenbroek impl::tc::set_md_var(const std::string& var, const std::string& val)
271*00b67f09SDavid van Moolenbroek {
272*00b67f09SDavid van Moolenbroek     atf_error_t err = atf_tc_set_md_var(&pimpl->m_tc, var.c_str(), val.c_str());
273*00b67f09SDavid van Moolenbroek     if (atf_is_error(err))
274*00b67f09SDavid van Moolenbroek         throw_atf_error(err);
275*00b67f09SDavid van Moolenbroek }
276*00b67f09SDavid van Moolenbroek 
277*00b67f09SDavid van Moolenbroek void
run(const std::string & resfile) const278*00b67f09SDavid van Moolenbroek impl::tc::run(const std::string& resfile)
279*00b67f09SDavid van Moolenbroek     const
280*00b67f09SDavid van Moolenbroek {
281*00b67f09SDavid van Moolenbroek     atf_error_t err = atf_tc_run(&pimpl->m_tc, resfile.c_str());
282*00b67f09SDavid van Moolenbroek     if (atf_is_error(err))
283*00b67f09SDavid van Moolenbroek         throw_atf_error(err);
284*00b67f09SDavid van Moolenbroek }
285*00b67f09SDavid van Moolenbroek 
286*00b67f09SDavid van Moolenbroek void
run_cleanup(void) const287*00b67f09SDavid van Moolenbroek impl::tc::run_cleanup(void)
288*00b67f09SDavid van Moolenbroek     const
289*00b67f09SDavid van Moolenbroek {
290*00b67f09SDavid van Moolenbroek     atf_error_t err = atf_tc_cleanup(&pimpl->m_tc);
291*00b67f09SDavid van Moolenbroek     if (atf_is_error(err))
292*00b67f09SDavid van Moolenbroek         throw_atf_error(err);
293*00b67f09SDavid van Moolenbroek }
294*00b67f09SDavid van Moolenbroek 
295*00b67f09SDavid van Moolenbroek void
head(void)296*00b67f09SDavid van Moolenbroek impl::tc::head(void)
297*00b67f09SDavid van Moolenbroek {
298*00b67f09SDavid van Moolenbroek }
299*00b67f09SDavid van Moolenbroek 
300*00b67f09SDavid van Moolenbroek void
cleanup(void) const301*00b67f09SDavid van Moolenbroek impl::tc::cleanup(void)
302*00b67f09SDavid van Moolenbroek     const
303*00b67f09SDavid van Moolenbroek {
304*00b67f09SDavid van Moolenbroek }
305*00b67f09SDavid van Moolenbroek 
306*00b67f09SDavid van Moolenbroek void
require_prog(const std::string & prog) const307*00b67f09SDavid van Moolenbroek impl::tc::require_prog(const std::string& prog)
308*00b67f09SDavid van Moolenbroek     const
309*00b67f09SDavid van Moolenbroek {
310*00b67f09SDavid van Moolenbroek     atf_tc_require_prog(prog.c_str());
311*00b67f09SDavid van Moolenbroek }
312*00b67f09SDavid van Moolenbroek 
313*00b67f09SDavid van Moolenbroek void
pass(void)314*00b67f09SDavid van Moolenbroek impl::tc::pass(void)
315*00b67f09SDavid van Moolenbroek {
316*00b67f09SDavid van Moolenbroek     atf_tc_pass();
317*00b67f09SDavid van Moolenbroek }
318*00b67f09SDavid van Moolenbroek 
319*00b67f09SDavid van Moolenbroek void
fail(const std::string & reason)320*00b67f09SDavid van Moolenbroek impl::tc::fail(const std::string& reason)
321*00b67f09SDavid van Moolenbroek {
322*00b67f09SDavid van Moolenbroek     atf_tc_fail("%s", reason.c_str());
323*00b67f09SDavid van Moolenbroek }
324*00b67f09SDavid van Moolenbroek 
325*00b67f09SDavid van Moolenbroek void
fail_nonfatal(const std::string & reason)326*00b67f09SDavid van Moolenbroek impl::tc::fail_nonfatal(const std::string& reason)
327*00b67f09SDavid van Moolenbroek {
328*00b67f09SDavid van Moolenbroek     atf_tc_fail_nonfatal("%s", reason.c_str());
329*00b67f09SDavid van Moolenbroek }
330*00b67f09SDavid van Moolenbroek 
331*00b67f09SDavid van Moolenbroek void
skip(const std::string & reason)332*00b67f09SDavid van Moolenbroek impl::tc::skip(const std::string& reason)
333*00b67f09SDavid van Moolenbroek {
334*00b67f09SDavid van Moolenbroek     atf_tc_skip("%s", reason.c_str());
335*00b67f09SDavid van Moolenbroek }
336*00b67f09SDavid van Moolenbroek 
337*00b67f09SDavid van Moolenbroek void
check_errno(const char * file,const int line,const int exp_errno,const char * expr_str,const bool result)338*00b67f09SDavid van Moolenbroek impl::tc::check_errno(const char* file, const int line, const int exp_errno,
339*00b67f09SDavid van Moolenbroek                       const char* expr_str, const bool result)
340*00b67f09SDavid van Moolenbroek {
341*00b67f09SDavid van Moolenbroek     atf_tc_check_errno(file, line, exp_errno, expr_str, result);
342*00b67f09SDavid van Moolenbroek }
343*00b67f09SDavid van Moolenbroek 
344*00b67f09SDavid van Moolenbroek void
require_errno(const char * file,const int line,const int exp_errno,const char * expr_str,const bool result)345*00b67f09SDavid van Moolenbroek impl::tc::require_errno(const char* file, const int line, const int exp_errno,
346*00b67f09SDavid van Moolenbroek                         const char* expr_str, const bool result)
347*00b67f09SDavid van Moolenbroek {
348*00b67f09SDavid van Moolenbroek     atf_tc_require_errno(file, line, exp_errno, expr_str, result);
349*00b67f09SDavid van Moolenbroek }
350*00b67f09SDavid van Moolenbroek 
351*00b67f09SDavid van Moolenbroek void
expect_pass(void)352*00b67f09SDavid van Moolenbroek impl::tc::expect_pass(void)
353*00b67f09SDavid van Moolenbroek {
354*00b67f09SDavid van Moolenbroek     atf_tc_expect_pass();
355*00b67f09SDavid van Moolenbroek }
356*00b67f09SDavid van Moolenbroek 
357*00b67f09SDavid van Moolenbroek void
expect_fail(const std::string & reason)358*00b67f09SDavid van Moolenbroek impl::tc::expect_fail(const std::string& reason)
359*00b67f09SDavid van Moolenbroek {
360*00b67f09SDavid van Moolenbroek     atf_tc_expect_fail("%s", reason.c_str());
361*00b67f09SDavid van Moolenbroek }
362*00b67f09SDavid van Moolenbroek 
363*00b67f09SDavid van Moolenbroek void
expect_exit(const int exitcode,const std::string & reason)364*00b67f09SDavid van Moolenbroek impl::tc::expect_exit(const int exitcode, const std::string& reason)
365*00b67f09SDavid van Moolenbroek {
366*00b67f09SDavid van Moolenbroek     atf_tc_expect_exit(exitcode, "%s", reason.c_str());
367*00b67f09SDavid van Moolenbroek }
368*00b67f09SDavid van Moolenbroek 
369*00b67f09SDavid van Moolenbroek void
expect_signal(const int signo,const std::string & reason)370*00b67f09SDavid van Moolenbroek impl::tc::expect_signal(const int signo, const std::string& reason)
371*00b67f09SDavid van Moolenbroek {
372*00b67f09SDavid van Moolenbroek     atf_tc_expect_signal(signo, "%s", reason.c_str());
373*00b67f09SDavid van Moolenbroek }
374*00b67f09SDavid van Moolenbroek 
375*00b67f09SDavid van Moolenbroek void
expect_death(const std::string & reason)376*00b67f09SDavid van Moolenbroek impl::tc::expect_death(const std::string& reason)
377*00b67f09SDavid van Moolenbroek {
378*00b67f09SDavid van Moolenbroek     atf_tc_expect_death("%s", reason.c_str());
379*00b67f09SDavid van Moolenbroek }
380*00b67f09SDavid van Moolenbroek 
381*00b67f09SDavid van Moolenbroek void
expect_timeout(const std::string & reason)382*00b67f09SDavid van Moolenbroek impl::tc::expect_timeout(const std::string& reason)
383*00b67f09SDavid van Moolenbroek {
384*00b67f09SDavid van Moolenbroek     atf_tc_expect_timeout("%s", reason.c_str());
385*00b67f09SDavid van Moolenbroek }
386*00b67f09SDavid van Moolenbroek 
387*00b67f09SDavid van Moolenbroek // ------------------------------------------------------------------------
388*00b67f09SDavid van Moolenbroek // The "tp" class.
389*00b67f09SDavid van Moolenbroek // ------------------------------------------------------------------------
390*00b67f09SDavid van Moolenbroek 
391*00b67f09SDavid van Moolenbroek class tp : public atf::application::app {
392*00b67f09SDavid van Moolenbroek public:
393*00b67f09SDavid van Moolenbroek     typedef std::vector< impl::tc * > tc_vector;
394*00b67f09SDavid van Moolenbroek 
395*00b67f09SDavid van Moolenbroek private:
396*00b67f09SDavid van Moolenbroek     static const char* m_description;
397*00b67f09SDavid van Moolenbroek 
398*00b67f09SDavid van Moolenbroek     bool m_lflag;
399*00b67f09SDavid van Moolenbroek     atf::fs::path m_resfile;
400*00b67f09SDavid van Moolenbroek     std::string m_srcdir_arg;
401*00b67f09SDavid van Moolenbroek     atf::fs::path m_srcdir;
402*00b67f09SDavid van Moolenbroek 
403*00b67f09SDavid van Moolenbroek     atf::tests::vars_map m_vars;
404*00b67f09SDavid van Moolenbroek 
405*00b67f09SDavid van Moolenbroek     std::string specific_args(void) const;
406*00b67f09SDavid van Moolenbroek     options_set specific_options(void) const;
407*00b67f09SDavid van Moolenbroek     void process_option(int, const char*);
408*00b67f09SDavid van Moolenbroek 
409*00b67f09SDavid van Moolenbroek     void (*m_add_tcs)(tc_vector&);
410*00b67f09SDavid van Moolenbroek     tc_vector m_tcs;
411*00b67f09SDavid van Moolenbroek 
412*00b67f09SDavid van Moolenbroek     void parse_vflag(const std::string&);
413*00b67f09SDavid van Moolenbroek     void handle_srcdir(void);
414*00b67f09SDavid van Moolenbroek 
415*00b67f09SDavid van Moolenbroek     tc_vector init_tcs(void);
416*00b67f09SDavid van Moolenbroek 
417*00b67f09SDavid van Moolenbroek     enum tc_part {
418*00b67f09SDavid van Moolenbroek         BODY,
419*00b67f09SDavid van Moolenbroek         CLEANUP,
420*00b67f09SDavid van Moolenbroek     };
421*00b67f09SDavid van Moolenbroek 
422*00b67f09SDavid van Moolenbroek     void list_tcs(void);
423*00b67f09SDavid van Moolenbroek     impl::tc* find_tc(tc_vector, const std::string&);
424*00b67f09SDavid van Moolenbroek     static std::pair< std::string, tc_part > process_tcarg(const std::string&);
425*00b67f09SDavid van Moolenbroek     int run_tc(const std::string&);
426*00b67f09SDavid van Moolenbroek 
427*00b67f09SDavid van Moolenbroek public:
428*00b67f09SDavid van Moolenbroek     tp(void (*)(tc_vector&));
429*00b67f09SDavid van Moolenbroek     ~tp(void);
430*00b67f09SDavid van Moolenbroek 
431*00b67f09SDavid van Moolenbroek     int main(void);
432*00b67f09SDavid van Moolenbroek };
433*00b67f09SDavid van Moolenbroek 
434*00b67f09SDavid van Moolenbroek const char* tp::m_description =
435*00b67f09SDavid van Moolenbroek     "This is an independent atf test program.";
436*00b67f09SDavid van Moolenbroek 
tp(void (* add_tcs)(tc_vector &))437*00b67f09SDavid van Moolenbroek tp::tp(void (*add_tcs)(tc_vector&)) :
438*00b67f09SDavid van Moolenbroek     app(m_description, "atf-test-program(1)", "atf(7)", false),
439*00b67f09SDavid van Moolenbroek     m_lflag(false),
440*00b67f09SDavid van Moolenbroek     m_resfile("/dev/stdout"),
441*00b67f09SDavid van Moolenbroek     m_srcdir("."),
442*00b67f09SDavid van Moolenbroek     m_add_tcs(add_tcs)
443*00b67f09SDavid van Moolenbroek {
444*00b67f09SDavid van Moolenbroek }
445*00b67f09SDavid van Moolenbroek 
~tp(void)446*00b67f09SDavid van Moolenbroek tp::~tp(void)
447*00b67f09SDavid van Moolenbroek {
448*00b67f09SDavid van Moolenbroek     for (tc_vector::iterator iter = m_tcs.begin();
449*00b67f09SDavid van Moolenbroek          iter != m_tcs.end(); iter++) {
450*00b67f09SDavid van Moolenbroek         impl::tc* tc = *iter;
451*00b67f09SDavid van Moolenbroek 
452*00b67f09SDavid van Moolenbroek         delete tc;
453*00b67f09SDavid van Moolenbroek     }
454*00b67f09SDavid van Moolenbroek }
455*00b67f09SDavid van Moolenbroek 
456*00b67f09SDavid van Moolenbroek std::string
specific_args(void) const457*00b67f09SDavid van Moolenbroek tp::specific_args(void)
458*00b67f09SDavid van Moolenbroek     const
459*00b67f09SDavid van Moolenbroek {
460*00b67f09SDavid van Moolenbroek     return "test_case";
461*00b67f09SDavid van Moolenbroek }
462*00b67f09SDavid van Moolenbroek 
463*00b67f09SDavid van Moolenbroek tp::options_set
specific_options(void) const464*00b67f09SDavid van Moolenbroek tp::specific_options(void)
465*00b67f09SDavid van Moolenbroek     const
466*00b67f09SDavid van Moolenbroek {
467*00b67f09SDavid van Moolenbroek     using atf::application::option;
468*00b67f09SDavid van Moolenbroek     options_set opts;
469*00b67f09SDavid van Moolenbroek     opts.insert(option('l', "", "List test cases and their purpose"));
470*00b67f09SDavid van Moolenbroek     opts.insert(option('r', "resfile", "The file to which the test program "
471*00b67f09SDavid van Moolenbroek                                        "will write the results of the "
472*00b67f09SDavid van Moolenbroek                                        "executed test case"));
473*00b67f09SDavid van Moolenbroek     opts.insert(option('s', "srcdir", "Directory where the test's data "
474*00b67f09SDavid van Moolenbroek                                       "files are located"));
475*00b67f09SDavid van Moolenbroek     opts.insert(option('v', "var=value", "Sets the configuration variable "
476*00b67f09SDavid van Moolenbroek                                          "`var' to `value'"));
477*00b67f09SDavid van Moolenbroek     return opts;
478*00b67f09SDavid van Moolenbroek }
479*00b67f09SDavid van Moolenbroek 
480*00b67f09SDavid van Moolenbroek void
process_option(int ch,const char * arg)481*00b67f09SDavid van Moolenbroek tp::process_option(int ch, const char* arg)
482*00b67f09SDavid van Moolenbroek {
483*00b67f09SDavid van Moolenbroek     switch (ch) {
484*00b67f09SDavid van Moolenbroek     case 'l':
485*00b67f09SDavid van Moolenbroek         m_lflag = true;
486*00b67f09SDavid van Moolenbroek         break;
487*00b67f09SDavid van Moolenbroek 
488*00b67f09SDavid van Moolenbroek     case 'r':
489*00b67f09SDavid van Moolenbroek         m_resfile = atf::fs::path(arg);
490*00b67f09SDavid van Moolenbroek         break;
491*00b67f09SDavid van Moolenbroek 
492*00b67f09SDavid van Moolenbroek     case 's':
493*00b67f09SDavid van Moolenbroek         m_srcdir_arg = arg;
494*00b67f09SDavid van Moolenbroek         break;
495*00b67f09SDavid van Moolenbroek 
496*00b67f09SDavid van Moolenbroek     case 'v':
497*00b67f09SDavid van Moolenbroek         parse_vflag(arg);
498*00b67f09SDavid van Moolenbroek         break;
499*00b67f09SDavid van Moolenbroek 
500*00b67f09SDavid van Moolenbroek     default:
501*00b67f09SDavid van Moolenbroek         UNREACHABLE;
502*00b67f09SDavid van Moolenbroek     }
503*00b67f09SDavid van Moolenbroek }
504*00b67f09SDavid van Moolenbroek 
505*00b67f09SDavid van Moolenbroek void
parse_vflag(const std::string & str)506*00b67f09SDavid van Moolenbroek tp::parse_vflag(const std::string& str)
507*00b67f09SDavid van Moolenbroek {
508*00b67f09SDavid van Moolenbroek     if (str.empty())
509*00b67f09SDavid van Moolenbroek         throw std::runtime_error("-v requires a non-empty argument");
510*00b67f09SDavid van Moolenbroek 
511*00b67f09SDavid van Moolenbroek     std::vector< std::string > ws = atf::text::split(str, "=");
512*00b67f09SDavid van Moolenbroek     if (ws.size() == 1 && str[str.length() - 1] == '=') {
513*00b67f09SDavid van Moolenbroek         m_vars[ws[0]] = "";
514*00b67f09SDavid van Moolenbroek     } else {
515*00b67f09SDavid van Moolenbroek         if (ws.size() != 2)
516*00b67f09SDavid van Moolenbroek             throw std::runtime_error("-v requires an argument of the form "
517*00b67f09SDavid van Moolenbroek                                      "var=value");
518*00b67f09SDavid van Moolenbroek 
519*00b67f09SDavid van Moolenbroek         m_vars[ws[0]] = ws[1];
520*00b67f09SDavid van Moolenbroek     }
521*00b67f09SDavid van Moolenbroek }
522*00b67f09SDavid van Moolenbroek 
523*00b67f09SDavid van Moolenbroek void
handle_srcdir(void)524*00b67f09SDavid van Moolenbroek tp::handle_srcdir(void)
525*00b67f09SDavid van Moolenbroek {
526*00b67f09SDavid van Moolenbroek     if (m_srcdir_arg.empty()) {
527*00b67f09SDavid van Moolenbroek         m_srcdir = atf::fs::path(m_argv0).branch_path();
528*00b67f09SDavid van Moolenbroek         if (m_srcdir.leaf_name() == ".libs")
529*00b67f09SDavid van Moolenbroek             m_srcdir = m_srcdir.branch_path();
530*00b67f09SDavid van Moolenbroek     } else
531*00b67f09SDavid van Moolenbroek         m_srcdir = atf::fs::path(m_srcdir_arg);
532*00b67f09SDavid van Moolenbroek 
533*00b67f09SDavid van Moolenbroek     if (!atf::fs::exists(m_srcdir / m_prog_name))
534*00b67f09SDavid van Moolenbroek         throw std::runtime_error("Cannot find the test program in the "
535*00b67f09SDavid van Moolenbroek                                  "source directory `" + m_srcdir.str() + "'");
536*00b67f09SDavid van Moolenbroek 
537*00b67f09SDavid van Moolenbroek     if (!m_srcdir.is_absolute())
538*00b67f09SDavid van Moolenbroek         m_srcdir = m_srcdir.to_absolute();
539*00b67f09SDavid van Moolenbroek 
540*00b67f09SDavid van Moolenbroek     m_vars["srcdir"] = m_srcdir.str();
541*00b67f09SDavid van Moolenbroek }
542*00b67f09SDavid van Moolenbroek 
543*00b67f09SDavid van Moolenbroek tp::tc_vector
init_tcs(void)544*00b67f09SDavid van Moolenbroek tp::init_tcs(void)
545*00b67f09SDavid van Moolenbroek {
546*00b67f09SDavid van Moolenbroek     m_add_tcs(m_tcs);
547*00b67f09SDavid van Moolenbroek     for (tc_vector::iterator iter = m_tcs.begin();
548*00b67f09SDavid van Moolenbroek          iter != m_tcs.end(); iter++) {
549*00b67f09SDavid van Moolenbroek         impl::tc* tc = *iter;
550*00b67f09SDavid van Moolenbroek 
551*00b67f09SDavid van Moolenbroek         tc->init(m_vars);
552*00b67f09SDavid van Moolenbroek     }
553*00b67f09SDavid van Moolenbroek     return m_tcs;
554*00b67f09SDavid van Moolenbroek }
555*00b67f09SDavid van Moolenbroek 
556*00b67f09SDavid van Moolenbroek //
557*00b67f09SDavid van Moolenbroek // An auxiliary unary predicate that compares the given test case's
558*00b67f09SDavid van Moolenbroek // identifier to the identifier stored in it.
559*00b67f09SDavid van Moolenbroek //
560*00b67f09SDavid van Moolenbroek class tc_equal_to_ident {
561*00b67f09SDavid van Moolenbroek     const std::string& m_ident;
562*00b67f09SDavid van Moolenbroek 
563*00b67f09SDavid van Moolenbroek public:
tc_equal_to_ident(const std::string & i)564*00b67f09SDavid van Moolenbroek     tc_equal_to_ident(const std::string& i) :
565*00b67f09SDavid van Moolenbroek         m_ident(i)
566*00b67f09SDavid van Moolenbroek     {
567*00b67f09SDavid van Moolenbroek     }
568*00b67f09SDavid van Moolenbroek 
operator ()(const impl::tc * tc)569*00b67f09SDavid van Moolenbroek     bool operator()(const impl::tc* tc)
570*00b67f09SDavid van Moolenbroek     {
571*00b67f09SDavid van Moolenbroek         return tc->get_md_var("ident") == m_ident;
572*00b67f09SDavid van Moolenbroek     }
573*00b67f09SDavid van Moolenbroek };
574*00b67f09SDavid van Moolenbroek 
575*00b67f09SDavid van Moolenbroek void
list_tcs(void)576*00b67f09SDavid van Moolenbroek tp::list_tcs(void)
577*00b67f09SDavid van Moolenbroek {
578*00b67f09SDavid van Moolenbroek     tc_vector tcs = init_tcs();
579*00b67f09SDavid van Moolenbroek     detail::atf_tp_writer writer(std::cout);
580*00b67f09SDavid van Moolenbroek 
581*00b67f09SDavid van Moolenbroek     for (tc_vector::const_iterator iter = tcs.begin();
582*00b67f09SDavid van Moolenbroek          iter != tcs.end(); iter++) {
583*00b67f09SDavid van Moolenbroek         const impl::vars_map vars = (*iter)->get_md_vars();
584*00b67f09SDavid van Moolenbroek 
585*00b67f09SDavid van Moolenbroek         {
586*00b67f09SDavid van Moolenbroek             impl::vars_map::const_iterator iter2 = vars.find("ident");
587*00b67f09SDavid van Moolenbroek             INV(iter2 != vars.end());
588*00b67f09SDavid van Moolenbroek             writer.start_tc((*iter2).second);
589*00b67f09SDavid van Moolenbroek         }
590*00b67f09SDavid van Moolenbroek 
591*00b67f09SDavid van Moolenbroek         for (impl::vars_map::const_iterator iter2 = vars.begin();
592*00b67f09SDavid van Moolenbroek              iter2 != vars.end(); iter2++) {
593*00b67f09SDavid van Moolenbroek             const std::string& key = (*iter2).first;
594*00b67f09SDavid van Moolenbroek             if (key != "ident")
595*00b67f09SDavid van Moolenbroek                 writer.tc_meta_data(key, (*iter2).second);
596*00b67f09SDavid van Moolenbroek         }
597*00b67f09SDavid van Moolenbroek 
598*00b67f09SDavid van Moolenbroek         writer.end_tc();
599*00b67f09SDavid van Moolenbroek     }
600*00b67f09SDavid van Moolenbroek }
601*00b67f09SDavid van Moolenbroek 
602*00b67f09SDavid van Moolenbroek impl::tc*
find_tc(tc_vector tcs,const std::string & name)603*00b67f09SDavid van Moolenbroek tp::find_tc(tc_vector tcs, const std::string& name)
604*00b67f09SDavid van Moolenbroek {
605*00b67f09SDavid van Moolenbroek     std::vector< std::string > ids;
606*00b67f09SDavid van Moolenbroek     for (tc_vector::iterator iter = tcs.begin();
607*00b67f09SDavid van Moolenbroek          iter != tcs.end(); iter++) {
608*00b67f09SDavid van Moolenbroek         impl::tc* tc = *iter;
609*00b67f09SDavid van Moolenbroek 
610*00b67f09SDavid van Moolenbroek         if (tc->get_md_var("ident") == name)
611*00b67f09SDavid van Moolenbroek             return tc;
612*00b67f09SDavid van Moolenbroek     }
613*00b67f09SDavid van Moolenbroek     throw atf::application::usage_error("Unknown test case `%s'",
614*00b67f09SDavid van Moolenbroek                                         name.c_str());
615*00b67f09SDavid van Moolenbroek }
616*00b67f09SDavid van Moolenbroek 
617*00b67f09SDavid van Moolenbroek std::pair< std::string, tp::tc_part >
process_tcarg(const std::string & tcarg)618*00b67f09SDavid van Moolenbroek tp::process_tcarg(const std::string& tcarg)
619*00b67f09SDavid van Moolenbroek {
620*00b67f09SDavid van Moolenbroek     const std::string::size_type pos = tcarg.find(':');
621*00b67f09SDavid van Moolenbroek     if (pos == std::string::npos) {
622*00b67f09SDavid van Moolenbroek         return std::make_pair(tcarg, BODY);
623*00b67f09SDavid van Moolenbroek     } else {
624*00b67f09SDavid van Moolenbroek         const std::string tcname = tcarg.substr(0, pos);
625*00b67f09SDavid van Moolenbroek 
626*00b67f09SDavid van Moolenbroek         const std::string partname = tcarg.substr(pos + 1);
627*00b67f09SDavid van Moolenbroek         if (partname == "body")
628*00b67f09SDavid van Moolenbroek             return std::make_pair(tcname, BODY);
629*00b67f09SDavid van Moolenbroek         else if (partname == "cleanup")
630*00b67f09SDavid van Moolenbroek             return std::make_pair(tcname, CLEANUP);
631*00b67f09SDavid van Moolenbroek         else {
632*00b67f09SDavid van Moolenbroek             using atf::application::usage_error;
633*00b67f09SDavid van Moolenbroek             throw usage_error("Invalid test case part `%s'", partname.c_str());
634*00b67f09SDavid van Moolenbroek         }
635*00b67f09SDavid van Moolenbroek     }
636*00b67f09SDavid van Moolenbroek }
637*00b67f09SDavid van Moolenbroek 
638*00b67f09SDavid van Moolenbroek int
run_tc(const std::string & tcarg)639*00b67f09SDavid van Moolenbroek tp::run_tc(const std::string& tcarg)
640*00b67f09SDavid van Moolenbroek {
641*00b67f09SDavid van Moolenbroek     const std::pair< std::string, tc_part > fields = process_tcarg(tcarg);
642*00b67f09SDavid van Moolenbroek 
643*00b67f09SDavid van Moolenbroek     impl::tc* tc = find_tc(init_tcs(), fields.first);
644*00b67f09SDavid van Moolenbroek 
645*00b67f09SDavid van Moolenbroek     if (!atf::env::has("__RUNNING_INSIDE_ATF_RUN") || atf::env::get(
646*00b67f09SDavid van Moolenbroek         "__RUNNING_INSIDE_ATF_RUN") != "internal-yes-value")
647*00b67f09SDavid van Moolenbroek     {
648*00b67f09SDavid van Moolenbroek         std::cerr << m_prog_name << ": WARNING: Running test cases without "
649*00b67f09SDavid van Moolenbroek             "atf-run(1) is unsupported\n";
650*00b67f09SDavid van Moolenbroek         std::cerr << m_prog_name << ": WARNING: No isolation nor timeout "
651*00b67f09SDavid van Moolenbroek             "control is being applied; you may get unexpected failures; see "
652*00b67f09SDavid van Moolenbroek             "atf-test-case(4)\n";
653*00b67f09SDavid van Moolenbroek     }
654*00b67f09SDavid van Moolenbroek 
655*00b67f09SDavid van Moolenbroek     try {
656*00b67f09SDavid van Moolenbroek         switch (fields.second) {
657*00b67f09SDavid van Moolenbroek         case BODY:
658*00b67f09SDavid van Moolenbroek             tc->run(m_resfile.str());
659*00b67f09SDavid van Moolenbroek             break;
660*00b67f09SDavid van Moolenbroek         case CLEANUP:
661*00b67f09SDavid van Moolenbroek             tc->run_cleanup();
662*00b67f09SDavid van Moolenbroek             break;
663*00b67f09SDavid van Moolenbroek         default:
664*00b67f09SDavid van Moolenbroek             UNREACHABLE;
665*00b67f09SDavid van Moolenbroek         }
666*00b67f09SDavid van Moolenbroek         return EXIT_SUCCESS;
667*00b67f09SDavid van Moolenbroek     } catch (const std::runtime_error& e) {
668*00b67f09SDavid van Moolenbroek         std::cerr << "ERROR: " << e.what() << "\n";
669*00b67f09SDavid van Moolenbroek         return EXIT_FAILURE;
670*00b67f09SDavid van Moolenbroek     }
671*00b67f09SDavid van Moolenbroek }
672*00b67f09SDavid van Moolenbroek 
673*00b67f09SDavid van Moolenbroek int
main(void)674*00b67f09SDavid van Moolenbroek tp::main(void)
675*00b67f09SDavid van Moolenbroek {
676*00b67f09SDavid van Moolenbroek     using atf::application::usage_error;
677*00b67f09SDavid van Moolenbroek 
678*00b67f09SDavid van Moolenbroek     int errcode;
679*00b67f09SDavid van Moolenbroek 
680*00b67f09SDavid van Moolenbroek     handle_srcdir();
681*00b67f09SDavid van Moolenbroek 
682*00b67f09SDavid van Moolenbroek     if (m_lflag) {
683*00b67f09SDavid van Moolenbroek         if (m_argc > 0)
684*00b67f09SDavid van Moolenbroek             throw usage_error("Cannot provide test case names with -l");
685*00b67f09SDavid van Moolenbroek 
686*00b67f09SDavid van Moolenbroek         list_tcs();
687*00b67f09SDavid van Moolenbroek         errcode = EXIT_SUCCESS;
688*00b67f09SDavid van Moolenbroek     } else {
689*00b67f09SDavid van Moolenbroek         if (m_argc == 0)
690*00b67f09SDavid van Moolenbroek             throw usage_error("Must provide a test case name");
691*00b67f09SDavid van Moolenbroek         else if (m_argc > 1)
692*00b67f09SDavid van Moolenbroek             throw usage_error("Cannot provide more than one test case name");
693*00b67f09SDavid van Moolenbroek         INV(m_argc == 1);
694*00b67f09SDavid van Moolenbroek 
695*00b67f09SDavid van Moolenbroek         errcode = run_tc(m_argv[0]);
696*00b67f09SDavid van Moolenbroek     }
697*00b67f09SDavid van Moolenbroek 
698*00b67f09SDavid van Moolenbroek     return errcode;
699*00b67f09SDavid van Moolenbroek }
700*00b67f09SDavid van Moolenbroek 
701*00b67f09SDavid van Moolenbroek namespace atf {
702*00b67f09SDavid van Moolenbroek     namespace tests {
703*00b67f09SDavid van Moolenbroek         int run_tp(int, char* const*, void (*)(tp::tc_vector&));
704*00b67f09SDavid van Moolenbroek     }
705*00b67f09SDavid van Moolenbroek }
706*00b67f09SDavid van Moolenbroek 
707*00b67f09SDavid van Moolenbroek int
run_tp(int argc,char * const * argv,void (* add_tcs)(tp::tc_vector &))708*00b67f09SDavid van Moolenbroek impl::run_tp(int argc, char* const* argv, void (*add_tcs)(tp::tc_vector&))
709*00b67f09SDavid van Moolenbroek {
710*00b67f09SDavid van Moolenbroek     return tp(add_tcs).run(argc, argv);
711*00b67f09SDavid van Moolenbroek }
712