Chris@16
|
1 // (C) Copyright Gennadiy Rozental 2005-2008.
|
Chris@16
|
2 // Use, modification, and distribution are subject to the
|
Chris@16
|
3 // Boost Software License, Version 1.0. (See accompanying file
|
Chris@16
|
4 // http://www.boost.org/LICENSE_1_0.txt)
|
Chris@16
|
5
|
Chris@16
|
6 // See http://www.boost.org/libs/test for the library home page.
|
Chris@16
|
7 //
|
Chris@16
|
8 // File : $RCSfile$
|
Chris@16
|
9 //
|
Chris@101
|
10 // Version : $Revision$
|
Chris@16
|
11 //
|
Chris@16
|
12 // Description : Facilities to perform exception safety tests
|
Chris@16
|
13 // ***************************************************************************
|
Chris@16
|
14
|
Chris@16
|
15 #ifndef BOOST_TEST_EXECUTION_SAFETY_IPP_112005GER
|
Chris@16
|
16 #define BOOST_TEST_EXECUTION_SAFETY_IPP_112005GER
|
Chris@16
|
17
|
Chris@16
|
18 // Boost.Test
|
Chris@16
|
19 #include <boost/test/detail/config.hpp>
|
Chris@16
|
20
|
Chris@16
|
21 #if BOOST_TEST_SUPPORT_INTERACTION_TESTING
|
Chris@16
|
22
|
Chris@16
|
23 #include <boost/test/detail/global_typedef.hpp>
|
Chris@16
|
24 #include <boost/test/detail/unit_test_parameters.hpp>
|
Chris@16
|
25
|
Chris@16
|
26 #include <boost/test/utils/callback.hpp>
|
Chris@16
|
27 #include <boost/test/utils/wrap_stringstream.hpp>
|
Chris@16
|
28 #include <boost/test/utils/iterator/token_iterator.hpp>
|
Chris@16
|
29
|
Chris@16
|
30 #include <boost/test/interaction_based.hpp>
|
Chris@16
|
31 #include <boost/test/test_tools.hpp>
|
Chris@16
|
32 #include <boost/test/unit_test_log.hpp>
|
Chris@16
|
33 #include <boost/test/framework.hpp>
|
Chris@16
|
34 #include <boost/test/test_observer.hpp>
|
Chris@16
|
35 #include <boost/test/debug.hpp>
|
Chris@16
|
36
|
Chris@16
|
37 #include <boost/test/detail/suppress_warnings.hpp>
|
Chris@16
|
38
|
Chris@16
|
39 // Boost
|
Chris@16
|
40 #include <boost/lexical_cast.hpp>
|
Chris@16
|
41
|
Chris@16
|
42 // STL
|
Chris@16
|
43 #include <vector>
|
Chris@16
|
44 #include <cstdlib>
|
Chris@16
|
45 #include <map>
|
Chris@16
|
46 #include <iomanip>
|
Chris@16
|
47 #include <cctype>
|
Chris@16
|
48 #include <boost/limits.hpp>
|
Chris@16
|
49
|
Chris@16
|
50 //____________________________________________________________________________//
|
Chris@16
|
51
|
Chris@16
|
52 namespace boost {
|
Chris@16
|
53
|
Chris@16
|
54 using namespace ::boost::unit_test;
|
Chris@16
|
55
|
Chris@16
|
56 namespace itest {
|
Chris@16
|
57
|
Chris@16
|
58 // ************************************************************************** //
|
Chris@16
|
59 // ************** execution_path_point ************** //
|
Chris@16
|
60 // ************************************************************************** //
|
Chris@16
|
61
|
Chris@16
|
62 enum exec_path_point_type { EPP_SCOPE, EPP_EXCEPT, EPP_DECISION, EPP_ALLOC };
|
Chris@16
|
63
|
Chris@16
|
64 struct execution_path_point {
|
Chris@16
|
65 execution_path_point( exec_path_point_type t, const_string file, std::size_t line_num )
|
Chris@16
|
66 : m_type( t )
|
Chris@16
|
67 , m_file_name( file )
|
Chris@16
|
68 , m_line_num( line_num )
|
Chris@16
|
69 {}
|
Chris@16
|
70
|
Chris@16
|
71 exec_path_point_type m_type;
|
Chris@16
|
72 const_string m_file_name;
|
Chris@16
|
73 std::size_t m_line_num;
|
Chris@16
|
74
|
Chris@16
|
75 // Execution path point specific
|
Chris@16
|
76 struct decision_data {
|
Chris@16
|
77 bool value;
|
Chris@16
|
78 unsigned forced_exception_point;
|
Chris@16
|
79 };
|
Chris@16
|
80 struct scope_data {
|
Chris@16
|
81 unsigned size;
|
Chris@16
|
82 char const* name;
|
Chris@16
|
83 };
|
Chris@16
|
84 struct except_data {
|
Chris@16
|
85 char const* description;
|
Chris@16
|
86 };
|
Chris@16
|
87 struct alloc_data {
|
Chris@16
|
88 void* ptr;
|
Chris@16
|
89 std::size_t size;
|
Chris@16
|
90 };
|
Chris@16
|
91
|
Chris@16
|
92 union {
|
Chris@16
|
93 struct decision_data m_decision;
|
Chris@16
|
94 struct scope_data m_scope;
|
Chris@16
|
95 struct except_data m_except;
|
Chris@16
|
96 struct alloc_data m_alloc;
|
Chris@16
|
97 };
|
Chris@16
|
98 };
|
Chris@16
|
99
|
Chris@16
|
100 // ************************************************************************** //
|
Chris@16
|
101 // ************** exception safety test implementation ************** //
|
Chris@16
|
102 // ************************************************************************** //
|
Chris@16
|
103
|
Chris@16
|
104 struct exception_safety_tester : itest::manager, test_observer {
|
Chris@16
|
105 // helpers types
|
Chris@16
|
106 struct unique_exception {};
|
Chris@16
|
107
|
Chris@16
|
108 // Constructor
|
Chris@16
|
109 explicit exception_safety_tester( const_string test_name );
|
Chris@16
|
110 ~exception_safety_tester();
|
Chris@16
|
111
|
Chris@16
|
112 // check last run and prepare for next
|
Chris@16
|
113 bool next_execution_path();
|
Chris@16
|
114
|
Chris@16
|
115 // memory tracking
|
Chris@16
|
116
|
Chris@16
|
117 // manager interface implementation
|
Chris@16
|
118 virtual void exception_point( const_string file, std::size_t line_num, const_string description );
|
Chris@16
|
119 virtual bool decision_point( const_string file, std::size_t line_num );
|
Chris@16
|
120 virtual unsigned enter_scope( const_string file, std::size_t line_num, const_string scope_name );
|
Chris@16
|
121 virtual void leave_scope( unsigned enter_scope_point );
|
Chris@16
|
122 virtual void allocated( const_string file, std::size_t line_num, void* p, std::size_t s );
|
Chris@16
|
123 virtual void freed( void* p );
|
Chris@16
|
124
|
Chris@16
|
125 // test observer interface
|
Chris@16
|
126 virtual void assertion_result( bool passed );
|
Chris@16
|
127 virtual int priority() { return (std::numeric_limits<int>::max)(); } // we want this observer to run the last
|
Chris@16
|
128
|
Chris@16
|
129 private:
|
Chris@16
|
130 void failure_point();
|
Chris@16
|
131 void report_error();
|
Chris@16
|
132
|
Chris@16
|
133 typedef std::vector<execution_path_point> exec_path;
|
Chris@16
|
134 typedef std::map<void*,unsigned> registry;
|
Chris@16
|
135
|
Chris@16
|
136 // Data members
|
Chris@16
|
137 bool m_internal_activity;
|
Chris@16
|
138
|
Chris@16
|
139 unsigned m_exception_point_counter;
|
Chris@16
|
140 unsigned m_forced_exception_point;
|
Chris@16
|
141
|
Chris@16
|
142 unsigned m_exec_path_point;
|
Chris@16
|
143 exec_path m_execution_path;
|
Chris@16
|
144
|
Chris@16
|
145 unsigned m_exec_path_counter;
|
Chris@16
|
146 unsigned m_break_exec_path;
|
Chris@16
|
147
|
Chris@16
|
148 bool m_invairant_failed;
|
Chris@16
|
149 registry m_memory_in_use;
|
Chris@16
|
150 };
|
Chris@16
|
151
|
Chris@16
|
152 //____________________________________________________________________________//
|
Chris@16
|
153
|
Chris@16
|
154 struct activity_guard {
|
Chris@16
|
155 bool& m_v;
|
Chris@16
|
156
|
Chris@16
|
157 activity_guard( bool& v ) : m_v( v ) { m_v = true; }
|
Chris@16
|
158 ~activity_guard() { m_v = false; }
|
Chris@16
|
159 };
|
Chris@16
|
160
|
Chris@16
|
161 //____________________________________________________________________________//
|
Chris@16
|
162
|
Chris@16
|
163 exception_safety_tester::exception_safety_tester( const_string test_name )
|
Chris@16
|
164 : m_internal_activity( true )
|
Chris@16
|
165 , m_exception_point_counter( 0 )
|
Chris@16
|
166 , m_forced_exception_point( 1 )
|
Chris@16
|
167 , m_exec_path_point( 0 )
|
Chris@16
|
168 , m_exec_path_counter( 1 )
|
Chris@16
|
169 , m_break_exec_path( static_cast<unsigned>(-1) )
|
Chris@16
|
170 , m_invairant_failed( false )
|
Chris@16
|
171 {
|
Chris@16
|
172 framework::register_observer( *this );
|
Chris@16
|
173
|
Chris@16
|
174 if( !runtime_config::break_exec_path().is_empty() ) {
|
Chris@16
|
175 using namespace unit_test;
|
Chris@16
|
176
|
Chris@16
|
177 string_token_iterator tit( runtime_config::break_exec_path(),
|
Chris@16
|
178 (dropped_delimeters = ":",kept_delimeters = " ") );
|
Chris@16
|
179
|
Chris@16
|
180 const_string test_to_break = *tit;
|
Chris@16
|
181
|
Chris@16
|
182 if( test_to_break == test_name ) {
|
Chris@16
|
183 ++tit;
|
Chris@16
|
184
|
Chris@16
|
185 m_break_exec_path = lexical_cast<unsigned>( *tit );
|
Chris@16
|
186 }
|
Chris@16
|
187 }
|
Chris@16
|
188
|
Chris@16
|
189 m_internal_activity = false;
|
Chris@16
|
190 }
|
Chris@16
|
191
|
Chris@16
|
192 //____________________________________________________________________________//
|
Chris@16
|
193
|
Chris@16
|
194 exception_safety_tester::~exception_safety_tester()
|
Chris@16
|
195 {
|
Chris@16
|
196 m_internal_activity = true;
|
Chris@16
|
197
|
Chris@16
|
198 framework::deregister_observer( *this );
|
Chris@16
|
199 }
|
Chris@16
|
200
|
Chris@16
|
201 //____________________________________________________________________________//
|
Chris@16
|
202
|
Chris@16
|
203 bool
|
Chris@16
|
204 exception_safety_tester::next_execution_path()
|
Chris@16
|
205 {
|
Chris@16
|
206 activity_guard ag( m_internal_activity );
|
Chris@16
|
207
|
Chris@16
|
208 // check memory usage
|
Chris@16
|
209 if( m_execution_path.size() > 0 ) {
|
Chris@16
|
210 bool errors_detected = m_invairant_failed || (m_memory_in_use.size() != 0);
|
Chris@16
|
211 framework::assertion_result( !errors_detected );
|
Chris@16
|
212
|
Chris@16
|
213 if( errors_detected )
|
Chris@16
|
214 report_error();
|
Chris@16
|
215
|
Chris@16
|
216 m_memory_in_use.clear();
|
Chris@16
|
217 }
|
Chris@16
|
218
|
Chris@16
|
219 m_exec_path_point = 0;
|
Chris@16
|
220 m_exception_point_counter = 0;
|
Chris@16
|
221 m_invairant_failed = false;
|
Chris@16
|
222 ++m_exec_path_counter;
|
Chris@16
|
223
|
Chris@16
|
224 while( m_execution_path.size() > 0 ) {
|
Chris@16
|
225 switch( m_execution_path.back().m_type ) {
|
Chris@16
|
226 case EPP_SCOPE:
|
Chris@16
|
227 case EPP_ALLOC:
|
Chris@16
|
228 m_execution_path.pop_back();
|
Chris@16
|
229 break;
|
Chris@16
|
230
|
Chris@16
|
231 case EPP_DECISION:
|
Chris@16
|
232 if( !m_execution_path.back().m_decision.value ) {
|
Chris@16
|
233 m_execution_path.pop_back();
|
Chris@16
|
234 break;
|
Chris@16
|
235 }
|
Chris@16
|
236
|
Chris@16
|
237 m_execution_path.back().m_decision.value = false;
|
Chris@16
|
238 m_forced_exception_point = m_execution_path.back().m_decision.forced_exception_point;
|
Chris@16
|
239 return true;
|
Chris@16
|
240
|
Chris@16
|
241 case EPP_EXCEPT:
|
Chris@16
|
242 m_execution_path.pop_back();
|
Chris@16
|
243 ++m_forced_exception_point;
|
Chris@16
|
244 return true;
|
Chris@16
|
245 }
|
Chris@16
|
246 }
|
Chris@16
|
247
|
Chris@16
|
248 BOOST_TEST_MESSAGE( "Total tested " << --m_exec_path_counter << " execution path" );
|
Chris@16
|
249
|
Chris@16
|
250 return false;
|
Chris@16
|
251 }
|
Chris@16
|
252
|
Chris@16
|
253 //____________________________________________________________________________//
|
Chris@16
|
254
|
Chris@16
|
255 void
|
Chris@16
|
256 exception_safety_tester::exception_point( const_string file, std::size_t line_num, const_string description )
|
Chris@16
|
257 {
|
Chris@16
|
258 activity_guard ag( m_internal_activity );
|
Chris@16
|
259
|
Chris@16
|
260 if( ++m_exception_point_counter == m_forced_exception_point ) {
|
Chris@16
|
261 m_execution_path.push_back(
|
Chris@16
|
262 execution_path_point( EPP_EXCEPT, file, line_num ) );
|
Chris@16
|
263
|
Chris@16
|
264 m_execution_path.back().m_except.description = description.begin();
|
Chris@16
|
265
|
Chris@16
|
266 ++m_exec_path_point;
|
Chris@16
|
267
|
Chris@16
|
268 failure_point();
|
Chris@16
|
269 }
|
Chris@16
|
270 }
|
Chris@16
|
271
|
Chris@16
|
272 //____________________________________________________________________________//
|
Chris@16
|
273
|
Chris@16
|
274 bool
|
Chris@16
|
275 exception_safety_tester::decision_point( const_string file, std::size_t line_num )
|
Chris@16
|
276 {
|
Chris@16
|
277 activity_guard ag( m_internal_activity );
|
Chris@16
|
278
|
Chris@16
|
279 if( m_exec_path_point < m_execution_path.size() ) {
|
Chris@16
|
280 BOOST_REQUIRE_MESSAGE( m_execution_path[m_exec_path_point].m_type == EPP_DECISION &&
|
Chris@16
|
281 m_execution_path[m_exec_path_point].m_file_name == file &&
|
Chris@16
|
282 m_execution_path[m_exec_path_point].m_line_num == line_num,
|
Chris@16
|
283 "Function under test exibit non-deterministic behavior" );
|
Chris@16
|
284 }
|
Chris@16
|
285 else {
|
Chris@16
|
286 m_execution_path.push_back(
|
Chris@16
|
287 execution_path_point( EPP_DECISION, file, line_num ) );
|
Chris@16
|
288
|
Chris@16
|
289 m_execution_path.back().m_decision.value = true;
|
Chris@16
|
290 m_execution_path.back().m_decision.forced_exception_point = m_forced_exception_point;
|
Chris@16
|
291 }
|
Chris@16
|
292
|
Chris@16
|
293 return m_execution_path[m_exec_path_point++].m_decision.value;
|
Chris@16
|
294 }
|
Chris@16
|
295
|
Chris@16
|
296 //____________________________________________________________________________//
|
Chris@16
|
297
|
Chris@16
|
298 unsigned
|
Chris@16
|
299 exception_safety_tester::enter_scope( const_string file, std::size_t line_num, const_string scope_name )
|
Chris@16
|
300 {
|
Chris@16
|
301 activity_guard ag( m_internal_activity );
|
Chris@16
|
302
|
Chris@16
|
303 if( m_exec_path_point < m_execution_path.size() ) {
|
Chris@16
|
304 BOOST_REQUIRE_MESSAGE( m_execution_path[m_exec_path_point].m_type == EPP_SCOPE &&
|
Chris@16
|
305 m_execution_path[m_exec_path_point].m_file_name == file &&
|
Chris@16
|
306 m_execution_path[m_exec_path_point].m_line_num == line_num,
|
Chris@16
|
307 "Function under test exibit non-deterministic behavior" );
|
Chris@16
|
308 }
|
Chris@16
|
309 else {
|
Chris@16
|
310 m_execution_path.push_back(
|
Chris@16
|
311 execution_path_point( EPP_SCOPE, file, line_num ) );
|
Chris@16
|
312 }
|
Chris@16
|
313
|
Chris@16
|
314 m_execution_path[m_exec_path_point].m_scope.size = 0;
|
Chris@16
|
315 m_execution_path[m_exec_path_point].m_scope.name = scope_name.begin();
|
Chris@16
|
316
|
Chris@16
|
317 return m_exec_path_point++;
|
Chris@16
|
318 }
|
Chris@16
|
319
|
Chris@16
|
320 //____________________________________________________________________________//
|
Chris@16
|
321
|
Chris@16
|
322 void
|
Chris@16
|
323 exception_safety_tester::leave_scope( unsigned enter_scope_point )
|
Chris@16
|
324 {
|
Chris@16
|
325 activity_guard ag( m_internal_activity );
|
Chris@16
|
326
|
Chris@16
|
327 BOOST_REQUIRE_MESSAGE( m_execution_path[enter_scope_point].m_type == EPP_SCOPE,
|
Chris@16
|
328 "Function under test exibit non-deterministic behavior" );
|
Chris@16
|
329
|
Chris@16
|
330 m_execution_path[enter_scope_point].m_scope.size = m_exec_path_point - enter_scope_point;
|
Chris@16
|
331 }
|
Chris@16
|
332
|
Chris@16
|
333 //____________________________________________________________________________//
|
Chris@16
|
334
|
Chris@16
|
335 void
|
Chris@16
|
336 exception_safety_tester::allocated( const_string file, std::size_t line_num, void* p, std::size_t s )
|
Chris@16
|
337 {
|
Chris@16
|
338 if( m_internal_activity )
|
Chris@16
|
339 return;
|
Chris@16
|
340
|
Chris@16
|
341 activity_guard ag( m_internal_activity );
|
Chris@16
|
342
|
Chris@16
|
343 if( m_exec_path_point < m_execution_path.size() )
|
Chris@16
|
344 BOOST_REQUIRE_MESSAGE( m_execution_path[m_exec_path_point].m_type == EPP_ALLOC,
|
Chris@16
|
345 "Function under test exibit non-deterministic behavior" );
|
Chris@16
|
346 else
|
Chris@16
|
347 m_execution_path.push_back(
|
Chris@16
|
348 execution_path_point( EPP_ALLOC, file, line_num ) );
|
Chris@16
|
349
|
Chris@16
|
350 m_execution_path[m_exec_path_point].m_alloc.ptr = p;
|
Chris@16
|
351 m_execution_path[m_exec_path_point].m_alloc.size = s;
|
Chris@16
|
352
|
Chris@16
|
353 m_memory_in_use.insert( std::make_pair( p, m_exec_path_point++ ) );
|
Chris@16
|
354 }
|
Chris@16
|
355
|
Chris@16
|
356 //____________________________________________________________________________//
|
Chris@16
|
357
|
Chris@16
|
358 void
|
Chris@16
|
359 exception_safety_tester::freed( void* p )
|
Chris@16
|
360 {
|
Chris@16
|
361 if( m_internal_activity )
|
Chris@16
|
362 return;
|
Chris@16
|
363
|
Chris@16
|
364 activity_guard ag( m_internal_activity );
|
Chris@16
|
365
|
Chris@16
|
366 registry::iterator it = m_memory_in_use.find( p );
|
Chris@16
|
367 if( it != m_memory_in_use.end() ) {
|
Chris@16
|
368 m_execution_path[it->second].m_alloc.ptr = 0;
|
Chris@16
|
369 m_memory_in_use.erase( it );
|
Chris@16
|
370 }
|
Chris@16
|
371 }
|
Chris@16
|
372
|
Chris@16
|
373 //____________________________________________________________________________//
|
Chris@16
|
374
|
Chris@16
|
375 void
|
Chris@16
|
376 exception_safety_tester::assertion_result( bool passed )
|
Chris@16
|
377 {
|
Chris@16
|
378 if( !m_internal_activity && !passed ) {
|
Chris@16
|
379 m_invairant_failed = true;
|
Chris@16
|
380
|
Chris@16
|
381 failure_point();
|
Chris@16
|
382 }
|
Chris@16
|
383 }
|
Chris@16
|
384
|
Chris@16
|
385 //____________________________________________________________________________//
|
Chris@16
|
386
|
Chris@16
|
387 void
|
Chris@16
|
388 exception_safety_tester::failure_point()
|
Chris@16
|
389 {
|
Chris@16
|
390 if( m_exec_path_counter == m_break_exec_path )
|
Chris@16
|
391 debug::debugger_break();
|
Chris@16
|
392
|
Chris@16
|
393 throw unique_exception();
|
Chris@16
|
394 }
|
Chris@16
|
395
|
Chris@16
|
396 //____________________________________________________________________________//
|
Chris@16
|
397
|
Chris@16
|
398 namespace {
|
Chris@16
|
399
|
Chris@16
|
400 inline void
|
Chris@16
|
401 format_location( wrap_stringstream& formatter, execution_path_point const& /*p*/, unsigned indent )
|
Chris@16
|
402 {
|
Chris@16
|
403 if( indent )
|
Chris@16
|
404 formatter << std::left << std::setw( indent ) << "";
|
Chris@16
|
405
|
Chris@16
|
406 // !! ?? optional if( p.m_file_name )
|
Chris@16
|
407 // formatter << p.m_file_name << '(' << p.m_line_num << "): ";
|
Chris@16
|
408 }
|
Chris@16
|
409
|
Chris@16
|
410 //____________________________________________________________________________//
|
Chris@16
|
411
|
Chris@16
|
412 template<typename ExecPathIt>
|
Chris@16
|
413 inline void
|
Chris@16
|
414 format_execution_path( wrap_stringstream& formatter, ExecPathIt it, ExecPathIt end, unsigned indent = 0 )
|
Chris@16
|
415 {
|
Chris@16
|
416 while( it != end ) {
|
Chris@16
|
417 switch( it->m_type ) {
|
Chris@16
|
418 case EPP_SCOPE:
|
Chris@16
|
419 format_location( formatter, *it, indent );
|
Chris@16
|
420 formatter << "> \"" << it->m_scope.name << "\"\n";
|
Chris@16
|
421 format_execution_path( formatter, it+1, it + it->m_scope.size, indent + 2 );
|
Chris@16
|
422 format_location( formatter, *it, indent );
|
Chris@16
|
423 formatter << "< \"" << it->m_scope.name << "\"\n";
|
Chris@16
|
424 it += it->m_scope.size;
|
Chris@16
|
425 break;
|
Chris@16
|
426
|
Chris@16
|
427 case EPP_DECISION:
|
Chris@16
|
428 format_location( formatter, *it, indent );
|
Chris@16
|
429 formatter << "Decision made as " << std::boolalpha << it->m_decision.value << '\n';
|
Chris@16
|
430 ++it;
|
Chris@16
|
431 break;
|
Chris@16
|
432
|
Chris@16
|
433 case EPP_EXCEPT:
|
Chris@16
|
434 format_location( formatter, *it, indent );
|
Chris@16
|
435 formatter << "Forced failure";
|
Chris@16
|
436 if( it->m_except.description )
|
Chris@16
|
437 formatter << ": " << it->m_except.description;
|
Chris@16
|
438 formatter << "\n";
|
Chris@16
|
439 ++it;
|
Chris@16
|
440 break;
|
Chris@16
|
441
|
Chris@16
|
442 case EPP_ALLOC:
|
Chris@16
|
443 if( it->m_alloc.ptr ) {
|
Chris@16
|
444 format_location( formatter, *it, indent );
|
Chris@16
|
445 formatter << "Allocated memory block 0x" << std::uppercase << it->m_alloc.ptr
|
Chris@16
|
446 << ", " << it->m_alloc.size << " bytes long: <";
|
Chris@16
|
447
|
Chris@16
|
448 unsigned i;
|
Chris@16
|
449 for( i = 0; i < std::min<std::size_t>( it->m_alloc.size, 8 ); i++ ) {
|
Chris@16
|
450 unsigned char c = static_cast<unsigned char*>(it->m_alloc.ptr)[i];
|
Chris@16
|
451 if( (std::isprint)( c ) )
|
Chris@16
|
452 formatter << c;
|
Chris@16
|
453 else
|
Chris@16
|
454 formatter << '.';
|
Chris@16
|
455 }
|
Chris@16
|
456
|
Chris@16
|
457 formatter << "> ";
|
Chris@16
|
458
|
Chris@16
|
459 for( i = 0; i < std::min<std::size_t>( it->m_alloc.size, 8 ); i++ ) {
|
Chris@16
|
460 unsigned c = static_cast<unsigned char*>(it->m_alloc.ptr)[i];
|
Chris@16
|
461 formatter << std::hex << std::uppercase << c << ' ';
|
Chris@16
|
462 }
|
Chris@16
|
463
|
Chris@16
|
464 formatter << "\n";
|
Chris@16
|
465 }
|
Chris@16
|
466 ++it;
|
Chris@16
|
467 break;
|
Chris@16
|
468 }
|
Chris@16
|
469 }
|
Chris@16
|
470 }
|
Chris@16
|
471
|
Chris@16
|
472 //____________________________________________________________________________//
|
Chris@16
|
473
|
Chris@16
|
474 } // local namespace
|
Chris@16
|
475
|
Chris@16
|
476 void
|
Chris@16
|
477 exception_safety_tester::report_error()
|
Chris@16
|
478 {
|
Chris@16
|
479 activity_guard ag( m_internal_activity );
|
Chris@16
|
480
|
Chris@16
|
481 unit_test_log << unit_test::log::begin( m_execution_path.back().m_file_name,
|
Chris@16
|
482 m_execution_path.back().m_line_num )
|
Chris@16
|
483 << log_all_errors;
|
Chris@16
|
484
|
Chris@16
|
485 wrap_stringstream formatter;
|
Chris@16
|
486
|
Chris@16
|
487 if( m_invairant_failed )
|
Chris@16
|
488 formatter << "Failed invariant";
|
Chris@16
|
489
|
Chris@16
|
490 if( m_memory_in_use.size() != 0 ) {
|
Chris@16
|
491 if( m_invairant_failed )
|
Chris@16
|
492 formatter << " and ";
|
Chris@16
|
493
|
Chris@16
|
494 formatter << static_cast<unsigned int>(m_memory_in_use.size()) << " memory leak";
|
Chris@16
|
495 if( m_memory_in_use.size() > 1 )
|
Chris@16
|
496 formatter << 's';
|
Chris@16
|
497 }
|
Chris@16
|
498 formatter << " detected in the execution path " << m_exec_path_counter << ":\n";
|
Chris@16
|
499
|
Chris@16
|
500 format_execution_path( formatter, m_execution_path.begin(), m_execution_path.end() );
|
Chris@16
|
501
|
Chris@16
|
502 unit_test_log << const_string( formatter.str() ) << unit_test::log::end();
|
Chris@16
|
503 }
|
Chris@16
|
504
|
Chris@16
|
505 //____________________________________________________________________________//
|
Chris@16
|
506
|
Chris@16
|
507 // ************************************************************************** //
|
Chris@16
|
508 // ************** exception safety test ************** //
|
Chris@16
|
509 // ************************************************************************** //
|
Chris@16
|
510
|
Chris@16
|
511 void BOOST_TEST_DECL
|
Chris@16
|
512 exception_safety( callback0<> const& F, const_string test_name )
|
Chris@16
|
513 {
|
Chris@16
|
514 exception_safety_tester est( test_name );
|
Chris@16
|
515
|
Chris@16
|
516 do {
|
Chris@16
|
517 try {
|
Chris@16
|
518 F();
|
Chris@16
|
519 }
|
Chris@16
|
520 catch( exception_safety_tester::unique_exception const& ) {}
|
Chris@16
|
521
|
Chris@16
|
522 } while( est.next_execution_path() );
|
Chris@16
|
523 }
|
Chris@16
|
524
|
Chris@16
|
525 //____________________________________________________________________________//
|
Chris@16
|
526
|
Chris@16
|
527 } // namespace itest
|
Chris@16
|
528
|
Chris@16
|
529 } // namespace boost
|
Chris@16
|
530
|
Chris@16
|
531 //____________________________________________________________________________//
|
Chris@16
|
532
|
Chris@16
|
533 #include <boost/test/detail/enable_warnings.hpp>
|
Chris@16
|
534
|
Chris@16
|
535 #endif // non-ancient compiler
|
Chris@16
|
536
|
Chris@16
|
537 #endif // BOOST_TEST_EXECUTION_SAFETY_IPP_112005GER
|