Files
openmesh/Tools/Utils/TestingFramework.hh

331 lines
7.8 KiB
C++
Raw Normal View History

// ============================================================================
// $Id: TestingFramework.hh,v 1.1.1.1 2006-10-25 16:14:15 habbecke Exp $
// ----------------------------------------------------------------------------
#ifndef TESTINGFRAMEWORK_HH
#define TESTINGFRAMEWORK_HH
// ----------------------------------------------------------------------------
/** \file TestingFramework.hh
This file contains a little framework for test programms
*/
// ----------------------------------------------------------------------------
#include "Config.hh"
#include <iosfwd>
#include <sstream>
#include <vector>
#include <algorithm>
#include <stdexcept>
#include <OpenMesh/Core/Utils/Noncopyable.hh>
// ------------------------------------------------------------- namespace ----
namespace OpenMesh { // BEGIN_NS_OPENMESH
namespace Utils { // BEGIN_NS_UTILS
// ----------------------------------------------------------------- class ----
//
// Usage Example
//
// #include <iostream>
// #include <.../TestingFramework.hh>
//
// struct test_func : public TestingFramework::TestFunc
// {
// typedef test_func Self;
//
// // define ctor and copy-ctor
// test_func( TestingFramework& _th, std::string _n ) : TestingFramework::TestFunc( _th, _n ) { }
// test_func( Self& _cpy ) : TestingFramework::TestFunc(_cpy) { }
//
// // overload body()
// void body()
// {
//
// // Do the tests
// // direct call to verify
// verify( testResult, expectedResult, "additional information" );
//
// // or use the define TH_VERIFY. The test-expression will be used as the message string
// TH_VERIFY( testResult, expectedResult );
//
// ...
// }
// };
//
// int main(...)
// {
// TestingFramework testSuite(std::cout); // send output to stdout
//
// new test_func(testSuite); // create new test instance. It registers with testSuite.
// return testSuite.run();
// }
//
//
#define TH_VERIFY( expr, expt ) \
verify( expr, expt, #expr )
//
#define TH_VERIFY_X( expr, expt ) \
verify_x( expr, expt, #expr )
/** Helper class for test programms.
\internal
*/
class TestingFramework : Noncopyable
{
public:
typedef TestingFramework Self;
typedef std::logic_error verify_error;
#ifndef DOXY_IGNORE_THIS
class TestFunc
{
public:
TestFunc( TestingFramework& _th, const std::string& _n )
: th_(_th), name_(_n)
{
th_.reg(this);
}
virtual ~TestFunc()
{ }
void operator() ( void )
{
prolog();
try
{
body();
}
catch( std::exception& x )
{
std::cerr << "<<Error>>: Cannot proceed test due to failure of last"
<< " test: " << x.what() << std::endl;
}
catch(...)
{
std::cerr << "Fatal: cannot proceed test due to unknown error!"
<< std::endl;
}
epilog();
}
const TestingFramework& testHelper() const { return th_; }
protected:
virtual void prolog(void)
{
begin(name_);
}
virtual void body(void) = 0;
virtual void epilog(void)
{
end();
}
protected:
TestingFramework& testHelper() { return th_; }
TestFunc( const TestFunc& _cpy ) : th_(_cpy.th_), name_(_cpy.name_) { }
// Use the following method in prolog()
TestFunc& begin(std::string _title, const std::string& _info = "")
{ th_.begin(_title,_info); return *this; }
// Use the following method in epilog()
TestFunc& end(void)
{ th_.end(); return *this; }
// Use the followin methods in body()
template <typename ValueType>
bool
verify( const ValueType& _rc, const ValueType& _expected,
std::string _info )
{ return th_.verify( _rc, _expected, _info ); }
template <typename ValueType>
void
verify_x( const ValueType& _rc, const ValueType& _expected,
std::string _info )
{
if ( !verify(_rc, _expected, _info) )
throw verify_error(_info);
}
TestFunc& info(const std::string& _info)
{ th_.info(_info); return *this; }
TestFunc& info(const std::ostringstream& _ostr)
{ th_.info(_ostr); return *this; }
private:
TestFunc();
protected:
TestingFramework& th_;
std::string name_;
};
#endif
typedef TestFunc* TestFuncPtr;
typedef std::vector<TestFuncPtr> TestSet;
public:
TestingFramework(std::ostream& _os)
: errTotal_(0), errCount_(0),
verifyTotal_(0), verifyCount_(0),
testTotal_(0), testCount_(0),
os_(_os)
{ }
protected:
#ifndef DOXY_IGNORE_THIS
struct TestDeleter
{
void operator() (TestFuncPtr _tfptr) { delete _tfptr; }
};
#endif
public:
virtual ~TestingFramework()
{
std::for_each(tests_.begin(), tests_.end(), TestDeleter() );
}
public:
template <typename ValueType>
bool verify(const ValueType& _rc,
const ValueType& _expected,
const std::string& _info)
{
++verifyTotal_;
if ( _rc == _expected )
{
os_ << " " << _info << ", result: " << _rc << ", OK!" << std::endl;
return true;
}
++errTotal_;
os_ << " " << _info << ", result: " << _rc << " != " << _expected
<< " <<ERROR>>" << std::endl;
return false;
}
Self& begin(std::string _title, const std::string& _info = "")
{
std::ostringstream ostr;
testTitle_ = _title;
errCount_ = errTotal_;
++testTotal_;
ostr << _title;
if ( !_info.empty() )
ostr << " ["<< _info << "]";
testTitle_ = ostr.str();
os_ << "Begin " << testTitle_ << std::endl;
return *this;
}
Self& end()
{
if (errorCount()==0)
++testCount_;
os_ << "End " << testTitle_ << ": " << errorCount() << " Error(s)." << std::endl;
return *this;
}
Self& info(const std::string& _info)
{
os_ << " + " << _info << std::endl;
return *this;
}
Self& info(const std::ostringstream& _ostr)
{
os_ << " + " << _ostr.str() << std::endl;
return *this;
}
size_t errorTotal() const { return errTotal_; }
size_t errorCount() const { return errTotal_ - errCount_; }
size_t verifyTotal() const { return verifyTotal_; }
size_t verifyCount() const { return verifyTotal_ - verifyCount_; }
size_t goodTotal() const { return verifyTotal() - errorTotal(); }
size_t goodCount() const { return verifyCount() - errorCount(); }
size_t testTotal() const { return testTotal_; }
size_t testCount() const { return testCount_; }
public:
int run(void)
{
os_ << "Test started\n";
TestRunner executer;
std::for_each(tests_.begin(), tests_.end(), executer );
os_ << std::endl;
os_ << "All tests completed" << std::endl
<< " #Tests: " << testCount() << "/" << testTotal() << std::endl
<< " #Errors: " << errorTotal() << "/" << verifyTotal() << std::endl;
return errorTotal();
}
protected:
#ifndef DOXY_IGNORE_THIS
struct TestRunner
{
void operator() (TestFuncPtr _tfptr) { (*_tfptr)(); }
};
#endif
int reg(TestFuncPtr _tfptr)
{
tests_.push_back(_tfptr);
return true;
}
friend class TestFunc;
private:
size_t errTotal_;
size_t errCount_;
size_t verifyTotal_;
size_t verifyCount_;
size_t testTotal_; // #Tests
size_t testCount_; // #Tests ohne Fehler
std::string testTitle_;
std::ostream& os_;
TestSet tests_;
};
// ============================================================================
} // END_NS_UTILS
} // END_NS_OPENMESH
// ============================================================================
#endif // TESTINGFRMEWORK_HH
// ============================================================================