tut logo

TUT: tut.hpp Source File


tut.hpp

00001 #ifndef TUT_H_GUARD
00002 #define TUT_H_GUARD
00003 #include <tut/tut_config.hpp>
00004 
00005 #include <iostream>
00006 #include <map>
00007 #include <vector>
00008 #include <set>
00009 #include <string>
00010 #include <sstream>
00011 #include <iterator>
00012 #include <algorithm>
00013 
00014 #include "tut_exception.hpp"
00015 #include "tut_result.hpp"
00016 #include "tut_posix.hpp"
00017 #include "tut_assert.hpp"
00018 #include "tut_runner.hpp"
00019 
00020 #if defined(TUT_USE_SEH)
00021 #include <windows.h>
00022 #include <winbase.h>
00023 #endif
00024 
00031 namespace tut
00032 {
00033 
00034 template <class, int>
00035 class test_group;
00036 
00042 template <class Data>
00043 class test_object : public Data, public test_object_posix
00044 {
00045     template<class D, int M>
00046     friend class test_group;
00047 
00048     void set_test_group(const char *group)
00049     {
00050         current_test_group_ = group;
00051     }
00052 
00053     void set_test_id(int current_test_id)
00054     {
00055         current_test_id_ = current_test_id;
00056     }
00057 
00058 public:
00059 
00063     test_object()
00064         : called_method_was_a_dummy_test_(false),
00065           current_test_id_(0),
00066           current_test_name_(),
00067           current_test_group_()
00068     {
00069     }
00070 
00071     void set_test_name(const std::string& current_test_name)
00072     {
00073         current_test_name_ = current_test_name;
00074     }
00075 
00076     const std::string& get_test_name() const
00077     {
00078         return current_test_name_;
00079     }
00080 
00081     const std::string& get_test_group() const
00082     {
00083         return current_test_group_;
00084     }
00085 
00086     int get_test_id() const
00087     {
00088         return current_test_id_;
00089     }
00090 
00094     template <int n>
00095     void test()
00096     {
00097         called_method_was_a_dummy_test_ = true;
00098     }
00099 
00106     bool called_method_was_a_dummy_test_;
00107 
00108     virtual ~test_object()
00109     {
00110     }
00111 
00112 private:
00113     int             current_test_id_;
00114     std::string     current_test_name_;
00115     std::string     current_test_group_;
00116 };
00117 
00118 
00123 template <class Test, class Group, int n>
00124 struct tests_registerer
00125 {
00126     static void reg(Group& group)
00127     {
00128         group.reg(n, &Test::template test<n>);
00129         tests_registerer<Test, Group, n - 1>::reg(group);
00130     }
00131 };
00132 
00133 template <class Test, class Group>
00134 struct tests_registerer<Test, Group, 0>
00135 {
00136     static void reg(Group&)
00137     {
00138     }
00139 };
00140 
00146 template <class Data, int MaxTestsInGroup = 50>
00147 class test_group : public group_base, public test_group_posix
00148 {
00149     test_group(const test_group&);
00150     void operator=(const test_group&);
00151 
00152     const char* name_;
00153 
00154     typedef void (test_object<Data>::*testmethod)();
00155     typedef std::map<int, testmethod> tests;
00156     typedef typename tests::iterator tests_iterator;
00157     typedef typename tests::const_iterator tests_const_iterator;
00158     typedef typename tests::const_reverse_iterator
00159     tests_const_reverse_iterator;
00160     typedef typename tests::size_type size_type;
00161 
00162     tests tests_;
00163     tests_iterator current_test_;
00164 
00165     enum seh_result
00166     {
00167         SEH_OK,
00168 #if defined(TUT_USE_SEH)
00169         SEH_CTOR,
00170         SEH_TEST,
00171 #endif
00172         SEH_DUMMY
00173     };
00174 
00178     template <class T>
00179     class safe_holder
00180     {
00181         T* p_;
00182         bool permit_throw_in_dtor;
00183 
00184         safe_holder(const safe_holder&);
00185         safe_holder& operator=(const safe_holder&);
00186 
00187     public:
00188         safe_holder()
00189             : p_(0),
00190               permit_throw_in_dtor(false)
00191         {
00192         }
00193 
00194         ~safe_holder()
00195         {
00196             release();
00197         }
00198 
00199         T* operator->() const
00200         {
00201             return p_;
00202         }
00203 
00204         T* get() const
00205         {
00206             return p_;
00207         }
00208 
00214         void permit_throw()
00215         {
00216             permit_throw_in_dtor = true;
00217         }
00218 
00225         void release()
00226         {
00227             try
00228             {
00229 #if defined(TUT_USE_SEH)
00230                 if (delete_obj() == false)
00231                 {
00232                     throw warning("destructor of test object raised"
00233                         " an SEH exception");
00234                 }
00235 #else
00236                 bool d = delete_obj();
00237                 assert(d && "delete failed with SEH disabled: runtime bug?");
00238 #endif
00239             }
00240             catch (const std::exception& ex)
00241             {
00242                 if (permit_throw_in_dtor)
00243                 {
00244                     std::string msg = "destructor of test object raised"
00245                         " exception: ";
00246                     msg += ex.what();
00247                     throw warning(msg);
00248                 }
00249             }
00250             catch( ... )
00251             {
00252                 if (permit_throw_in_dtor)
00253                 {
00254                     throw warning("destructor of test object raised an"
00255                         " exception");
00256                 }
00257             }
00258         }
00259 
00263         void reset()
00264         {
00265             release();
00266             permit_throw_in_dtor = false;
00267             p_ = new T();
00268         }
00269 
00270         bool delete_obj()
00271         {
00272 #if defined(TUT_USE_SEH)
00273             __try
00274             {
00275 #endif
00276                 T* p = p_;
00277                 p_ = 0;
00278                 delete p;
00279 #if defined(TUT_USE_SEH)
00280             }
00281             __except(handle_seh_(::GetExceptionCode()))
00282             {
00283                 if (permit_throw_in_dtor)
00284                 {
00285                     return false;
00286                 }
00287             }
00288 #endif
00289             return true;
00290         }
00291     };
00292 
00293 public:
00294 
00295     typedef test_object<Data> object;
00296 
00300     test_group(const char* name)
00301         : name_(name),
00302           tests_(),
00303           current_test_()
00304     {
00305         // register itself
00306         runner.get().register_group(name_,this);
00307 
00308         // register all tests
00309         tests_registerer<object, test_group, MaxTestsInGroup>::reg(*this);
00310     }
00311 
00315     test_group(const char* name, test_runner& another_runner)
00316         : name_(name),
00317           tests_(),
00318           current_test_()
00319     {
00320         // register itself
00321         another_runner.register_group(name_, this);
00322 
00323         // register all tests
00324         tests_registerer<test_object<Data>, test_group,
00325             MaxTestsInGroup>::reg(*this);
00326     };
00327 
00331     void reg(int n, testmethod tm)
00332     {
00333         tests_[n] = tm;
00334     }
00335 
00339     void rewind()
00340     {
00341         current_test_ = tests_.begin();
00342     }
00343 
00347     bool run_next(test_result &tr)
00348     {
00349         if (current_test_ == tests_.end())
00350         {
00351             return false;
00352         }
00353 
00354         // find next user-specialized test
00355         safe_holder<object> obj;
00356         while (current_test_ != tests_.end())
00357         {
00358             tests_iterator current_test = current_test_++;
00359 
00360             if(run_test_(current_test, obj, tr) && tr.result != test_result::dummy)
00361             {
00362                 return true;
00363             }
00364         }
00365 
00366         return false;
00367     }
00368 
00372     bool run_test(int n, test_result &tr)
00373     {
00374         if (tests_.rbegin() == tests_.rend() ||
00375             tests_.rbegin()->first < n)
00376         {
00377             return false;
00378         }
00379 
00380         // withing scope; check if given test exists
00381         tests_iterator ti = tests_.find(n);
00382         if (ti == tests_.end())
00383         {
00384             return false;
00385         }
00386 
00387         safe_holder<object> obj;
00388         return run_test_(ti, obj, tr);
00389     }
00390 
00395     bool run_test_(const tests_iterator& ti, safe_holder<object>& obj, test_result &tr)
00396     {
00397         std::string current_test_name;
00398 
00399         tr = test_result(name_, ti->first, current_test_name, test_result::ok);
00400 
00401         try
00402         {
00403             switch (run_test_seh_(ti->second, obj, current_test_name, ti->first))
00404             {
00405 #if defined(TUT_USE_SEH)
00406                 case SEH_CTOR:
00407                     throw bad_ctor("seh");
00408                     break;
00409 
00410                 case SEH_TEST:
00411                     throw seh("seh");
00412                     break;
00413 #endif
00414                 case SEH_DUMMY:
00415                     tr.result = test_result::dummy;
00416                     break;
00417 
00418                 case SEH_OK:
00419                     // ok
00420                     break;
00421             }
00422         }
00423         catch (const rethrown& ex)
00424         {
00425             tr = ex.tr;
00426             tr.result = test_result::rethrown;
00427         }
00428         catch (const tut_error& ex)
00429         {
00430             tr.result = ex.result();
00431             tr.exception_typeid = ex.type();
00432             tr.message = ex.what();
00433         }
00434         catch (const std::exception& ex)
00435         {
00436             tr.result = test_result::ex;
00437             tr.exception_typeid = type_name(ex);
00438             tr.message = ex.what();
00439         }
00440         catch (...)
00441         {
00442             // test failed with unknown exception
00443             tr.result = test_result::ex;
00444         }
00445 
00446         if (obj.get())
00447         {
00448             tr.name = obj->get_test_name();
00449 
00450             // try to report to parent, if exists
00451             send_result_(obj.get(), tr);
00452         }
00453         else
00454         {
00455             tr.name = current_test_name;
00456         }
00457 
00458         return true;
00459     }
00460 
00464     seh_result run_test_seh_(testmethod tm, safe_holder<object>& obj,
00465                              std::string& current_test_name, int current_test_id)
00466     {
00467 #if defined(TUT_USE_SEH)
00468         __try
00469         {
00470 #endif
00471             if (obj.get() == 0)
00472             {
00473                 reset_holder_(obj);
00474             }
00475 
00476             obj->called_method_was_a_dummy_test_ = false;
00477 
00478 #if defined(TUT_USE_SEH)
00479 
00480             __try
00481             {
00482 #endif
00483                 obj.get()->set_test_id(current_test_id);
00484                 obj.get()->set_test_group(name_);
00485                 (obj.get()->*tm)();
00486 #if defined(TUT_USE_SEH)
00487             }
00488             __except(handle_seh_(::GetExceptionCode()))
00489             {
00490                 current_test_name = obj->get_test_name();
00491                 return SEH_TEST;
00492             }
00493 #endif
00494 
00495             if (obj->called_method_was_a_dummy_test_)
00496             {
00497                 // do not call obj.release(); reuse object
00498                 return SEH_DUMMY;
00499             }
00500 
00501             current_test_name = obj->get_test_name();
00502             obj.permit_throw();
00503             obj.release();
00504 #if defined(TUT_USE_SEH)
00505         }
00506         __except(handle_seh_(::GetExceptionCode()))
00507         {
00508             return SEH_CTOR;
00509         }
00510 #endif
00511         return SEH_OK;
00512     }
00513 
00514     void reset_holder_(safe_holder<object>& obj)
00515     {
00516         try
00517         {
00518             obj.reset();
00519         }
00520         catch (const std::exception& ex)
00521         {
00522             throw bad_ctor(ex.what());
00523         }
00524         catch (...)
00525         {
00526             throw bad_ctor("test constructor has generated an exception;"
00527                 " group execution is terminated");
00528         }
00529     }
00530 };
00531 
00532 #if defined(TUT_USE_SEH)
00533 
00536 inline int handle_seh_(DWORD excode)
00537 {
00538     switch(excode)
00539     {
00540     case EXCEPTION_ACCESS_VIOLATION:
00541     case EXCEPTION_DATATYPE_MISALIGNMENT:
00542     case EXCEPTION_BREAKPOINT:
00543     case EXCEPTION_SINGLE_STEP:
00544     case EXCEPTION_ARRAY_BOUNDS_EXCEEDED:
00545     case EXCEPTION_FLT_DENORMAL_OPERAND:
00546     case EXCEPTION_FLT_DIVIDE_BY_ZERO:
00547     case EXCEPTION_FLT_INEXACT_RESULT:
00548     case EXCEPTION_FLT_INVALID_OPERATION:
00549     case EXCEPTION_FLT_OVERFLOW:
00550     case EXCEPTION_FLT_STACK_CHECK:
00551     case EXCEPTION_FLT_UNDERFLOW:
00552     case EXCEPTION_INT_DIVIDE_BY_ZERO:
00553     case EXCEPTION_INT_OVERFLOW:
00554     case EXCEPTION_PRIV_INSTRUCTION:
00555     case EXCEPTION_IN_PAGE_ERROR:
00556     case EXCEPTION_ILLEGAL_INSTRUCTION:
00557     case EXCEPTION_NONCONTINUABLE_EXCEPTION:
00558     case EXCEPTION_STACK_OVERFLOW:
00559     case EXCEPTION_INVALID_DISPOSITION:
00560     case EXCEPTION_GUARD_PAGE:
00561     case EXCEPTION_INVALID_HANDLE:
00562         return EXCEPTION_EXECUTE_HANDLER;
00563     };
00564 
00565     return EXCEPTION_CONTINUE_SEARCH;
00566 }
00567 #endif
00568 }
00569 
00570 #endif // TUT_H_GUARD
00571 

All Rights Reserved. Generated on Sun Jan 31 00:39:47 2010 for TUT by doxygen 1.5.1