2007-08-13 09:55:32 +02:00
|
|
|
/*
|
|
|
|
|
Suite - helper class for running collections of tests
|
2010-12-17 23:28:49 +01:00
|
|
|
|
2008-03-10 04:25:03 +01:00
|
|
|
Copyright (C) Lumiera.org
|
|
|
|
|
2008, Hermann Vosseler <Ichthyostega@web.de>
|
2010-12-17 23:28:49 +01:00
|
|
|
|
2007-08-13 09:55:32 +02:00
|
|
|
This program is free software; you can redistribute it and/or
|
|
|
|
|
modify it under the terms of the GNU General Public License as
|
2010-12-17 23:28:49 +01:00
|
|
|
published by the Free Software Foundation; either version 2 of
|
|
|
|
|
the License, or (at your option) any later version.
|
|
|
|
|
|
2007-08-13 09:55:32 +02:00
|
|
|
This program 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.
|
2010-12-17 23:28:49 +01:00
|
|
|
|
2007-08-13 09:55:32 +02:00
|
|
|
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., 675 Mass Ave, Cambridge, MA 02139, USA.
|
2010-12-17 23:28:49 +01:00
|
|
|
|
2007-08-13 09:55:32 +02:00
|
|
|
* *****************************************************/
|
|
|
|
|
|
|
|
|
|
|
2007-08-26 19:14:39 +02:00
|
|
|
|
2009-01-25 00:24:42 +01:00
|
|
|
#include "include/logging.h"
|
2014-08-17 08:03:21 +02:00
|
|
|
#include "lib/hash-standard.hpp"
|
2009-10-02 17:26:50 +02:00
|
|
|
#include "lib/test/test-helper.hpp"
|
2008-12-17 17:53:32 +01:00
|
|
|
#include "lib/test/suite.hpp"
|
|
|
|
|
#include "lib/test/run.hpp"
|
2014-08-17 08:03:21 +02:00
|
|
|
#include "lib/cmdline.hpp"
|
2008-12-27 00:53:35 +01:00
|
|
|
#include "lib/error.hpp"
|
2008-12-17 17:53:32 +01:00
|
|
|
#include "lib/util.hpp"
|
2007-08-17 00:36:07 +02:00
|
|
|
|
2009-10-02 17:26:50 +02:00
|
|
|
#include <boost/algorithm/string.hpp>
|
2014-04-03 22:42:48 +02:00
|
|
|
#include <memory>
|
2009-10-02 17:26:50 +02:00
|
|
|
#include <iostream>
|
|
|
|
|
#include <sstream>
|
|
|
|
|
#include <memory>
|
|
|
|
|
#include <vector>
|
|
|
|
|
#include <map>
|
2007-08-13 09:55:32 +02:00
|
|
|
|
|
|
|
|
|
2009-07-19 05:47:36 +02:00
|
|
|
namespace test {
|
|
|
|
|
|
2007-08-13 09:55:32 +02:00
|
|
|
using std::map;
|
2009-10-02 17:26:50 +02:00
|
|
|
using std::cout;
|
|
|
|
|
using std::cerr;
|
|
|
|
|
using std::endl;
|
2007-08-13 09:55:32 +02:00
|
|
|
using std::vector;
|
2014-04-03 22:42:48 +02:00
|
|
|
using std::shared_ptr;
|
2007-08-23 17:52:33 +02:00
|
|
|
using boost::algorithm::trim;
|
2009-07-19 05:47:36 +02:00
|
|
|
|
2007-08-17 00:36:07 +02:00
|
|
|
using util::isnil;
|
2007-08-23 17:52:33 +02:00
|
|
|
using util::contains;
|
2009-10-02 17:26:50 +02:00
|
|
|
using lib::test::showType;
|
2007-08-13 09:55:32 +02:00
|
|
|
|
|
|
|
|
typedef map<string, Launcher*> TestMap;
|
|
|
|
|
typedef shared_ptr<TestMap> PTestMap;
|
|
|
|
|
typedef map<string,PTestMap> GroupMap;
|
2009-07-19 05:47:36 +02:00
|
|
|
|
2007-08-13 09:55:32 +02:00
|
|
|
|
|
|
|
|
|
2014-09-15 02:03:10 +02:00
|
|
|
namespace {
|
|
|
|
|
/**
|
|
|
|
|
* helper to collect and manage the test cases.
|
|
|
|
|
* Every testcase class should create a Launch instance,
|
|
|
|
|
* which causes a call to Suite::enrol(), so we can add a pointer
|
|
|
|
|
* to this Launcher into a map indexed by the provided testIDs and groupIDs.
|
|
|
|
|
* This enables us to build a Suite instance for any requested group
|
|
|
|
|
* and then instantiate and invoke individual testcases accordingly.
|
|
|
|
|
*/
|
|
|
|
|
class Registry
|
|
|
|
|
{
|
|
|
|
|
GroupMap groups_;
|
|
|
|
|
|
|
|
|
|
public:
|
|
|
|
|
Registry() { };
|
|
|
|
|
|
|
|
|
|
PTestMap&
|
|
|
|
|
getGroup (string grpID)
|
|
|
|
|
{
|
|
|
|
|
return groups_[grpID];
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
void
|
|
|
|
|
add2group (Launcher* test, string testID, string groupID)
|
|
|
|
|
{
|
|
|
|
|
REQUIRE( test );
|
|
|
|
|
REQUIRE( !isnil(testID) );
|
|
|
|
|
REQUIRE( !isnil(groupID) );
|
|
|
|
|
|
|
|
|
|
PTestMap& group = getGroup(groupID);
|
|
|
|
|
if (!group)
|
|
|
|
|
group.reset( new TestMap );
|
|
|
|
|
(*group)[testID] = test;
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
Registry testcases;
|
2007-08-26 19:14:39 +02:00
|
|
|
}
|
2007-08-13 09:55:32 +02:00
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/** register the given test-launcher, so it can be later accessed
|
2009-07-19 05:47:36 +02:00
|
|
|
* either as a member of one of the specified groups, or directly
|
2007-08-13 09:55:32 +02:00
|
|
|
* by its testID. Any test is automatically added to the groupID
|
|
|
|
|
* #ALLGROUP
|
2007-08-24 16:41:16 +02:00
|
|
|
* @param test the Launcher object used to run this test
|
2009-07-19 05:47:36 +02:00
|
|
|
* @param testID unique ID to refer to this test (will be used as std::map key)
|
2007-08-13 09:55:32 +02:00
|
|
|
* @param groups List of group-IDs selected by whitespace
|
2007-08-24 16:41:16 +02:00
|
|
|
*
|
2007-08-13 09:55:32 +02:00
|
|
|
*/
|
2007-08-14 08:14:21 +02:00
|
|
|
void
|
2009-07-19 05:47:36 +02:00
|
|
|
Suite::enrol (Launcher* test, string testID, string groups)
|
2007-08-26 19:14:39 +02:00
|
|
|
{
|
|
|
|
|
REQUIRE( test );
|
|
|
|
|
REQUIRE( !isnil(testID) );
|
|
|
|
|
|
|
|
|
|
std::istringstream ss(groups);
|
|
|
|
|
string group;
|
|
|
|
|
while (ss >> group )
|
|
|
|
|
testcases.add2group(test, testID, group);
|
|
|
|
|
|
2009-07-19 05:47:36 +02:00
|
|
|
// Magic: always add any testcase to groupID="ALL"
|
2007-08-26 19:14:39 +02:00
|
|
|
testcases.add2group(test,testID, ALLGROUP);
|
|
|
|
|
}
|
2007-08-13 09:55:32 +02:00
|
|
|
|
|
|
|
|
/** "magic" groupID containing all registered testcases */
|
|
|
|
|
const string Suite::ALLGROUP = "ALL";
|
|
|
|
|
|
2009-10-02 17:49:38 +02:00
|
|
|
/** exit code returned when any individual test threw */
|
|
|
|
|
const int Suite::EXCEPTION_THROWN = 5;
|
|
|
|
|
const int Suite::TEST_OK = 0;
|
|
|
|
|
|
2007-08-13 09:55:32 +02:00
|
|
|
|
|
|
|
|
|
|
|
|
|
/** create a suite comprised of all the testcases
|
2009-07-19 05:47:36 +02:00
|
|
|
* previously @link #enrol() registered @endlink with this
|
2007-08-13 09:55:32 +02:00
|
|
|
* this group.
|
|
|
|
|
* @see #run() running tests in a Suite
|
|
|
|
|
*/
|
|
|
|
|
Suite::Suite(string groupID)
|
|
|
|
|
: groupID_(groupID)
|
2009-10-02 17:49:38 +02:00
|
|
|
, exitCode_(0)
|
2007-08-26 19:14:39 +02:00
|
|
|
{
|
|
|
|
|
REQUIRE( !isnil(groupID) );
|
|
|
|
|
TRACE(test, "Test-Suite( groupID=%s )\n", groupID.c_str () );
|
|
|
|
|
|
2011-10-21 01:09:12 +02:00
|
|
|
// Seed random number generator
|
|
|
|
|
std::srand (std::time (NULL));
|
|
|
|
|
|
2007-08-26 19:14:39 +02:00
|
|
|
if (!testcases.getGroup(groupID))
|
2009-10-02 17:26:50 +02:00
|
|
|
throw lumiera::error::Invalid ("empty testsuite");
|
2007-08-26 19:14:39 +02:00
|
|
|
}
|
2009-10-02 17:49:38 +02:00
|
|
|
|
|
|
|
|
|
|
|
|
|
int
|
|
|
|
|
Suite::getExitCode () const
|
|
|
|
|
{
|
|
|
|
|
return exitCode_;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
2007-08-13 09:55:32 +02:00
|
|
|
|
2014-05-06 00:24:45 +02:00
|
|
|
#define IS_VALID(test,testID) \
|
2009-07-19 05:47:36 +02:00
|
|
|
ASSERT ((test), "NULL testcase launcher for test '%s' found in testsuite '%s'", groupID_.c_str(),testID.c_str());
|
2007-08-23 17:52:33 +02:00
|
|
|
|
2007-08-13 09:55:32 +02:00
|
|
|
|
2009-10-02 17:26:50 +02:00
|
|
|
namespace { // internal helper for launching with error logging
|
|
|
|
|
|
2009-10-02 17:49:38 +02:00
|
|
|
int
|
2009-10-02 17:26:50 +02:00
|
|
|
invokeTestCase (Test& theTest, Arg cmdline)
|
|
|
|
|
{
|
2009-10-02 17:49:38 +02:00
|
|
|
try
|
|
|
|
|
{
|
2011-09-25 19:10:57 +02:00
|
|
|
INFO (test, "++------------------- invoking TEST: %s", showType(theTest).c());
|
2009-10-02 17:49:38 +02:00
|
|
|
theTest.run (cmdline);
|
|
|
|
|
return Suite::TEST_OK;
|
|
|
|
|
}
|
2009-10-02 17:26:50 +02:00
|
|
|
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());
|
2009-10-02 17:49:38 +02:00
|
|
|
return Suite::EXCEPTION_THROWN;
|
2009-10-02 17:26:50 +02:00
|
|
|
} }
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
2007-08-13 09:55:32 +02:00
|
|
|
/** run all testcases contained in this Suite.
|
2007-08-23 17:52:33 +02:00
|
|
|
* The first argument in the commandline, if present,
|
|
|
|
|
* will select one single testcase with a matching ID.
|
|
|
|
|
* In case of invoking a single testcase, the given cmdline
|
2009-07-19 05:47:36 +02:00
|
|
|
* will be forwarded to the testcase, after removing the
|
2007-08-23 17:52:33 +02:00
|
|
|
* testcaseID from cmdline[0]. Otherwise, every testcase
|
|
|
|
|
* in this suite is invoked with a empty cmdline vector.
|
|
|
|
|
* @param cmdline ref to the vector of commandline tokens
|
2007-08-13 09:55:32 +02:00
|
|
|
*/
|
2014-05-05 22:59:23 +02:00
|
|
|
bool
|
2007-08-23 17:52:33 +02:00
|
|
|
Suite::run (Arg cmdline)
|
2007-08-26 19:14:39 +02:00
|
|
|
{
|
|
|
|
|
PTestMap tests = testcases.getGroup(groupID_);
|
|
|
|
|
if (!tests)
|
2014-05-06 00:24:45 +02:00
|
|
|
throw lumiera::error::Invalid ("No tests found for test group \""+groupID_+"\"");
|
2007-08-26 19:14:39 +02:00
|
|
|
|
|
|
|
|
if (0 < cmdline.size())
|
|
|
|
|
{
|
|
|
|
|
string& testID (cmdline[0]);
|
|
|
|
|
trim(testID);
|
|
|
|
|
if ( contains (*tests, testID))
|
|
|
|
|
{
|
|
|
|
|
// first cmdline argument denotes a valid testcase registered in
|
|
|
|
|
// this group: invoke just this test with the remaining cmdline
|
|
|
|
|
Launcher* test = (*tests)[testID];
|
2014-05-06 00:24:45 +02:00
|
|
|
IS_VALID (test,testID);
|
|
|
|
|
|
|
|
|
|
// Special contract: in case the cmdline holds no actual arguments
|
|
|
|
|
// beyond the test name, then it's cleared entirely.
|
2014-09-15 02:03:10 +02:00
|
|
|
if (1 == cmdline.size()) cmdline.clear(); // TODO this invalidates also testID -- really need to redesign the API ////TICKET #289
|
2014-05-06 00:24:45 +02:00
|
|
|
|
2014-09-15 02:03:10 +02:00
|
|
|
exitCode_ |= invokeTestCase (*test->makeInstance(), cmdline); // TODO confusing statement, improve definition of test collection datatype Ticket #289
|
2014-05-05 22:59:23 +02:00
|
|
|
return true;
|
2010-07-16 15:59:07 +02:00
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
throw lumiera::error::Invalid ("unknown test : "+testID);
|
|
|
|
|
}
|
2007-08-26 19:14:39 +02:00
|
|
|
|
|
|
|
|
// no test-ID was specified.
|
2009-07-19 05:47:36 +02:00
|
|
|
// Instantiate all tests cases and execute them.
|
2007-08-26 19:14:39 +02:00
|
|
|
for ( TestMap::iterator i=tests->begin(); i!=tests->end(); ++i )
|
|
|
|
|
{
|
|
|
|
|
std::cout << "\n ----------"<< i->first<< "----------\n";
|
|
|
|
|
Launcher* test = (i->second);
|
2014-05-06 00:24:45 +02:00
|
|
|
IS_VALID (test, i->first);
|
2014-09-15 02:03:10 +02:00
|
|
|
exitCode_ |= invokeTestCase (*test->makeInstance(), cmdline); // actually no cmdline arguments
|
2007-08-26 19:14:39 +02:00
|
|
|
}
|
2014-05-05 22:59:23 +02:00
|
|
|
return true;
|
2007-08-26 19:14:39 +02:00
|
|
|
}
|
2007-08-23 17:52:33 +02:00
|
|
|
|
|
|
|
|
|
2009-07-19 05:47:36 +02:00
|
|
|
/** print to stdout an enumeration of all testcases in this suite,
|
2007-08-23 17:52:33 +02:00
|
|
|
* in a format suitable for use with Cehteh's ./test.sh
|
|
|
|
|
*/
|
|
|
|
|
void
|
|
|
|
|
Suite::describe ()
|
2007-08-26 19:14:39 +02:00
|
|
|
{
|
2011-02-05 23:53:37 +01:00
|
|
|
lib::Cmdline noCmdline("");
|
2007-08-26 19:14:39 +02:00
|
|
|
PTestMap tests = testcases.getGroup(groupID_);
|
|
|
|
|
ASSERT (tests);
|
|
|
|
|
|
2009-10-02 17:26:50 +02:00
|
|
|
cout << "TESTING \"Component Test Suite: " << groupID_ << "\" ./test-components\n\n";
|
2009-07-19 05:47:36 +02:00
|
|
|
|
2007-08-26 19:14:39 +02:00
|
|
|
for ( TestMap::iterator i=tests->begin(); i!=tests->end(); ++i )
|
|
|
|
|
{
|
|
|
|
|
string key (i->first);
|
2009-10-02 17:26:50 +02:00
|
|
|
cout << "\n\n";
|
|
|
|
|
cout << "TEST \""<<key<<"\" "<<key<<" <<END\n";
|
2007-08-26 19:14:39 +02:00
|
|
|
Launcher* test = (i->second);
|
2014-05-06 00:24:45 +02:00
|
|
|
IS_VALID (test, i->first);
|
2007-09-25 23:39:46 +02:00
|
|
|
try
|
|
|
|
|
{
|
2014-09-15 02:03:10 +02:00
|
|
|
test->makeInstance()->run(noCmdline); // run it to insert test generated output
|
2007-09-25 23:39:46 +02:00
|
|
|
}
|
|
|
|
|
catch (...)
|
|
|
|
|
{
|
2009-10-02 17:26:50 +02:00
|
|
|
cout << "PLANNED ============= " << lumiera_error() << "\n";
|
2007-09-25 23:39:46 +02:00
|
|
|
}
|
2009-10-02 17:26:50 +02:00
|
|
|
cout << "END\n";
|
2007-08-26 19:14:39 +02:00
|
|
|
}
|
|
|
|
|
}
|
2009-07-19 05:47:36 +02:00
|
|
|
|
|
|
|
|
|
|
|
|
|
|
2007-08-13 09:55:32 +02:00
|
|
|
} // namespace test
|