331 lines
7.8 KiB
C++
331 lines
7.8 KiB
C++
|
|
// ============================================================================
|
||
|
|
// $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
|
||
|
|
// ============================================================================
|