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