summaryrefslogtreecommitdiffstats
path: root/atf-c++/tests.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'atf-c++/tests.cpp')
-rw-r--r--atf-c++/tests.cpp388
1 files changed, 168 insertions, 220 deletions
diff --git a/atf-c++/tests.cpp b/atf-c++/tests.cpp
index 801ed7c..ede9609 100644
--- a/atf-c++/tests.cpp
+++ b/atf-c++/tests.cpp
@@ -1,6 +1,3 @@
-//
-// Automated Testing Framework (atf)
-//
// Copyright (c) 2007 The NetBSD Foundation, Inc.
// All rights reserved.
//
@@ -25,7 +22,12 @@
// IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
// OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
// IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-//
+
+#include "atf-c++/tests.hpp"
+
+#if defined(HAVE_CONFIG_H)
+#include "config.h"
+#endif
extern "C" {
#include <sys/types.h>
@@ -55,20 +57,26 @@ extern "C" {
#include "atf-c/utils.h"
}
-#include "tests.hpp"
+#include "atf-c++/detail/application.hpp"
+#include "atf-c++/detail/auto_array.hpp"
+#include "atf-c++/detail/env.hpp"
+#include "atf-c++/detail/exceptions.hpp"
+#include "atf-c++/detail/fs.hpp"
+#include "atf-c++/detail/sanity.hpp"
+#include "atf-c++/detail/text.hpp"
-#include "detail/application.hpp"
-#include "detail/auto_array.hpp"
-#include "detail/env.hpp"
-#include "detail/exceptions.hpp"
-#include "detail/fs.hpp"
-#include "detail/sanity.hpp"
-#include "detail/text.hpp"
+#if defined(HAVE_GNU_GETOPT)
+# define GETOPT_POSIX "+"
+#else
+# define GETOPT_POSIX ""
+#endif
namespace impl = atf::tests;
namespace detail = atf::tests::detail;
#define IMPL_NAME "atf::tests"
+using atf::application::usage_error;
+
// ------------------------------------------------------------------------
// The "atf_tp_writer" class.
// ------------------------------------------------------------------------
@@ -109,6 +117,21 @@ detail::atf_tp_writer::tc_meta_data(const std::string& name,
// Free helper functions.
// ------------------------------------------------------------------------
+std::string Program_Name;
+
+static void
+set_program_name(const char* argv0)
+{
+ const std::string program_name = atf::fs::path(argv0).leaf_name();
+ // Libtool workaround: if running from within the source tree (binaries
+ // that are not installed yet), skip the "lt-" prefix added to files in
+ // the ".libs" directory to show the real (not temporary) name.
+ if (program_name.substr(0, 3) == "lt-")
+ Program_Name = program_name.substr(3);
+ else
+ Program_Name = program_name;
+}
+
bool
detail::match(const std::string& regexp, const std::string& str)
{
@@ -153,14 +176,7 @@ public:
std::map< const atf_tc_t*, const impl::tc* >::const_iterator iter =
cwraps.find(tc);
INV(iter != cwraps.end());
- try {
- (*iter).second->body();
- } catch (const std::exception& e) {
- (*iter).second->fail("Caught unhandled exception: " + std::string(
- e.what()));
- } catch (...) {
- (*iter).second->fail("Caught unknown exception");
- }
+ (*iter).second->body();
}
static void
@@ -384,197 +400,70 @@ impl::tc::expect_timeout(const std::string& reason)
}
// ------------------------------------------------------------------------
-// The "tp" class.
+// Test program main code.
// ------------------------------------------------------------------------
-class tp : public atf::application::app {
-public:
- typedef std::vector< impl::tc * > tc_vector;
-
-private:
- static const char* m_description;
-
- bool m_lflag;
- atf::fs::path m_resfile;
- std::string m_srcdir_arg;
- atf::fs::path m_srcdir;
-
- atf::tests::vars_map m_vars;
-
- std::string specific_args(void) const;
- options_set specific_options(void) const;
- void process_option(int, const char*);
-
- void (*m_add_tcs)(tc_vector&);
- tc_vector m_tcs;
-
- void parse_vflag(const std::string&);
- void handle_srcdir(void);
-
- tc_vector init_tcs(void);
-
- enum tc_part {
- BODY,
- CLEANUP,
- };
+namespace {
- void list_tcs(void);
- impl::tc* find_tc(tc_vector, const std::string&);
- static std::pair< std::string, tc_part > process_tcarg(const std::string&);
- int run_tc(const std::string&);
+typedef std::vector< impl::tc * > tc_vector;
-public:
- tp(void (*)(tc_vector&));
- ~tp(void);
-
- int main(void);
-};
-
-const char* tp::m_description =
- "This is an independent atf test program.";
-
-tp::tp(void (*add_tcs)(tc_vector&)) :
- app(m_description, "atf-test-program(1)"),
- m_lflag(false),
- m_resfile("/dev/stdout"),
- m_srcdir("."),
- m_add_tcs(add_tcs)
-{
-}
+enum tc_part { BODY, CLEANUP };
-tp::~tp(void)
-{
- for (tc_vector::iterator iter = m_tcs.begin();
- iter != m_tcs.end(); iter++) {
- impl::tc* tc = *iter;
-
- delete tc;
- }
-}
-
-std::string
-tp::specific_args(void)
- const
-{
- return "test_case";
-}
-
-tp::options_set
-tp::specific_options(void)
- const
-{
- using atf::application::option;
- options_set opts;
- opts.insert(option('l', "", "List test cases and their purpose"));
- opts.insert(option('r', "resfile", "The file to which the test program "
- "will write the results of the "
- "executed test case"));
- opts.insert(option('s', "srcdir", "Directory where the test's data "
- "files are located"));
- opts.insert(option('v', "var=value", "Sets the configuration variable "
- "`var' to `value'"));
- return opts;
-}
-
-void
-tp::process_option(int ch, const char* arg)
-{
- switch (ch) {
- case 'l':
- m_lflag = true;
- break;
-
- case 'r':
- m_resfile = atf::fs::path(arg);
- break;
-
- case 's':
- m_srcdir_arg = arg;
- break;
-
- case 'v':
- parse_vflag(arg);
- break;
-
- default:
- UNREACHABLE;
- }
-}
-
-void
-tp::parse_vflag(const std::string& str)
+static void
+parse_vflag(const std::string& str, atf::tests::vars_map& vars)
{
if (str.empty())
throw std::runtime_error("-v requires a non-empty argument");
std::vector< std::string > ws = atf::text::split(str, "=");
if (ws.size() == 1 && str[str.length() - 1] == '=') {
- m_vars[ws[0]] = "";
+ vars[ws[0]] = "";
} else {
if (ws.size() != 2)
throw std::runtime_error("-v requires an argument of the form "
"var=value");
- m_vars[ws[0]] = ws[1];
+ vars[ws[0]] = ws[1];
}
}
-void
-tp::handle_srcdir(void)
+static atf::fs::path
+handle_srcdir(const char* argv0, const std::string& srcdir_arg)
{
- if (m_srcdir_arg.empty()) {
- m_srcdir = atf::fs::path(m_argv0).branch_path();
- if (m_srcdir.leaf_name() == ".libs")
- m_srcdir = m_srcdir.branch_path();
+ atf::fs::path srcdir(".");
+
+ if (srcdir_arg.empty()) {
+ srcdir = atf::fs::path(argv0).branch_path();
+ if (srcdir.leaf_name() == ".libs")
+ srcdir = srcdir.branch_path();
} else
- m_srcdir = atf::fs::path(m_srcdir_arg);
+ srcdir = atf::fs::path(srcdir_arg);
- if (!atf::fs::exists(m_srcdir / m_prog_name))
- throw std::runtime_error("Cannot find the test program in the "
- "source directory `" + m_srcdir.str() + "'");
+ if (!atf::fs::exists(srcdir / Program_Name))
+ throw usage_error("Cannot find the test program in the source "
+ "directory `%s'", srcdir.c_str());
- if (!m_srcdir.is_absolute())
- m_srcdir = m_srcdir.to_absolute();
+ if (!srcdir.is_absolute())
+ srcdir = srcdir.to_absolute();
- m_vars["srcdir"] = m_srcdir.str();
+ return srcdir;
}
-tp::tc_vector
-tp::init_tcs(void)
+static void
+init_tcs(void (*add_tcs)(tc_vector&), tc_vector& tcs,
+ const atf::tests::vars_map& vars)
{
- m_add_tcs(m_tcs);
- for (tc_vector::iterator iter = m_tcs.begin();
- iter != m_tcs.end(); iter++) {
+ add_tcs(tcs);
+ for (tc_vector::iterator iter = tcs.begin(); iter != tcs.end(); iter++) {
impl::tc* tc = *iter;
- tc->init(m_vars);
+ tc->init(vars);
}
- return m_tcs;
}
-//
-// An auxiliary unary predicate that compares the given test case's
-// identifier to the identifier stored in it.
-//
-class tc_equal_to_ident {
- const std::string& m_ident;
-
-public:
- tc_equal_to_ident(const std::string& i) :
- m_ident(i)
- {
- }
-
- bool operator()(const impl::tc* tc)
- {
- return tc->get_md_var("ident") == m_ident;
- }
-};
-
-void
-tp::list_tcs(void)
+static int
+list_tcs(const tc_vector& tcs)
{
- tc_vector tcs = init_tcs();
detail::atf_tp_writer writer(std::cout);
for (tc_vector::const_iterator iter = tcs.begin();
@@ -596,10 +485,12 @@ tp::list_tcs(void)
writer.end_tc();
}
+
+ return EXIT_SUCCESS;
}
-impl::tc*
-tp::find_tc(tc_vector tcs, const std::string& name)
+static impl::tc*
+find_tc(tc_vector tcs, const std::string& name)
{
std::vector< std::string > ids;
for (tc_vector::iterator iter = tcs.begin();
@@ -609,12 +500,11 @@ tp::find_tc(tc_vector tcs, const std::string& name)
if (tc->get_md_var("ident") == name)
return tc;
}
- throw atf::application::usage_error("Unknown test case `%s'",
- name.c_str());
+ throw usage_error("Unknown test case `%s'", name.c_str());
}
-std::pair< std::string, tp::tc_part >
-tp::process_tcarg(const std::string& tcarg)
+static std::pair< std::string, tc_part >
+process_tcarg(const std::string& tcarg)
{
const std::string::size_type pos = tcarg.find(':');
if (pos == std::string::npos) {
@@ -628,83 +518,141 @@ tp::process_tcarg(const std::string& tcarg)
else if (partname == "cleanup")
return std::make_pair(tcname, CLEANUP);
else {
- using atf::application::usage_error;
throw usage_error("Invalid test case part `%s'", partname.c_str());
}
}
}
-int
-tp::run_tc(const std::string& tcarg)
+static int
+run_tc(tc_vector& tcs, const std::string& tcarg, const atf::fs::path& resfile)
{
const std::pair< std::string, tc_part > fields = process_tcarg(tcarg);
- impl::tc* tc = find_tc(init_tcs(), fields.first);
+ impl::tc* tc = find_tc(tcs, fields.first);
if (!atf::env::has("__RUNNING_INSIDE_ATF_RUN") || atf::env::get(
"__RUNNING_INSIDE_ATF_RUN") != "internal-yes-value")
{
- std::cerr << m_prog_name << ": WARNING: Running test cases without "
- "atf-run(1) is unsupported\n";
- std::cerr << m_prog_name << ": WARNING: No isolation nor timeout "
+ std::cerr << Program_Name << ": WARNING: Running test cases outside "
+ "of kyua(1) is unsupported\n";
+ std::cerr << Program_Name << ": WARNING: No isolation nor timeout "
"control is being applied; you may get unexpected failures; see "
"atf-test-case(4)\n";
}
- try {
- switch (fields.second) {
- case BODY:
- tc->run(m_resfile.str());
+ switch (fields.second) {
+ case BODY:
+ tc->run(resfile.str());
+ break;
+ case CLEANUP:
+ tc->run_cleanup();
+ break;
+ default:
+ UNREACHABLE;
+ }
+ return EXIT_SUCCESS;
+}
+
+static int
+safe_main(int argc, char** argv, void (*add_tcs)(tc_vector&))
+{
+ const char* argv0 = argv[0];
+
+ bool lflag = false;
+ atf::fs::path resfile("/dev/stdout");
+ std::string srcdir_arg;
+ atf::tests::vars_map vars;
+
+ int ch;
+ int old_opterr;
+
+ old_opterr = opterr;
+ ::opterr = 0;
+ while ((ch = ::getopt(argc, argv, GETOPT_POSIX ":lr:s:v:")) != -1) {
+ switch (ch) {
+ case 'l':
+ lflag = true;
+ break;
+
+ case 'r':
+ resfile = atf::fs::path(::optarg);
break;
- case CLEANUP:
- tc->run_cleanup();
+
+ case 's':
+ srcdir_arg = ::optarg;
+ break;
+
+ case 'v':
+ parse_vflag(::optarg, vars);
break;
+
+ case ':':
+ throw usage_error("Option -%c requires an argument.", ::optopt);
+ break;
+
+ case '?':
default:
- UNREACHABLE;
+ throw usage_error("Unknown option -%c.", ::optopt);
}
- return EXIT_SUCCESS;
- } catch (const std::runtime_error& e) {
- std::cerr << "ERROR: " << e.what() << "\n";
- return EXIT_FAILURE;
}
-}
+ argc -= optind;
+ argv += optind;
-int
-tp::main(void)
-{
- using atf::application::usage_error;
+ // Clear getopt state just in case the test wants to use it.
+ ::opterr = old_opterr;
+ ::optind = 1;
+#if defined(HAVE_OPTRESET)
+ ::optreset = 1;
+#endif
- int errcode;
+ vars["srcdir"] = handle_srcdir(argv0, srcdir_arg).str();
- handle_srcdir();
+ int errcode;
- if (m_lflag) {
- if (m_argc > 0)
+ tc_vector tcs;
+ if (lflag) {
+ if (argc > 0)
throw usage_error("Cannot provide test case names with -l");
- list_tcs();
- errcode = EXIT_SUCCESS;
+ init_tcs(add_tcs, tcs, vars);
+ errcode = list_tcs(tcs);
} else {
- if (m_argc == 0)
+ if (argc == 0)
throw usage_error("Must provide a test case name");
- else if (m_argc > 1)
+ else if (argc > 1)
throw usage_error("Cannot provide more than one test case name");
- INV(m_argc == 1);
+ INV(argc == 1);
- errcode = run_tc(m_argv[0]);
+ init_tcs(add_tcs, tcs, vars);
+ errcode = run_tc(tcs, argv[0], resfile);
+ }
+ for (tc_vector::iterator iter = tcs.begin(); iter != tcs.end(); iter++) {
+ impl::tc* tc = *iter;
+
+ delete tc;
}
return errcode;
}
+} // anonymous namespace
+
namespace atf {
namespace tests {
- int run_tp(int, char* const*, void (*)(tp::tc_vector&));
+ int run_tp(int, char**, void (*)(tc_vector&));
}
}
int
-impl::run_tp(int argc, char* const* argv, void (*add_tcs)(tp::tc_vector&))
+impl::run_tp(int argc, char** argv, void (*add_tcs)(tc_vector&))
{
- return tp(add_tcs).run(argc, argv);
+ try {
+ set_program_name(argv[0]);
+ return ::safe_main(argc, argv, add_tcs);
+ } catch (const usage_error& e) {
+ std::cerr
+ << Program_Name << ": ERROR: " << e.what() << '\n'
+ << Program_Name << ": See atf-test-program(1) for usage details.\n";
+ return EXIT_FAILURE;
+ }
}
OpenPOWER on IntegriCloud