diff --git a/src/common/appstate.cpp b/src/common/appstate.cpp index 1b949e2b0..dfcab9834 100644 --- a/src/common/appstate.cpp +++ b/src/common/appstate.cpp @@ -48,7 +48,7 @@ namespace lumiera { inline void log_and_clear_unexpected_errorstate () { - if (const char * errorstate = lumiera_error ()) + if (lumiera_err errorstate = lumiera_error ()) ALERT (common, "*** Unexpected error: %s\n Triggering emergency exit.", errorstate); } diff --git a/src/lib/test/run.hpp b/src/lib/test/run.hpp index cd7621c89..ff61cf30c 100644 --- a/src/lib/test/run.hpp +++ b/src/lib/test/run.hpp @@ -21,6 +21,17 @@ */ +/** @file run.hpp + ** Simple test class runner. Allows for writing unit tests as subclass of + ** test::Test . They may be installed for automatic invocation through test::Suite + ** by defining a Launcher instance, which can be done conveniently by the macro LAUNCHER + ** + ** @see HelloWorld_test + ** @see test::Suite + ** @see mainsuite.cpp + ** @see main.cpp + */ + #ifndef TESTHELPER_RUN_H #define TESTHELPER_RUN_H @@ -37,12 +48,11 @@ #include -namespace test - { - +namespace test { + using std::string; using std::auto_ptr; - + typedef std::vector & Arg; @@ -60,7 +70,7 @@ namespace test - /** interface: generic testcase creating functor. */ + /** interface: generic testcase creating functor. */ class Launcher { public: @@ -86,7 +96,7 @@ namespace test public: Launch (string testID, string groups) { Suite::enrol (this,testID,groups); }; virtual auto_ptr operator() () { return auto_ptr (new TEST ); }; - }; + }; } // namespace test diff --git a/src/lib/test/suite.cpp b/src/lib/test/suite.cpp index d1d383d71..5c8af1357 100644 --- a/src/lib/test/suite.cpp +++ b/src/lib/test/suite.cpp @@ -22,26 +22,29 @@ -#include -#include -#include -#include -#include -#include -#include - #include "include/logging.h" #include "lib/cmdline.hpp" +#include "lib/test/test-helper.hpp" #include "lib/test/suite.hpp" #include "lib/test/run.hpp" #include "lib/error.hpp" #include "lib/util.hpp" +#include +#include +#include +#include +#include +#include +#include namespace test { using std::map; + using std::cout; + using std::cerr; + using std::endl; using std::vector; using std::auto_ptr; using std::tr1::shared_ptr; @@ -49,6 +52,7 @@ namespace test { using util::isnil; using util::contains; + using lib::test::showType; typedef map TestMap; typedef shared_ptr PTestMap; @@ -133,14 +137,30 @@ namespace test { TRACE(test, "Test-Suite( groupID=%s )\n", groupID.c_str () ); if (!testcases.getGroup(groupID)) - throw lumiera::error::Invalid (); - //throw "empty testsuite"; /////////// TODO Errorhandling! + throw lumiera::error::Invalid ("empty testsuite"); } #define VALID(test,testID) \ ASSERT ((test), "NULL testcase launcher for test '%s' found in testsuite '%s'", groupID_.c_str(),testID.c_str()); + namespace { // internal helper for launching with error logging + + void + invokeTestCase (Test& theTest, Arg cmdline) + { + try { theTest.run (cmdline); } + catch (lumiera::Error& failure) + { + lumiera_err errorID = lumiera_error(); // reset error flag + cerr << "*** Test Failure " << showType(theTest) << endl; + cerr << "*** : " << failure.what() << endl; + ERROR (test, "Error state %s", errorID); + WARN (progress, "Caught exception %s", failure.what()); + } } + } + + /** run all testcases contained in this Suite. * The first argument in the commandline, if present, * will select one single testcase with a matching ID. @@ -155,7 +175,7 @@ namespace test { { PTestMap tests = testcases.getGroup(groupID_); if (!tests) - throw lumiera::error::Invalid (); ///////// TODO: pass error description + throw lumiera::error::Invalid ("test group not found"); ///////// TODO: pass error description if (0 < cmdline.size()) { @@ -168,7 +188,7 @@ namespace test { Launcher* test = (*tests)[testID]; cmdline.erase (cmdline.begin()); VALID (test,testID); - (*test)()->run(cmdline); + invokeTestCase (*(*test)(), cmdline); // TODO confusing statement, improve definition of test collection datatype Ticket #289 return; } } @@ -179,7 +199,7 @@ namespace test { std::cout << "\n ----------"<< i->first<< "----------\n"; Launcher* test = (i->second); VALID (test, i->first); - (*test)()->run(cmdline); // actually no cmdline arguments + invokeTestCase (*(*test)(), cmdline); // actually no cmdline arguments } } @@ -194,13 +214,13 @@ namespace test { PTestMap tests = testcases.getGroup(groupID_); ASSERT (tests); - std::cout << "TESTING \"Component Test Suite: " << groupID_ << "\" ./test-components\n\n"; + cout << "TESTING \"Component Test Suite: " << groupID_ << "\" ./test-components\n\n"; for ( TestMap::iterator i=tests->begin(); i!=tests->end(); ++i ) { string key (i->first); - std::cout << "\n\n"; - std::cout << "TEST \""<second); VALID (test, i->first); try @@ -209,9 +229,9 @@ namespace test { } catch (...) { - std::cout << "PLANNED ============= " << lumiera_error() << "\n"; + cout << "PLANNED ============= " << lumiera_error() << "\n"; } - std::cout << "END\n"; + cout << "END\n"; } } diff --git a/src/lib/test/suite.hpp b/src/lib/test/suite.hpp index ad378b54a..13a883888 100644 --- a/src/lib/test/suite.hpp +++ b/src/lib/test/suite.hpp @@ -20,6 +20,22 @@ */ +/** @file suite.hpp + ** Building and running a suite of tests, implemented as test classes. + ** This simple test suite runner is intended to be linked into a standalone C++ application, + ** allowing to invoke individual tests by ID, invoking groups of tests and producing a + ** report of all registered tests. Registration of individual testcases happens + ** automatically through static test::Launcher instances. + ** + ** @todo as of 9/09, the implementation seems OKish but a bit clumsy. See Ticket #289 + ** + ** @see HelloWorld_test + ** @see test::Test + ** @see test::TestOption + ** @see run.hpp + ** @see mainsuite.cpp + */ + #ifndef TESTHELPER_SUITE_H #define TESTHELPER_SUITE_H @@ -29,21 +45,21 @@ -namespace test - { +namespace test { + using std::string; - // Forward decls needed for run.hpp + // Forward declarations for run.hpp class Test; class Launcher; - + typedef std::vector & Arg; /** * Enables running a collection of tests. * An internal registration service #enrol() is provided - * for the individual Test - inscances to be recognized as + * for the individual Test - instances to be recognised as * testcases. The groupID passed to the constructor selects * all testcases declared as belonging to this Group. */