Testsuite: catch exceptions at the level of invoking individual tests

This commit is contained in:
Fischlurch 2009-10-02 17:26:50 +02:00
parent cb7c884293
commit 3835399c5f
4 changed files with 76 additions and 30 deletions

View file

@ -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);
}

View file

@ -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 <string>
namespace test
{
namespace test {
using std::string;
using std::auto_ptr;
typedef std::vector<string> & 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<Test> operator() () { return auto_ptr<Test> (new TEST ); };
};
};
} // namespace test

View file

@ -22,26 +22,29 @@
#include <map>
#include <vector>
#include <memory>
#include <tr1/memory>
#include <iostream>
#include <sstream>
#include <boost/algorithm/string.hpp>
#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 <boost/algorithm/string.hpp>
#include <tr1/memory>
#include <iostream>
#include <sstream>
#include <memory>
#include <vector>
#include <map>
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<string, Launcher*> TestMap;
typedef shared_ptr<TestMap> 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 \""<<key<<"\" "<<key<<" <<END\n";
cout << "\n\n";
cout << "TEST \""<<key<<"\" "<<key<<" <<END\n";
Launcher* test = (i->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";
}
}

View file

@ -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<string> & 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.
*/