xref: /freebsd/contrib/atf/atf-c++/tests.cpp (revision 83a1ee578c9d1ab7013e997289c7cd470c0e6902)
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.
250677dfd1SJulio Merino 
260677dfd1SJulio Merino #include "atf-c++/tests.hpp"
270677dfd1SJulio Merino 
280677dfd1SJulio Merino #if defined(HAVE_CONFIG_H)
290677dfd1SJulio Merino #include "config.h"
300677dfd1SJulio 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 
600677dfd1SJulio Merino #include "atf-c++/detail/application.hpp"
610677dfd1SJulio Merino #include "atf-c++/detail/auto_array.hpp"
620677dfd1SJulio Merino #include "atf-c++/detail/env.hpp"
630677dfd1SJulio Merino #include "atf-c++/detail/exceptions.hpp"
640677dfd1SJulio Merino #include "atf-c++/detail/fs.hpp"
650677dfd1SJulio Merino #include "atf-c++/detail/sanity.hpp"
660677dfd1SJulio Merino #include "atf-c++/detail/text.hpp"
67c243e490SMarcel Moolenaar 
680677dfd1SJulio Merino #if defined(HAVE_GNU_GETOPT)
690677dfd1SJulio Merino #   define GETOPT_POSIX "+"
700677dfd1SJulio Merino #else
710677dfd1SJulio Merino #   define GETOPT_POSIX ""
720677dfd1SJulio 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 
780677dfd1SJulio Merino using atf::application::usage_error;
790677dfd1SJulio 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 
1200677dfd1SJulio Merino std::string Program_Name;
1210677dfd1SJulio Merino 
1220677dfd1SJulio Merino static void
set_program_name(const char * argv0)1230677dfd1SJulio Merino set_program_name(const char* argv0)
1240677dfd1SJulio Merino {
1250677dfd1SJulio Merino     const std::string program_name = atf::fs::path(argv0).leaf_name();
1260677dfd1SJulio Merino     // Libtool workaround: if running from within the source tree (binaries
1270677dfd1SJulio Merino     // that are not installed yet), skip the "lt-" prefix added to files in
1280677dfd1SJulio Merino     // the ".libs" directory to show the real (not temporary) name.
1290677dfd1SJulio Merino     if (program_name.substr(0, 3) == "lt-")
1300677dfd1SJulio Merino         Program_Name = program_name.substr(3);
1310677dfd1SJulio Merino     else
1320677dfd1SJulio Merino         Program_Name = program_name;
1330677dfd1SJulio Merino }
1340677dfd1SJulio 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_kmod(const std::string & kmod) const322*83a1ee57SDag-Erling Smørgrav impl::tc::require_kmod(const std::string& kmod)
323*83a1ee57SDag-Erling Smørgrav     const
324*83a1ee57SDag-Erling Smørgrav {
325*83a1ee57SDag-Erling Smørgrav     atf_tc_require_kmod(kmod.c_str());
326*83a1ee57SDag-Erling Smørgrav }
327*83a1ee57SDag-Erling Smørgrav 
328*83a1ee57SDag-Erling Smørgrav void
require_prog(const std::string & prog) const329c243e490SMarcel Moolenaar impl::tc::require_prog(const std::string& prog)
330c243e490SMarcel Moolenaar     const
331c243e490SMarcel Moolenaar {
332c243e490SMarcel Moolenaar     atf_tc_require_prog(prog.c_str());
333c243e490SMarcel Moolenaar }
334c243e490SMarcel Moolenaar 
335c243e490SMarcel Moolenaar void
pass(void)336c243e490SMarcel Moolenaar impl::tc::pass(void)
337c243e490SMarcel Moolenaar {
338c243e490SMarcel Moolenaar     atf_tc_pass();
339c243e490SMarcel Moolenaar }
340c243e490SMarcel Moolenaar 
341c243e490SMarcel Moolenaar void
fail(const std::string & reason)342c243e490SMarcel Moolenaar impl::tc::fail(const std::string& reason)
343c243e490SMarcel Moolenaar {
344c243e490SMarcel Moolenaar     atf_tc_fail("%s", reason.c_str());
345c243e490SMarcel Moolenaar }
346c243e490SMarcel Moolenaar 
347c243e490SMarcel Moolenaar void
fail_nonfatal(const std::string & reason)348c243e490SMarcel Moolenaar impl::tc::fail_nonfatal(const std::string& reason)
349c243e490SMarcel Moolenaar {
350c243e490SMarcel Moolenaar     atf_tc_fail_nonfatal("%s", reason.c_str());
351c243e490SMarcel Moolenaar }
352c243e490SMarcel Moolenaar 
353c243e490SMarcel Moolenaar void
skip(const std::string & reason)354c243e490SMarcel Moolenaar impl::tc::skip(const std::string& reason)
355c243e490SMarcel Moolenaar {
356c243e490SMarcel Moolenaar     atf_tc_skip("%s", reason.c_str());
357c243e490SMarcel Moolenaar }
358c243e490SMarcel Moolenaar 
359c243e490SMarcel Moolenaar void
check_errno(const char * file,const int line,const int exp_errno,const char * expr_str,const bool result)360c243e490SMarcel Moolenaar impl::tc::check_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_check_errno(file, line, exp_errno, expr_str, result);
364c243e490SMarcel Moolenaar }
365c243e490SMarcel Moolenaar 
366c243e490SMarcel Moolenaar void
require_errno(const char * file,const int line,const int exp_errno,const char * expr_str,const bool result)367c243e490SMarcel Moolenaar impl::tc::require_errno(const char* file, const int line, const int exp_errno,
368c243e490SMarcel Moolenaar                         const char* expr_str, const bool result)
369c243e490SMarcel Moolenaar {
370c243e490SMarcel Moolenaar     atf_tc_require_errno(file, line, exp_errno, expr_str, result);
371c243e490SMarcel Moolenaar }
372c243e490SMarcel Moolenaar 
373c243e490SMarcel Moolenaar void
expect_pass(void)374c243e490SMarcel Moolenaar impl::tc::expect_pass(void)
375c243e490SMarcel Moolenaar {
376c243e490SMarcel Moolenaar     atf_tc_expect_pass();
377c243e490SMarcel Moolenaar }
378c243e490SMarcel Moolenaar 
379c243e490SMarcel Moolenaar void
expect_fail(const std::string & reason)380c243e490SMarcel Moolenaar impl::tc::expect_fail(const std::string& reason)
381c243e490SMarcel Moolenaar {
382c243e490SMarcel Moolenaar     atf_tc_expect_fail("%s", reason.c_str());
383c243e490SMarcel Moolenaar }
384c243e490SMarcel Moolenaar 
385c243e490SMarcel Moolenaar void
expect_exit(const int exitcode,const std::string & reason)386c243e490SMarcel Moolenaar impl::tc::expect_exit(const int exitcode, const std::string& reason)
387c243e490SMarcel Moolenaar {
388c243e490SMarcel Moolenaar     atf_tc_expect_exit(exitcode, "%s", reason.c_str());
389c243e490SMarcel Moolenaar }
390c243e490SMarcel Moolenaar 
391c243e490SMarcel Moolenaar void
expect_signal(const int signo,const std::string & reason)392c243e490SMarcel Moolenaar impl::tc::expect_signal(const int signo, const std::string& reason)
393c243e490SMarcel Moolenaar {
394c243e490SMarcel Moolenaar     atf_tc_expect_signal(signo, "%s", reason.c_str());
395c243e490SMarcel Moolenaar }
396c243e490SMarcel Moolenaar 
397c243e490SMarcel Moolenaar void
expect_death(const std::string & reason)398c243e490SMarcel Moolenaar impl::tc::expect_death(const std::string& reason)
399c243e490SMarcel Moolenaar {
400c243e490SMarcel Moolenaar     atf_tc_expect_death("%s", reason.c_str());
401c243e490SMarcel Moolenaar }
402c243e490SMarcel Moolenaar 
403c243e490SMarcel Moolenaar void
expect_timeout(const std::string & reason)404c243e490SMarcel Moolenaar impl::tc::expect_timeout(const std::string& reason)
405c243e490SMarcel Moolenaar {
406c243e490SMarcel Moolenaar     atf_tc_expect_timeout("%s", reason.c_str());
407c243e490SMarcel Moolenaar }
408c243e490SMarcel Moolenaar 
409c243e490SMarcel Moolenaar // ------------------------------------------------------------------------
4100677dfd1SJulio Merino // Test program main code.
411c243e490SMarcel Moolenaar // ------------------------------------------------------------------------
412c243e490SMarcel Moolenaar 
4130677dfd1SJulio Merino namespace {
4140677dfd1SJulio Merino 
415c243e490SMarcel Moolenaar typedef std::vector< impl::tc * > tc_vector;
416c243e490SMarcel Moolenaar 
4170677dfd1SJulio Merino enum tc_part { BODY, CLEANUP };
418c243e490SMarcel Moolenaar 
4190677dfd1SJulio Merino static void
parse_vflag(const std::string & str,atf::tests::vars_map & vars)4200677dfd1SJulio Merino parse_vflag(const std::string& str, atf::tests::vars_map& vars)
421c243e490SMarcel Moolenaar {
422c243e490SMarcel Moolenaar     if (str.empty())
423c243e490SMarcel Moolenaar         throw std::runtime_error("-v requires a non-empty argument");
424c243e490SMarcel Moolenaar 
425c243e490SMarcel Moolenaar     std::vector< std::string > ws = atf::text::split(str, "=");
426c243e490SMarcel Moolenaar     if (ws.size() == 1 && str[str.length() - 1] == '=') {
4270677dfd1SJulio Merino         vars[ws[0]] = "";
428c243e490SMarcel Moolenaar     } else {
429c243e490SMarcel Moolenaar         if (ws.size() != 2)
430c243e490SMarcel Moolenaar             throw std::runtime_error("-v requires an argument of the form "
431c243e490SMarcel Moolenaar                                      "var=value");
432c243e490SMarcel Moolenaar 
4330677dfd1SJulio Merino         vars[ws[0]] = ws[1];
434c243e490SMarcel Moolenaar     }
435c243e490SMarcel Moolenaar }
436c243e490SMarcel Moolenaar 
4370677dfd1SJulio Merino static atf::fs::path
handle_srcdir(const char * argv0,const std::string & srcdir_arg)4380677dfd1SJulio Merino handle_srcdir(const char* argv0, const std::string& srcdir_arg)
439c243e490SMarcel Moolenaar {
4400677dfd1SJulio Merino     atf::fs::path srcdir(".");
4410677dfd1SJulio Merino 
4420677dfd1SJulio Merino     if (srcdir_arg.empty()) {
4430677dfd1SJulio Merino         srcdir = atf::fs::path(argv0).branch_path();
4440677dfd1SJulio Merino         if (srcdir.leaf_name() == ".libs")
4450677dfd1SJulio Merino             srcdir = srcdir.branch_path();
446c243e490SMarcel Moolenaar     } else
4470677dfd1SJulio Merino         srcdir = atf::fs::path(srcdir_arg);
448c243e490SMarcel Moolenaar 
4490677dfd1SJulio Merino     if (!atf::fs::exists(srcdir / Program_Name))
4500677dfd1SJulio Merino         throw usage_error("Cannot find the test program in the source "
4510677dfd1SJulio Merino                           "directory `%s'", srcdir.c_str());
452c243e490SMarcel Moolenaar 
4530677dfd1SJulio Merino     if (!srcdir.is_absolute())
4540677dfd1SJulio Merino         srcdir = srcdir.to_absolute();
455c243e490SMarcel Moolenaar 
4560677dfd1SJulio Merino     return srcdir;
457c243e490SMarcel Moolenaar }
458c243e490SMarcel Moolenaar 
4590677dfd1SJulio Merino static void
init_tcs(void (* add_tcs)(tc_vector &),tc_vector & tcs,const atf::tests::vars_map & vars)4600677dfd1SJulio Merino init_tcs(void (*add_tcs)(tc_vector&), tc_vector& tcs,
4610677dfd1SJulio Merino          const atf::tests::vars_map& vars)
462c243e490SMarcel Moolenaar {
4630677dfd1SJulio Merino     add_tcs(tcs);
4640677dfd1SJulio Merino     for (tc_vector::iterator iter = tcs.begin(); iter != tcs.end(); iter++) {
465c243e490SMarcel Moolenaar         impl::tc* tc = *iter;
466c243e490SMarcel Moolenaar 
4670677dfd1SJulio Merino         tc->init(vars);
468c243e490SMarcel Moolenaar     }
469c243e490SMarcel Moolenaar }
470c243e490SMarcel Moolenaar 
4710677dfd1SJulio Merino static int
list_tcs(const tc_vector & tcs)4720677dfd1SJulio Merino list_tcs(const tc_vector& tcs)
473c243e490SMarcel Moolenaar {
474c243e490SMarcel Moolenaar     detail::atf_tp_writer writer(std::cout);
475c243e490SMarcel Moolenaar 
476c243e490SMarcel Moolenaar     for (tc_vector::const_iterator iter = tcs.begin();
477c243e490SMarcel Moolenaar          iter != tcs.end(); iter++) {
478c243e490SMarcel Moolenaar         const impl::vars_map vars = (*iter)->get_md_vars();
479c243e490SMarcel Moolenaar 
480c243e490SMarcel Moolenaar         {
481c243e490SMarcel Moolenaar             impl::vars_map::const_iterator iter2 = vars.find("ident");
482c243e490SMarcel Moolenaar             INV(iter2 != vars.end());
483c243e490SMarcel Moolenaar             writer.start_tc((*iter2).second);
484c243e490SMarcel Moolenaar         }
485c243e490SMarcel Moolenaar 
486c243e490SMarcel Moolenaar         for (impl::vars_map::const_iterator iter2 = vars.begin();
487c243e490SMarcel Moolenaar              iter2 != vars.end(); iter2++) {
488c243e490SMarcel Moolenaar             const std::string& key = (*iter2).first;
489c243e490SMarcel Moolenaar             if (key != "ident")
490c243e490SMarcel Moolenaar                 writer.tc_meta_data(key, (*iter2).second);
491c243e490SMarcel Moolenaar         }
492c243e490SMarcel Moolenaar 
493c243e490SMarcel Moolenaar         writer.end_tc();
494c243e490SMarcel Moolenaar     }
4950677dfd1SJulio Merino 
4960677dfd1SJulio Merino     return EXIT_SUCCESS;
497c243e490SMarcel Moolenaar }
498c243e490SMarcel Moolenaar 
4990677dfd1SJulio Merino static impl::tc*
find_tc(tc_vector tcs,const std::string & name)5000677dfd1SJulio Merino find_tc(tc_vector tcs, const std::string& name)
501c243e490SMarcel Moolenaar {
502c243e490SMarcel Moolenaar     std::vector< std::string > ids;
503c243e490SMarcel Moolenaar     for (tc_vector::iterator iter = tcs.begin();
504c243e490SMarcel Moolenaar          iter != tcs.end(); iter++) {
505c243e490SMarcel Moolenaar         impl::tc* tc = *iter;
506c243e490SMarcel Moolenaar 
507c243e490SMarcel Moolenaar         if (tc->get_md_var("ident") == name)
508c243e490SMarcel Moolenaar             return tc;
509c243e490SMarcel Moolenaar     }
5100677dfd1SJulio Merino     throw usage_error("Unknown test case `%s'", name.c_str());
511c243e490SMarcel Moolenaar }
512c243e490SMarcel Moolenaar 
5130677dfd1SJulio Merino static std::pair< std::string, tc_part >
process_tcarg(const std::string & tcarg)5140677dfd1SJulio Merino process_tcarg(const std::string& tcarg)
515c243e490SMarcel Moolenaar {
516c243e490SMarcel Moolenaar     const std::string::size_type pos = tcarg.find(':');
517c243e490SMarcel Moolenaar     if (pos == std::string::npos) {
518c243e490SMarcel Moolenaar         return std::make_pair(tcarg, BODY);
519c243e490SMarcel Moolenaar     } else {
520c243e490SMarcel Moolenaar         const std::string tcname = tcarg.substr(0, pos);
521c243e490SMarcel Moolenaar 
522c243e490SMarcel Moolenaar         const std::string partname = tcarg.substr(pos + 1);
523c243e490SMarcel Moolenaar         if (partname == "body")
524c243e490SMarcel Moolenaar             return std::make_pair(tcname, BODY);
525c243e490SMarcel Moolenaar         else if (partname == "cleanup")
526c243e490SMarcel Moolenaar             return std::make_pair(tcname, CLEANUP);
527c243e490SMarcel Moolenaar         else {
528c243e490SMarcel Moolenaar             throw usage_error("Invalid test case part `%s'", partname.c_str());
529c243e490SMarcel Moolenaar         }
530c243e490SMarcel Moolenaar     }
531c243e490SMarcel Moolenaar }
532c243e490SMarcel Moolenaar 
5330677dfd1SJulio Merino static int
run_tc(tc_vector & tcs,const std::string & tcarg,const atf::fs::path & resfile)5340677dfd1SJulio Merino run_tc(tc_vector& tcs, const std::string& tcarg, const atf::fs::path& resfile)
535c243e490SMarcel Moolenaar {
536c243e490SMarcel Moolenaar     const std::pair< std::string, tc_part > fields = process_tcarg(tcarg);
537c243e490SMarcel Moolenaar 
5380677dfd1SJulio Merino     impl::tc* tc = find_tc(tcs, fields.first);
539c243e490SMarcel Moolenaar 
540c243e490SMarcel Moolenaar     if (!atf::env::has("__RUNNING_INSIDE_ATF_RUN") || atf::env::get(
541c243e490SMarcel Moolenaar         "__RUNNING_INSIDE_ATF_RUN") != "internal-yes-value")
542c243e490SMarcel Moolenaar     {
5430677dfd1SJulio Merino         std::cerr << Program_Name << ": WARNING: Running test cases outside "
5440677dfd1SJulio Merino             "of kyua(1) is unsupported\n";
5450677dfd1SJulio Merino         std::cerr << Program_Name << ": WARNING: No isolation nor timeout "
546c243e490SMarcel Moolenaar             "control is being applied; you may get unexpected failures; see "
547c243e490SMarcel Moolenaar             "atf-test-case(4)\n";
548c243e490SMarcel Moolenaar     }
549c243e490SMarcel Moolenaar 
550c243e490SMarcel Moolenaar     switch (fields.second) {
551c243e490SMarcel Moolenaar     case BODY:
5520677dfd1SJulio Merino         tc->run(resfile.str());
553c243e490SMarcel Moolenaar         break;
554c243e490SMarcel Moolenaar     case CLEANUP:
555c243e490SMarcel Moolenaar         tc->run_cleanup();
556c243e490SMarcel Moolenaar         break;
557c243e490SMarcel Moolenaar     default:
558c243e490SMarcel Moolenaar         UNREACHABLE;
559c243e490SMarcel Moolenaar     }
560c243e490SMarcel Moolenaar     return EXIT_SUCCESS;
561c243e490SMarcel Moolenaar }
562c243e490SMarcel Moolenaar 
5630677dfd1SJulio Merino static int
safe_main(int argc,char ** argv,void (* add_tcs)(tc_vector &))5640677dfd1SJulio Merino safe_main(int argc, char** argv, void (*add_tcs)(tc_vector&))
565c243e490SMarcel Moolenaar {
5660677dfd1SJulio Merino     const char* argv0 = argv[0];
5670677dfd1SJulio Merino 
5680677dfd1SJulio Merino     bool lflag = false;
5690677dfd1SJulio Merino     atf::fs::path resfile("/dev/stdout");
5700677dfd1SJulio Merino     std::string srcdir_arg;
5710677dfd1SJulio Merino     atf::tests::vars_map vars;
5720677dfd1SJulio Merino 
5730677dfd1SJulio Merino     int ch;
5740677dfd1SJulio Merino     int old_opterr;
5750677dfd1SJulio Merino 
5760677dfd1SJulio Merino     old_opterr = opterr;
5770677dfd1SJulio Merino     ::opterr = 0;
5780677dfd1SJulio Merino     while ((ch = ::getopt(argc, argv, GETOPT_POSIX ":lr:s:v:")) != -1) {
5790677dfd1SJulio Merino         switch (ch) {
5800677dfd1SJulio Merino         case 'l':
5810677dfd1SJulio Merino             lflag = true;
5820677dfd1SJulio Merino             break;
5830677dfd1SJulio Merino 
5840677dfd1SJulio Merino         case 'r':
5850677dfd1SJulio Merino             resfile = atf::fs::path(::optarg);
5860677dfd1SJulio Merino             break;
5870677dfd1SJulio Merino 
5880677dfd1SJulio Merino         case 's':
5890677dfd1SJulio Merino             srcdir_arg = ::optarg;
5900677dfd1SJulio Merino             break;
5910677dfd1SJulio Merino 
5920677dfd1SJulio Merino         case 'v':
5930677dfd1SJulio Merino             parse_vflag(::optarg, vars);
5940677dfd1SJulio Merino             break;
5950677dfd1SJulio Merino 
5960677dfd1SJulio Merino         case ':':
5970677dfd1SJulio Merino             throw usage_error("Option -%c requires an argument.", ::optopt);
5980677dfd1SJulio Merino             break;
5990677dfd1SJulio Merino 
6000677dfd1SJulio Merino         case '?':
6010677dfd1SJulio Merino         default:
6020677dfd1SJulio Merino             throw usage_error("Unknown option -%c.", ::optopt);
6030677dfd1SJulio Merino         }
6040677dfd1SJulio Merino     }
6050677dfd1SJulio Merino     argc -= optind;
6060677dfd1SJulio Merino     argv += optind;
6070677dfd1SJulio Merino 
6080677dfd1SJulio Merino     // Clear getopt state just in case the test wants to use it.
6090677dfd1SJulio Merino     ::opterr = old_opterr;
6100677dfd1SJulio Merino     ::optind = 1;
6110677dfd1SJulio Merino #if defined(HAVE_OPTRESET)
6120677dfd1SJulio Merino     ::optreset = 1;
6130677dfd1SJulio Merino #endif
6140677dfd1SJulio Merino 
6150677dfd1SJulio Merino     vars["srcdir"] = handle_srcdir(argv0, srcdir_arg).str();
616c243e490SMarcel Moolenaar 
617c243e490SMarcel Moolenaar     int errcode;
618c243e490SMarcel Moolenaar 
6190677dfd1SJulio Merino     tc_vector tcs;
6200677dfd1SJulio Merino     if (lflag) {
6210677dfd1SJulio Merino         if (argc > 0)
622c243e490SMarcel Moolenaar             throw usage_error("Cannot provide test case names with -l");
623c243e490SMarcel Moolenaar 
6240677dfd1SJulio Merino         init_tcs(add_tcs, tcs, vars);
6250677dfd1SJulio Merino         errcode = list_tcs(tcs);
626c243e490SMarcel Moolenaar     } else {
6270677dfd1SJulio Merino         if (argc == 0)
628c243e490SMarcel Moolenaar             throw usage_error("Must provide a test case name");
6290677dfd1SJulio Merino         else if (argc > 1)
630c243e490SMarcel Moolenaar             throw usage_error("Cannot provide more than one test case name");
6310677dfd1SJulio Merino         INV(argc == 1);
632c243e490SMarcel Moolenaar 
6330677dfd1SJulio Merino         init_tcs(add_tcs, tcs, vars);
6340677dfd1SJulio Merino         errcode = run_tc(tcs, argv[0], resfile);
6350677dfd1SJulio Merino     }
6360677dfd1SJulio Merino     for (tc_vector::iterator iter = tcs.begin(); iter != tcs.end(); iter++) {
6370677dfd1SJulio Merino         impl::tc* tc = *iter;
6380677dfd1SJulio Merino 
6390677dfd1SJulio Merino         delete tc;
640c243e490SMarcel Moolenaar     }
641c243e490SMarcel Moolenaar 
642c243e490SMarcel Moolenaar     return errcode;
643c243e490SMarcel Moolenaar }
644c243e490SMarcel Moolenaar 
6450677dfd1SJulio Merino }  // anonymous namespace
6460677dfd1SJulio Merino 
647c243e490SMarcel Moolenaar namespace atf {
648c243e490SMarcel Moolenaar     namespace tests {
6490677dfd1SJulio Merino         int run_tp(int, char**, void (*)(tc_vector&));
650c243e490SMarcel Moolenaar     }
651c243e490SMarcel Moolenaar }
652c243e490SMarcel Moolenaar 
653c243e490SMarcel Moolenaar int
run_tp(int argc,char ** argv,void (* add_tcs)(tc_vector &))6540677dfd1SJulio Merino impl::run_tp(int argc, char** argv, void (*add_tcs)(tc_vector&))
655c243e490SMarcel Moolenaar {
6560677dfd1SJulio Merino     try {
6570677dfd1SJulio Merino         set_program_name(argv[0]);
6580677dfd1SJulio Merino         return ::safe_main(argc, argv, add_tcs);
6590677dfd1SJulio Merino     } catch (const usage_error& e) {
6600677dfd1SJulio Merino         std::cerr
6610677dfd1SJulio Merino             << Program_Name << ": ERROR: " << e.what() << '\n'
6620677dfd1SJulio Merino             << Program_Name << ": See atf-test-program(1) for usage details.\n";
6630677dfd1SJulio Merino         return EXIT_FAILURE;
6640677dfd1SJulio Merino     }
665c243e490SMarcel Moolenaar }
666