xref: /minix3/external/bsd/atf/dist/atf-c++/tests.cpp (revision 0a6a1f1d05b60e214de2f05a7310ddd1f0e590e7)
111be35a1SLionel Sambuc //
211be35a1SLionel Sambuc // Automated Testing Framework (atf)
311be35a1SLionel Sambuc //
411be35a1SLionel Sambuc // Copyright (c) 2007 The NetBSD Foundation, Inc.
511be35a1SLionel Sambuc // All rights reserved.
611be35a1SLionel Sambuc //
711be35a1SLionel Sambuc // Redistribution and use in source and binary forms, with or without
811be35a1SLionel Sambuc // modification, are permitted provided that the following conditions
911be35a1SLionel Sambuc // are met:
1011be35a1SLionel Sambuc // 1. Redistributions of source code must retain the above copyright
1111be35a1SLionel Sambuc //    notice, this list of conditions and the following disclaimer.
1211be35a1SLionel Sambuc // 2. Redistributions in binary form must reproduce the above copyright
1311be35a1SLionel Sambuc //    notice, this list of conditions and the following disclaimer in the
1411be35a1SLionel Sambuc //    documentation and/or other materials provided with the distribution.
1511be35a1SLionel Sambuc //
1611be35a1SLionel Sambuc // THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND
1711be35a1SLionel Sambuc // CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
1811be35a1SLionel Sambuc // INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
1911be35a1SLionel Sambuc // MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
2011be35a1SLionel Sambuc // IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS BE LIABLE FOR ANY
2111be35a1SLionel Sambuc // DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
2211be35a1SLionel Sambuc // DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
2311be35a1SLionel Sambuc // GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
2411be35a1SLionel Sambuc // INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
2511be35a1SLionel Sambuc // IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
2611be35a1SLionel Sambuc // OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
2711be35a1SLionel Sambuc // IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
2811be35a1SLionel Sambuc //
2911be35a1SLionel Sambuc 
3011be35a1SLionel Sambuc extern "C" {
3111be35a1SLionel Sambuc #include <sys/types.h>
3211be35a1SLionel Sambuc #include <sys/stat.h>
3311be35a1SLionel Sambuc #include <sys/time.h>
3411be35a1SLionel Sambuc #include <sys/wait.h>
3511be35a1SLionel Sambuc #include <signal.h>
3611be35a1SLionel Sambuc #include <unistd.h>
3711be35a1SLionel Sambuc }
3811be35a1SLionel Sambuc 
3911be35a1SLionel Sambuc #include <algorithm>
4011be35a1SLionel Sambuc #include <cctype>
4111be35a1SLionel Sambuc #include <cerrno>
4211be35a1SLionel Sambuc #include <cstdlib>
4311be35a1SLionel Sambuc #include <cstring>
4411be35a1SLionel Sambuc #include <fstream>
4511be35a1SLionel Sambuc #include <iostream>
4611be35a1SLionel Sambuc #include <map>
4711be35a1SLionel Sambuc #include <memory>
4811be35a1SLionel Sambuc #include <sstream>
4911be35a1SLionel Sambuc #include <stdexcept>
5011be35a1SLionel Sambuc #include <vector>
5111be35a1SLionel Sambuc 
5211be35a1SLionel Sambuc extern "C" {
5311be35a1SLionel Sambuc #include "atf-c/error.h"
5411be35a1SLionel Sambuc #include "atf-c/tc.h"
5511be35a1SLionel Sambuc #include "atf-c/utils.h"
5611be35a1SLionel Sambuc }
5711be35a1SLionel Sambuc 
5811be35a1SLionel Sambuc #include "tests.hpp"
5911be35a1SLionel Sambuc 
6011be35a1SLionel Sambuc #include "detail/application.hpp"
6111be35a1SLionel Sambuc #include "detail/auto_array.hpp"
6211be35a1SLionel Sambuc #include "detail/env.hpp"
6311be35a1SLionel Sambuc #include "detail/exceptions.hpp"
6411be35a1SLionel Sambuc #include "detail/fs.hpp"
6511be35a1SLionel Sambuc #include "detail/sanity.hpp"
6611be35a1SLionel Sambuc #include "detail/text.hpp"
6711be35a1SLionel Sambuc 
6811be35a1SLionel Sambuc namespace impl = atf::tests;
6911be35a1SLionel Sambuc namespace detail = atf::tests::detail;
7011be35a1SLionel Sambuc #define IMPL_NAME "atf::tests"
7111be35a1SLionel Sambuc 
7211be35a1SLionel Sambuc // ------------------------------------------------------------------------
7311be35a1SLionel Sambuc // The "atf_tp_writer" class.
7411be35a1SLionel Sambuc // ------------------------------------------------------------------------
7511be35a1SLionel Sambuc 
atf_tp_writer(std::ostream & os)7611be35a1SLionel Sambuc detail::atf_tp_writer::atf_tp_writer(std::ostream& os) :
7711be35a1SLionel Sambuc     m_os(os),
7811be35a1SLionel Sambuc     m_is_first(true)
7911be35a1SLionel Sambuc {
80*0a6a1f1dSLionel Sambuc     m_os << "Content-Type: application/X-atf-tp; version=\"1\"\n\n";
8111be35a1SLionel Sambuc }
8211be35a1SLionel Sambuc 
8311be35a1SLionel Sambuc void
start_tc(const std::string & ident)8411be35a1SLionel Sambuc detail::atf_tp_writer::start_tc(const std::string& ident)
8511be35a1SLionel Sambuc {
8611be35a1SLionel Sambuc     if (!m_is_first)
8711be35a1SLionel Sambuc         m_os << "\n";
8811be35a1SLionel Sambuc     m_os << "ident: " << ident << "\n";
8911be35a1SLionel Sambuc     m_os.flush();
9011be35a1SLionel Sambuc }
9111be35a1SLionel Sambuc 
9211be35a1SLionel Sambuc void
end_tc(void)9311be35a1SLionel Sambuc detail::atf_tp_writer::end_tc(void)
9411be35a1SLionel Sambuc {
9511be35a1SLionel Sambuc     if (m_is_first)
9611be35a1SLionel Sambuc         m_is_first = false;
9711be35a1SLionel Sambuc }
9811be35a1SLionel Sambuc 
9911be35a1SLionel Sambuc void
tc_meta_data(const std::string & name,const std::string & value)10011be35a1SLionel Sambuc detail::atf_tp_writer::tc_meta_data(const std::string& name,
10111be35a1SLionel Sambuc                                     const std::string& value)
10211be35a1SLionel Sambuc {
10311be35a1SLionel Sambuc     PRE(name != "ident");
10411be35a1SLionel Sambuc     m_os << name << ": " << value << "\n";
10511be35a1SLionel Sambuc     m_os.flush();
10611be35a1SLionel Sambuc }
10711be35a1SLionel Sambuc 
10811be35a1SLionel Sambuc // ------------------------------------------------------------------------
10911be35a1SLionel Sambuc // Free helper functions.
11011be35a1SLionel Sambuc // ------------------------------------------------------------------------
11111be35a1SLionel Sambuc 
11211be35a1SLionel Sambuc bool
match(const std::string & regexp,const std::string & str)11311be35a1SLionel Sambuc detail::match(const std::string& regexp, const std::string& str)
11411be35a1SLionel Sambuc {
11511be35a1SLionel Sambuc     return atf::text::match(str, regexp);
11611be35a1SLionel Sambuc }
11711be35a1SLionel Sambuc 
11811be35a1SLionel Sambuc // ------------------------------------------------------------------------
11911be35a1SLionel Sambuc // The "tc" class.
12011be35a1SLionel Sambuc // ------------------------------------------------------------------------
12111be35a1SLionel Sambuc 
12211be35a1SLionel Sambuc static std::map< atf_tc_t*, impl::tc* > wraps;
12311be35a1SLionel Sambuc static std::map< const atf_tc_t*, const impl::tc* > cwraps;
12411be35a1SLionel Sambuc 
125*0a6a1f1dSLionel Sambuc struct impl::tc_impl {
126*0a6a1f1dSLionel Sambuc private:
127*0a6a1f1dSLionel Sambuc     // Non-copyable.
128*0a6a1f1dSLionel Sambuc     tc_impl(const tc_impl&);
129*0a6a1f1dSLionel Sambuc     tc_impl& operator=(const tc_impl&);
130*0a6a1f1dSLionel Sambuc 
131*0a6a1f1dSLionel Sambuc public:
13211be35a1SLionel Sambuc     std::string m_ident;
13311be35a1SLionel Sambuc     atf_tc_t m_tc;
13411be35a1SLionel Sambuc     bool m_has_cleanup;
13511be35a1SLionel Sambuc 
tc_implimpl::tc_impl13611be35a1SLionel Sambuc     tc_impl(const std::string& ident, const bool has_cleanup) :
13711be35a1SLionel Sambuc         m_ident(ident),
13811be35a1SLionel Sambuc         m_has_cleanup(has_cleanup)
13911be35a1SLionel Sambuc     {
14011be35a1SLionel Sambuc     }
14111be35a1SLionel Sambuc 
14211be35a1SLionel Sambuc     static void
wrap_headimpl::tc_impl14311be35a1SLionel Sambuc     wrap_head(atf_tc_t *tc)
14411be35a1SLionel Sambuc     {
14511be35a1SLionel Sambuc         std::map< atf_tc_t*, impl::tc* >::iterator iter = wraps.find(tc);
14611be35a1SLionel Sambuc         INV(iter != wraps.end());
14711be35a1SLionel Sambuc         (*iter).second->head();
14811be35a1SLionel Sambuc     }
14911be35a1SLionel Sambuc 
15011be35a1SLionel Sambuc     static void
wrap_bodyimpl::tc_impl15111be35a1SLionel Sambuc     wrap_body(const atf_tc_t *tc)
15211be35a1SLionel Sambuc     {
15311be35a1SLionel Sambuc         std::map< const atf_tc_t*, const impl::tc* >::const_iterator iter =
15411be35a1SLionel Sambuc             cwraps.find(tc);
15511be35a1SLionel Sambuc         INV(iter != cwraps.end());
15611be35a1SLionel Sambuc         try {
15711be35a1SLionel Sambuc             (*iter).second->body();
15811be35a1SLionel Sambuc         } catch (const std::exception& e) {
15911be35a1SLionel Sambuc             (*iter).second->fail("Caught unhandled exception: " + std::string(
16011be35a1SLionel Sambuc                                      e.what()));
16111be35a1SLionel Sambuc         } catch (...) {
16211be35a1SLionel Sambuc             (*iter).second->fail("Caught unknown exception");
16311be35a1SLionel Sambuc         }
16411be35a1SLionel Sambuc     }
16511be35a1SLionel Sambuc 
16611be35a1SLionel Sambuc     static void
wrap_cleanupimpl::tc_impl16711be35a1SLionel Sambuc     wrap_cleanup(const atf_tc_t *tc)
16811be35a1SLionel Sambuc     {
16911be35a1SLionel Sambuc         std::map< const atf_tc_t*, const impl::tc* >::const_iterator iter =
17011be35a1SLionel Sambuc             cwraps.find(tc);
17111be35a1SLionel Sambuc         INV(iter != cwraps.end());
17211be35a1SLionel Sambuc         (*iter).second->cleanup();
17311be35a1SLionel Sambuc     }
17411be35a1SLionel Sambuc };
17511be35a1SLionel Sambuc 
tc(const std::string & ident,const bool has_cleanup)17611be35a1SLionel Sambuc impl::tc::tc(const std::string& ident, const bool has_cleanup) :
17711be35a1SLionel Sambuc     pimpl(new tc_impl(ident, has_cleanup))
17811be35a1SLionel Sambuc {
17911be35a1SLionel Sambuc }
18011be35a1SLionel Sambuc 
~tc(void)18111be35a1SLionel Sambuc impl::tc::~tc(void)
18211be35a1SLionel Sambuc {
18311be35a1SLionel Sambuc     cwraps.erase(&pimpl->m_tc);
18411be35a1SLionel Sambuc     wraps.erase(&pimpl->m_tc);
18511be35a1SLionel Sambuc 
18611be35a1SLionel Sambuc     atf_tc_fini(&pimpl->m_tc);
18711be35a1SLionel Sambuc }
18811be35a1SLionel Sambuc 
18911be35a1SLionel Sambuc void
init(const vars_map & config)19011be35a1SLionel Sambuc impl::tc::init(const vars_map& config)
19111be35a1SLionel Sambuc {
19211be35a1SLionel Sambuc     atf_error_t err;
19311be35a1SLionel Sambuc 
19411be35a1SLionel Sambuc     auto_array< const char * > array(new const char*[(config.size() * 2) + 1]);
19511be35a1SLionel Sambuc     const char **ptr = array.get();
19611be35a1SLionel Sambuc     for (vars_map::const_iterator iter = config.begin();
19711be35a1SLionel Sambuc          iter != config.end(); iter++) {
19811be35a1SLionel Sambuc          *ptr = (*iter).first.c_str();
19911be35a1SLionel Sambuc          *(ptr + 1) = (*iter).second.c_str();
20011be35a1SLionel Sambuc          ptr += 2;
20111be35a1SLionel Sambuc     }
20211be35a1SLionel Sambuc     *ptr = NULL;
20311be35a1SLionel Sambuc 
20411be35a1SLionel Sambuc     wraps[&pimpl->m_tc] = this;
20511be35a1SLionel Sambuc     cwraps[&pimpl->m_tc] = this;
20611be35a1SLionel Sambuc 
20711be35a1SLionel Sambuc     err = atf_tc_init(&pimpl->m_tc, pimpl->m_ident.c_str(), pimpl->wrap_head,
20811be35a1SLionel Sambuc         pimpl->wrap_body, pimpl->m_has_cleanup ? pimpl->wrap_cleanup : NULL,
20911be35a1SLionel Sambuc         array.get());
21011be35a1SLionel Sambuc     if (atf_is_error(err))
21111be35a1SLionel Sambuc         throw_atf_error(err);
21211be35a1SLionel Sambuc }
21311be35a1SLionel Sambuc 
21411be35a1SLionel Sambuc bool
has_config_var(const std::string & var) const21511be35a1SLionel Sambuc impl::tc::has_config_var(const std::string& var)
21611be35a1SLionel Sambuc     const
21711be35a1SLionel Sambuc {
21811be35a1SLionel Sambuc     return atf_tc_has_config_var(&pimpl->m_tc, var.c_str());
21911be35a1SLionel Sambuc }
22011be35a1SLionel Sambuc 
22111be35a1SLionel Sambuc bool
has_md_var(const std::string & var) const22211be35a1SLionel Sambuc impl::tc::has_md_var(const std::string& var)
22311be35a1SLionel Sambuc     const
22411be35a1SLionel Sambuc {
22511be35a1SLionel Sambuc     return atf_tc_has_md_var(&pimpl->m_tc, var.c_str());
22611be35a1SLionel Sambuc }
22711be35a1SLionel Sambuc 
22811be35a1SLionel Sambuc const std::string
get_config_var(const std::string & var) const22911be35a1SLionel Sambuc impl::tc::get_config_var(const std::string& var)
23011be35a1SLionel Sambuc     const
23111be35a1SLionel Sambuc {
23211be35a1SLionel Sambuc     return atf_tc_get_config_var(&pimpl->m_tc, var.c_str());
23311be35a1SLionel Sambuc }
23411be35a1SLionel Sambuc 
23511be35a1SLionel Sambuc const std::string
get_config_var(const std::string & var,const std::string & defval) const23611be35a1SLionel Sambuc impl::tc::get_config_var(const std::string& var, const std::string& defval)
23711be35a1SLionel Sambuc     const
23811be35a1SLionel Sambuc {
23911be35a1SLionel Sambuc     return atf_tc_get_config_var_wd(&pimpl->m_tc, var.c_str(), defval.c_str());
24011be35a1SLionel Sambuc }
24111be35a1SLionel Sambuc 
24211be35a1SLionel Sambuc const std::string
get_md_var(const std::string & var) const24311be35a1SLionel Sambuc impl::tc::get_md_var(const std::string& var)
24411be35a1SLionel Sambuc     const
24511be35a1SLionel Sambuc {
24611be35a1SLionel Sambuc     return atf_tc_get_md_var(&pimpl->m_tc, var.c_str());
24711be35a1SLionel Sambuc }
24811be35a1SLionel Sambuc 
24911be35a1SLionel Sambuc const impl::vars_map
get_md_vars(void) const25011be35a1SLionel Sambuc impl::tc::get_md_vars(void)
25111be35a1SLionel Sambuc     const
25211be35a1SLionel Sambuc {
25311be35a1SLionel Sambuc     vars_map vars;
25411be35a1SLionel Sambuc 
25511be35a1SLionel Sambuc     char **array = atf_tc_get_md_vars(&pimpl->m_tc);
25611be35a1SLionel Sambuc     try {
25711be35a1SLionel Sambuc         char **ptr;
25811be35a1SLionel Sambuc         for (ptr = array; *ptr != NULL; ptr += 2)
25911be35a1SLionel Sambuc             vars[*ptr] = *(ptr + 1);
26011be35a1SLionel Sambuc     } catch (...) {
26111be35a1SLionel Sambuc         atf_utils_free_charpp(array);
26211be35a1SLionel Sambuc         throw;
26311be35a1SLionel Sambuc     }
26411be35a1SLionel Sambuc 
26511be35a1SLionel Sambuc     return vars;
26611be35a1SLionel Sambuc }
26711be35a1SLionel Sambuc 
26811be35a1SLionel Sambuc void
set_md_var(const std::string & var,const std::string & val)26911be35a1SLionel Sambuc impl::tc::set_md_var(const std::string& var, const std::string& val)
27011be35a1SLionel Sambuc {
271*0a6a1f1dSLionel Sambuc     atf_error_t err = atf_tc_set_md_var(&pimpl->m_tc, var.c_str(), "%s", val.c_str());
27211be35a1SLionel Sambuc     if (atf_is_error(err))
27311be35a1SLionel Sambuc         throw_atf_error(err);
27411be35a1SLionel Sambuc }
27511be35a1SLionel Sambuc 
27611be35a1SLionel Sambuc void
run(const std::string & resfile) const27711be35a1SLionel Sambuc impl::tc::run(const std::string& resfile)
27811be35a1SLionel Sambuc     const
27911be35a1SLionel Sambuc {
28011be35a1SLionel Sambuc     atf_error_t err = atf_tc_run(&pimpl->m_tc, resfile.c_str());
28111be35a1SLionel Sambuc     if (atf_is_error(err))
28211be35a1SLionel Sambuc         throw_atf_error(err);
28311be35a1SLionel Sambuc }
28411be35a1SLionel Sambuc 
28511be35a1SLionel Sambuc void
run_cleanup(void) const28611be35a1SLionel Sambuc impl::tc::run_cleanup(void)
28711be35a1SLionel Sambuc     const
28811be35a1SLionel Sambuc {
28911be35a1SLionel Sambuc     atf_error_t err = atf_tc_cleanup(&pimpl->m_tc);
29011be35a1SLionel Sambuc     if (atf_is_error(err))
29111be35a1SLionel Sambuc         throw_atf_error(err);
29211be35a1SLionel Sambuc }
29311be35a1SLionel Sambuc 
29411be35a1SLionel Sambuc void
head(void)29511be35a1SLionel Sambuc impl::tc::head(void)
29611be35a1SLionel Sambuc {
29711be35a1SLionel Sambuc }
29811be35a1SLionel Sambuc 
29911be35a1SLionel Sambuc void
cleanup(void) const30011be35a1SLionel Sambuc impl::tc::cleanup(void)
30111be35a1SLionel Sambuc     const
30211be35a1SLionel Sambuc {
30311be35a1SLionel Sambuc }
30411be35a1SLionel Sambuc 
30511be35a1SLionel Sambuc void
require_prog(const std::string & prog) const30611be35a1SLionel Sambuc impl::tc::require_prog(const std::string& prog)
30711be35a1SLionel Sambuc     const
30811be35a1SLionel Sambuc {
30911be35a1SLionel Sambuc     atf_tc_require_prog(prog.c_str());
31011be35a1SLionel Sambuc }
31111be35a1SLionel Sambuc 
31211be35a1SLionel Sambuc void
pass(void)31311be35a1SLionel Sambuc impl::tc::pass(void)
31411be35a1SLionel Sambuc {
31511be35a1SLionel Sambuc     atf_tc_pass();
31611be35a1SLionel Sambuc }
31711be35a1SLionel Sambuc 
31811be35a1SLionel Sambuc void
fail(const std::string & reason)31911be35a1SLionel Sambuc impl::tc::fail(const std::string& reason)
32011be35a1SLionel Sambuc {
32111be35a1SLionel Sambuc     atf_tc_fail("%s", reason.c_str());
32211be35a1SLionel Sambuc }
32311be35a1SLionel Sambuc 
32411be35a1SLionel Sambuc void
fail_nonfatal(const std::string & reason)32511be35a1SLionel Sambuc impl::tc::fail_nonfatal(const std::string& reason)
32611be35a1SLionel Sambuc {
32711be35a1SLionel Sambuc     atf_tc_fail_nonfatal("%s", reason.c_str());
32811be35a1SLionel Sambuc }
32911be35a1SLionel Sambuc 
33011be35a1SLionel Sambuc void
skip(const std::string & reason)33111be35a1SLionel Sambuc impl::tc::skip(const std::string& reason)
33211be35a1SLionel Sambuc {
33311be35a1SLionel Sambuc     atf_tc_skip("%s", reason.c_str());
33411be35a1SLionel Sambuc }
33511be35a1SLionel Sambuc 
33611be35a1SLionel Sambuc void
check_errno(const char * file,const int line,const int exp_errno,const char * expr_str,const bool result)33711be35a1SLionel Sambuc impl::tc::check_errno(const char* file, const int line, const int exp_errno,
33811be35a1SLionel Sambuc                       const char* expr_str, const bool result)
33911be35a1SLionel Sambuc {
34011be35a1SLionel Sambuc     atf_tc_check_errno(file, line, exp_errno, expr_str, result);
34111be35a1SLionel Sambuc }
34211be35a1SLionel Sambuc 
34311be35a1SLionel Sambuc void
require_errno(const char * file,const int line,const int exp_errno,const char * expr_str,const bool result)34411be35a1SLionel Sambuc impl::tc::require_errno(const char* file, const int line, const int exp_errno,
34511be35a1SLionel Sambuc                         const char* expr_str, const bool result)
34611be35a1SLionel Sambuc {
34711be35a1SLionel Sambuc     atf_tc_require_errno(file, line, exp_errno, expr_str, result);
34811be35a1SLionel Sambuc }
34911be35a1SLionel Sambuc 
35011be35a1SLionel Sambuc void
expect_pass(void)35111be35a1SLionel Sambuc impl::tc::expect_pass(void)
35211be35a1SLionel Sambuc {
35311be35a1SLionel Sambuc     atf_tc_expect_pass();
35411be35a1SLionel Sambuc }
35511be35a1SLionel Sambuc 
35611be35a1SLionel Sambuc void
expect_fail(const std::string & reason)35711be35a1SLionel Sambuc impl::tc::expect_fail(const std::string& reason)
35811be35a1SLionel Sambuc {
35911be35a1SLionel Sambuc     atf_tc_expect_fail("%s", reason.c_str());
36011be35a1SLionel Sambuc }
36111be35a1SLionel Sambuc 
36211be35a1SLionel Sambuc void
expect_exit(const int exitcode,const std::string & reason)36311be35a1SLionel Sambuc impl::tc::expect_exit(const int exitcode, const std::string& reason)
36411be35a1SLionel Sambuc {
36511be35a1SLionel Sambuc     atf_tc_expect_exit(exitcode, "%s", reason.c_str());
36611be35a1SLionel Sambuc }
36711be35a1SLionel Sambuc 
36811be35a1SLionel Sambuc void
expect_signal(const int signo,const std::string & reason)36911be35a1SLionel Sambuc impl::tc::expect_signal(const int signo, const std::string& reason)
37011be35a1SLionel Sambuc {
37111be35a1SLionel Sambuc     atf_tc_expect_signal(signo, "%s", reason.c_str());
37211be35a1SLionel Sambuc }
37311be35a1SLionel Sambuc 
37411be35a1SLionel Sambuc void
expect_death(const std::string & reason)37511be35a1SLionel Sambuc impl::tc::expect_death(const std::string& reason)
37611be35a1SLionel Sambuc {
37711be35a1SLionel Sambuc     atf_tc_expect_death("%s", reason.c_str());
37811be35a1SLionel Sambuc }
37911be35a1SLionel Sambuc 
38011be35a1SLionel Sambuc void
expect_timeout(const std::string & reason)38111be35a1SLionel Sambuc impl::tc::expect_timeout(const std::string& reason)
38211be35a1SLionel Sambuc {
38311be35a1SLionel Sambuc     atf_tc_expect_timeout("%s", reason.c_str());
38411be35a1SLionel Sambuc }
38511be35a1SLionel Sambuc 
38611be35a1SLionel Sambuc // ------------------------------------------------------------------------
38711be35a1SLionel Sambuc // The "tp" class.
38811be35a1SLionel Sambuc // ------------------------------------------------------------------------
38911be35a1SLionel Sambuc 
39011be35a1SLionel Sambuc class tp : public atf::application::app {
39111be35a1SLionel Sambuc public:
39211be35a1SLionel Sambuc     typedef std::vector< impl::tc * > tc_vector;
39311be35a1SLionel Sambuc 
39411be35a1SLionel Sambuc private:
39511be35a1SLionel Sambuc     static const char* m_description;
39611be35a1SLionel Sambuc 
39711be35a1SLionel Sambuc     bool m_lflag;
39811be35a1SLionel Sambuc     atf::fs::path m_resfile;
39911be35a1SLionel Sambuc     std::string m_srcdir_arg;
40011be35a1SLionel Sambuc     atf::fs::path m_srcdir;
40111be35a1SLionel Sambuc 
40211be35a1SLionel Sambuc     atf::tests::vars_map m_vars;
40311be35a1SLionel Sambuc 
40411be35a1SLionel Sambuc     std::string specific_args(void) const;
40511be35a1SLionel Sambuc     options_set specific_options(void) const;
40611be35a1SLionel Sambuc     void process_option(int, const char*);
40711be35a1SLionel Sambuc 
40811be35a1SLionel Sambuc     void (*m_add_tcs)(tc_vector&);
40911be35a1SLionel Sambuc     tc_vector m_tcs;
41011be35a1SLionel Sambuc 
41111be35a1SLionel Sambuc     void parse_vflag(const std::string&);
41211be35a1SLionel Sambuc     void handle_srcdir(void);
41311be35a1SLionel Sambuc 
41411be35a1SLionel Sambuc     tc_vector init_tcs(void);
41511be35a1SLionel Sambuc 
41611be35a1SLionel Sambuc     enum tc_part {
41711be35a1SLionel Sambuc         BODY,
41811be35a1SLionel Sambuc         CLEANUP,
41911be35a1SLionel Sambuc     };
42011be35a1SLionel Sambuc 
42111be35a1SLionel Sambuc     void list_tcs(void);
42211be35a1SLionel Sambuc     impl::tc* find_tc(tc_vector, const std::string&);
42311be35a1SLionel Sambuc     static std::pair< std::string, tc_part > process_tcarg(const std::string&);
42411be35a1SLionel Sambuc     int run_tc(const std::string&);
42511be35a1SLionel Sambuc 
42611be35a1SLionel Sambuc public:
42711be35a1SLionel Sambuc     tp(void (*)(tc_vector&));
42811be35a1SLionel Sambuc     ~tp(void);
42911be35a1SLionel Sambuc 
43011be35a1SLionel Sambuc     int main(void);
43111be35a1SLionel Sambuc };
43211be35a1SLionel Sambuc 
43311be35a1SLionel Sambuc const char* tp::m_description =
43411be35a1SLionel Sambuc     "This is an independent atf test program.";
43511be35a1SLionel Sambuc 
tp(void (* add_tcs)(tc_vector &))43611be35a1SLionel Sambuc tp::tp(void (*add_tcs)(tc_vector&)) :
437*0a6a1f1dSLionel Sambuc     app(m_description, "atf-test-program(1)"),
43811be35a1SLionel Sambuc     m_lflag(false),
43911be35a1SLionel Sambuc     m_resfile("/dev/stdout"),
44011be35a1SLionel Sambuc     m_srcdir("."),
44111be35a1SLionel Sambuc     m_add_tcs(add_tcs)
44211be35a1SLionel Sambuc {
44311be35a1SLionel Sambuc }
44411be35a1SLionel Sambuc 
~tp(void)44511be35a1SLionel Sambuc tp::~tp(void)
44611be35a1SLionel Sambuc {
44711be35a1SLionel Sambuc     for (tc_vector::iterator iter = m_tcs.begin();
44811be35a1SLionel Sambuc          iter != m_tcs.end(); iter++) {
44911be35a1SLionel Sambuc         impl::tc* tc = *iter;
45011be35a1SLionel Sambuc 
45111be35a1SLionel Sambuc         delete tc;
45211be35a1SLionel Sambuc     }
45311be35a1SLionel Sambuc }
45411be35a1SLionel Sambuc 
45511be35a1SLionel Sambuc std::string
specific_args(void) const45611be35a1SLionel Sambuc tp::specific_args(void)
45711be35a1SLionel Sambuc     const
45811be35a1SLionel Sambuc {
45911be35a1SLionel Sambuc     return "test_case";
46011be35a1SLionel Sambuc }
46111be35a1SLionel Sambuc 
46211be35a1SLionel Sambuc tp::options_set
specific_options(void) const46311be35a1SLionel Sambuc tp::specific_options(void)
46411be35a1SLionel Sambuc     const
46511be35a1SLionel Sambuc {
46611be35a1SLionel Sambuc     using atf::application::option;
46711be35a1SLionel Sambuc     options_set opts;
46811be35a1SLionel Sambuc     opts.insert(option('l', "", "List test cases and their purpose"));
46911be35a1SLionel Sambuc     opts.insert(option('r', "resfile", "The file to which the test program "
47011be35a1SLionel Sambuc                                        "will write the results of the "
47111be35a1SLionel Sambuc                                        "executed test case"));
47211be35a1SLionel Sambuc     opts.insert(option('s', "srcdir", "Directory where the test's data "
47311be35a1SLionel Sambuc                                       "files are located"));
47411be35a1SLionel Sambuc     opts.insert(option('v', "var=value", "Sets the configuration variable "
47511be35a1SLionel Sambuc                                          "`var' to `value'"));
47611be35a1SLionel Sambuc     return opts;
47711be35a1SLionel Sambuc }
47811be35a1SLionel Sambuc 
47911be35a1SLionel Sambuc void
process_option(int ch,const char * arg)48011be35a1SLionel Sambuc tp::process_option(int ch, const char* arg)
48111be35a1SLionel Sambuc {
48211be35a1SLionel Sambuc     switch (ch) {
48311be35a1SLionel Sambuc     case 'l':
48411be35a1SLionel Sambuc         m_lflag = true;
48511be35a1SLionel Sambuc         break;
48611be35a1SLionel Sambuc 
48711be35a1SLionel Sambuc     case 'r':
48811be35a1SLionel Sambuc         m_resfile = atf::fs::path(arg);
48911be35a1SLionel Sambuc         break;
49011be35a1SLionel Sambuc 
49111be35a1SLionel Sambuc     case 's':
49211be35a1SLionel Sambuc         m_srcdir_arg = arg;
49311be35a1SLionel Sambuc         break;
49411be35a1SLionel Sambuc 
49511be35a1SLionel Sambuc     case 'v':
49611be35a1SLionel Sambuc         parse_vflag(arg);
49711be35a1SLionel Sambuc         break;
49811be35a1SLionel Sambuc 
49911be35a1SLionel Sambuc     default:
50011be35a1SLionel Sambuc         UNREACHABLE;
50111be35a1SLionel Sambuc     }
50211be35a1SLionel Sambuc }
50311be35a1SLionel Sambuc 
50411be35a1SLionel Sambuc void
parse_vflag(const std::string & str)50511be35a1SLionel Sambuc tp::parse_vflag(const std::string& str)
50611be35a1SLionel Sambuc {
50711be35a1SLionel Sambuc     if (str.empty())
50811be35a1SLionel Sambuc         throw std::runtime_error("-v requires a non-empty argument");
50911be35a1SLionel Sambuc 
51011be35a1SLionel Sambuc     std::vector< std::string > ws = atf::text::split(str, "=");
51111be35a1SLionel Sambuc     if (ws.size() == 1 && str[str.length() - 1] == '=') {
51211be35a1SLionel Sambuc         m_vars[ws[0]] = "";
51311be35a1SLionel Sambuc     } else {
51411be35a1SLionel Sambuc         if (ws.size() != 2)
51511be35a1SLionel Sambuc             throw std::runtime_error("-v requires an argument of the form "
51611be35a1SLionel Sambuc                                      "var=value");
51711be35a1SLionel Sambuc 
51811be35a1SLionel Sambuc         m_vars[ws[0]] = ws[1];
51911be35a1SLionel Sambuc     }
52011be35a1SLionel Sambuc }
52111be35a1SLionel Sambuc 
52211be35a1SLionel Sambuc void
handle_srcdir(void)52311be35a1SLionel Sambuc tp::handle_srcdir(void)
52411be35a1SLionel Sambuc {
52511be35a1SLionel Sambuc     if (m_srcdir_arg.empty()) {
52611be35a1SLionel Sambuc         m_srcdir = atf::fs::path(m_argv0).branch_path();
52711be35a1SLionel Sambuc         if (m_srcdir.leaf_name() == ".libs")
52811be35a1SLionel Sambuc             m_srcdir = m_srcdir.branch_path();
52911be35a1SLionel Sambuc     } else
53011be35a1SLionel Sambuc         m_srcdir = atf::fs::path(m_srcdir_arg);
53111be35a1SLionel Sambuc 
53211be35a1SLionel Sambuc     if (!atf::fs::exists(m_srcdir / m_prog_name))
53311be35a1SLionel Sambuc         throw std::runtime_error("Cannot find the test program in the "
53411be35a1SLionel Sambuc                                  "source directory `" + m_srcdir.str() + "'");
53511be35a1SLionel Sambuc 
53611be35a1SLionel Sambuc     if (!m_srcdir.is_absolute())
53711be35a1SLionel Sambuc         m_srcdir = m_srcdir.to_absolute();
53811be35a1SLionel Sambuc 
53911be35a1SLionel Sambuc     m_vars["srcdir"] = m_srcdir.str();
54011be35a1SLionel Sambuc }
54111be35a1SLionel Sambuc 
54211be35a1SLionel Sambuc tp::tc_vector
init_tcs(void)54311be35a1SLionel Sambuc tp::init_tcs(void)
54411be35a1SLionel Sambuc {
54511be35a1SLionel Sambuc     m_add_tcs(m_tcs);
54611be35a1SLionel Sambuc     for (tc_vector::iterator iter = m_tcs.begin();
54711be35a1SLionel Sambuc          iter != m_tcs.end(); iter++) {
54811be35a1SLionel Sambuc         impl::tc* tc = *iter;
54911be35a1SLionel Sambuc 
55011be35a1SLionel Sambuc         tc->init(m_vars);
55111be35a1SLionel Sambuc     }
55211be35a1SLionel Sambuc     return m_tcs;
55311be35a1SLionel Sambuc }
55411be35a1SLionel Sambuc 
55511be35a1SLionel Sambuc //
55611be35a1SLionel Sambuc // An auxiliary unary predicate that compares the given test case's
55711be35a1SLionel Sambuc // identifier to the identifier stored in it.
55811be35a1SLionel Sambuc //
55911be35a1SLionel Sambuc class tc_equal_to_ident {
56011be35a1SLionel Sambuc     const std::string& m_ident;
56111be35a1SLionel Sambuc 
56211be35a1SLionel Sambuc public:
tc_equal_to_ident(const std::string & i)56311be35a1SLionel Sambuc     tc_equal_to_ident(const std::string& i) :
56411be35a1SLionel Sambuc         m_ident(i)
56511be35a1SLionel Sambuc     {
56611be35a1SLionel Sambuc     }
56711be35a1SLionel Sambuc 
operator ()(const impl::tc * tc)56811be35a1SLionel Sambuc     bool operator()(const impl::tc* tc)
56911be35a1SLionel Sambuc     {
57011be35a1SLionel Sambuc         return tc->get_md_var("ident") == m_ident;
57111be35a1SLionel Sambuc     }
57211be35a1SLionel Sambuc };
57311be35a1SLionel Sambuc 
57411be35a1SLionel Sambuc void
list_tcs(void)57511be35a1SLionel Sambuc tp::list_tcs(void)
57611be35a1SLionel Sambuc {
57711be35a1SLionel Sambuc     tc_vector tcs = init_tcs();
57811be35a1SLionel Sambuc     detail::atf_tp_writer writer(std::cout);
57911be35a1SLionel Sambuc 
58011be35a1SLionel Sambuc     for (tc_vector::const_iterator iter = tcs.begin();
58111be35a1SLionel Sambuc          iter != tcs.end(); iter++) {
58211be35a1SLionel Sambuc         const impl::vars_map vars = (*iter)->get_md_vars();
58311be35a1SLionel Sambuc 
58411be35a1SLionel Sambuc         {
58511be35a1SLionel Sambuc             impl::vars_map::const_iterator iter2 = vars.find("ident");
58611be35a1SLionel Sambuc             INV(iter2 != vars.end());
58711be35a1SLionel Sambuc             writer.start_tc((*iter2).second);
58811be35a1SLionel Sambuc         }
58911be35a1SLionel Sambuc 
59011be35a1SLionel Sambuc         for (impl::vars_map::const_iterator iter2 = vars.begin();
59111be35a1SLionel Sambuc              iter2 != vars.end(); iter2++) {
59211be35a1SLionel Sambuc             const std::string& key = (*iter2).first;
59311be35a1SLionel Sambuc             if (key != "ident")
59411be35a1SLionel Sambuc                 writer.tc_meta_data(key, (*iter2).second);
59511be35a1SLionel Sambuc         }
59611be35a1SLionel Sambuc 
59711be35a1SLionel Sambuc         writer.end_tc();
59811be35a1SLionel Sambuc     }
59911be35a1SLionel Sambuc }
60011be35a1SLionel Sambuc 
60111be35a1SLionel Sambuc impl::tc*
find_tc(tc_vector tcs,const std::string & name)60211be35a1SLionel Sambuc tp::find_tc(tc_vector tcs, const std::string& name)
60311be35a1SLionel Sambuc {
60411be35a1SLionel Sambuc     std::vector< std::string > ids;
60511be35a1SLionel Sambuc     for (tc_vector::iterator iter = tcs.begin();
60611be35a1SLionel Sambuc          iter != tcs.end(); iter++) {
60711be35a1SLionel Sambuc         impl::tc* tc = *iter;
60811be35a1SLionel Sambuc 
60911be35a1SLionel Sambuc         if (tc->get_md_var("ident") == name)
61011be35a1SLionel Sambuc             return tc;
61111be35a1SLionel Sambuc     }
61211be35a1SLionel Sambuc     throw atf::application::usage_error("Unknown test case `%s'",
61311be35a1SLionel Sambuc                                         name.c_str());
61411be35a1SLionel Sambuc }
61511be35a1SLionel Sambuc 
61611be35a1SLionel Sambuc std::pair< std::string, tp::tc_part >
process_tcarg(const std::string & tcarg)61711be35a1SLionel Sambuc tp::process_tcarg(const std::string& tcarg)
61811be35a1SLionel Sambuc {
61911be35a1SLionel Sambuc     const std::string::size_type pos = tcarg.find(':');
62011be35a1SLionel Sambuc     if (pos == std::string::npos) {
62111be35a1SLionel Sambuc         return std::make_pair(tcarg, BODY);
62211be35a1SLionel Sambuc     } else {
62311be35a1SLionel Sambuc         const std::string tcname = tcarg.substr(0, pos);
62411be35a1SLionel Sambuc 
62511be35a1SLionel Sambuc         const std::string partname = tcarg.substr(pos + 1);
62611be35a1SLionel Sambuc         if (partname == "body")
62711be35a1SLionel Sambuc             return std::make_pair(tcname, BODY);
62811be35a1SLionel Sambuc         else if (partname == "cleanup")
62911be35a1SLionel Sambuc             return std::make_pair(tcname, CLEANUP);
63011be35a1SLionel Sambuc         else {
63111be35a1SLionel Sambuc             using atf::application::usage_error;
63211be35a1SLionel Sambuc             throw usage_error("Invalid test case part `%s'", partname.c_str());
63311be35a1SLionel Sambuc         }
63411be35a1SLionel Sambuc     }
63511be35a1SLionel Sambuc }
63611be35a1SLionel Sambuc 
63711be35a1SLionel Sambuc int
run_tc(const std::string & tcarg)63811be35a1SLionel Sambuc tp::run_tc(const std::string& tcarg)
63911be35a1SLionel Sambuc {
64011be35a1SLionel Sambuc     const std::pair< std::string, tc_part > fields = process_tcarg(tcarg);
64111be35a1SLionel Sambuc 
64211be35a1SLionel Sambuc     impl::tc* tc = find_tc(init_tcs(), fields.first);
64311be35a1SLionel Sambuc 
64411be35a1SLionel Sambuc     if (!atf::env::has("__RUNNING_INSIDE_ATF_RUN") || atf::env::get(
64511be35a1SLionel Sambuc         "__RUNNING_INSIDE_ATF_RUN") != "internal-yes-value")
64611be35a1SLionel Sambuc     {
64711be35a1SLionel Sambuc         std::cerr << m_prog_name << ": WARNING: Running test cases without "
64811be35a1SLionel Sambuc             "atf-run(1) is unsupported\n";
64911be35a1SLionel Sambuc         std::cerr << m_prog_name << ": WARNING: No isolation nor timeout "
65011be35a1SLionel Sambuc             "control is being applied; you may get unexpected failures; see "
65111be35a1SLionel Sambuc             "atf-test-case(4)\n";
65211be35a1SLionel Sambuc     }
65311be35a1SLionel Sambuc 
65411be35a1SLionel Sambuc     try {
65511be35a1SLionel Sambuc         switch (fields.second) {
65611be35a1SLionel Sambuc         case BODY:
65711be35a1SLionel Sambuc             tc->run(m_resfile.str());
65811be35a1SLionel Sambuc             break;
65911be35a1SLionel Sambuc         case CLEANUP:
66011be35a1SLionel Sambuc             tc->run_cleanup();
66111be35a1SLionel Sambuc             break;
66211be35a1SLionel Sambuc         default:
66311be35a1SLionel Sambuc             UNREACHABLE;
66411be35a1SLionel Sambuc         }
66511be35a1SLionel Sambuc         return EXIT_SUCCESS;
66611be35a1SLionel Sambuc     } catch (const std::runtime_error& e) {
66711be35a1SLionel Sambuc         std::cerr << "ERROR: " << e.what() << "\n";
66811be35a1SLionel Sambuc         return EXIT_FAILURE;
66911be35a1SLionel Sambuc     }
67011be35a1SLionel Sambuc }
67111be35a1SLionel Sambuc 
67211be35a1SLionel Sambuc int
main(void)67311be35a1SLionel Sambuc tp::main(void)
67411be35a1SLionel Sambuc {
67511be35a1SLionel Sambuc     using atf::application::usage_error;
67611be35a1SLionel Sambuc 
67711be35a1SLionel Sambuc     int errcode;
67811be35a1SLionel Sambuc 
67911be35a1SLionel Sambuc     handle_srcdir();
68011be35a1SLionel Sambuc 
68111be35a1SLionel Sambuc     if (m_lflag) {
68211be35a1SLionel Sambuc         if (m_argc > 0)
68311be35a1SLionel Sambuc             throw usage_error("Cannot provide test case names with -l");
68411be35a1SLionel Sambuc 
68511be35a1SLionel Sambuc         list_tcs();
68611be35a1SLionel Sambuc         errcode = EXIT_SUCCESS;
68711be35a1SLionel Sambuc     } else {
68811be35a1SLionel Sambuc         if (m_argc == 0)
68911be35a1SLionel Sambuc             throw usage_error("Must provide a test case name");
69011be35a1SLionel Sambuc         else if (m_argc > 1)
69111be35a1SLionel Sambuc             throw usage_error("Cannot provide more than one test case name");
69211be35a1SLionel Sambuc         INV(m_argc == 1);
69311be35a1SLionel Sambuc 
69411be35a1SLionel Sambuc         errcode = run_tc(m_argv[0]);
69511be35a1SLionel Sambuc     }
69611be35a1SLionel Sambuc 
69711be35a1SLionel Sambuc     return errcode;
69811be35a1SLionel Sambuc }
69911be35a1SLionel Sambuc 
70011be35a1SLionel Sambuc namespace atf {
70111be35a1SLionel Sambuc     namespace tests {
70211be35a1SLionel Sambuc         int run_tp(int, char* const*, void (*)(tp::tc_vector&));
70311be35a1SLionel Sambuc     }
70411be35a1SLionel Sambuc }
70511be35a1SLionel Sambuc 
70611be35a1SLionel Sambuc int
run_tp(int argc,char * const * argv,void (* add_tcs)(tp::tc_vector &))70711be35a1SLionel Sambuc impl::run_tp(int argc, char* const* argv, void (*add_tcs)(tp::tc_vector&))
70811be35a1SLionel Sambuc {
70911be35a1SLionel Sambuc     return tp(add_tcs).run(argc, argv);
71011be35a1SLionel Sambuc }
711