// ============================================================================ // $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 #include #include #include #include #include // ------------------------------------------------------------- namespace ---- namespace OpenMesh { // BEGIN_NS_OPENMESH namespace Utils { // BEGIN_NS_UTILS // ----------------------------------------------------------------- class ---- // // Usage Example // // #include // #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 << "<>: 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 bool verify( const ValueType& _rc, const ValueType& _expected, std::string _info ) { return th_.verify( _rc, _expected, _info ); } template 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 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 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 << " <>" << 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 // ============================================================================