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