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