tut.h.svn-base
上传用户:market2
上传日期:2018-11-18
资源大小:18786k
文件大小:23k
源码类别:

外挂编程

开发平台:

Windows_Unix

  1. /**
  2.  * TUT unit testing framework.
  3.  * http://tut-framework.sourceforge.net/
  4.  *
  5.  * Copyright 2002-2006 Vladimir Dyuzhev.
  6.  *
  7.  * Redistribution and use in source and binary forms, with or without
  8.  * modification, are permitted provided that the following conditions are met:
  9.  *
  10.  * Redistributions of source code must retain the above copyright notice, this
  11.  * list of conditions and the following disclaimer.
  12.  * Redistributions in binary form must reproduce the above copyright notice,
  13.  * this list of conditions and the following disclaimer in the documentation
  14.  * and/or other materials provided with the distribution.
  15.  *
  16.  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
  17.  * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
  18.  * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
  19.  * AUTHOR OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
  20.  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
  21.  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
  22.  * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
  23.  * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
  24.  * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
  25.  * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  26.  */
  27. // Slightly modified for use in this software package.
  28. #ifndef TUT_H_GUARD
  29. #define TUT_H_GUARD
  30. #include <iostream>
  31. #include <map>
  32. #include <vector>
  33. #include <string>
  34. #include <sstream>
  35. #include <stdexcept>
  36. #include <typeinfo>
  37. #if defined(TUT_USE_SEH)
  38. #include <windows.h>
  39. #include <winbase.h>
  40. #endif
  41. #define DEFINE_TEST_GROUP(name) 
  42. using namespace tut; 
  43. using namespace OSL; 
  44. typedef test_group<name> factory; 
  45. typedef factory::object object; 
  46. factory name## _group(#name)
  47. #define TEST_METHOD(i) 
  48. template<> template<> 
  49. void object::test<i>()
  50. /**
  51.  * Template Unit Tests Framework for C++.
  52.  * http://tut.dozen.ru
  53.  *
  54.  * @author dozen, tut@dozen.ru
  55.  */
  56. namespace tut
  57. {
  58.   /**
  59.    * Exception to be throwed when attempted to execute 
  60.    * missed test by number.
  61.    */
  62.   struct no_such_test : public std::logic_error
  63.   {
  64.     no_such_test() : std::logic_error("no such test"){};
  65.   };
  66.   /**
  67.    * No such test and passed test number is higher than
  68.    * any test number in current group. Used in one-by-one
  69.    * test running when upper bound is not known.
  70.    */
  71.   struct beyond_last_test : public no_such_test
  72.   {
  73.     beyond_last_test(){};
  74.   };
  75.   /**
  76.    * Group not found exception.
  77.    */
  78.   struct no_such_group : public std::logic_error
  79.   {
  80.     no_such_group(const std::string& grp) : 
  81.       std::logic_error(grp){};
  82.   };
  83.   /**
  84.    * Internal exception to be throwed when 
  85.    * no more tests left in group or journal.
  86.    */
  87.   struct no_more_tests
  88.   {
  89.     no_more_tests(){};
  90.   };
  91.   /**
  92.    * Internal exception to be throwed when 
  93.    * test constructor has failed.
  94.    */
  95.   struct bad_ctor : public std::logic_error
  96.   {
  97.     bad_ctor(const std::string& msg) : 
  98.       std::logic_error(msg){};
  99.   };
  100.   /**
  101.    * Exception to be throwed when ensure() fails or fail() called.
  102.    */
  103.   class failure : public std::logic_error
  104.   {
  105.     public:
  106.       failure(const std::string& msg) : std::logic_error(msg){};
  107.   };
  108.   /**
  109.    * Exception to be throwed when test desctructor throwed an exception.
  110.    */
  111.   class warning : public std::logic_error
  112.   {
  113.     public:
  114.       warning(const std::string& msg) : std::logic_error(msg){};
  115.   };
  116.   /**
  117.    * Exception to be throwed when test issued SEH (Win32)
  118.    */
  119.   class seh : public std::logic_error
  120.   {
  121.     public:
  122.       seh(const std::string& msg) : std::logic_error(msg){};
  123.   };
  124.   /**
  125.    * Return type of runned test/test group.
  126.    *
  127.    * For test: contains result of test and, possible, message
  128.    * for failure or exception.
  129.    */
  130.   struct test_result
  131.   {
  132.     /**
  133.      * Test group name.
  134.      */
  135.     std::string group;
  136.     /**
  137.      * Test number in group.
  138.      */
  139.     int test;
  140.     
  141.     /**
  142.      * ok - test finished successfully
  143.      * fail - test failed with ensure() or fail() methods
  144.      * ex - test throwed an exceptions
  145.      * warn - test finished successfully, but test destructor throwed
  146.      * term - test forced test application to terminate abnormally
  147.      */
  148.     typedef enum { ok, fail, ex, warn, term, ex_ctor } result_type;
  149.     result_type result;
  150.     /**
  151.      * Exception message for failed test.
  152.      */
  153.     std::string message;
  154.     std::string exception_typeid;
  155.     /**
  156.      * Default constructor.
  157.      */
  158.     test_result()
  159.       : test(0),result(ok)
  160.     {
  161.     }
  162.     /**
  163.      * Constructor.
  164.      */
  165.     test_result( const std::string& grp,int pos,result_type res)
  166.       : group(grp),test(pos),result(res)
  167.     {
  168.     }
  169.     /**
  170.      * Constructor with exception.
  171.      */
  172.     test_result( const std::string& grp,int pos,
  173.                  result_type res,
  174.                  const std::exception& ex)
  175.       : group(grp),test(pos),result(res),
  176.         message(ex.what()),exception_typeid(typeid(ex).name())
  177.     {
  178.     }
  179.   };
  180.   /**
  181.    * Interface.
  182.    * Test group operations.
  183.    */
  184.   struct group_base
  185.   {
  186.     virtual ~group_base(){};
  187.     // execute tests iteratively
  188.     virtual void rewind() = 0;
  189.     virtual test_result run_next() = 0;
  190.     // execute one test
  191.     virtual test_result run_test(int n) = 0;
  192.   };
  193.   /**
  194.    * Test runner callback interface.
  195.    * Can be implemented by caller to update
  196.    * tests results in real-time. User can implement 
  197.    * any of callback methods, and leave unused 
  198.    * in default implementation.
  199.    */
  200.   struct callback
  201.   {
  202.     /**
  203.      * Virtual destructor is a must for subclassed types.
  204.      */
  205.     virtual ~callback(){};
  206.     /**
  207.      * Called when new test run started.
  208.      */
  209.     virtual void run_started(){};
  210.     /**
  211.      * Called when a group started
  212.      * @param name Name of the group
  213.      */
  214.     virtual void group_started(const std::string& /*name*/){};
  215.     /**
  216.      * Called when a test finished.
  217.      * @param tr Test results.
  218.      */
  219.     virtual void test_completed(const test_result& /*tr*/){};
  220.     /**
  221.      * Called when a group is completed
  222.      * @param name Name of the group
  223.      */
  224.     virtual void group_completed(const std::string& /*name*/){};
  225.     /**
  226.      * Called when all tests in run completed.
  227.      */
  228.     virtual void run_completed(){};
  229.   };
  230.   /**
  231.    * Typedef for runner::list_groups()
  232.    */
  233.   typedef std::vector<std::string> groupnames;
  234.   /**
  235.    * Test runner.
  236.    */
  237.   class test_runner
  238.   {
  239.     protected:
  240.       typedef std::map<std::string,group_base*> groups;
  241.       typedef groups::iterator iterator;
  242.       typedef groups::const_iterator const_iterator;
  243.       groups groups_;
  244.       callback  default_callback_;
  245.       callback* callback_;
  246.     public:
  247.     /**
  248.      * Constructor
  249.      */
  250.     test_runner() : callback_(&default_callback_)
  251.     {
  252.     }
  253.     /**
  254.      * Stores another group for getting by name.
  255.      */
  256.     void register_group(const std::string& name,group_base* gr)
  257.     {
  258.       if( gr == 0 )
  259.       {
  260.         throw std::invalid_argument("group shall be non-null");
  261.       }
  262.       groups::iterator found = groups_.find(name);
  263.       if( found != groups_.end() )
  264.       {
  265.         std::string msg("attempt to add already existent group "+name);
  266.         // this exception terminates application so we use cerr also
  267.         std::cerr << msg << std::endl;
  268.         throw std::logic_error(msg);
  269.       }
  270.       groups_[name] = gr;
  271.     }
  272.     /**
  273.      * Stores callback object.
  274.      */
  275.     void set_callback(callback* cb)
  276.     {
  277.       callback_ = cb==0? &default_callback_:cb;
  278.     }
  279.     /**
  280.      * Returns callback object.
  281.      */
  282.     callback& get_callback() const
  283.     {
  284.       return *callback_;
  285.     }
  286.     /**
  287.      * Returns list of known test groups.
  288.      */
  289.     const groupnames list_groups() const
  290.     {
  291.       groupnames ret;
  292.       const_iterator i = groups_.begin();
  293.       const_iterator e = groups_.end();
  294.       while( i != e )
  295.       {
  296.         ret.push_back(i->first);
  297.         ++i;
  298.       }
  299.       return ret;
  300.     }
  301.     /**
  302.      * Runs all tests in all groups.
  303.      * @param callback Callback object if exists; null otherwise
  304.      */
  305.     void run_tests() const
  306.     {
  307.       callback_->run_started();
  308.       const_iterator i = groups_.begin();
  309.       const_iterator e = groups_.end();
  310.       while( i != e )
  311.       {
  312.         callback_->group_started(i->first);
  313.         try
  314.         {
  315.           run_all_tests_in_group_(i);
  316.         }
  317.         catch( const no_more_tests& )
  318.         {
  319.           callback_->group_completed(i->first);
  320.         }
  321.         ++i;
  322.       }
  323.       callback_->run_completed();
  324.     }
  325.     /**
  326.      * Runs all tests in specified group.
  327.      */
  328.     void run_tests(const std::string& group_name) const
  329.     {
  330.       callback_->run_started();
  331.       const_iterator i = groups_.find(group_name);
  332.       if( i == groups_.end() )
  333.       {
  334.         callback_->run_completed();
  335.         throw no_such_group(group_name);
  336.       }
  337.       callback_->group_started(group_name);
  338.       try
  339.       {
  340.         run_all_tests_in_group_(i);
  341.       }
  342.       catch( const no_more_tests& )
  343.       {
  344.         // ok
  345.       }
  346.       callback_->group_completed(group_name);
  347.       callback_->run_completed();
  348.     }
  349.     /**
  350.      * Runs one test in specified group.
  351.      */
  352.     test_result run_test(const std::string& group_name,int n) const
  353.     {
  354.       callback_->run_started();
  355.       const_iterator i = groups_.find(group_name);
  356.       if( i == groups_.end() )
  357.       {
  358.         callback_->run_completed();
  359.         throw no_such_group(group_name);
  360.       }
  361.       callback_->group_started(group_name);
  362.       try
  363.       {
  364.         test_result tr = i->second->run_test(n);
  365.         callback_->test_completed(tr);
  366.         callback_->group_completed(group_name);
  367.         callback_->run_completed();
  368.         return tr;
  369.       }
  370.       catch( const beyond_last_test& )
  371.       {
  372.         callback_->group_completed(group_name);
  373.         callback_->run_completed();
  374.         throw;
  375.       }      
  376.       catch( const no_such_test& )
  377.       {
  378.         callback_->group_completed(group_name);
  379.         callback_->run_completed();
  380.         throw;
  381.       }
  382.     }
  383.     private:
  384.     void run_all_tests_in_group_(const_iterator i) const
  385.     {
  386.       i->second->rewind();
  387.       for( ;; )
  388.       {
  389.         test_result tr = i->second->run_next();
  390.         callback_->test_completed(tr);
  391. if( tr.result == test_result::ex_ctor )
  392. {
  393.           throw no_more_tests();
  394.         }
  395.       }
  396.     }
  397.   };
  398.   /**
  399.    * Singleton for test_runner implementation.
  400.    * Instance with name runner_singleton shall be implemented
  401.    * by user.
  402.    */
  403.   class test_runner_singleton
  404.   {
  405.     public:
  406.       static test_runner& get()
  407.       {
  408.         static test_runner tr;
  409.         return tr;
  410.       }
  411.   };
  412.   extern test_runner_singleton runner;
  413.   /**
  414.    * Test object. Contains data test run upon and default test method 
  415.    * implementation. Inherited from Data to allow tests to  
  416.    * access test data as members.
  417.    */
  418.   template <class Data>
  419.   class test_object : public Data
  420.   {
  421.     public:
  422.     /**
  423.      * Default constructor
  424.      */
  425.     test_object(){};
  426.     /**
  427.      * The flag is set to true by default (dummy) test.
  428.      * Used to detect usused test numbers and avoid unnecessary
  429.      * test object creation which may be time-consuming depending
  430.      * on operations described in Data::Data() and Data::~Data().
  431.      * TODO: replace with throwing special exception from default test.
  432.      */
  433.     bool called_method_was_a_dummy_test_;
  434.     /**
  435.      * Default do-nothing test.
  436.      */
  437.     template <int n>
  438.     void test()
  439.     {
  440.       called_method_was_a_dummy_test_ = true;
  441.     }
  442.   };
  443.   namespace 
  444.   {
  445.     /**
  446.      * Tests provided condition.
  447.      * Throws if false.
  448.      */
  449.     void ensure(bool cond)
  450.     {
  451.        if( !cond ) throw failure("");
  452.     }
  453.     /**
  454.      * Tests provided condition.
  455.      * Throws if false.
  456.      */
  457.     template<typename T>
  458.     void ensure(const T msg,bool cond)
  459.     {
  460.        if( !cond ) throw failure(msg);
  461.     }
  462.     /**
  463.      * Tests two objects for being equal.
  464.      * Throws if false.
  465.      *
  466.      * NB: both T and Q must have operator << defined somewhere, or
  467.      * client code will not compile at all!
  468.      */
  469.     template <class T,class Q>
  470.     void ensure_equals(const char* msg,const Q& actual,const T& expected)
  471.     {
  472.       if( expected != actual )
  473.       {
  474.         std::stringstream ss;
  475.         ss << (msg?msg:"") << (msg?": ":"") << "expected " << expected << " actual " << actual;
  476.         throw failure(ss.str().c_str());
  477.       }
  478.     }
  479.     template <class T,class Q>
  480.     void ensure_equals(const Q& actual,const T& expected)
  481.     {
  482.       ensure_equals<>(0,actual,expected);
  483.     }
  484.     /**
  485.      * Tests two objects for being at most in given distance one from another.
  486.      * Borders are excluded.
  487.      * Throws if false.
  488.      *
  489.      * NB: T must have operator << defined somewhere, or
  490.      * client code will not compile at all! Also, T shall have
  491.      * operators + and -, and be comparable.
  492.      */
  493.     template <class T>
  494.     void ensure_distance(const char* msg,const T& actual,const T& expected,const T& distance)
  495.     {
  496.       if( expected-distance >= actual || expected+distance <= actual )
  497.       {
  498.         std::stringstream ss;
  499.         ss << (msg?msg:"") << (msg?": ":"") << "expected [" << expected-distance << ";" 
  500.            << expected+distance << "] actual " << actual;
  501.         throw failure(ss.str().c_str());
  502.       }
  503.     }
  504.     template <class T>
  505.     void ensure_distance(const T& actual,const T& expected,const T& distance)
  506.     {
  507.       ensure_distance<>(0,actual,expected,distance);
  508.     }
  509.     /**
  510.      * Unconditionally fails with message.
  511.      */
  512.     void fail(const char* msg="")
  513.     {
  514.       throw failure(msg);
  515.     }
  516.   }
  517.   /**
  518.    * Walks through test tree and stores address of each
  519.    * test method in group. Instantiation stops at 0.
  520.    */
  521.   template <class Test,class Group,int n>
  522.   struct tests_registerer
  523.   {
  524.     static void reg(Group& group)
  525.     {
  526.       group.reg(n,&Test::template test<n>);
  527.       tests_registerer<Test,Group,n-1>::reg(group);
  528.     }
  529.   };
  530.   template<class Test,class Group>
  531.   struct tests_registerer<Test,Group,0>
  532.   {
  533.     static void reg(Group&){};
  534.   };
  535.   /**
  536.    * Test group; used to recreate test object instance for
  537.    * each new test since we have to have reinitialized 
  538.    * Data base class.
  539.    */
  540.   template <class Data,int MaxTestsInGroup = 50>
  541.   class test_group : public group_base
  542.   {
  543.     const char* name_;
  544.     typedef void (test_object<Data>::*testmethod)();
  545.     typedef std::map<int,testmethod> tests;
  546.     typedef typename tests::iterator tests_iterator;
  547.     typedef typename tests::const_iterator tests_const_iterator;
  548.     typedef typename tests::const_reverse_iterator 
  549.                      tests_const_reverse_iterator;
  550.     typedef typename tests::size_type size_type;
  551.     tests tests_;
  552.     tests_iterator current_test_;
  553.     /**
  554.      * Exception-in-destructor-safe smart-pointer class.
  555.      */
  556.     template <class T>
  557.     class safe_holder
  558.     {
  559.       T* p_;
  560.       bool permit_throw_in_dtor;
  561.       safe_holder(const safe_holder&);
  562.       safe_holder& operator = (const safe_holder&);
  563.       public:
  564.       safe_holder() : p_(0),permit_throw_in_dtor(false)
  565.       { 
  566.       }
  567.       ~safe_holder()
  568.       {
  569.         release();
  570.       }
  571.       T* operator -> () const { return p_; };
  572.       T* get() const { return p_; };
  573.       /**
  574.        * Tell ptr it can throw from destructor. Right way is to
  575.        * use std::uncaught_exception(), but some compilers lack
  576.        * correct implementation of the function.
  577.        */
  578.       void permit_throw(){ permit_throw_in_dtor = true; }
  579.       /**
  580.        * Specially treats exceptions in test object destructor; 
  581.        * if test itself failed, exceptions in destructor
  582.        * are ignored; if test was successful and destructor failed,
  583.        * warning exception throwed.
  584.        */
  585.       void release()
  586.       {
  587.         try
  588.         {
  589.           if( delete_obj() == false )
  590.           {
  591.             throw warning("destructor of test object raised an SEH exception");
  592.           }
  593.         }
  594.         catch( const std::exception& ex )
  595.         {
  596.           if( permit_throw_in_dtor ) 
  597.           {
  598.             std::string msg = "destructor of test object raised exception: ";
  599.             msg += ex.what();
  600.             throw warning(msg);
  601.           }
  602.         }
  603.         catch( ... )
  604.         {
  605.           if( permit_throw_in_dtor )
  606.           {
  607.             throw warning("destructor of test object raised an exception");
  608.           }
  609.         }
  610.       }
  611.       /**
  612.        * Re-init holder to get brand new object.
  613.        */
  614.       void reset()
  615.       {
  616.         release();
  617.         permit_throw_in_dtor = false;
  618.         p_ = new T();
  619.       }
  620.       bool delete_obj()
  621.       {
  622. #if defined(TUT_USE_SEH)
  623.         __try
  624.         {
  625. #endif
  626.           T* p = p_; 
  627.           p_ = 0;
  628.           delete p;
  629. #if defined(TUT_USE_SEH)
  630.         }
  631.         __except(handle_seh_(::GetExceptionCode()))
  632.         {
  633.           if( permit_throw_in_dtor )
  634.           {
  635.             return false;
  636.           }
  637.         }
  638. #endif
  639.         return true;
  640.       }
  641.     };
  642.     public:
  643.     typedef test_object<Data> object;    
  644.     /**
  645.      * Creates and registers test group with specified name.
  646.      */
  647.     test_group(const char* name)
  648.       : name_(name)
  649.     {
  650.       // register itself
  651.       runner.get().register_group(name_,this);
  652.     
  653.       // register all tests
  654.       tests_registerer<object,test_group,MaxTestsInGroup>::reg(*this);
  655.     };
  656.     /**
  657.      * This constructor is used in self-test run only.
  658.      */
  659.     test_group(const char* name,test_runner& another_runner)
  660.       : name_(name)
  661.     {
  662.       // register itself
  663.       another_runner.register_group(name_,this); 
  664.     
  665.       // register all tests
  666.       tests_registerer<test_object<Data>,
  667.                        test_group,MaxTestsInGroup>::reg(*this);
  668.     };
  669.     /**
  670.      * Registers test method under given number.
  671.      */
  672.     void reg(int n,testmethod tm)
  673.     {
  674.       tests_[n] = tm;
  675.     }
  676.     /**
  677.      * Reset test position before first test.
  678.      */
  679.     void rewind()
  680.     {
  681.       current_test_ = tests_.begin();
  682.     }
  683.     /**
  684.      * Runs next test.
  685.      */
  686.     test_result run_next()
  687.     {
  688.       if( current_test_ == tests_.end() )
  689.       {
  690.         throw no_more_tests();
  691.       }
  692.       // find next user-specialized test
  693.       safe_holder<object> obj;
  694.       while( current_test_ != tests_.end() )
  695.       {
  696.         try
  697.         {
  698.           return run_test_(current_test_++,obj);
  699.         }
  700.         catch( const no_such_test& )
  701.         {
  702.           continue; 
  703.         }
  704.       } 
  705.       throw no_more_tests();
  706.     }
  707.     /**
  708.      * Runs one test by position.
  709.      */
  710.     test_result run_test(int n)
  711.     {
  712.       // beyond tests is special case to discover upper limit
  713.       if( tests_.rbegin() == tests_.rend() ) throw beyond_last_test();
  714.       if( tests_.rbegin()->first < n ) throw beyond_last_test();
  715.       // withing scope; check if given test exists
  716.       tests_iterator ti = tests_.find(n);
  717.       if( ti == tests_.end() ) throw no_such_test();
  718.       safe_holder<object> obj;
  719.       return run_test_(ti,obj);
  720.     }
  721.   private:
  722.     /**
  723.      * VC allows only one exception handling type per function,
  724.      * so I have to split the method
  725.      */
  726.     test_result run_test_(const tests_iterator& ti,safe_holder<object>& obj)
  727.     {
  728.       try
  729.       {
  730.         if( run_test_seh_(ti->second,obj) == false )
  731.           throw seh("seh");
  732.       }
  733.       catch(const no_such_test&)
  734.       {
  735.         throw;
  736.       }
  737.       catch(const warning& ex)
  738.       {
  739.         // test ok, but destructor failed
  740.         test_result tr(name_,ti->first,test_result::warn,ex);
  741.         return tr;
  742.       }
  743.       catch(const failure& ex)
  744.       {
  745.         // test failed because of ensure() or similar method
  746.         test_result tr(name_,ti->first,test_result::fail,ex);
  747.         return tr;
  748.       }
  749.       catch(const seh& ex)
  750.       {
  751.         // test failed with sigsegv, divide by zero, etc
  752.         test_result tr(name_,ti->first,test_result::term,ex);
  753.         return tr;
  754.       }
  755.       catch(const bad_ctor& ex)
  756.       {
  757.         // test failed because test ctor failed; stop the whole group
  758.         test_result tr(name_,ti->first,test_result::ex_ctor,ex);
  759.         return tr;
  760.       }
  761.       catch(const std::exception& ex)
  762.       {
  763.         // test failed with std::exception
  764.         test_result tr(name_,ti->first,test_result::ex,ex);
  765.         return tr;
  766.       }
  767.       catch(...)
  768.       {
  769.         // test failed with unknown exception
  770.         test_result tr(name_,ti->first,test_result::ex);
  771.         return tr;
  772.       }
  773.       // test passed
  774.       test_result tr(name_,ti->first,test_result::ok);
  775.       return tr;
  776.     }
  777.     /**
  778.      * Runs one under SEH if platform supports it.
  779.      */
  780.     bool run_test_seh_(testmethod tm,safe_holder<object>& obj)
  781.     {
  782. #if defined(TUT_USE_SEH)
  783.       __try
  784.       {
  785. #endif
  786.         if( obj.get() == 0 ) 
  787. {
  788.           reset_holder_(obj);
  789. }
  790.         obj->called_method_was_a_dummy_test_ = false;
  791. #if defined(TUT_USE_SEH)
  792.         __try
  793.         {
  794. #endif
  795.           (obj.get()->*tm)();
  796. #if defined(TUT_USE_SEH)
  797.         }
  798.         __except(handle_seh_(::GetExceptionCode()))
  799.         {
  800.           // throw seh("SEH");
  801.           return false;
  802.         }
  803. #endif
  804.         if( obj->called_method_was_a_dummy_test_ )
  805.         {
  806.           // do not call obj.release(); reuse object
  807.           throw no_such_test();
  808.         }
  809.         obj.permit_throw();
  810.         obj.release();
  811. #if defined(TUT_USE_SEH)
  812.       }
  813.       __except(handle_seh_(::GetExceptionCode()))
  814.       {
  815.         return false;
  816.       }
  817. #endif
  818.       return true;
  819.     }
  820.     void reset_holder_(safe_holder<object>& obj)
  821.     {
  822.       try 
  823.       {
  824.         obj.reset();
  825.       }
  826.       catch(const std::exception& ex)
  827.       {
  828.         throw bad_ctor(ex.what());
  829.       }
  830.       catch(...)
  831.       {
  832.         throw bad_ctor("test constructor has generated an exception; group execution is terminated");
  833.       }
  834.     }
  835.   };
  836. #if defined(TUT_USE_SEH)
  837.   /**
  838.    * Decides should we execute handler or ignore SE.
  839.    */
  840.   inline int handle_seh_(DWORD excode)
  841.   {
  842.     switch(excode)
  843.     {
  844.       case EXCEPTION_ACCESS_VIOLATION:
  845.       case EXCEPTION_DATATYPE_MISALIGNMENT:
  846.       case EXCEPTION_BREAKPOINT:
  847.       case EXCEPTION_SINGLE_STEP:
  848.       case EXCEPTION_ARRAY_BOUNDS_EXCEEDED:
  849.       case EXCEPTION_FLT_DENORMAL_OPERAND:     
  850.       case EXCEPTION_FLT_DIVIDE_BY_ZERO:
  851.       case EXCEPTION_FLT_INEXACT_RESULT:        
  852.       case EXCEPTION_FLT_INVALID_OPERATION:
  853.       case EXCEPTION_FLT_OVERFLOW:
  854.       case EXCEPTION_FLT_STACK_CHECK:
  855.       case EXCEPTION_FLT_UNDERFLOW:
  856.       case EXCEPTION_INT_DIVIDE_BY_ZERO:
  857.       case EXCEPTION_INT_OVERFLOW:
  858.       case EXCEPTION_PRIV_INSTRUCTION:
  859.       case EXCEPTION_IN_PAGE_ERROR:
  860.       case EXCEPTION_ILLEGAL_INSTRUCTION:
  861.       case EXCEPTION_NONCONTINUABLE_EXCEPTION:
  862.       case EXCEPTION_STACK_OVERFLOW:
  863.       case EXCEPTION_INVALID_DISPOSITION:
  864.       case EXCEPTION_GUARD_PAGE:
  865.       case EXCEPTION_INVALID_HANDLE:
  866.         return EXCEPTION_EXECUTE_HANDLER;
  867.     };    
  868.     return EXCEPTION_CONTINUE_SEARCH;
  869.   }
  870. #endif
  871. }
  872. #endif