OpenMesh
OpenMesh/Tools/Utils/TestingFramework.hh
Go to the documentation of this file.
00001 /*===========================================================================*\
00002  *                                                                           *
00003  *                               OpenMesh                                    *
00004  *      Copyright (C) 2001-2011 by Computer Graphics Group, RWTH Aachen      *
00005  *                           www.openmesh.org                                *
00006  *                                                                           *
00007  *---------------------------------------------------------------------------* 
00008  *  This file is part of OpenMesh.                                           *
00009  *                                                                           *
00010  *  OpenMesh is free software: you can redistribute it and/or modify         * 
00011  *  it under the terms of the GNU Lesser General Public License as           *
00012  *  published by the Free Software Foundation, either version 3 of           *
00013  *  the License, or (at your option) any later version with the              *
00014  *  following exceptions:                                                    *
00015  *                                                                           *
00016  *  If other files instantiate templates or use macros                       *
00017  *  or inline functions from this file, or you compile this file and         *
00018  *  link it with other files to produce an executable, this file does        *
00019  *  not by itself cause the resulting executable to be covered by the        *
00020  *  GNU Lesser General Public License. This exception does not however       *
00021  *  invalidate any other reasons why the executable file might be            *
00022  *  covered by the GNU Lesser General Public License.                        *
00023  *                                                                           *
00024  *  OpenMesh is distributed in the hope that it will be useful,              *
00025  *  but WITHOUT ANY WARRANTY; without even the implied warranty of           *
00026  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the            *
00027  *  GNU Lesser General Public License for more details.                      *
00028  *                                                                           *
00029  *  You should have received a copy of the GNU LesserGeneral Public          *
00030  *  License along with OpenMesh.  If not,                                    *
00031  *  see <http://www.gnu.org/licenses/>.                                      *
00032  *                                                                           *
00033 \*===========================================================================*/ 
00034 
00035 /*===========================================================================*\
00036  *                                                                           *             
00037  *   $Revision: 362 $                                                         *
00038  *   $Date: 2011-01-26 10:21:12 +0100 (Mi, 26 Jan 2011) $                   *
00039  *                                                                           *
00040 \*===========================================================================*/
00041 
00042 #ifndef TESTINGFRAMEWORK_HH
00043 #define TESTINGFRAMEWORK_HH
00044 // ----------------------------------------------------------------------------
00045 
00051 // ----------------------------------------------------------------------------
00052 
00053 #include "Config.hh"
00054 #include <iosfwd>
00055 #include <sstream>
00056 #include <vector>
00057 #include <algorithm>
00058 #include <stdexcept>
00059 #include <OpenMesh/Core/Utils/Noncopyable.hh>
00060 
00061 // ------------------------------------------------------------- namespace ----
00062 
00063 namespace OpenMesh { // BEGIN_NS_OPENMESH
00064 namespace Utils { // BEGIN_NS_UTILS
00065 
00066 
00067 // ----------------------------------------------------------------- class ----
00068 //
00069 // Usage Example
00070 //
00071 // #include <iostream>
00072 // #include <.../TestingFramework.hh>
00073 //
00074 // struct test_func : public TestingFramework::TestFunc
00075 // {
00076 //    typedef test_func Self;
00077 //
00078 //    // define ctor and copy-ctor
00079 //    test_func( TestingFramework& _th, std::string _n ) : TestingFramework::TestFunc( _th, _n ) { }
00080 //    test_func( Self& _cpy ) : TestingFramework::TestFunc(_cpy) { }
00081 //
00082 //    // overload body()
00083 //    void body()
00084 //    {
00085 //
00086 //       // Do the tests
00087 //       // direct call to verify
00088 //       verify( testResult, expectedResult, "additional information" );
00089 //
00090 //       // or use the define TH_VERIFY. The test-expression will be used as the message string
00091 //       TH_VERIFY( testResult, expectedResult );
00092 //
00093 //       ...
00094 //    }
00095 // };
00096 //
00097 // int main(...)
00098 // {
00099 //    TestingFramework testSuite(std::cout); // send output to stdout
00100 //
00101 //    new test_func(testSuite);        // create new test instance. It registers with testSuite.
00102 //    return testSuite.run();
00103 // }
00104 //
00105 
00106 // 
00107 #define TH_VERIFY( expr, expt ) \
00108      verify( expr, expt, #expr )
00109 
00110 //
00111 #define TH_VERIFY_X( expr, expt ) \
00112      verify_x( expr, expt, #expr )
00113 
00117 class TestingFramework : Noncopyable
00118 {
00119 public:
00120 
00121   typedef TestingFramework Self;
00122   typedef std::logic_error verify_error;
00123    
00124 #ifndef DOXY_IGNORE_THIS
00125   class TestFunc
00126   {
00127   public:
00128     TestFunc( TestingFramework& _th, const std::string& _n ) 
00129       : th_(_th), name_(_n)
00130     {
00131       th_.reg(this);
00132     }
00133     
00134     virtual ~TestFunc()
00135     { }
00136     
00137     void operator() ( void )
00138     {
00139       prolog();
00140       try
00141       {
00142         body();
00143       }
00144       catch( std::exception& x )
00145       {
00146         std::cerr << "<<Error>>: Cannot proceed test due to failure of last"
00147                   << "  test: " << x.what() << std::endl;
00148       }
00149       catch(...)
00150       {
00151         std::cerr << "Fatal: cannot proceed test due to unknown error!" 
00152                   << std::endl;
00153       }
00154       epilog();
00155     }
00156     
00157     const TestingFramework& testHelper() const { return th_; }
00158     
00159   protected:
00160     
00161     virtual void prolog(void)
00162     {
00163       begin(name_);
00164     }
00165     
00166     virtual void body(void) = 0;
00167     
00168     virtual void epilog(void)
00169     {
00170       end();
00171     }
00172     
00173   protected:
00174     
00175     TestingFramework& testHelper() { return th_; }
00176     
00177     TestFunc( const TestFunc& _cpy ) : th_(_cpy.th_), name_(_cpy.name_) { }
00178     
00179     
00180     // Use the following method in prolog()
00181     TestFunc& begin(std::string _title, const std::string& _info = "")
00182     { th_.begin(_title,_info); return *this; }
00183     
00184     
00185     // Use the following method in epilog()
00186     TestFunc& end(void)
00187     { th_.end(); return *this; }
00188     
00189     
00190     // Use the followin methods in body()
00191     
00192     template <typename ValueType>
00193     bool
00194     verify( const ValueType& _rc, const ValueType& _expected, 
00195             std::string _info )
00196     { return th_.verify( _rc, _expected, _info ); }
00197     
00198     template <typename ValueType>
00199     void
00200     verify_x( const ValueType& _rc, const ValueType& _expected, 
00201               std::string _info )
00202     {
00203       if ( !verify(_rc, _expected, _info) )
00204         throw verify_error(_info);
00205     }
00206     
00207     TestFunc& info(const std::string& _info) 
00208     { th_.info(_info); return *this; }
00209 
00210     TestFunc& info(const std::ostringstream& _ostr) 
00211     { th_.info(_ostr); return *this; }
00212     
00213   private:      
00214     TestFunc();
00215     
00216   protected:
00217     TestingFramework& th_;
00218     std::string name_;      
00219   };
00220 #endif
00221 
00222   typedef TestFunc*                TestFuncPtr;
00223   typedef std::vector<TestFuncPtr> TestSet;
00224   
00225 public:
00226   
00227   TestingFramework(std::ostream& _os) 
00228     : errTotal_(0),    errCount_(0),
00229       verifyTotal_(0), verifyCount_(0),
00230       testTotal_(0),   testCount_(0),
00231       os_(_os)
00232   { }
00233   
00234 protected:
00235   
00236 #ifndef DOXY_IGNORE_THIS
00237   struct TestDeleter
00238   {
00239     void operator() (TestFuncPtr _tfptr) { delete _tfptr; }
00240   };
00241 #endif
00242 
00243 public:   
00244 
00245    virtual ~TestingFramework()
00246    {
00247       std::for_each(tests_.begin(), tests_.end(), TestDeleter() );
00248    }
00249 
00250 public:
00251    
00252    template <typename ValueType>
00253    bool verify(const ValueType& _rc, 
00254                const ValueType& _expected, 
00255                const std::string& _info)
00256    {
00257       ++verifyTotal_;
00258       if ( _rc == _expected )
00259       {
00260          os_ << "    " << _info << ", result: " << _rc << ", OK!" << std::endl;
00261          return true;
00262       }
00263       ++errTotal_;
00264       os_ << "    " << _info << ", result: " << _rc << " != " << _expected
00265           << " <<ERROR>>" << std::endl;
00266       return false;
00267    }
00268    
00269    Self& begin(std::string _title, const std::string& _info = "")
00270    {
00271       std::ostringstream ostr;
00272       
00273       testTitle_ = _title;
00274       errCount_  = errTotal_;
00275       ++testTotal_;
00276       
00277       ostr << _title;
00278       if ( !_info.empty() )
00279          ostr << " ["<< _info << "]";
00280       testTitle_ = ostr.str();
00281       os_ << "Begin " << testTitle_ << std::endl;
00282       return *this;
00283    }
00284    
00285    Self& end()
00286    {
00287       if (errorCount()==0)
00288          ++testCount_;
00289       
00290       os_ << "End " << testTitle_ << ": " << errorCount() << " Error(s)." << std::endl;
00291       return *this;
00292    }
00293 
00294    Self& info(const std::string& _info)
00295    {
00296       os_ << "  + " << _info << std::endl;
00297       return *this;
00298    }
00299    
00300    Self& info(const std::ostringstream& _ostr)
00301    {
00302       os_ << "  + " << _ostr.str() << std::endl;
00303       return *this;
00304    }
00305    
00306    size_t errorTotal()  const { return errTotal_; }
00307    size_t errorCount()  const { return errTotal_ - errCount_; }
00308    size_t verifyTotal() const { return verifyTotal_; }
00309    size_t verifyCount() const { return verifyTotal_ - verifyCount_; }
00310    size_t goodTotal()   const { return verifyTotal() - errorTotal(); }
00311    size_t goodCount()   const { return verifyCount() - errorCount(); }
00312    
00313    size_t testTotal()   const { return testTotal_; }
00314    size_t testCount()   const { return testCount_; }
00315 
00316 public:
00317 
00318    int run(void)
00319    {
00320       os_ << "Test started\n";
00321       TestRunner executer;
00322       std::for_each(tests_.begin(), tests_.end(), executer );
00323       os_ << std::endl;
00324       os_ << "All tests completed" << std::endl
00325           << "   #Tests: " << testCount() << "/" << testTotal() << std::endl
00326           << "  #Errors: " << errorTotal() << "/" << verifyTotal() << std::endl;
00327       return errorTotal();
00328    }
00329 
00330 protected:
00331 
00332 #ifndef DOXY_IGNORE_THIS
00333   struct TestRunner
00334   {
00335     void operator() (TestFuncPtr _tfptr) { (*_tfptr)(); }
00336   };   
00337 #endif
00338 
00339   int reg(TestFuncPtr _tfptr)
00340   {
00341     tests_.push_back(_tfptr);
00342     return true;
00343   }
00344 
00345   friend class TestFunc;
00346    
00347 private:
00348 
00349   size_t errTotal_;    
00350   size_t errCount_;    
00351   size_t verifyTotal_;
00352   size_t verifyCount_;   
00353   size_t testTotal_;   // #Tests
00354   size_t testCount_;   // #Tests ohne Fehler
00355   
00356   std::string testTitle_;
00357   std::ostream& os_;
00358   
00359   TestSet tests_;
00360   
00361 };
00362 
00363 // ============================================================================
00364 } // END_NS_UTILS
00365 } // END_NS_OPENMESH
00366 // ============================================================================
00367 #endif // TESTINGFRMEWORK_HH
00368 // ============================================================================