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