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