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