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