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