1240116Smarcel// 2240116Smarcel// Automated Testing Framework (atf) 3240116Smarcel// 4240116Smarcel// Copyright (c) 2007 The NetBSD Foundation, Inc. 5240116Smarcel// All rights reserved. 6240116Smarcel// 7240116Smarcel// Redistribution and use in source and binary forms, with or without 8240116Smarcel// modification, are permitted provided that the following conditions 9240116Smarcel// are met: 10240116Smarcel// 1. Redistributions of source code must retain the above copyright 11240116Smarcel// notice, this list of conditions and the following disclaimer. 12240116Smarcel// 2. Redistributions in binary form must reproduce the above copyright 13240116Smarcel// notice, this list of conditions and the following disclaimer in the 14240116Smarcel// documentation and/or other materials provided with the distribution. 15240116Smarcel// 16240116Smarcel// THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND 17240116Smarcel// CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, 18240116Smarcel// INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 19240116Smarcel// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 20240116Smarcel// IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS BE LIABLE FOR ANY 21240116Smarcel// DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 22240116Smarcel// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE 23240116Smarcel// GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 24240116Smarcel// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER 25240116Smarcel// IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR 26240116Smarcel// OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN 27240116Smarcel// IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 28240116Smarcel// 29240116Smarcel 30240116Smarcelextern "C" { 31240116Smarcel#include <sys/types.h> 32240116Smarcel#include <sys/stat.h> 33240116Smarcel#include <sys/time.h> 34240116Smarcel#include <sys/wait.h> 35240116Smarcel#include <signal.h> 36240116Smarcel#include <unistd.h> 37240116Smarcel} 38240116Smarcel 39240116Smarcel#include <algorithm> 40240116Smarcel#include <cctype> 41240116Smarcel#include <cerrno> 42240116Smarcel#include <cstdlib> 43240116Smarcel#include <cstring> 44240116Smarcel#include <fstream> 45240116Smarcel#include <iostream> 46240116Smarcel#include <map> 47240116Smarcel#include <memory> 48240116Smarcel#include <sstream> 49240116Smarcel#include <stdexcept> 50240116Smarcel#include <vector> 51240116Smarcel 52240116Smarcelextern "C" { 53240116Smarcel#include "atf-c/error.h" 54240116Smarcel#include "atf-c/tc.h" 55240116Smarcel#include "atf-c/utils.h" 56240116Smarcel} 57240116Smarcel 58240116Smarcel#include "tests.hpp" 59240116Smarcel 60240116Smarcel#include "detail/application.hpp" 61260029Sjmmv#include "detail/auto_array.hpp" 62240116Smarcel#include "detail/env.hpp" 63240116Smarcel#include "detail/exceptions.hpp" 64240116Smarcel#include "detail/fs.hpp" 65240116Smarcel#include "detail/sanity.hpp" 66240116Smarcel#include "detail/text.hpp" 67240116Smarcel 68240116Smarcelnamespace impl = atf::tests; 69240116Smarcelnamespace detail = atf::tests::detail; 70240116Smarcel#define IMPL_NAME "atf::tests" 71240116Smarcel 72240116Smarcel// ------------------------------------------------------------------------ 73240116Smarcel// The "atf_tp_writer" class. 74240116Smarcel// ------------------------------------------------------------------------ 75240116Smarcel 76240116Smarceldetail::atf_tp_writer::atf_tp_writer(std::ostream& os) : 77240116Smarcel m_os(os), 78240116Smarcel m_is_first(true) 79240116Smarcel{ 80262855Sjmmv m_os << "Content-Type: application/X-atf-tp; version=\"1\"\n\n"; 81240116Smarcel} 82240116Smarcel 83240116Smarcelvoid 84240116Smarceldetail::atf_tp_writer::start_tc(const std::string& ident) 85240116Smarcel{ 86240116Smarcel if (!m_is_first) 87240116Smarcel m_os << "\n"; 88240116Smarcel m_os << "ident: " << ident << "\n"; 89240116Smarcel m_os.flush(); 90240116Smarcel} 91240116Smarcel 92240116Smarcelvoid 93240116Smarceldetail::atf_tp_writer::end_tc(void) 94240116Smarcel{ 95240116Smarcel if (m_is_first) 96240116Smarcel m_is_first = false; 97240116Smarcel} 98240116Smarcel 99240116Smarcelvoid 100240116Smarceldetail::atf_tp_writer::tc_meta_data(const std::string& name, 101240116Smarcel const std::string& value) 102240116Smarcel{ 103240116Smarcel PRE(name != "ident"); 104240116Smarcel m_os << name << ": " << value << "\n"; 105240116Smarcel m_os.flush(); 106240116Smarcel} 107240116Smarcel 108240116Smarcel// ------------------------------------------------------------------------ 109240116Smarcel// Free helper functions. 110240116Smarcel// ------------------------------------------------------------------------ 111240116Smarcel 112240116Smarcelbool 113240116Smarceldetail::match(const std::string& regexp, const std::string& str) 114240116Smarcel{ 115240116Smarcel return atf::text::match(str, regexp); 116240116Smarcel} 117240116Smarcel 118240116Smarcel// ------------------------------------------------------------------------ 119240116Smarcel// The "tc" class. 120240116Smarcel// ------------------------------------------------------------------------ 121240116Smarcel 122240116Smarcelstatic std::map< atf_tc_t*, impl::tc* > wraps; 123240116Smarcelstatic std::map< const atf_tc_t*, const impl::tc* > cwraps; 124240116Smarcel 125262855Sjmmvstruct impl::tc_impl { 126262855Sjmmvprivate: 127262855Sjmmv // Non-copyable. 128262855Sjmmv tc_impl(const tc_impl&); 129262855Sjmmv tc_impl& operator=(const tc_impl&); 130262855Sjmmv 131262855Sjmmvpublic: 132240116Smarcel std::string m_ident; 133240116Smarcel atf_tc_t m_tc; 134240116Smarcel bool m_has_cleanup; 135240116Smarcel 136240116Smarcel tc_impl(const std::string& ident, const bool has_cleanup) : 137240116Smarcel m_ident(ident), 138240116Smarcel m_has_cleanup(has_cleanup) 139240116Smarcel { 140240116Smarcel } 141240116Smarcel 142240116Smarcel static void 143240116Smarcel wrap_head(atf_tc_t *tc) 144240116Smarcel { 145240116Smarcel std::map< atf_tc_t*, impl::tc* >::iterator iter = wraps.find(tc); 146240116Smarcel INV(iter != wraps.end()); 147240116Smarcel (*iter).second->head(); 148240116Smarcel } 149240116Smarcel 150240116Smarcel static void 151240116Smarcel wrap_body(const atf_tc_t *tc) 152240116Smarcel { 153240116Smarcel std::map< const atf_tc_t*, const impl::tc* >::const_iterator iter = 154240116Smarcel cwraps.find(tc); 155240116Smarcel INV(iter != cwraps.end()); 156240116Smarcel try { 157240116Smarcel (*iter).second->body(); 158240116Smarcel } catch (const std::exception& e) { 159240116Smarcel (*iter).second->fail("Caught unhandled exception: " + std::string( 160240116Smarcel e.what())); 161240116Smarcel } catch (...) { 162240116Smarcel (*iter).second->fail("Caught unknown exception"); 163240116Smarcel } 164240116Smarcel } 165240116Smarcel 166240116Smarcel static void 167240116Smarcel wrap_cleanup(const atf_tc_t *tc) 168240116Smarcel { 169240116Smarcel std::map< const atf_tc_t*, const impl::tc* >::const_iterator iter = 170240116Smarcel cwraps.find(tc); 171240116Smarcel INV(iter != cwraps.end()); 172240116Smarcel (*iter).second->cleanup(); 173240116Smarcel } 174240116Smarcel}; 175240116Smarcel 176240116Smarcelimpl::tc::tc(const std::string& ident, const bool has_cleanup) : 177240116Smarcel pimpl(new tc_impl(ident, has_cleanup)) 178240116Smarcel{ 179240116Smarcel} 180240116Smarcel 181240116Smarcelimpl::tc::~tc(void) 182240116Smarcel{ 183240116Smarcel cwraps.erase(&pimpl->m_tc); 184240116Smarcel wraps.erase(&pimpl->m_tc); 185240116Smarcel 186240116Smarcel atf_tc_fini(&pimpl->m_tc); 187240116Smarcel} 188240116Smarcel 189240116Smarcelvoid 190240116Smarcelimpl::tc::init(const vars_map& config) 191240116Smarcel{ 192240116Smarcel atf_error_t err; 193240116Smarcel 194260029Sjmmv auto_array< const char * > array(new const char*[(config.size() * 2) + 1]); 195240116Smarcel const char **ptr = array.get(); 196240116Smarcel for (vars_map::const_iterator iter = config.begin(); 197240116Smarcel iter != config.end(); iter++) { 198240116Smarcel *ptr = (*iter).first.c_str(); 199240116Smarcel *(ptr + 1) = (*iter).second.c_str(); 200240116Smarcel ptr += 2; 201240116Smarcel } 202240116Smarcel *ptr = NULL; 203240116Smarcel 204240116Smarcel wraps[&pimpl->m_tc] = this; 205240116Smarcel cwraps[&pimpl->m_tc] = this; 206240116Smarcel 207240116Smarcel err = atf_tc_init(&pimpl->m_tc, pimpl->m_ident.c_str(), pimpl->wrap_head, 208240116Smarcel pimpl->wrap_body, pimpl->m_has_cleanup ? pimpl->wrap_cleanup : NULL, 209240116Smarcel array.get()); 210240116Smarcel if (atf_is_error(err)) 211240116Smarcel throw_atf_error(err); 212240116Smarcel} 213240116Smarcel 214240116Smarcelbool 215240116Smarcelimpl::tc::has_config_var(const std::string& var) 216240116Smarcel const 217240116Smarcel{ 218240116Smarcel return atf_tc_has_config_var(&pimpl->m_tc, var.c_str()); 219240116Smarcel} 220240116Smarcel 221240116Smarcelbool 222240116Smarcelimpl::tc::has_md_var(const std::string& var) 223240116Smarcel const 224240116Smarcel{ 225240116Smarcel return atf_tc_has_md_var(&pimpl->m_tc, var.c_str()); 226240116Smarcel} 227240116Smarcel 228240116Smarcelconst std::string 229240116Smarcelimpl::tc::get_config_var(const std::string& var) 230240116Smarcel const 231240116Smarcel{ 232240116Smarcel return atf_tc_get_config_var(&pimpl->m_tc, var.c_str()); 233240116Smarcel} 234240116Smarcel 235240116Smarcelconst std::string 236240116Smarcelimpl::tc::get_config_var(const std::string& var, const std::string& defval) 237240116Smarcel const 238240116Smarcel{ 239240116Smarcel return atf_tc_get_config_var_wd(&pimpl->m_tc, var.c_str(), defval.c_str()); 240240116Smarcel} 241240116Smarcel 242240116Smarcelconst std::string 243240116Smarcelimpl::tc::get_md_var(const std::string& var) 244240116Smarcel const 245240116Smarcel{ 246240116Smarcel return atf_tc_get_md_var(&pimpl->m_tc, var.c_str()); 247240116Smarcel} 248240116Smarcel 249240116Smarcelconst impl::vars_map 250240116Smarcelimpl::tc::get_md_vars(void) 251240116Smarcel const 252240116Smarcel{ 253240116Smarcel vars_map vars; 254240116Smarcel 255240116Smarcel char **array = atf_tc_get_md_vars(&pimpl->m_tc); 256240116Smarcel try { 257240116Smarcel char **ptr; 258240116Smarcel for (ptr = array; *ptr != NULL; ptr += 2) 259240116Smarcel vars[*ptr] = *(ptr + 1); 260240116Smarcel } catch (...) { 261240116Smarcel atf_utils_free_charpp(array); 262240116Smarcel throw; 263240116Smarcel } 264240116Smarcel 265240116Smarcel return vars; 266240116Smarcel} 267240116Smarcel 268240116Smarcelvoid 269240116Smarcelimpl::tc::set_md_var(const std::string& var, const std::string& val) 270240116Smarcel{ 271240116Smarcel atf_error_t err = atf_tc_set_md_var(&pimpl->m_tc, var.c_str(), val.c_str()); 272240116Smarcel if (atf_is_error(err)) 273240116Smarcel throw_atf_error(err); 274240116Smarcel} 275240116Smarcel 276240116Smarcelvoid 277240116Smarcelimpl::tc::run(const std::string& resfile) 278240116Smarcel const 279240116Smarcel{ 280240116Smarcel atf_error_t err = atf_tc_run(&pimpl->m_tc, resfile.c_str()); 281240116Smarcel if (atf_is_error(err)) 282240116Smarcel throw_atf_error(err); 283240116Smarcel} 284240116Smarcel 285240116Smarcelvoid 286240116Smarcelimpl::tc::run_cleanup(void) 287240116Smarcel const 288240116Smarcel{ 289240116Smarcel atf_error_t err = atf_tc_cleanup(&pimpl->m_tc); 290240116Smarcel if (atf_is_error(err)) 291240116Smarcel throw_atf_error(err); 292240116Smarcel} 293240116Smarcel 294240116Smarcelvoid 295240116Smarcelimpl::tc::head(void) 296240116Smarcel{ 297240116Smarcel} 298240116Smarcel 299240116Smarcelvoid 300240116Smarcelimpl::tc::cleanup(void) 301240116Smarcel const 302240116Smarcel{ 303240116Smarcel} 304240116Smarcel 305240116Smarcelvoid 306240116Smarcelimpl::tc::require_prog(const std::string& prog) 307240116Smarcel const 308240116Smarcel{ 309240116Smarcel atf_tc_require_prog(prog.c_str()); 310240116Smarcel} 311240116Smarcel 312240116Smarcelvoid 313240116Smarcelimpl::tc::pass(void) 314240116Smarcel{ 315240116Smarcel atf_tc_pass(); 316240116Smarcel} 317240116Smarcel 318240116Smarcelvoid 319240116Smarcelimpl::tc::fail(const std::string& reason) 320240116Smarcel{ 321240116Smarcel atf_tc_fail("%s", reason.c_str()); 322240116Smarcel} 323240116Smarcel 324240116Smarcelvoid 325240116Smarcelimpl::tc::fail_nonfatal(const std::string& reason) 326240116Smarcel{ 327240116Smarcel atf_tc_fail_nonfatal("%s", reason.c_str()); 328240116Smarcel} 329240116Smarcel 330240116Smarcelvoid 331240116Smarcelimpl::tc::skip(const std::string& reason) 332240116Smarcel{ 333240116Smarcel atf_tc_skip("%s", reason.c_str()); 334240116Smarcel} 335240116Smarcel 336240116Smarcelvoid 337240116Smarcelimpl::tc::check_errno(const char* file, const int line, const int exp_errno, 338240116Smarcel const char* expr_str, const bool result) 339240116Smarcel{ 340240116Smarcel atf_tc_check_errno(file, line, exp_errno, expr_str, result); 341240116Smarcel} 342240116Smarcel 343240116Smarcelvoid 344240116Smarcelimpl::tc::require_errno(const char* file, const int line, const int exp_errno, 345240116Smarcel const char* expr_str, const bool result) 346240116Smarcel{ 347240116Smarcel atf_tc_require_errno(file, line, exp_errno, expr_str, result); 348240116Smarcel} 349240116Smarcel 350240116Smarcelvoid 351240116Smarcelimpl::tc::expect_pass(void) 352240116Smarcel{ 353240116Smarcel atf_tc_expect_pass(); 354240116Smarcel} 355240116Smarcel 356240116Smarcelvoid 357240116Smarcelimpl::tc::expect_fail(const std::string& reason) 358240116Smarcel{ 359240116Smarcel atf_tc_expect_fail("%s", reason.c_str()); 360240116Smarcel} 361240116Smarcel 362240116Smarcelvoid 363240116Smarcelimpl::tc::expect_exit(const int exitcode, const std::string& reason) 364240116Smarcel{ 365240116Smarcel atf_tc_expect_exit(exitcode, "%s", reason.c_str()); 366240116Smarcel} 367240116Smarcel 368240116Smarcelvoid 369240116Smarcelimpl::tc::expect_signal(const int signo, const std::string& reason) 370240116Smarcel{ 371240116Smarcel atf_tc_expect_signal(signo, "%s", reason.c_str()); 372240116Smarcel} 373240116Smarcel 374240116Smarcelvoid 375240116Smarcelimpl::tc::expect_death(const std::string& reason) 376240116Smarcel{ 377240116Smarcel atf_tc_expect_death("%s", reason.c_str()); 378240116Smarcel} 379240116Smarcel 380240116Smarcelvoid 381240116Smarcelimpl::tc::expect_timeout(const std::string& reason) 382240116Smarcel{ 383240116Smarcel atf_tc_expect_timeout("%s", reason.c_str()); 384240116Smarcel} 385240116Smarcel 386240116Smarcel// ------------------------------------------------------------------------ 387240116Smarcel// The "tp" class. 388240116Smarcel// ------------------------------------------------------------------------ 389240116Smarcel 390240116Smarcelclass tp : public atf::application::app { 391240116Smarcelpublic: 392240116Smarcel typedef std::vector< impl::tc * > tc_vector; 393240116Smarcel 394240116Smarcelprivate: 395240116Smarcel static const char* m_description; 396240116Smarcel 397240116Smarcel bool m_lflag; 398240116Smarcel atf::fs::path m_resfile; 399240116Smarcel std::string m_srcdir_arg; 400240116Smarcel atf::fs::path m_srcdir; 401240116Smarcel 402240116Smarcel atf::tests::vars_map m_vars; 403240116Smarcel 404240116Smarcel std::string specific_args(void) const; 405240116Smarcel options_set specific_options(void) const; 406240116Smarcel void process_option(int, const char*); 407240116Smarcel 408240116Smarcel void (*m_add_tcs)(tc_vector&); 409240116Smarcel tc_vector m_tcs; 410240116Smarcel 411240116Smarcel void parse_vflag(const std::string&); 412240116Smarcel void handle_srcdir(void); 413240116Smarcel 414240116Smarcel tc_vector init_tcs(void); 415240116Smarcel 416240116Smarcel enum tc_part { 417240116Smarcel BODY, 418240116Smarcel CLEANUP, 419240116Smarcel }; 420240116Smarcel 421240116Smarcel void list_tcs(void); 422240116Smarcel impl::tc* find_tc(tc_vector, const std::string&); 423240116Smarcel static std::pair< std::string, tc_part > process_tcarg(const std::string&); 424240116Smarcel int run_tc(const std::string&); 425240116Smarcel 426240116Smarcelpublic: 427240116Smarcel tp(void (*)(tc_vector&)); 428240116Smarcel ~tp(void); 429240116Smarcel 430240116Smarcel int main(void); 431240116Smarcel}; 432240116Smarcel 433240116Smarcelconst char* tp::m_description = 434240116Smarcel "This is an independent atf test program."; 435240116Smarcel 436240116Smarceltp::tp(void (*add_tcs)(tc_vector&)) : 437262855Sjmmv app(m_description, "atf-test-program(1)"), 438240116Smarcel m_lflag(false), 439240116Smarcel m_resfile("/dev/stdout"), 440240116Smarcel m_srcdir("."), 441240116Smarcel m_add_tcs(add_tcs) 442240116Smarcel{ 443240116Smarcel} 444240116Smarcel 445240116Smarceltp::~tp(void) 446240116Smarcel{ 447240116Smarcel for (tc_vector::iterator iter = m_tcs.begin(); 448240116Smarcel iter != m_tcs.end(); iter++) { 449240116Smarcel impl::tc* tc = *iter; 450240116Smarcel 451240116Smarcel delete tc; 452240116Smarcel } 453240116Smarcel} 454240116Smarcel 455240116Smarcelstd::string 456240116Smarceltp::specific_args(void) 457240116Smarcel const 458240116Smarcel{ 459240116Smarcel return "test_case"; 460240116Smarcel} 461240116Smarcel 462240116Smarceltp::options_set 463240116Smarceltp::specific_options(void) 464240116Smarcel const 465240116Smarcel{ 466240116Smarcel using atf::application::option; 467240116Smarcel options_set opts; 468240116Smarcel opts.insert(option('l', "", "List test cases and their purpose")); 469240116Smarcel opts.insert(option('r', "resfile", "The file to which the test program " 470240116Smarcel "will write the results of the " 471240116Smarcel "executed test case")); 472240116Smarcel opts.insert(option('s', "srcdir", "Directory where the test's data " 473240116Smarcel "files are located")); 474240116Smarcel opts.insert(option('v', "var=value", "Sets the configuration variable " 475240116Smarcel "`var' to `value'")); 476240116Smarcel return opts; 477240116Smarcel} 478240116Smarcel 479240116Smarcelvoid 480240116Smarceltp::process_option(int ch, const char* arg) 481240116Smarcel{ 482240116Smarcel switch (ch) { 483240116Smarcel case 'l': 484240116Smarcel m_lflag = true; 485240116Smarcel break; 486240116Smarcel 487240116Smarcel case 'r': 488240116Smarcel m_resfile = atf::fs::path(arg); 489240116Smarcel break; 490240116Smarcel 491240116Smarcel case 's': 492240116Smarcel m_srcdir_arg = arg; 493240116Smarcel break; 494240116Smarcel 495240116Smarcel case 'v': 496240116Smarcel parse_vflag(arg); 497240116Smarcel break; 498240116Smarcel 499240116Smarcel default: 500240116Smarcel UNREACHABLE; 501240116Smarcel } 502240116Smarcel} 503240116Smarcel 504240116Smarcelvoid 505240116Smarceltp::parse_vflag(const std::string& str) 506240116Smarcel{ 507240116Smarcel if (str.empty()) 508240116Smarcel throw std::runtime_error("-v requires a non-empty argument"); 509240116Smarcel 510240116Smarcel std::vector< std::string > ws = atf::text::split(str, "="); 511240116Smarcel if (ws.size() == 1 && str[str.length() - 1] == '=') { 512240116Smarcel m_vars[ws[0]] = ""; 513240116Smarcel } else { 514240116Smarcel if (ws.size() != 2) 515240116Smarcel throw std::runtime_error("-v requires an argument of the form " 516240116Smarcel "var=value"); 517240116Smarcel 518240116Smarcel m_vars[ws[0]] = ws[1]; 519240116Smarcel } 520240116Smarcel} 521240116Smarcel 522240116Smarcelvoid 523240116Smarceltp::handle_srcdir(void) 524240116Smarcel{ 525240116Smarcel if (m_srcdir_arg.empty()) { 526240116Smarcel m_srcdir = atf::fs::path(m_argv0).branch_path(); 527240116Smarcel if (m_srcdir.leaf_name() == ".libs") 528240116Smarcel m_srcdir = m_srcdir.branch_path(); 529240116Smarcel } else 530240116Smarcel m_srcdir = atf::fs::path(m_srcdir_arg); 531240116Smarcel 532240116Smarcel if (!atf::fs::exists(m_srcdir / m_prog_name)) 533240116Smarcel throw std::runtime_error("Cannot find the test program in the " 534240116Smarcel "source directory `" + m_srcdir.str() + "'"); 535240116Smarcel 536240116Smarcel if (!m_srcdir.is_absolute()) 537240116Smarcel m_srcdir = m_srcdir.to_absolute(); 538240116Smarcel 539240116Smarcel m_vars["srcdir"] = m_srcdir.str(); 540240116Smarcel} 541240116Smarcel 542240116Smarceltp::tc_vector 543240116Smarceltp::init_tcs(void) 544240116Smarcel{ 545240116Smarcel m_add_tcs(m_tcs); 546240116Smarcel for (tc_vector::iterator iter = m_tcs.begin(); 547240116Smarcel iter != m_tcs.end(); iter++) { 548240116Smarcel impl::tc* tc = *iter; 549240116Smarcel 550240116Smarcel tc->init(m_vars); 551240116Smarcel } 552240116Smarcel return m_tcs; 553240116Smarcel} 554240116Smarcel 555240116Smarcel// 556240116Smarcel// An auxiliary unary predicate that compares the given test case's 557240116Smarcel// identifier to the identifier stored in it. 558240116Smarcel// 559240116Smarcelclass tc_equal_to_ident { 560240116Smarcel const std::string& m_ident; 561240116Smarcel 562240116Smarcelpublic: 563240116Smarcel tc_equal_to_ident(const std::string& i) : 564240116Smarcel m_ident(i) 565240116Smarcel { 566240116Smarcel } 567240116Smarcel 568240116Smarcel bool operator()(const impl::tc* tc) 569240116Smarcel { 570240116Smarcel return tc->get_md_var("ident") == m_ident; 571240116Smarcel } 572240116Smarcel}; 573240116Smarcel 574240116Smarcelvoid 575240116Smarceltp::list_tcs(void) 576240116Smarcel{ 577240116Smarcel tc_vector tcs = init_tcs(); 578240116Smarcel detail::atf_tp_writer writer(std::cout); 579240116Smarcel 580240116Smarcel for (tc_vector::const_iterator iter = tcs.begin(); 581240116Smarcel iter != tcs.end(); iter++) { 582240116Smarcel const impl::vars_map vars = (*iter)->get_md_vars(); 583240116Smarcel 584240116Smarcel { 585240116Smarcel impl::vars_map::const_iterator iter2 = vars.find("ident"); 586240116Smarcel INV(iter2 != vars.end()); 587240116Smarcel writer.start_tc((*iter2).second); 588240116Smarcel } 589240116Smarcel 590240116Smarcel for (impl::vars_map::const_iterator iter2 = vars.begin(); 591240116Smarcel iter2 != vars.end(); iter2++) { 592240116Smarcel const std::string& key = (*iter2).first; 593240116Smarcel if (key != "ident") 594240116Smarcel writer.tc_meta_data(key, (*iter2).second); 595240116Smarcel } 596240116Smarcel 597240116Smarcel writer.end_tc(); 598240116Smarcel } 599240116Smarcel} 600240116Smarcel 601240116Smarcelimpl::tc* 602240116Smarceltp::find_tc(tc_vector tcs, const std::string& name) 603240116Smarcel{ 604240116Smarcel std::vector< std::string > ids; 605240116Smarcel for (tc_vector::iterator iter = tcs.begin(); 606240116Smarcel iter != tcs.end(); iter++) { 607240116Smarcel impl::tc* tc = *iter; 608240116Smarcel 609240116Smarcel if (tc->get_md_var("ident") == name) 610240116Smarcel return tc; 611240116Smarcel } 612240116Smarcel throw atf::application::usage_error("Unknown test case `%s'", 613240116Smarcel name.c_str()); 614240116Smarcel} 615240116Smarcel 616240116Smarcelstd::pair< std::string, tp::tc_part > 617240116Smarceltp::process_tcarg(const std::string& tcarg) 618240116Smarcel{ 619240116Smarcel const std::string::size_type pos = tcarg.find(':'); 620240116Smarcel if (pos == std::string::npos) { 621240116Smarcel return std::make_pair(tcarg, BODY); 622240116Smarcel } else { 623240116Smarcel const std::string tcname = tcarg.substr(0, pos); 624240116Smarcel 625240116Smarcel const std::string partname = tcarg.substr(pos + 1); 626240116Smarcel if (partname == "body") 627240116Smarcel return std::make_pair(tcname, BODY); 628240116Smarcel else if (partname == "cleanup") 629240116Smarcel return std::make_pair(tcname, CLEANUP); 630240116Smarcel else { 631240116Smarcel using atf::application::usage_error; 632240116Smarcel throw usage_error("Invalid test case part `%s'", partname.c_str()); 633240116Smarcel } 634240116Smarcel } 635240116Smarcel} 636240116Smarcel 637240116Smarcelint 638240116Smarceltp::run_tc(const std::string& tcarg) 639240116Smarcel{ 640240116Smarcel const std::pair< std::string, tc_part > fields = process_tcarg(tcarg); 641240116Smarcel 642240116Smarcel impl::tc* tc = find_tc(init_tcs(), fields.first); 643240116Smarcel 644240116Smarcel if (!atf::env::has("__RUNNING_INSIDE_ATF_RUN") || atf::env::get( 645240116Smarcel "__RUNNING_INSIDE_ATF_RUN") != "internal-yes-value") 646240116Smarcel { 647240116Smarcel std::cerr << m_prog_name << ": WARNING: Running test cases without " 648240116Smarcel "atf-run(1) is unsupported\n"; 649240116Smarcel std::cerr << m_prog_name << ": WARNING: No isolation nor timeout " 650240116Smarcel "control is being applied; you may get unexpected failures; see " 651240116Smarcel "atf-test-case(4)\n"; 652240116Smarcel } 653240116Smarcel 654240116Smarcel try { 655240116Smarcel switch (fields.second) { 656240116Smarcel case BODY: 657240116Smarcel tc->run(m_resfile.str()); 658240116Smarcel break; 659240116Smarcel case CLEANUP: 660240116Smarcel tc->run_cleanup(); 661240116Smarcel break; 662240116Smarcel default: 663240116Smarcel UNREACHABLE; 664240116Smarcel } 665240116Smarcel return EXIT_SUCCESS; 666240116Smarcel } catch (const std::runtime_error& e) { 667240116Smarcel std::cerr << "ERROR: " << e.what() << "\n"; 668240116Smarcel return EXIT_FAILURE; 669240116Smarcel } 670240116Smarcel} 671240116Smarcel 672240116Smarcelint 673240116Smarceltp::main(void) 674240116Smarcel{ 675240116Smarcel using atf::application::usage_error; 676240116Smarcel 677240116Smarcel int errcode; 678240116Smarcel 679240116Smarcel handle_srcdir(); 680240116Smarcel 681240116Smarcel if (m_lflag) { 682240116Smarcel if (m_argc > 0) 683240116Smarcel throw usage_error("Cannot provide test case names with -l"); 684240116Smarcel 685240116Smarcel list_tcs(); 686240116Smarcel errcode = EXIT_SUCCESS; 687240116Smarcel } else { 688240116Smarcel if (m_argc == 0) 689240116Smarcel throw usage_error("Must provide a test case name"); 690240116Smarcel else if (m_argc > 1) 691240116Smarcel throw usage_error("Cannot provide more than one test case name"); 692240116Smarcel INV(m_argc == 1); 693240116Smarcel 694240116Smarcel errcode = run_tc(m_argv[0]); 695240116Smarcel } 696240116Smarcel 697240116Smarcel return errcode; 698240116Smarcel} 699240116Smarcel 700240116Smarcelnamespace atf { 701240116Smarcel namespace tests { 702240116Smarcel int run_tp(int, char* const*, void (*)(tp::tc_vector&)); 703240116Smarcel } 704240116Smarcel} 705240116Smarcel 706240116Smarcelint 707240116Smarcelimpl::run_tp(int argc, char* const* argv, void (*add_tcs)(tp::tc_vector&)) 708240116Smarcel{ 709240116Smarcel return tp(add_tcs).run(argc, argv); 710240116Smarcel} 711