Jeff Thompson | ef2d5a4 | 2013-08-22 19:09:24 -0700 | [diff] [blame] | 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 <ndnboost/test/detail/global_typedef.hpp> |
| 37 | #include <ndnboost/test/detail/fwd_decl.hpp> |
| 38 | #include <ndnboost/test/utils/callback.hpp> |
| 39 | #include <ndnboost/test/utils/class_properties.hpp> |
| 40 | |
| 41 | // Boost |
| 42 | #include <ndnboost/scoped_ptr.hpp> |
| 43 | #include <ndnboost/scoped_array.hpp> |
| 44 | #include <ndnboost/type.hpp> |
| 45 | #include <ndnboost/cstdlib.hpp> |
| 46 | |
| 47 | #include <ndnboost/test/detail/suppress_warnings.hpp> |
| 48 | |
| 49 | //____________________________________________________________________________// |
| 50 | |
| 51 | namespace ndnboost { |
| 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( ndnboost::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 | ndnboost::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 ndnboost::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, ndnboost::type<Exception>* = 0 ); |
| 187 | |
| 188 | private: |
| 189 | // implementation helpers |
| 190 | int catch_signals( unit_test::callback0<int> const& F ); |
| 191 | |
| 192 | // Data members |
| 193 | ndnboost::scoped_ptr<detail::translate_exception_base> m_custom_translators; |
| 194 | ndnboost::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 ndnboost::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 ndnboost::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, ndnboost::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 ::ndnboost::system_error( BOOST_STRINGIZE( exp ) ) |
| 256 | |
| 257 | } // namespace ndnboost |
| 258 | |
| 259 | //____________________________________________________________________________// |
| 260 | |
| 261 | #include <ndnboost/test/detail/enable_warnings.hpp> |
| 262 | |
| 263 | #endif |