Home | History | Annotate | Download | only in test
      1 //  (C) Copyright Gennadiy Rozental 2001-2008.
      2 //  (C) Copyright Beman Dawes 2001.
      3 //  Distributed under the Boost Software License, Version 1.0.
      4 //  (See accompanying file LICENSE_1_0.txt or copy at
      5 //  http://www.boost.org/LICENSE_1_0.txt)
      6 
      7 //  See http://www.boost.org/libs/test for the library home page.
      8 //
      9 //  File        : $RCSfile$
     10 //
     11 //  Version     : $Revision: 57992 $
     12 //
     13 //  Description : defines abstract monitor interfaces and implements execution exception
     14 //  The original Boost Test Library included an implementation detail function
     15 //  named catch_exceptions() which caught otherwise uncaught C++ exceptions.
     16 //  It was derived from an existing test framework by Beman Dawes.  The
     17 //  intent was to expand later to catch other detectable but platform dependent
     18 //  error events like Unix signals or Windows structured C exceptions.
     19 //
     20 //  Requests from early adopters of the Boost Test Library included
     21 //  configurable levels of error message detail, elimination of templates,
     22 //  separation of error reporting, and making the catch_exceptions() facilities
     23 //  available as a public interface.  Support for unit testing also stretched
     24 //  the function based design.  Implementation within the header became less
     25 //  attractive due to the need to include many huge system dependent headers,
     26 //  although still preferable in certain cases.
     27 //
     28 //  All those issues have been addressed by introducing the class-based
     29 //  design presented here.
     30 // ***************************************************************************
     31 
     32 #ifndef BOOST_TEST_EXECUTION_MONITOR_HPP_071894GER
     33 #define BOOST_TEST_EXECUTION_MONITOR_HPP_071894GER
     34 
     35 // Boost.Test
     36 #include <boost/test/detail/global_typedef.hpp>
     37 #include <boost/test/detail/fwd_decl.hpp>
     38 #include <boost/test/utils/callback.hpp>
     39 #include <boost/test/utils/class_properties.hpp>
     40 
     41 // Boost
     42 #include <boost/scoped_ptr.hpp>
     43 #include <boost/scoped_array.hpp>
     44 #include <boost/type.hpp>
     45 #include <boost/cstdlib.hpp>
     46 
     47 #include <boost/test/detail/suppress_warnings.hpp>
     48 
     49 //____________________________________________________________________________//
     50 
     51 namespace boost {
     52 
     53 namespace detail {
     54 
     55 // ************************************************************************** //
     56 // **************       detail::translate_exception_base       ************** //
     57 // ************************************************************************** //
     58 
     59 class BOOST_TEST_DECL translate_exception_base {
     60 public:
     61     // Constructor
     62     explicit    translate_exception_base( boost::scoped_ptr<translate_exception_base>& next )
     63     {
     64         next.swap( m_next );
     65     }
     66 
     67     // Destructor
     68     virtual     ~translate_exception_base() {}
     69 
     70     virtual int operator()( unit_test::callback0<int> const& F ) = 0;
     71 
     72 protected:
     73     // Data members
     74     boost::scoped_ptr<translate_exception_base> m_next;
     75 };
     76 
     77 } // namespace detail
     78 
     79 // ************************************************************************** //
     80 // **************              execution_exception             ************** //
     81 // ************************************************************************** //
     82 
     83 //  design rationale: fear of being out (or nearly out) of memory.
     84 
     85 class BOOST_TEST_DECL execution_exception {
     86     typedef boost::unit_test::const_string const_string;
     87 public:
     88     enum error_code {
     89         //  These values are sometimes used as program return codes.
     90         //  The particular values have been chosen to avoid conflicts with
     91         //  commonly used program return codes: values < 100 are often user
     92         //  assigned, values > 255 are sometimes used to report system errors.
     93         //  Gaps in values allow for orderly expansion.
     94 
     95         no_error               = 0,   // for completeness only; never returned
     96         user_error             = 200, // user reported non-fatal error
     97         cpp_exception_error    = 205, // see note (1) below
     98         system_error           = 210, // see note (2) below
     99         timeout_error          = 215, // only detectable on certain platforms
    100         user_fatal_error       = 220, // user reported fatal error
    101         system_fatal_error     = 225  // see note (2) below
    102 
    103         //  Note 1: Only uncaught C++ exceptions are treated as errors.
    104         //  If the application catches a C++ exception, it will never reach
    105         //  the execution_monitor.
    106 
    107         //  Note 2: These errors include Unix signals and Windows structured
    108         //  exceptions.  They are often initiated by hardware traps.
    109         //
    110         //  The implementation decides what is a fatal_system_exception and what is
    111         //  just a system_exception.  Fatal errors are so likely to have corrupted
    112         //  machine state (like a stack overflow or addressing exception) that it
    113         //  is unreasonable to continue execution.
    114     };
    115 
    116     struct BOOST_TEST_DECL location {
    117         explicit    location( char const* file_name = 0, size_t line_num = 0, char const* func = 0 );
    118 
    119         const_string    m_file_name;
    120         size_t          m_line_num;
    121         const_string    m_function;
    122     };
    123 
    124     // Constructor
    125     execution_exception( error_code ec_, const_string what_msg_, location const& location_ ); // max length 256 inc '\0'
    126 
    127     // Access methods
    128     error_code      code() const    { return m_error_code; }
    129     const_string    what() const    { return m_what; }
    130     location const& where() const   { return m_location; }
    131 
    132 private:
    133     // Data members
    134     error_code      m_error_code;
    135     const_string    m_what;
    136     location        m_location;
    137 }; // execution_exception
    138 
    139 // ************************************************************************** //
    140 // **************               execution_monitor              ************** //
    141 // ************************************************************************** //
    142 
    143 class BOOST_TEST_DECL execution_monitor {
    144 public:
    145     // Constructor
    146     execution_monitor()
    147     : p_catch_system_errors( true )
    148     , p_auto_start_dbg( false )
    149     , p_timeout( 0 )
    150     , p_use_alt_stack( true )
    151     , p_detect_fp_exceptions( false )
    152     {}
    153 
    154     // Public properties
    155 
    156     //  The p_catch_system_errors parameter specifies whether the monitor should
    157     //  try to catch system errors/exceptions that would cause program to crash
    158     //  in regular case
    159     unit_test::readwrite_property<bool> p_catch_system_errors;
    160     //  The p_auto_start_dbg parameter specifies whether the monitor should
    161     //  try to attach debugger in case of caught system error
    162     unit_test::readwrite_property<bool> p_auto_start_dbg;
    163     //  The p_timeout parameter specifies the seconds that elapse before
    164     //  a timer_error occurs.  May be ignored on some platforms.
    165     unit_test::readwrite_property<int>  p_timeout;
    166     //  The p_use_alt_stack parameter specifies whether the monitor should
    167     //  use alternative stack for the signal catching
    168     unit_test::readwrite_property<bool> p_use_alt_stack;
    169     //  The p_detect_fp_exceptions parameter specifies whether the monitor should
    170     //  try to detect hardware floating point exceptions
    171     unit_test::readwrite_property<bool> p_detect_fp_exceptions;
    172 
    173     int         execute( unit_test::callback0<int> const& F );
    174     //  Returns:  Value returned by function call F().
    175     //
    176     //  Effects:  Calls executes supplied function F inside a try/catch block which also may
    177     //  include other unspecified platform dependent error detection code.
    178     //
    179     //  Throws: execution_exception on an uncaught C++ exception,
    180     //  a hardware or software signal, trap, or other exception.
    181     //
    182     //  Note: execute() doesn't consider it an error for F to return a non-zero value.
    183 
    184     // register custom (user supplied) exception translator
    185     template<typename Exception, typename ExceptionTranslator>
    186     void        register_exception_translator( ExceptionTranslator const& tr, boost::type<Exception>* = 0 );
    187 
    188 private:
    189     // implementation helpers
    190     int         catch_signals( unit_test::callback0<int> const& F );
    191 
    192     // Data members
    193     boost::scoped_ptr<detail::translate_exception_base> m_custom_translators;
    194     boost::scoped_array<char>                           m_alt_stack;
    195 }; // execution_monitor
    196 
    197 namespace detail {
    198 
    199 // ************************************************************************** //
    200 // **************         detail::translate_exception          ************** //
    201 // ************************************************************************** //
    202 
    203 template<typename Exception, typename ExceptionTranslator>
    204 class translate_exception : public translate_exception_base
    205 {
    206     typedef boost::scoped_ptr<translate_exception_base> base_ptr;
    207 public:
    208     explicit    translate_exception( ExceptionTranslator const& tr, base_ptr& next )
    209     : translate_exception_base( next ), m_translator( tr ) {}
    210 
    211     int operator()( unit_test::callback0<int> const& F )
    212     {
    213         try {
    214             return m_next ? (*m_next)( F ) : F();
    215         } catch( Exception const& e ) {
    216             m_translator( e );
    217             return boost::exit_exception_failure;
    218         }
    219     }
    220 
    221 private:
    222     // Data members
    223     ExceptionTranslator m_translator;
    224 };
    225 
    226 } // namespace detail
    227 
    228 template<typename Exception, typename ExceptionTranslator>
    229 void
    230 execution_monitor::register_exception_translator( ExceptionTranslator const& tr, boost::type<Exception>* )
    231 {
    232     m_custom_translators.reset(
    233         new detail::translate_exception<Exception,ExceptionTranslator>( tr,m_custom_translators ) );
    234 }
    235 
    236 // ************************************************************************** //
    237 // **************               execution_aborted              ************** //
    238 // ************************************************************************** //
    239 
    240 struct execution_aborted {};
    241 
    242 // ************************************************************************** //
    243 // **************                  system_error                ************** //
    244 // ************************************************************************** //
    245 
    246 class system_error {
    247 public:
    248     // Constructor
    249     explicit    system_error( char const* exp );
    250 
    251     unit_test::readonly_property<long>          p_errno;
    252     unit_test::readonly_property<char const*>   p_failed_exp;
    253 };
    254 
    255 #define BOOST_TEST_SYS_ASSERT( exp ) if( (exp) ) ; else throw ::boost::system_error( BOOST_STRINGIZE( exp ) )
    256 
    257 }  // namespace boost
    258 
    259 //____________________________________________________________________________//
    260 
    261 #include <boost/test/detail/enable_warnings.hpp>
    262 
    263 #endif
    264