Files
SingularityViewer/libraries/include/tut/tut_runner.hpp
2010-04-02 02:48:44 -03:00

303 lines
6.0 KiB
C++

#ifndef TUT_RUNNER_H_GUARD
#define TUT_RUNNER_H_GUARD
#include <string>
#include <vector>
#include "tut_exception.hpp"
namespace tut
{
/**
* Interface.
* Test group operations.
*/
struct group_base
{
virtual ~group_base()
{
}
// execute tests iteratively
virtual void rewind() = 0;
virtual test_result run_next() = 0;
// execute one test
virtual test_result run_test(int n) = 0;
};
/**
* Test runner callback interface.
* Can be implemented by caller to update
* tests results in real-time. User can implement
* any of callback methods, and leave unused
* in default implementation.
*/
struct callback
{
/**
* Virtual destructor is a must for subclassed types.
*/
virtual ~callback()
{
}
/**
* Called when new test run started.
*/
virtual void run_started()
{
}
/**
* Called when a group started
* @param name Name of the group
*/
virtual void group_started(const std::string& /*name*/)
{
}
/**
* Called when a test finished.
* @param tr Test results.
*/
virtual void test_completed(const test_result& /*tr*/)
{
}
/**
* Called when a group is completed
* @param name Name of the group
*/
virtual void group_completed(const std::string& /*name*/)
{
}
/**
* Called when all tests in run completed.
*/
virtual void run_completed()
{
}
};
/**
* Typedef for runner::list_groups()
*/
typedef std::vector<std::string> groupnames;
/**
* Test runner.
*/
class test_runner
{
public:
/**
* Constructor
*/
test_runner()
: callback_(&default_callback_)
{
}
/**
* Stores another group for getting by name.
*/
void register_group(const std::string& name, group_base* gr)
{
if (gr == 0)
{
throw tut_error("group shall be non-null");
}
if (groups_.find(name) != groups_.end())
{
std::string msg("attempt to add already existent group " + name);
// this exception terminates application so we use cerr also
// TODO: should this message appear in stream?
std::cerr << msg << std::endl;
throw tut_error(msg);
}
groups_.insert( std::make_pair(name, gr) );
}
/**
* Stores callback object.
*/
void set_callback(callback* cb)
{
callback_ = cb == 0 ? &default_callback_ : cb;
}
/**
* Returns callback object.
*/
callback& get_callback() const
{
return *callback_;
}
/**
* Returns list of known test groups.
*/
const groupnames list_groups() const
{
groupnames ret;
const_iterator i = groups_.begin();
const_iterator e = groups_.end();
while (i != e)
{
ret.push_back(i->first);
++i;
}
return ret;
}
/**
* Runs all tests in all groups.
* @param callback Callback object if exists; null otherwise
*/
void run_tests() const
{
callback_->run_started();
const_iterator i = groups_.begin();
const_iterator e = groups_.end();
while (i != e)
{
callback_->group_started(i->first);
try
{
run_all_tests_in_group_(i);
}
catch (const no_more_tests&)
{
callback_->group_completed(i->first);
}
++i;
}
callback_->run_completed();
}
/**
* Runs all tests in specified group.
*/
void run_tests(const std::string& group_name) const
{
callback_->run_started();
const_iterator i = groups_.find(group_name);
if (i == groups_.end())
{
callback_->run_completed();
throw no_such_group(group_name);
}
callback_->group_started(group_name);
try
{
run_all_tests_in_group_(i);
}
catch (const no_more_tests&)
{
// ok
}
callback_->group_completed(group_name);
callback_->run_completed();
}
/**
* Runs one test in specified group.
*/
test_result run_test(const std::string& group_name, int n) const
{
callback_->run_started();
const_iterator i = groups_.find(group_name);
if (i == groups_.end())
{
callback_->run_completed();
throw no_such_group(group_name);
}
callback_->group_started(group_name);
try
{
test_result tr = i->second->run_test(n);
callback_->test_completed(tr);
callback_->group_completed(group_name);
callback_->run_completed();
return tr;
}
catch (const beyond_last_test&)
{
callback_->group_completed(group_name);
callback_->run_completed();
throw;
}
catch (const no_such_test&)
{
callback_->group_completed(group_name);
callback_->run_completed();
throw;
}
}
protected:
typedef std::map<std::string, group_base*> groups;
typedef groups::iterator iterator;
typedef groups::const_iterator const_iterator;
groups groups_;
callback default_callback_;
callback* callback_;
private:
void run_all_tests_in_group_(const_iterator i) const
{
i->second->rewind();
for ( ;; )
{
test_result tr = i->second->run_next();
callback_->test_completed(tr);
if (tr.result == test_result::ex_ctor)
{
throw no_more_tests();
}
}
}
};
/**
* Singleton for test_runner implementation.
* Instance with name runner_singleton shall be implemented
* by user.
*/
class test_runner_singleton
{
public:
static test_runner& get()
{
static test_runner tr;
return tr;
}
};
extern test_runner_singleton runner;
}
#endif