// (C) Copyright Gennadiy Rozental 2001-2008. // (C) Copyright Beman Dawes 2001. // Distributed under the Boost Software License, Version 1.0. // (See accompanying file LICENSE_1_0.txt or copy at // http://www.boost.org/LICENSE_1_0.txt) // See http://www.boost.org/libs/test for the library home page. // // File : $RCSfile$ // // Version : $Revision$ // // Description : defines abstract monitor interfaces and implements execution exception // The original Boost Test Library included an implementation detail function // named catch_exceptions() which caught otherwise uncaught C++ exceptions. // It was derived from an existing test framework by Beman Dawes. The // intent was to expand later to catch other detectable but platform dependent // error events like Unix signals or Windows structured C exceptions. // // Requests from early adopters of the Boost Test Library included // configurable levels of error message detail, elimination of templates, // separation of error reporting, and making the catch_exceptions() facilities // available as a public interface. Support for unit testing also stretched // the function based design. Implementation within the header became less // attractive due to the need to include many huge system dependent headers, // although still preferable in certain cases. // // All those issues have been addressed by introducing the class-based // design presented here. // *************************************************************************** #ifndef BOOST_TEST_EXECUTION_MONITOR_HPP_071894GER #define BOOST_TEST_EXECUTION_MONITOR_HPP_071894GER // Boost.Test #include #include #include #include // Boost #include #include #include #include #include //____________________________________________________________________________// namespace boost { namespace detail { // ************************************************************************** // // ************** detail::translate_exception_base ************** // // ************************************************************************** // class BOOST_TEST_DECL translate_exception_base { public: // Constructor explicit translate_exception_base( boost::scoped_ptr& next ) { next.swap( m_next ); } // Destructor virtual ~translate_exception_base() {} virtual int operator()( unit_test::callback0 const& F ) = 0; protected: // Data members boost::scoped_ptr m_next; }; } // namespace detail // ************************************************************************** // // ************** execution_exception ************** // // ************************************************************************** // // design rationale: fear of being out (or nearly out) of memory. class BOOST_TEST_DECL execution_exception { typedef boost::unit_test::const_string const_string; public: enum error_code { // These values are sometimes used as program return codes. // The particular values have been chosen to avoid conflicts with // commonly used program return codes: values < 100 are often user // assigned, values > 255 are sometimes used to report system errors. // Gaps in values allow for orderly expansion. no_error = 0, // for completeness only; never returned user_error = 200, // user reported non-fatal error cpp_exception_error = 205, // see note (1) below system_error = 210, // see note (2) below timeout_error = 215, // only detectable on certain platforms user_fatal_error = 220, // user reported fatal error system_fatal_error = 225 // see note (2) below // Note 1: Only uncaught C++ exceptions are treated as errors. // If the application catches a C++ exception, it will never reach // the execution_monitor. // Note 2: These errors include Unix signals and Windows structured // exceptions. They are often initiated by hardware traps. // // The implementation decides what is a fatal_system_exception and what is // just a system_exception. Fatal errors are so likely to have corrupted // machine state (like a stack overflow or addressing exception) that it // is unreasonable to continue execution. }; struct BOOST_TEST_DECL location { explicit location( char const* file_name = 0, size_t line_num = 0, char const* func = 0 ); const_string m_file_name; size_t m_line_num; const_string m_function; }; // Constructor execution_exception( error_code ec_, const_string what_msg_, location const& location_ ); // max length 256 inc '\0' // Access methods error_code code() const { return m_error_code; } const_string what() const { return m_what; } location const& where() const { return m_location; } private: // Data members error_code m_error_code; const_string m_what; location m_location; }; // execution_exception // ************************************************************************** // // ************** execution_monitor ************** // // ************************************************************************** // class BOOST_TEST_DECL execution_monitor { public: // Constructor execution_monitor() : p_catch_system_errors( true ) , p_auto_start_dbg( false ) , p_timeout( 0 ) , p_use_alt_stack( true ) , p_detect_fp_exceptions( false ) {} // Public properties // The p_catch_system_errors parameter specifies whether the monitor should // try to catch system errors/exceptions that would cause program to crash // in regular case unit_test::readwrite_property p_catch_system_errors; // The p_auto_start_dbg parameter specifies whether the monitor should // try to attach debugger in case of caught system error unit_test::readwrite_property p_auto_start_dbg; // The p_timeout parameter specifies the seconds that elapse before // a timer_error occurs. May be ignored on some platforms. unit_test::readwrite_property p_timeout; // The p_use_alt_stack parameter specifies whether the monitor should // use alternative stack for the signal catching unit_test::readwrite_property p_use_alt_stack; // The p_detect_fp_exceptions parameter specifies whether the monitor should // try to detect hardware floating point exceptions unit_test::readwrite_property p_detect_fp_exceptions; int execute( unit_test::callback0 const& F ); // Returns: Value returned by function call F(). // // Effects: Calls executes supplied function F inside a try/catch block which also may // include other unspecified platform dependent error detection code. // // Throws: execution_exception on an uncaught C++ exception, // a hardware or software signal, trap, or other exception. // // Note: execute() doesn't consider it an error for F to return a non-zero value. // register custom (user supplied) exception translator template void register_exception_translator( ExceptionTranslator const& tr, boost::type* = 0 ); private: // implementation helpers int catch_signals( unit_test::callback0 const& F ); // Data members boost::scoped_ptr m_custom_translators; boost::scoped_array m_alt_stack; }; // execution_monitor namespace detail { // ************************************************************************** // // ************** detail::translate_exception ************** // // ************************************************************************** // template class translate_exception : public translate_exception_base { typedef boost::scoped_ptr base_ptr; public: explicit translate_exception( ExceptionTranslator const& tr, base_ptr& next ) : translate_exception_base( next ), m_translator( tr ) {} int operator()( unit_test::callback0 const& F ) { try { return m_next ? (*m_next)( F ) : F(); } catch( Exception const& e ) { m_translator( e ); return boost::exit_exception_failure; } } private: // Data members ExceptionTranslator m_translator; }; } // namespace detail template void execution_monitor::register_exception_translator( ExceptionTranslator const& tr, boost::type* ) { m_custom_translators.reset( new detail::translate_exception( tr,m_custom_translators ) ); } // ************************************************************************** // // ************** execution_aborted ************** // // ************************************************************************** // struct execution_aborted {}; // ************************************************************************** // // ************** system_error ************** // // ************************************************************************** // class system_error { public: // Constructor explicit system_error( char const* exp ); unit_test::readonly_property p_errno; unit_test::readonly_property p_failed_exp; }; #define BOOST_TEST_SYS_ASSERT( exp ) if( (exp) ) ; else throw ::boost::system_error( BOOST_STRINGIZE( exp ) ) } // namespace boost //____________________________________________________________________________// #include #endif