aboutsummaryrefslogtreecommitdiff
path: root/0.8.0/test
diff options
context:
space:
mode:
Diffstat (limited to '0.8.0/test')
-rw-r--r--0.8.0/test/Makefile.am25
-rwxr-xr-x0.8.0/test/run_test.sh44
-rw-r--r--0.8.0/test/test_fail_TEST.cc47
-rw-r--r--0.8.0/test/test_framework.cc308
-rw-r--r--0.8.0/test/test_framework.hh285
-rw-r--r--0.8.0/test/test_pass_TEST.cc51
-rw-r--r--0.8.0/test/test_runner.cc99
-rw-r--r--0.8.0/test/test_runner.hh38
8 files changed, 897 insertions, 0 deletions
diff --git a/0.8.0/test/Makefile.am b/0.8.0/test/Makefile.am
new file mode 100644
index 0000000..90724b0
--- /dev/null
+++ b/0.8.0/test/Makefile.am
@@ -0,0 +1,25 @@
+CLEANFILES = *~ gmon.out *.gcov *.gcno *.gcda
+MAINTAINERCLEANFILES = Makefile.in
+AM_CXXFLAGS = -I$(top_srcdir) @PALUDIS_CXXFLAGS@
+EXTRA_DIST = run_test.sh
+
+libtest_a_SOURCES = \
+ test_framework.cc \
+ test_framework.hh \
+ test_runner.cc \
+ test_runner.hh
+
+XFAIL_TESTS = test_fail_TEST
+TESTS = test_pass_TEST $(XFAIL_TESTS)
+
+TESTS_ENVIRONMENT = env TEST_SCRIPT_DIR="$(srcdir)/" bash $(top_srcdir)/test/run_test.sh
+check_LIBRARIES = libtest.a
+check_PROGRAMS = $(TESTS) $(XFAIL_TESTS)
+check_SCRIPTS = run_test.sh
+
+test_pass_TEST_SOURCES = test_pass_TEST.cc
+test_pass_TEST_LDADD = libtest.a
+
+test_fail_TEST_SOURCES = test_fail_TEST.cc
+test_fail_TEST_LDADD = libtest.a
+
diff --git a/0.8.0/test/run_test.sh b/0.8.0/test/run_test.sh
new file mode 100755
index 0000000..c707978
--- /dev/null
+++ b/0.8.0/test/run_test.sh
@@ -0,0 +1,44 @@
+#!/bin/bash
+# vim: set ft=sh sw=4 sts=4 et :
+
+testname=${2:-${1}}
+testname=${testname%.rb}
+
+if test -f "$TEST_SCRIPT_DIR""${testname}"_"cleanup.sh" ; then
+ echo ">>> cleanup for test ${testname}"
+ if ! "$TEST_SCRIPT_DIR""${testname}"_"cleanup.sh" ; then
+ echo ">>> exiting with error for test ${testname}"
+ exit 255
+ fi
+fi
+
+if test -f "$TEST_SCRIPT_DIR""${testname}"_"setup.sh" ; then
+ echo ">>> setup for test ${testname}"
+ if ! "$TEST_SCRIPT_DIR""${testname}"_"setup.sh" ; then
+ echo ">>> exiting with error for test ${testname}"
+ exit 255
+ fi
+fi
+
+echo ">>> test ${testname}"
+if ! ${@} ; then
+ if test -f "$TEST_SCRIPT_DIR""${testname}"_"cleanup.sh" ; then
+ echo ">>> cleanup for test ${testname}"
+ "$TEST_SCRIPT_DIR""${testname}"_"cleanup.sh"
+ fi
+ echo ">>> exiting with error for test ${testname}"
+ exit 255
+fi
+
+if test -f "$TEST_SCRIPT_DIR""${testname}"_"cleanup.sh" ; then
+ echo ">>> cleanup for test ${testname}"
+ if ! "$TEST_SCRIPT_DIR""${testname}"_"cleanup.sh" ; then
+ echo ">>> exiting with error for test ${testname}"
+ exit 255
+ fi
+fi
+
+echo ">>> exiting with success for test ${testname}"
+exit 0
+
+
diff --git a/0.8.0/test/test_fail_TEST.cc b/0.8.0/test/test_fail_TEST.cc
new file mode 100644
index 0000000..46d04c1
--- /dev/null
+++ b/0.8.0/test/test_fail_TEST.cc
@@ -0,0 +1,47 @@
+/* vim: set sw=4 sts=4 et foldmethod=syntax : */
+
+/*
+ * Copyright (c) 2006 Ciaran McCreesh <ciaranm@ciaranm.org>
+ *
+ * This file is part of the Paludis package manager. Paludis is free software;
+ * you can redistribute it and/or modify it under the terms of the GNU General
+ * Public License version 2, as published by the Free Software Foundation.
+ *
+ * Paludis is distributed in the hope that it will be useful, but WITHOUT ANY
+ * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+ * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
+ * details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, write to the Free Software Foundation, Inc., 59 Temple
+ * Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#include <string>
+#include <test/test_framework.hh>
+#include <test/test_runner.hh>
+
+using namespace test;
+
+/** \file
+ * This test should fail.
+ *
+ * \ingroup Test
+ */
+
+namespace test_cases
+{
+ /**
+ * \test This test should fail.
+ */
+ struct FailTest : TestCase
+ {
+ FailTest() : TestCase("test the test code: this should fail") { }
+
+ void run()
+ {
+ TEST_CHECK_STRINGIFY_EQUAL("this comparison", "should fail");
+ }
+ } test_fail;
+}
+
diff --git a/0.8.0/test/test_framework.cc b/0.8.0/test/test_framework.cc
new file mode 100644
index 0000000..e34798e
--- /dev/null
+++ b/0.8.0/test/test_framework.cc
@@ -0,0 +1,308 @@
+/* vim: set sw=4 sts=4 et foldmethod=syntax : */
+
+/*
+ * Copyright (c) 2006 Ciaran McCreesh <ciaranm@ciaranm.org>
+ *
+ * This file is part of the Paludis package manager. Paludis is free software;
+ * you can redistribute it and/or modify it under the terms of the GNU General
+ * Public License version 2, as published by the Free Software Foundation.
+ *
+ * Paludis is distributed in the hope that it will be useful, but WITHOUT ANY
+ * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+ * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
+ * details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, write to the Free Software Foundation, Inc., 59 Temple
+ * Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#include "test_framework.hh"
+#include <algorithm>
+#include <iostream>
+#include <list>
+#include <paludis/util/attributes.hh>
+#include <unistd.h>
+
+/** \file
+ * Implementation for test framework classes.
+ *
+ * \ingroup Test
+ */
+
+using namespace test;
+
+#ifndef DOXYGEN
+namespace
+{
+ std::string exception_to_debug_string(const std::exception & e)
+ {
+ return e.what() + std::string(" (no further information)");
+ }
+
+ class DebugStringHolder
+ {
+ private:
+ std::string (*_f) (const std::exception &);
+
+ DebugStringHolder() :
+ _f(&exception_to_debug_string)
+ {
+ }
+
+ public:
+ static DebugStringHolder * get_instance()
+ {
+ static DebugStringHolder _instance;
+ return &_instance;
+ }
+
+ void set(std::string (*f) (const std::exception &))
+ {
+ _f = f;
+ }
+
+ std::string (*get() const) (const std::exception &)
+ {
+ return _f;
+ }
+ };
+}
+
+void
+test::set_exception_to_debug_string(std::string (*f) (const std::exception &))
+{
+ DebugStringHolder::get_instance()->set(f);
+}
+
+std::string (* test::get_exception_to_debug_string()) (const std::exception &)
+{
+ return DebugStringHolder::get_instance()->get();
+}
+
+namespace paludis
+{
+ template<>
+ struct Implementation<TestMessageSuffix> :
+ InternalCounted<Implementation<TestMessageSuffix> >
+ {
+ static std::list<std::string> suffixes;
+ };
+
+ std::list<std::string> Implementation<TestMessageSuffix>::suffixes;
+}
+
+std::string
+TestMessageSuffix::suffixes()
+{
+ std::string result;
+ std::list<std::string>::const_iterator i(paludis::Implementation<TestMessageSuffix>::suffixes.begin()),
+ end(paludis::Implementation<TestMessageSuffix>::suffixes.end());
+
+ while (i != end)
+ {
+ result += *i++;
+ if (end != i)
+ result += ", ";
+ }
+ return result;
+}
+
+TestMessageSuffix::TestMessageSuffix(const std::string & s, bool write) :
+ paludis::PrivateImplementationPattern<TestMessageSuffix>(
+ new paludis::Implementation<TestMessageSuffix>)
+{
+ paludis::Implementation<TestMessageSuffix>::suffixes.push_back(s);
+ if (write)
+ std::cout << "[" << s << "]" << std::flush;
+}
+
+TestMessageSuffix::~TestMessageSuffix()
+{
+ paludis::Implementation<TestMessageSuffix>::suffixes.pop_back();
+}
+
+namespace paludis
+{
+ template<>
+ struct Implementation<TestCase> :
+ InternalCounted<Implementation<TestCase> >
+ {
+ const std::string name;
+
+ Implementation(const std::string & the_name) :
+ name(the_name)
+ {
+ }
+ };
+}
+
+TestCase::TestCase(const std::string & our_name) :
+ paludis::PrivateImplementationPattern<TestCase>(new paludis::Implementation<TestCase>(our_name))
+{
+ TestCaseList::register_test_case(this);
+}
+
+TestCase::~TestCase()
+{
+}
+
+void
+TestCase::check(const char * const function, const char * const file,
+ const long line, bool was_ok, const std::string & message) const
+{
+ std::cout << "." << std::flush;
+ if (! was_ok)
+ throw TestFailedException(function, file, line, message);
+}
+
+void
+TestCase::call_run()
+{
+ try
+ {
+ run();
+ }
+ catch (TestFailedException)
+ {
+ throw;
+ }
+ catch (std::exception &e)
+ {
+ throw TestFailedException(__PRETTY_FUNCTION__, __FILE__, __LINE__,
+ "Test threw unexpected exception " + (DebugStringHolder::get_instance()->get())(e));
+ }
+ catch (...)
+ {
+ throw TestFailedException(__PRETTY_FUNCTION__, __FILE__, __LINE__,
+ "Test threw unexpected unknown exception");
+ }
+}
+
+std::string
+TestCase::name() const
+{
+ return _imp->name;
+}
+
+TestFailedException::TestFailedException(const char * const function, const char * const file,
+ const long line, const std::string & message) throw () :
+ _message(paludis::stringify(file) + ":" + paludis::stringify(line) + ": in " +
+ paludis::stringify(function) + ": " + message + (
+ TestMessageSuffix::suffixes().empty() ? std::string("") : " [context: " +
+ TestMessageSuffix::suffixes() + "]"))
+{
+}
+
+TestFailedException::~TestFailedException() throw ()
+{
+}
+
+namespace
+{
+ std::list<TestCase *> *
+ get_test_case_list()
+ {
+ static std::list<TestCase *> l;
+ return &l;
+ }
+}
+
+TestCaseList::TestCaseList()
+{
+}
+
+TestCaseList::~TestCaseList()
+{
+}
+
+void
+TestCaseList::register_test_case(TestCase * const t)
+{
+ get_test_case_list()->push_back(t);
+}
+
+class RunTest
+{
+ private:
+ bool * const _had_a_failure;
+
+ public:
+ RunTest(bool * had_a_failure) :
+ _had_a_failure(had_a_failure)
+ {
+ }
+
+ void operator() (TestCase * test_case) const;
+};
+
+void
+RunTest::operator() (TestCase * test_case) const
+{
+ bool had_local_failure(false);
+
+ std::cout << "* \"" << test_case->name() << "\": " << std::flush;
+
+ for (int repeat = 0 ; repeat < 2 ; ++repeat)
+ {
+ if (test_case->skip())
+ {
+ std::cout << "(skip)" << std::endl;
+ break;
+ }
+
+ if (0 != repeat)
+ std::cout << " (repeat): " << std::flush;
+
+ try
+ {
+ if (TestCaseList::use_alarm)
+ alarm(test_case->max_run_time());
+ test_case->call_run();
+ if (TestCaseList::use_alarm)
+ alarm(0);
+ }
+ catch (std::exception &e)
+ {
+ std::cout << "!{" << std::endl << (DebugStringHolder::get_instance()->get())(e) <<
+ std::endl << " } " << std::flush;
+ had_local_failure = true;
+ *_had_a_failure = true;
+ }
+ catch (...)
+ {
+ std::cout << "!{Unknown exception type} ";
+ had_local_failure = true;
+ *_had_a_failure = true;
+ }
+
+ if (had_local_failure)
+ std::cout << " NOT OK";
+ else
+ std::cout << " OK";
+
+ std::cout << std::endl;
+
+ if (! test_case->repeatable())
+ break;
+ }
+}
+
+bool
+TestCaseList::run_tests()
+{
+ bool had_a_failure(get_test_case_list()->empty());
+
+ std::for_each(
+ get_test_case_list()->begin(),
+ get_test_case_list()->end(),
+ RunTest(&had_a_failure));
+
+ return ! had_a_failure;
+}
+
+bool
+TestCaseList::use_alarm(true);
+
+#endif
+
diff --git a/0.8.0/test/test_framework.hh b/0.8.0/test/test_framework.hh
new file mode 100644
index 0000000..ee93d00
--- /dev/null
+++ b/0.8.0/test/test_framework.hh
@@ -0,0 +1,285 @@
+/* vim: set sw=4 sts=4 et foldmethod=syntax : */
+
+/*
+ * Copyright (c) 2006 Ciaran McCreesh <ciaranm@ciaranm.org>
+ *
+ * This file is part of the Paludis package manager. Paludis is free software;
+ * you can redistribute it and/or modify it under the terms of the GNU General
+ * Public License version 2, as published by the Free Software Foundation.
+ *
+ * Paludis is distributed in the hope that it will be useful, but WITHOUT ANY
+ * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+ * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
+ * details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, write to the Free Software Foundation, Inc., 59 Temple
+ * Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#ifndef PALUDIS_GUARD_TEST_TEST_FRAMEWORK_HH
+#define PALUDIS_GUARD_TEST_TEST_FRAMEWORK_HH 1
+
+#include <paludis/util/stringify.hh>
+#include <paludis/util/private_implementation_pattern.hh>
+#include <string>
+
+/** \file
+ * Test framework class definitions.
+ *
+ * \ingroup Test
+ */
+
+namespace test
+{
+ /**
+ * RAII suffix marker for TestCase context.
+ *
+ * \ingroup Test
+ */
+ class TestMessageSuffix :
+ paludis::PrivateImplementationPattern<TestMessageSuffix>
+ {
+ public:
+ /**
+ * Constructor.
+ */
+ explicit TestMessageSuffix(const std::string & s, bool write = false);
+
+ /**
+ * Destructor.
+ */
+ ~TestMessageSuffix();
+
+ /**
+ * Our suffixes.
+ */
+ static std::string suffixes();
+ };
+
+ /**
+ * Base TestCase class.
+ *
+ * \ingroup Test
+ */
+ class TestCase :
+ private paludis::PrivateImplementationPattern<TestCase>
+ {
+ protected:
+ /**
+ * Check that a given assertion is true.
+ */
+ void check(const char * const function, const char * const file,
+ const long line, bool was_ok, const std::string & message) const;
+
+ /**
+ * Run the tests (override this in descendents).
+ */
+ virtual void run() = 0;
+
+ public:
+ /**
+ * Constructor.
+ */
+ TestCase(const std::string & name);
+
+ /**
+ * Destructor.
+ */
+ virtual ~TestCase();
+
+ /**
+ * Call our run() function, and normalise exceptions.
+ */
+ void call_run();
+
+ /**
+ * Return our name.
+ */
+ std::string name() const;
+
+ /**
+ * Are we repeatable? Override if not.
+ */
+ virtual bool repeatable() const
+ {
+ return true;
+ }
+
+ /**
+ * Should we be skipped?
+ */
+ virtual bool skip() const
+ {
+ return false;
+ }
+
+ /**
+ * After how many seconds should we timeout?
+ */
+ virtual unsigned max_run_time() const
+ {
+ return 30;
+ }
+ };
+
+ /**
+ * Thrown if a TestCase failed.
+ *
+ * \ingroup Test
+ * \ingroup grpexceptions
+ */
+ class TestFailedException : public std::exception
+ {
+ private:
+ const std::string _message;
+
+ public:
+ /**
+ * Constructor.
+ */
+ TestFailedException(const char * const function, const char * const file,
+ const long line, const std::string & message) throw ();
+
+ /**
+ * Destructor.
+ */
+ virtual ~TestFailedException() throw ();
+
+ /**
+ * Description.
+ */
+ const char * what() const throw ()
+ {
+ return _message.c_str();
+ }
+ };
+
+ /**
+ * A list of TestCase instances.
+ *
+ * \ingroup Test
+ */
+ class TestCaseList
+ {
+ private:
+ TestCaseList();
+ ~TestCaseList();
+
+ public:
+ /**
+ * Register a TestCase instance.
+ */
+ static void register_test_case(TestCase * const test_case);
+
+ /**
+ * Run all tests.
+ */
+ static bool run_tests();
+
+ /**
+ * Should we use alarm?
+ */
+ static bool use_alarm;
+ };
+
+ /**
+ * Change the function used to get a string description of an exception.
+ */
+ void set_exception_to_debug_string(std::string (*) (const std::exception &));
+
+ /**
+ * Fetch the function used to get a string description of an exception.
+ */
+ std::string (* get_exception_to_debug_string()) (const std::exception &);
+}
+
+/**
+ * Check that a == b.
+ */
+#define TEST_CHECK_EQUAL(a, b) \
+ do { \
+ try { \
+ check(__PRETTY_FUNCTION__, __FILE__, __LINE__, a == b, \
+ "Expected '" #a "' to equal '" + paludis::stringify(b) + \
+ "' but got '" + paludis::stringify(a) + "'"); \
+ } catch (const TestFailedException &) { \
+ throw; \
+ } catch (const std::exception & e) { \
+ throw TestFailedException(__PRETTY_FUNCTION__, __FILE__, __LINE__, \
+ "Test threw unexpected exception " + test::get_exception_to_debug_string()(e) + \
+ " inside a TEST_CHECK_EQUAL block"); \
+ } catch (...) { \
+ throw TestFailedException(__PRETTY_FUNCTION__, __FILE__, __LINE__, \
+ "Test threw unexpected unknown exception inside a TEST_CHECK_EQUAL block"); \
+ } \
+ } while (false)
+
+/**
+ * Check that stringify(a) == stringify(b).
+ */
+#define TEST_CHECK_STRINGIFY_EQUAL(a, b) \
+ do { \
+ try { \
+ check(__PRETTY_FUNCTION__, __FILE__, __LINE__, paludis::stringify(a) == paludis::stringify(b), \
+ "Expected '" #a "' to equal '" + paludis::stringify(b) + \
+ "' but got '" + paludis::stringify(a) + "'"); \
+ } catch (const TestFailedException &) { \
+ throw; \
+ } catch (const std::exception & e) { \
+ throw TestFailedException(__PRETTY_FUNCTION__, __FILE__, __LINE__, \
+ "Test threw unexpected exception " + test::get_exception_to_debug_string()(e) + \
+ " inside a TEST_CHECK_STRINGIFY_EQUAL block"); \
+ } catch (...) { \
+ throw TestFailedException(__PRETTY_FUNCTION__, __FILE__, __LINE__, \
+ "Test threw unexpected unknown exception inside a TEST_CHECK_STRINGIFY_EQUAL block"); \
+ } \
+ } while (false)
+
+/**
+ * Check that a is true.
+ */
+#define TEST_CHECK(a) \
+ do { \
+ try { \
+ check(__PRETTY_FUNCTION__, __FILE__, __LINE__, a, \
+ "Check '" #a "' failed"); \
+ } catch (const TestFailedException &) { \
+ throw; \
+ } catch (const std::exception & e) { \
+ throw TestFailedException(__PRETTY_FUNCTION__, __FILE__, __LINE__, \
+ "Test threw unexpected exception " + test::get_exception_to_debug_string()(e) + \
+ " inside a TEST_CHECK block"); \
+ } catch (...) { \
+ throw TestFailedException(__PRETTY_FUNCTION__, __FILE__, __LINE__, \
+ "Test threw unexpected unknown exception inside a TEST_CHECK block"); \
+ } \
+ } while (false)
+
+/**
+ * Check that a throws an exception of type b.
+ */
+#define TEST_CHECK_THROWS(a, b) \
+ do { \
+ try { \
+ try { \
+ a; \
+ check(__PRETTY_FUNCTION__, __FILE__, __LINE__, false, \
+ "Expected exception of type '" #b "' not thrown"); \
+ } catch (b &) { \
+ TEST_CHECK(true); \
+ } \
+ } catch (const TestFailedException &) { \
+ throw; \
+ } catch (const std::exception & e) { \
+ throw TestFailedException(__PRETTY_FUNCTION__, __FILE__, __LINE__, \
+ "Test threw unexpected exception " + test::get_exception_to_debug_string()(e) + \
+ " inside a TEST_CHECK_THROWS block"); \
+ } catch (...) { \
+ throw TestFailedException(__PRETTY_FUNCTION__, __FILE__, __LINE__, \
+ "Test threw unexpected unknown exception inside a TEST_CHECK_THROWS block"); \
+ } \
+ } while (false)
+
+#endif
+
diff --git a/0.8.0/test/test_pass_TEST.cc b/0.8.0/test/test_pass_TEST.cc
new file mode 100644
index 0000000..9aff24e
--- /dev/null
+++ b/0.8.0/test/test_pass_TEST.cc
@@ -0,0 +1,51 @@
+/* vim: set sw=4 sts=4 et foldmethod=syntax : */
+
+/*
+ * Copyright (c) 2006 Ciaran McCreesh <ciaranm@ciaranm.org>
+ *
+ * This file is part of the Paludis package manager. Paludis is free software;
+ * you can redistribute it and/or modify it under the terms of the GNU General
+ * Public License version 2, as published by the Free Software Foundation.
+ *
+ * Paludis is distributed in the hope that it will be useful, but WITHOUT ANY
+ * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+ * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
+ * details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, write to the Free Software Foundation, Inc., 59 Temple
+ * Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#include <string>
+#include <test/test_framework.hh>
+#include <test/test_runner.hh>
+
+using namespace test;
+
+/** \file
+ * This test should pass.
+ *
+ * \ingroup Test
+ */
+
+namespace test_cases
+{
+ /**
+ * \test This test should pass.
+ *
+ * \ingroup Test
+ */
+ struct PassTest : TestCase
+ {
+ PassTest() : TestCase("test the test code: this should pass") { }
+
+ void run()
+ {
+ TEST_CHECK_EQUAL(1, 1);
+ TEST_CHECK(true);
+ TEST_CHECK_THROWS(std::string("1").at(10), std::exception);
+ }
+ } test_pass;
+}
+
diff --git a/0.8.0/test/test_runner.cc b/0.8.0/test/test_runner.cc
new file mode 100644
index 0000000..4e78d01
--- /dev/null
+++ b/0.8.0/test/test_runner.cc
@@ -0,0 +1,99 @@
+/* vim: set sw=4 sts=4 et foldmethod=syntax : */
+
+/*
+ * Copyright (c) 2006 Ciaran McCreesh <ciaranm@ciaranm.org>
+ *
+ * This file is part of the Paludis package manager. Paludis is free software;
+ * you can redistribute it and/or modify it under the terms of the GNU General
+ * Public License version 2, as published by the Free Software Foundation.
+ *
+ * Paludis is distributed in the hope that it will be useful, but WITHOUT ANY
+ * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+ * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
+ * details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, write to the Free Software Foundation, Inc., 59 Temple
+ * Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#include "test_framework.hh"
+#include "test_runner.hh"
+#include <paludis/util/stringify.hh>
+
+#include <iostream>
+#include <fstream>
+#include <cstdlib>
+#include <signal.h>
+#if defined(__GLIBC__)
+#include <execinfo.h>
+#endif
+#include <unistd.h>
+#include <sys/types.h>
+
+/** \file
+ * Implementation of the default test runner.
+ *
+ * \ingroup Test
+ */
+
+using namespace test;
+
+namespace
+{
+ void do_backtrace()
+ {
+#if defined(__GLIBC__)
+ void * bt[50];
+ size_t sz = backtrace(bt, 50);
+ char * * symbols = backtrace_symbols(bt, sz);
+
+ std::cerr << "Stack dump:" << std::endl;
+ for (unsigned n(0) ; n < sz ; ++n)
+ std::cerr << " * " << symbols[n] << std::endl;
+
+ std::free(symbols);
+#endif
+ }
+}
+
+void timeout_handler(int)
+{
+ std::cerr << std::endl << "Test aborted due to timeout!" << std::endl;
+ do_backtrace();
+ std::exit(EXIT_FAILURE);
+}
+
+void segfault_handler(int)
+{
+ std::cerr << std::endl << "Test aborted due to segmentation fault!" << std::endl;
+ do_backtrace();
+ std::exit(EXIT_FAILURE);
+}
+
+int
+main(int, char * argv[])
+{
+ {
+ std::ifstream ppid(("/proc/" + paludis::stringify(getppid()) + "/cmdline").c_str());
+ if (ppid)
+ {
+ std::string cmd;
+ std::getline(ppid, cmd, '\0');
+ std::string::size_type slash_pos(cmd.rfind('/'));
+ if (std::string::npos != slash_pos)
+ cmd.erase(0, slash_pos);
+ if (cmd != "gdb")
+ {
+ signal(SIGALRM, &timeout_handler);
+ signal(SIGSEGV, &segfault_handler);
+ }
+ else
+ TestCaseList::use_alarm = false;
+ }
+ }
+
+ std::cout << "Test program " << argv[0] << ":" << std::endl;
+ return TestCaseList::run_tests() ? EXIT_SUCCESS : EXIT_FAILURE;
+}
+
diff --git a/0.8.0/test/test_runner.hh b/0.8.0/test/test_runner.hh
new file mode 100644
index 0000000..540ac45
--- /dev/null
+++ b/0.8.0/test/test_runner.hh
@@ -0,0 +1,38 @@
+/* vim: set sw=4 sts=4 et foldmethod=syntax : */
+
+/*
+ * Copyright (c) 2006 Ciaran McCreesh <ciaranm@ciaranm.org>
+ *
+ * This file is part of the Paludis package manager. Paludis is free software;
+ * you can redistribute it and/or modify it under the terms of the GNU General
+ * Public License version 2, as published by the Free Software Foundation.
+ *
+ * Paludis is distributed in the hope that it will be useful, but WITHOUT ANY
+ * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+ * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
+ * details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, write to the Free Software Foundation, Inc., 59 Temple
+ * Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#ifndef PALUDIS_GUARD_TEST_TEST_RUNNER_HH
+#define PALUDIS_GUARD_TEST_TEST_RUNNER_HH 1
+
+#include <paludis/util/attributes.hh>
+
+/** \file
+ * Declarations for the default test runner.
+ */
+
+/// Main program.
+int main(int, char *[]);
+
+/// Called if we take too long.
+void timeout_handler(int) PALUDIS_ATTRIBUTE((noreturn));
+
+/// Called if we get a segfault.
+void segfault_handler(int) PALUDIS_ATTRIBUTE((noreturn));
+
+#endif