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