1 | // (C) Copyright Gennadiy Rozental 2001. |
2 | // Distributed under the Boost Software License, Version 1.0. |
3 | // (See accompanying file LICENSE_1_0.txt or copy at |
4 | // http://www.boost.org/LICENSE_1_0.txt) |
5 | |
6 | // See http://www.boost.org/libs/test for the library home page. |
7 | // |
8 | // File : $RCSfile$ |
9 | // |
10 | // Version : $Revision$ |
11 | // |
12 | // Description : implements framework API - main driver for the test |
13 | // *************************************************************************** |
14 | |
15 | #ifndef BOOST_TEST_FRAMEWORK_IPP_021005GER |
16 | #define BOOST_TEST_FRAMEWORK_IPP_021005GER |
17 | |
18 | // Boost.Test |
19 | #include <boost/test/framework.hpp> |
20 | #include <boost/test/execution_monitor.hpp> |
21 | #include <boost/test/debug.hpp> |
22 | #include <boost/test/unit_test_parameters.hpp> |
23 | |
24 | #include <boost/test/unit_test_log.hpp> |
25 | #include <boost/test/unit_test_monitor.hpp> |
26 | #include <boost/test/results_collector.hpp> |
27 | #include <boost/test/progress_monitor.hpp> |
28 | #include <boost/test/results_reporter.hpp> |
29 | |
30 | #include <boost/test/tree/observer.hpp> |
31 | #include <boost/test/tree/test_unit.hpp> |
32 | #include <boost/test/tree/visitor.hpp> |
33 | #include <boost/test/tree/traverse.hpp> |
34 | #include <boost/test/tree/test_case_counter.hpp> |
35 | |
36 | #if BOOST_TEST_SUPPORT_TOKEN_ITERATOR |
37 | #include <boost/test/utils/iterator/token_iterator.hpp> |
38 | #endif |
39 | |
40 | #include <boost/test/utils/foreach.hpp> |
41 | #include <boost/test/utils/basic_cstring/io.hpp> |
42 | |
43 | #include <boost/test/detail/global_typedef.hpp> |
44 | #include <boost/test/detail/throw_exception.hpp> |
45 | |
46 | // Boost |
47 | #include <boost/timer.hpp> |
48 | #include <boost/bind.hpp> |
49 | |
50 | // STL |
51 | #include <limits> |
52 | #include <map> |
53 | #include <set> |
54 | #include <cstdlib> |
55 | #include <ctime> |
56 | |
57 | #ifdef BOOST_NO_STDC_NAMESPACE |
58 | namespace std { using ::time; using ::srand; } |
59 | #endif |
60 | |
61 | #include <boost/test/detail/suppress_warnings.hpp> |
62 | |
63 | //____________________________________________________________________________// |
64 | |
65 | namespace boost { |
66 | namespace unit_test { |
67 | namespace framework { |
68 | namespace impl { |
69 | |
70 | // ************************************************************************** // |
71 | // ************** order detection helpers ************** // |
72 | // ************************************************************************** // |
73 | |
74 | struct order_info { |
75 | order_info() : depth(-1) {} |
76 | |
77 | int depth; |
78 | std::vector<test_unit_id> dependant_siblings; |
79 | }; |
80 | |
81 | typedef std::set<test_unit_id> tu_id_set; |
82 | typedef std::map<test_unit_id,order_info> order_info_per_tu; // !! ?? unordered map |
83 | |
84 | //____________________________________________________________________________// |
85 | |
86 | static test_unit_id |
87 | get_tu_parent( test_unit_id tu_id ) |
88 | { |
89 | return framework::get( tu_id, tu_type: TUT_ANY ).p_parent_id; |
90 | } |
91 | |
92 | //____________________________________________________________________________// |
93 | |
94 | static int |
95 | tu_depth( test_unit_id tu_id, test_unit_id master_tu_id, order_info_per_tu& tuoi ) |
96 | { |
97 | if( tu_id == master_tu_id ) |
98 | return 0; |
99 | |
100 | order_info& info = tuoi[tu_id]; |
101 | |
102 | if( info.depth == -1 ) |
103 | info.depth = tu_depth( tu_id: get_tu_parent( tu_id ), master_tu_id, tuoi ) + 1; |
104 | |
105 | return info.depth; |
106 | } |
107 | |
108 | //____________________________________________________________________________// |
109 | |
110 | static void |
111 | collect_dependant_siblings( test_unit_id from, test_unit_id to, test_unit_id master_tu_id, order_info_per_tu& tuoi ) |
112 | { |
113 | int from_depth = tu_depth( tu_id: from, master_tu_id, tuoi ); |
114 | int to_depth = tu_depth( tu_id: to, master_tu_id, tuoi ); |
115 | |
116 | while(from_depth > to_depth) { |
117 | from = get_tu_parent( tu_id: from ); |
118 | --from_depth; |
119 | } |
120 | |
121 | while(from_depth < to_depth) { |
122 | to = get_tu_parent( tu_id: to ); |
123 | --to_depth; |
124 | } |
125 | |
126 | while(true) { |
127 | test_unit_id from_parent = get_tu_parent( tu_id: from ); |
128 | test_unit_id to_parent = get_tu_parent( tu_id: to ); |
129 | if( from_parent == to_parent ) |
130 | break; |
131 | from = from_parent; |
132 | to = to_parent; |
133 | } |
134 | |
135 | tuoi[from].dependant_siblings.push_back( x: to ); |
136 | } |
137 | |
138 | //____________________________________________________________________________// |
139 | |
140 | static counter_t |
141 | assign_sibling_rank( test_unit_id tu_id, order_info_per_tu& tuoi ) |
142 | { |
143 | test_unit& tu = framework::get( tu_id, tu_type: TUT_ANY ); |
144 | |
145 | BOOST_TEST_SETUP_ASSERT( tu.p_sibling_rank != (std::numeric_limits<counter_t>::max)(), |
146 | "Cyclic dependency detected involving test unit \"" + tu.full_name() + "\"" ); |
147 | |
148 | if( tu.p_sibling_rank != 0 ) |
149 | return tu.p_sibling_rank; |
150 | |
151 | order_info const& info = tuoi[tu_id]; |
152 | |
153 | // indicate in progress |
154 | tu.p_sibling_rank.value = (std::numeric_limits<counter_t>::max)(); |
155 | |
156 | counter_t new_rank = 1; |
157 | BOOST_TEST_FOREACH( test_unit_id, sibling_id, info.dependant_siblings ) |
158 | new_rank = (std::max)(a: new_rank, b: assign_sibling_rank( tu_id: sibling_id, tuoi ) + 1); |
159 | |
160 | return tu.p_sibling_rank.value = new_rank; |
161 | } |
162 | |
163 | //____________________________________________________________________________// |
164 | |
165 | // ************************************************************************** // |
166 | // ************** test_init call wrapper ************** // |
167 | // ************************************************************************** // |
168 | |
169 | static void |
170 | invoke_init_func( init_unit_test_func init_func ) |
171 | { |
172 | #ifdef BOOST_TEST_ALTERNATIVE_INIT_API |
173 | BOOST_TEST_I_ASSRT( (*init_func)(), std::runtime_error( "test module initialization failed" ) ); |
174 | #else |
175 | test_suite* manual_test_units = (*init_func)( framework::master_test_suite().argc, framework::master_test_suite().argv ); |
176 | |
177 | if( manual_test_units ) |
178 | framework::master_test_suite().add( tu: manual_test_units ); |
179 | #endif |
180 | } |
181 | |
182 | // ************************************************************************** // |
183 | // ************** name_filter ************** // |
184 | // ************************************************************************** // |
185 | |
186 | class name_filter : public test_tree_visitor { |
187 | struct component { |
188 | component( const_string name ) // has to be implicit |
189 | { |
190 | if( name == "*" ) |
191 | m_kind = SFK_ALL; |
192 | else if( first_char( source: name ) == '*' && last_char( source: name ) == '*' ) { |
193 | m_kind = SFK_SUBSTR; |
194 | m_name = name.substr( beg_index: 1, end_index: name.size()-1 ); |
195 | } |
196 | else if( first_char( source: name ) == '*' ) { |
197 | m_kind = SFK_TRAILING; |
198 | m_name = name.substr( beg_index: 1 ); |
199 | } |
200 | else if( last_char( source: name ) == '*' ) { |
201 | m_kind = SFK_LEADING; |
202 | m_name = name.substr( beg_index: 0, end_index: name.size()-1 ); |
203 | } |
204 | else { |
205 | m_kind = SFK_MATCH; |
206 | m_name = name; |
207 | } |
208 | } |
209 | |
210 | bool pass( test_unit const& tu ) const |
211 | { |
212 | const_string name( tu.p_name ); |
213 | |
214 | switch( m_kind ) { |
215 | default: |
216 | case SFK_ALL: |
217 | return true; |
218 | case SFK_LEADING: |
219 | return name.substr( beg_index: 0, end_index: m_name.size() ) == m_name; |
220 | case SFK_TRAILING: |
221 | return name.size() >= m_name.size() && name.substr( beg_index: name.size() - m_name.size() ) == m_name; |
222 | case SFK_SUBSTR: |
223 | return name.find( str: m_name ) != const_string::npos; |
224 | case SFK_MATCH: |
225 | return m_name == tu.p_name.get(); |
226 | } |
227 | } |
228 | enum kind { SFK_ALL, SFK_LEADING, SFK_TRAILING, SFK_SUBSTR, SFK_MATCH }; |
229 | |
230 | kind m_kind; |
231 | const_string m_name; |
232 | }; |
233 | |
234 | public: |
235 | // Constructor |
236 | name_filter( test_unit_id_list& targ_list, const_string filter_expr ) : m_targ_list( targ_list ), m_depth( 0 ) |
237 | { |
238 | #ifdef BOOST_TEST_SUPPORT_TOKEN_ITERATOR |
239 | utils::string_token_iterator tit( filter_expr, (utils::dropped_delimeters = "/" , |
240 | utils::kept_delimeters = utils::dt_none) ); |
241 | |
242 | while( tit != utils::string_token_iterator() ) { |
243 | m_components.push_back( |
244 | x: std::vector<component>( utils::string_token_iterator( *tit, (utils::dropped_delimeters = "," , |
245 | utils::kept_delimeters = utils::dt_none) ), |
246 | utils::string_token_iterator() ) ); |
247 | |
248 | ++tit; |
249 | } |
250 | #endif |
251 | } |
252 | |
253 | private: |
254 | bool filter_unit( test_unit const& tu ) |
255 | { |
256 | // skip master test suite |
257 | if( m_depth == 0 ) |
258 | return true; |
259 | |
260 | // corresponding name filters are at level m_depth-1 |
261 | std::vector<component> const& filters = m_components[m_depth-1]; |
262 | |
263 | // look for match |
264 | return std::find_if( first: filters.begin(), last: filters.end(), pred: bind( f: &component::pass, a1: _1, a2: boost::ref(t: tu) ) ) != filters.end(); |
265 | } |
266 | |
267 | // test_tree_visitor interface |
268 | virtual void visit( test_case const& tc ) |
269 | { |
270 | // make sure we only accept test cases if we match last component of the filter |
271 | if( m_depth == m_components.size() && filter_unit( tu: tc ) ) |
272 | m_targ_list.push_back( x: tc.p_id ); // found a test case |
273 | } |
274 | virtual bool test_suite_start( test_suite const& ts ) |
275 | { |
276 | if( !filter_unit( tu: ts ) ) |
277 | return false; |
278 | |
279 | if( m_depth < m_components.size() ) { |
280 | ++m_depth; |
281 | return true; |
282 | } |
283 | |
284 | m_targ_list.push_back( x: ts.p_id ); // found a test suite |
285 | |
286 | return false; |
287 | } |
288 | virtual void test_suite_finish( test_suite const& /*ts*/ ) |
289 | { |
290 | --m_depth; |
291 | } |
292 | |
293 | // Data members |
294 | typedef std::vector<std::vector<component> > components_per_level; |
295 | |
296 | components_per_level m_components; |
297 | test_unit_id_list& m_targ_list; |
298 | unsigned m_depth; |
299 | }; |
300 | |
301 | // ************************************************************************** // |
302 | // ************** label_filter ************** // |
303 | // ************************************************************************** // |
304 | |
305 | class label_filter : public test_tree_visitor { |
306 | public: |
307 | label_filter( test_unit_id_list& targ_list, const_string label ) |
308 | : m_targ_list( targ_list ) |
309 | , m_label( label ) |
310 | {} |
311 | |
312 | private: |
313 | // test_tree_visitor interface |
314 | virtual bool visit( test_unit const& tu ) |
315 | { |
316 | if( tu.has_label( l: m_label ) ) { |
317 | // found a test unit; add it to list of tu to enable with children and stop recursion in case of suites |
318 | m_targ_list.push_back( x: tu.p_id ); |
319 | return false; |
320 | } |
321 | |
322 | return true; |
323 | } |
324 | |
325 | // Data members |
326 | test_unit_id_list& m_targ_list; |
327 | const_string m_label; |
328 | }; |
329 | |
330 | // ************************************************************************** // |
331 | // ************** set_run_status ************** // |
332 | // ************************************************************************** // |
333 | |
334 | class set_run_status : public test_tree_visitor { |
335 | public: |
336 | explicit set_run_status( test_unit::run_status rs, test_unit_id_list* dep_collector = 0 ) |
337 | : m_new_status( rs ) |
338 | , m_dep_collector( dep_collector ) |
339 | {} |
340 | |
341 | private: |
342 | // test_tree_visitor interface |
343 | virtual bool visit( test_unit const& tu ) |
344 | { |
345 | const_cast<test_unit&>(tu).p_run_status.value = m_new_status == test_unit::RS_INVALID ? tu.p_default_status : m_new_status; |
346 | |
347 | if( m_dep_collector ) { |
348 | BOOST_TEST_FOREACH( test_unit_id, dep_id, tu.p_dependencies.get() ) { |
349 | test_unit const& dep = framework::get( tu_id: dep_id, tu_type: TUT_ANY ); |
350 | |
351 | if( dep.p_run_status == tu.p_run_status ) |
352 | continue; |
353 | |
354 | BOOST_TEST_MESSAGE( "Including test " << dep.p_type_name << ' ' << dep.full_name() << |
355 | " as a dependency of test " << tu.p_type_name << ' ' << tu.full_name() ); |
356 | |
357 | m_dep_collector->push_back( x: dep_id ); |
358 | } |
359 | } |
360 | return true; |
361 | } |
362 | |
363 | // Data members |
364 | test_unit::run_status m_new_status; |
365 | test_unit_id_list* m_dep_collector; |
366 | }; |
367 | |
368 | // ************************************************************************** // |
369 | // ************** parse_filters ************** // |
370 | // ************************************************************************** // |
371 | |
372 | static void |
373 | add_filtered_test_units( test_unit_id master_tu_id, const_string filter, test_unit_id_list& targ ) |
374 | { |
375 | // Choose between two kinds of filters |
376 | if( filter[0] == '@' ) { |
377 | filter.trim_left( trim_size: 1 ); |
378 | label_filter lf( targ, filter ); |
379 | traverse_test_tree( master_tu_id, lf, ignore_status: true ); |
380 | } |
381 | else { |
382 | name_filter nf( targ, filter ); |
383 | traverse_test_tree( master_tu_id, nf, ignore_status: true ); |
384 | } |
385 | } |
386 | |
387 | //____________________________________________________________________________// |
388 | |
389 | static bool |
390 | parse_filters( test_unit_id master_tu_id, test_unit_id_list& tu_to_enable, test_unit_id_list& tu_to_disable ) |
391 | { |
392 | // 10. collect tu to enable and disable based on filters |
393 | bool had_selector_filter = false; |
394 | |
395 | std::vector<std::string> const& filters = runtime_config::get<std::vector<std::string> >( parameter_name: runtime_config::RUN_FILTERS ); |
396 | |
397 | BOOST_TEST_FOREACH( const_string, filter, filters ) { |
398 | BOOST_TEST_SETUP_ASSERT( !filter.is_empty(), "Invalid filter specification" ); |
399 | |
400 | enum { SELECTOR, ENABLER, DISABLER } filter_type = SELECTOR; |
401 | |
402 | // 11. Deduce filter type |
403 | if( filter[0] == '!' || filter[0] == '+' ) { |
404 | filter_type = filter[0] == '+' ? ENABLER : DISABLER; |
405 | filter.trim_left( trim_size: 1 ); |
406 | BOOST_TEST_SETUP_ASSERT( !filter.is_empty(), "Invalid filter specification" ); |
407 | } |
408 | |
409 | had_selector_filter |= filter_type == SELECTOR; |
410 | |
411 | // 12. Add test units to corresponding list |
412 | switch( filter_type ) { |
413 | case SELECTOR: |
414 | case ENABLER: add_filtered_test_units( master_tu_id, filter, targ&: tu_to_enable ); break; |
415 | case DISABLER: add_filtered_test_units( master_tu_id, filter, targ&: tu_to_disable ); break; |
416 | } |
417 | } |
418 | |
419 | return had_selector_filter; |
420 | } |
421 | |
422 | //____________________________________________________________________________// |
423 | |
424 | } // namespace impl |
425 | |
426 | // ************************************************************************** // |
427 | // ************** framework::state ************** // |
428 | // ************************************************************************** // |
429 | |
430 | unsigned const TIMEOUT_EXCEEDED = static_cast<unsigned>( -1 ); |
431 | |
432 | class state { |
433 | public: |
434 | state() |
435 | : m_curr_test_case( INV_TEST_UNIT_ID ) |
436 | , m_next_test_case_id( MIN_TEST_CASE_ID ) |
437 | , m_next_test_suite_id( MIN_TEST_SUITE_ID ) |
438 | , m_test_in_progress( false ) |
439 | , m_context_idx( 0 ) |
440 | , m_log_sink( std::cout ) |
441 | , m_report_sink( std::cerr ) |
442 | { |
443 | } |
444 | |
445 | ~state() { clear(); } |
446 | |
447 | void clear() |
448 | { |
449 | while( !m_test_units.empty() ) { |
450 | test_unit_store::value_type const& tu = *m_test_units.begin(); |
451 | test_unit const* tu_ptr = tu.second; |
452 | |
453 | // the delete will erase this element from map |
454 | if( ut_detail::test_id_2_unit_type( id: tu.second->p_id ) == TUT_SUITE ) |
455 | delete static_cast<test_suite const*>(tu_ptr); |
456 | else |
457 | delete static_cast<test_case const*>(tu_ptr); |
458 | } |
459 | } |
460 | |
461 | void set_tu_id( test_unit& tu, test_unit_id id ) { tu.p_id.value = id; } |
462 | |
463 | ////////////////////////////////////////////////////////////////// |
464 | |
465 | // Validates the dependency graph and deduces the sibling dependency rank for each child |
466 | void deduce_siblings_order( test_unit_id tu_id, test_unit_id master_tu_id, impl::order_info_per_tu& tuoi ) |
467 | { |
468 | test_unit& tu = framework::get( tu_id, tu_type: TUT_ANY ); |
469 | |
470 | // collect all sibling dependancy from tu own list |
471 | BOOST_TEST_FOREACH( test_unit_id, dep_id, tu.p_dependencies.get() ) |
472 | collect_dependant_siblings( from: tu_id, to: dep_id, master_tu_id, tuoi ); |
473 | |
474 | if( tu.p_type != TUT_SUITE ) |
475 | return; |
476 | |
477 | test_suite& ts = static_cast<test_suite&>(tu); |
478 | |
479 | // recursive call to children first |
480 | BOOST_TEST_FOREACH( test_unit_id, chld_id, ts.m_children ) |
481 | deduce_siblings_order( tu_id: chld_id, master_tu_id, tuoi ); |
482 | |
483 | BOOST_TEST_FOREACH( test_unit_id, chld_id, ts.m_children ) { |
484 | counter_t rank = assign_sibling_rank( tu_id: chld_id, tuoi ); |
485 | ts.m_ranked_children.insert( x: std::make_pair( x&: rank, y&: chld_id ) ); |
486 | } |
487 | } |
488 | |
489 | ////////////////////////////////////////////////////////////////// |
490 | |
491 | // Finalize default run status: |
492 | // 1) inherit run status from parent where applicable |
493 | // 2) if any of test units in test suite enabled enable it as well |
494 | bool finalize_default_run_status( test_unit_id tu_id, test_unit::run_status parent_status ) |
495 | { |
496 | test_unit& tu = framework::get( tu_id, tu_type: TUT_ANY ); |
497 | |
498 | if( tu.p_default_status == test_suite::RS_INHERIT ) |
499 | tu.p_default_status.value = parent_status; |
500 | |
501 | // go through list of children |
502 | if( tu.p_type == TUT_SUITE ) { |
503 | bool has_enabled_child = false; |
504 | BOOST_TEST_FOREACH( test_unit_id, chld_id, static_cast<test_suite const&>(tu).m_children ) |
505 | has_enabled_child |= finalize_default_run_status( tu_id: chld_id, parent_status: tu.p_default_status ); |
506 | |
507 | tu.p_default_status.value = has_enabled_child ? test_suite::RS_ENABLED : test_suite::RS_DISABLED; |
508 | } |
509 | |
510 | return tu.p_default_status == test_suite::RS_ENABLED; |
511 | } |
512 | |
513 | ////////////////////////////////////////////////////////////////// |
514 | |
515 | bool finalize_run_status( test_unit_id tu_id ) |
516 | { |
517 | test_unit& tu = framework::get( tu_id, tu_type: TUT_ANY ); |
518 | |
519 | // go through list of children |
520 | if( tu.p_type == TUT_SUITE ) { |
521 | bool has_enabled_child = false; |
522 | BOOST_TEST_FOREACH( test_unit_id, chld_id, static_cast<test_suite const&>(tu).m_children) |
523 | has_enabled_child |= finalize_run_status( tu_id: chld_id ); |
524 | |
525 | tu.p_run_status.value = has_enabled_child ? test_suite::RS_ENABLED : test_suite::RS_DISABLED; |
526 | } |
527 | |
528 | return tu.is_enabled(); |
529 | } |
530 | |
531 | ////////////////////////////////////////////////////////////////// |
532 | |
533 | void deduce_run_status( test_unit_id master_tu_id ) |
534 | { |
535 | using namespace framework::impl; |
536 | test_unit_id_list tu_to_enable; |
537 | test_unit_id_list tu_to_disable; |
538 | |
539 | // 10. If there are any filters supplied, figure out lists of test units to enable/disable |
540 | bool had_selector_filter = !runtime_config::get<std::vector<std::string> >( parameter_name: runtime_config::RUN_FILTERS ).empty() && |
541 | parse_filters( master_tu_id, tu_to_enable, tu_to_disable ); |
542 | |
543 | // 20. Set the stage: either use default run status or disable all test units |
544 | set_run_status initial_setter( had_selector_filter ? test_unit::RS_DISABLED : test_unit::RS_INVALID ); |
545 | traverse_test_tree( master_tu_id, initial_setter, ignore_status: true ); |
546 | |
547 | // 30. Apply all selectors and enablers. |
548 | while( !tu_to_enable.empty() ) { |
549 | test_unit& tu = framework::get( tu_id: tu_to_enable.back(), tu_type: TUT_ANY ); |
550 | |
551 | tu_to_enable.pop_back(); |
552 | |
553 | // 35. Ignore test units which already enabled |
554 | if( tu.is_enabled() ) |
555 | continue; |
556 | |
557 | // set new status and add all dependencies into tu_to_enable |
558 | set_run_status enabler( test_unit::RS_ENABLED, &tu_to_enable ); |
559 | traverse_test_tree( tu.p_id, enabler, ignore_status: true ); |
560 | } |
561 | |
562 | // 40. Apply all disablers |
563 | while( !tu_to_disable.empty() ) { |
564 | test_unit const& tu = framework::get( tu_id: tu_to_disable.back(), tu_type: TUT_ANY ); |
565 | |
566 | tu_to_disable.pop_back(); |
567 | |
568 | // 35. Ignore test units which already disabled |
569 | if( !tu.is_enabled() ) |
570 | continue; |
571 | |
572 | set_run_status disabler( test_unit::RS_DISABLED ); |
573 | traverse_test_tree( tu.p_id, disabler, ignore_status: true ); |
574 | } |
575 | |
576 | // 50. Make sure parents of enabled test units are also enabled |
577 | finalize_run_status( tu_id: master_tu_id ); |
578 | } |
579 | |
580 | ////////////////////////////////////////////////////////////////// |
581 | |
582 | typedef unit_test_monitor_t::error_level execution_result; |
583 | |
584 | // Executed the test tree with the root at specified test unit |
585 | execution_result execute_test_tree( test_unit_id tu_id, unsigned timeout = 0 ) |
586 | { |
587 | test_unit const& tu = framework::get( tu_id, tu_type: TUT_ANY ); |
588 | |
589 | execution_result result = unit_test_monitor_t::test_ok; |
590 | |
591 | if( !tu.is_enabled() ) |
592 | return result; |
593 | |
594 | // 10. Check preconditions, including zero time left for execution and |
595 | // successful execution of all dependencies |
596 | if( timeout == TIMEOUT_EXCEEDED ) { |
597 | // notify all observers about skipped test unit |
598 | BOOST_TEST_FOREACH( test_observer*, to, m_observers ) |
599 | to->test_unit_skipped( tu, "timeout for the test unit is exceeded" ); |
600 | |
601 | return unit_test_monitor_t::os_timeout; |
602 | } |
603 | else if( timeout == 0 || timeout > tu.p_timeout ) // deduce timeout for this test unit |
604 | timeout = tu.p_timeout; |
605 | |
606 | test_tools::assertion_result const precondition_res = tu.check_preconditions(); |
607 | if( !precondition_res ) { |
608 | // notify all observers about skipped test unit |
609 | BOOST_TEST_FOREACH( test_observer*, to, m_observers ) |
610 | to->test_unit_skipped( tu, precondition_res.message() ); |
611 | |
612 | return unit_test_monitor_t::precondition_failure; |
613 | } |
614 | |
615 | // 20. Notify all observers about the start of the test unit |
616 | BOOST_TEST_FOREACH( test_observer*, to, m_observers ) |
617 | to->test_unit_start( tu ); |
618 | |
619 | // 30. Execute setup fixtures if any; any failure here leads to test unit abortion |
620 | BOOST_TEST_FOREACH( test_unit_fixture_ptr, F, tu.p_fixtures.get() ) { |
621 | result = unit_test_monitor.execute_and_translate( func: boost::bind( f: &test_unit_fixture::setup, a1: F ) ); |
622 | if( result != unit_test_monitor_t::test_ok ) |
623 | break; |
624 | } |
625 | |
626 | // This is the time we are going to spend executing the test unit |
627 | unsigned long elapsed = 0; |
628 | |
629 | if( result == unit_test_monitor_t::test_ok ) { |
630 | // 40. We are going to time the execution |
631 | boost::timer tu_timer; |
632 | |
633 | if( tu.p_type == TUT_SUITE ) { |
634 | test_suite const& ts = static_cast<test_suite const&>( tu ); |
635 | |
636 | if( runtime_config::get<unsigned>( parameter_name: runtime_config::RANDOM_SEED ) == 0 ) { |
637 | typedef std::pair<counter_t,test_unit_id> value_type; |
638 | |
639 | BOOST_TEST_FOREACH( value_type, chld, ts.m_ranked_children ) { |
640 | unsigned chld_timeout = child_timeout( tu_timeout: timeout, elapsed: tu_timer.elapsed() ); |
641 | |
642 | result = (std::min)( a: result, b: execute_test_tree( tu_id: chld.second, timeout: chld_timeout ) ); |
643 | |
644 | if( unit_test_monitor.is_critical_error( e: result ) ) |
645 | break; |
646 | } |
647 | } |
648 | else { |
649 | // Go through ranges of chldren with the same dependency rank and shuffle them |
650 | // independently. Execute each subtree in this order |
651 | test_unit_id_list children_with_the_same_rank; |
652 | |
653 | typedef test_suite::children_per_rank::const_iterator it_type; |
654 | it_type it = ts.m_ranked_children.begin(); |
655 | while( it != ts.m_ranked_children.end() ) { |
656 | children_with_the_same_rank.clear(); |
657 | |
658 | std::pair<it_type,it_type> range = ts.m_ranked_children.equal_range( x: it->first ); |
659 | it = range.first; |
660 | while( it != range.second ) { |
661 | children_with_the_same_rank.push_back( x: it->second ); |
662 | it++; |
663 | } |
664 | |
665 | std::random_shuffle( first: children_with_the_same_rank.begin(), last: children_with_the_same_rank.end() ); |
666 | |
667 | BOOST_TEST_FOREACH( test_unit_id, chld, children_with_the_same_rank ) { |
668 | unsigned chld_timeout = child_timeout( tu_timeout: timeout, elapsed: tu_timer.elapsed() ); |
669 | |
670 | result = (std::min)( a: result, b: execute_test_tree( tu_id: chld, timeout: chld_timeout ) ); |
671 | |
672 | if( unit_test_monitor.is_critical_error( e: result ) ) |
673 | break; |
674 | } |
675 | } |
676 | } |
677 | |
678 | elapsed = static_cast<unsigned long>( tu_timer.elapsed() * 1e6 ); |
679 | } |
680 | else { // TUT_CASE |
681 | test_case const& tc = static_cast<test_case const&>( tu ); |
682 | |
683 | // setup contexts |
684 | m_context_idx = 0; |
685 | |
686 | // setup current test case |
687 | test_unit_id bkup = m_curr_test_case; |
688 | m_curr_test_case = tc.p_id; |
689 | |
690 | // execute the test case body |
691 | result = unit_test_monitor.execute_and_translate( func: tc.p_test_func, timeout ); |
692 | elapsed = static_cast<unsigned long>( tu_timer.elapsed() * 1e6 ); |
693 | |
694 | // cleanup leftover context |
695 | m_context.clear(); |
696 | |
697 | // restore state and abort if necessary |
698 | m_curr_test_case = bkup; |
699 | } |
700 | } |
701 | |
702 | // if run error is critical skip teardown, who knows what the state of the program at this point |
703 | if( !unit_test_monitor.is_critical_error( e: result ) ) { |
704 | // execute teardown fixtures if any in reverse order |
705 | BOOST_TEST_REVERSE_FOREACH( test_unit_fixture_ptr, F, tu.p_fixtures.get() ) { |
706 | result = (std::min)( a: result, b: unit_test_monitor.execute_and_translate( func: boost::bind( f: &test_unit_fixture::teardown, a1: F ), timeout: 0 ) ); |
707 | |
708 | if( unit_test_monitor.is_critical_error( e: result ) ) |
709 | break; |
710 | } |
711 | } |
712 | |
713 | // notify all observers about abortion |
714 | if( unit_test_monitor.is_critical_error( e: result ) ) { |
715 | BOOST_TEST_FOREACH( test_observer*, to, m_observers ) |
716 | to->test_aborted(); |
717 | } |
718 | |
719 | // notify all observers about completion |
720 | BOOST_TEST_REVERSE_FOREACH( test_observer*, to, m_observers ) |
721 | to->test_unit_finish( tu, elapsed ); |
722 | |
723 | return result; |
724 | } |
725 | |
726 | ////////////////////////////////////////////////////////////////// |
727 | |
728 | unsigned child_timeout( unsigned tu_timeout, double elapsed ) |
729 | { |
730 | if( tu_timeout == 0U ) |
731 | return 0U; |
732 | |
733 | unsigned elpsed_sec = static_cast<unsigned>(elapsed); // rounding to number of whole seconds |
734 | |
735 | return tu_timeout > elpsed_sec ? tu_timeout - elpsed_sec : TIMEOUT_EXCEEDED; |
736 | } |
737 | |
738 | struct priority_order { |
739 | bool operator()( test_observer* lhs, test_observer* rhs ) const |
740 | { |
741 | return (lhs->priority() < rhs->priority()) || ((lhs->priority() == rhs->priority()) && (lhs < rhs)); |
742 | } |
743 | }; |
744 | |
745 | // Data members |
746 | typedef std::map<test_unit_id,test_unit*> test_unit_store; |
747 | typedef std::set<test_observer*,priority_order> observer_store; |
748 | struct context_frame { |
749 | context_frame( std::string const& d, int id, bool sticky ) |
750 | : descr( d ) |
751 | , frame_id( id ) |
752 | , is_sticky( sticky ) |
753 | {} |
754 | |
755 | std::string descr; |
756 | int frame_id; |
757 | bool is_sticky; |
758 | }; |
759 | typedef std::vector<context_frame> context_data; |
760 | |
761 | master_test_suite_t* m_master_test_suite; |
762 | std::vector<test_suite*> m_auto_test_suites; |
763 | |
764 | test_unit_id m_curr_test_case; |
765 | test_unit_store m_test_units; |
766 | |
767 | test_unit_id m_next_test_case_id; |
768 | test_unit_id m_next_test_suite_id; |
769 | |
770 | bool m_test_in_progress; |
771 | |
772 | observer_store m_observers; |
773 | context_data m_context; |
774 | int m_context_idx; |
775 | |
776 | boost::execution_monitor m_aux_em; |
777 | |
778 | runtime_config::stream_holder m_log_sink; |
779 | runtime_config::stream_holder m_report_sink; |
780 | }; |
781 | |
782 | //____________________________________________________________________________// |
783 | |
784 | namespace impl { |
785 | namespace { |
786 | |
787 | #if defined(__CYGWIN__) |
788 | framework::state& s_frk_state() { static framework::state* the_inst = 0; if(!the_inst) the_inst = new framework::state; return *the_inst; } |
789 | #else |
790 | framework::state& s_frk_state() { static framework::state the_inst; return the_inst; } |
791 | #endif |
792 | |
793 | } // local namespace |
794 | |
795 | void |
796 | setup_for_execution( test_unit const& tu ) |
797 | { |
798 | s_frk_state().deduce_run_status( master_tu_id: tu.p_id ); |
799 | } |
800 | |
801 | //____________________________________________________________________________// |
802 | |
803 | } // namespace impl |
804 | |
805 | //____________________________________________________________________________// |
806 | |
807 | // ************************************************************************** // |
808 | // ************** framework::init ************** // |
809 | // ************************************************************************** // |
810 | |
811 | void |
812 | init( init_unit_test_func init_func, int argc, char* argv[] ) |
813 | { |
814 | using namespace impl; |
815 | |
816 | // 10. Set up runtime parameters |
817 | runtime_config::init( argc, argv ); |
818 | |
819 | // 20. Set the desired log level, format and sink |
820 | unit_test_log.set_threshold_level( runtime_config::get<log_level>( parameter_name: runtime_config::LOG_LEVEL ) ); |
821 | unit_test_log.set_format( runtime_config::get<output_format>( parameter_name: runtime_config::LOG_FORMAT ) ); |
822 | s_frk_state().m_log_sink.setup( runtime_config::LOG_SINK ); |
823 | unit_test_log.set_stream( s_frk_state().m_log_sink.ref() ); |
824 | |
825 | // 30. Set the desired report level, format and sink |
826 | results_reporter::set_level( runtime_config::get<report_level>( parameter_name: runtime_config::REPORT_LEVEL ) ); |
827 | results_reporter::set_format( runtime_config::get<output_format>( parameter_name: runtime_config::REPORT_FORMAT ) ); |
828 | s_frk_state().m_report_sink.setup( runtime_config::REPORT_SINK ); |
829 | results_reporter::set_stream( s_frk_state().m_report_sink.ref() ); |
830 | |
831 | // 40. Register default test observers |
832 | register_observer( to&: results_collector ); |
833 | register_observer( to&: unit_test_log ); |
834 | |
835 | if( runtime_config::get<bool>( parameter_name: runtime_config::SHOW_PROGRESS ) ) { |
836 | progress_monitor.set_stream( s_frk_state().m_log_sink.ref() ); |
837 | register_observer( to&: progress_monitor ); |
838 | } |
839 | |
840 | // 50. Set up memory leak detection |
841 | unsigned long detect_mem_leak = runtime_config::get<unsigned long>( parameter_name: runtime_config::DETECT_MEM_LEAKS ); |
842 | if( detect_mem_leak > 0 ) { |
843 | debug::detect_memory_leaks( on_off: true, report_file: runtime_config::get<std::string>( parameter_name: runtime_config::REPORT_MEM_LEAKS ) ); |
844 | debug::break_memory_alloc( mem_alloc_order_num: (long)detect_mem_leak ); |
845 | } |
846 | |
847 | // 60. Initialize master unit test suite |
848 | master_test_suite().argc = argc; |
849 | master_test_suite().argv = argv; |
850 | |
851 | // 70. Invoke test module initialization routine |
852 | BOOST_TEST_I_TRY { |
853 | s_frk_state().m_aux_em.vexecute( F: boost::bind( f: &impl::invoke_init_func, a1: init_func ) ); |
854 | } |
855 | BOOST_TEST_I_CATCH( execution_exception, ex ) { |
856 | BOOST_TEST_SETUP_ASSERT( false, ex.what() ); |
857 | } |
858 | } |
859 | |
860 | //____________________________________________________________________________// |
861 | |
862 | void |
863 | finalize_setup_phase( test_unit_id master_tu_id ) |
864 | { |
865 | if( master_tu_id == INV_TEST_UNIT_ID ) |
866 | master_tu_id = master_test_suite().p_id; |
867 | |
868 | // 10. Apply all decorators to the auto test units |
869 | class apply_decorators : public test_tree_visitor { |
870 | private: |
871 | // test_tree_visitor interface |
872 | virtual bool visit( test_unit const& tu ) |
873 | { |
874 | BOOST_TEST_FOREACH( decorator::base_ptr, d, tu.p_decorators.get() ) |
875 | d->apply( tu&: const_cast<test_unit&>(tu) ); |
876 | |
877 | return true; |
878 | } |
879 | } ad; |
880 | traverse_test_tree( master_tu_id, ad, ignore_status: true ); |
881 | |
882 | // 20. Finalize setup phase |
883 | impl::order_info_per_tu tuoi; |
884 | impl::s_frk_state().deduce_siblings_order( tu_id: master_tu_id, master_tu_id, tuoi ); |
885 | impl::s_frk_state().finalize_default_run_status( tu_id: master_tu_id, parent_status: test_unit::RS_INVALID ); |
886 | } |
887 | |
888 | // ************************************************************************** // |
889 | // ************** test_in_progress ************** // |
890 | // ************************************************************************** // |
891 | |
892 | bool |
893 | test_in_progress() |
894 | { |
895 | return impl::s_frk_state().m_test_in_progress; |
896 | } |
897 | |
898 | //____________________________________________________________________________// |
899 | |
900 | // ************************************************************************** // |
901 | // ************** framework::shutdown ************** // |
902 | // ************************************************************************** // |
903 | |
904 | void |
905 | shutdown() |
906 | { |
907 | // eliminating some fake memory leak reports. See for more details: |
908 | // http://connect.microsoft.com/VisualStudio/feedback/details/106937/memory-leaks-reported-by-debug-crt-inside-typeinfo-name |
909 | |
910 | # if BOOST_WORKAROUND(BOOST_MSVC, <= 1600 ) && !defined(_DLL) && defined(_DEBUG) |
911 | # if BOOST_WORKAROUND(BOOST_MSVC, < 1600 ) |
912 | #define _Next next |
913 | #define _MemPtr memPtr |
914 | #endif |
915 | __type_info_node* pNode = __type_info_root_node._Next; |
916 | __type_info_node* tmpNode = &__type_info_root_node; |
917 | |
918 | for( ; pNode!=NULL; pNode = tmpNode ) { |
919 | tmpNode = pNode->_Next; |
920 | delete pNode->_MemPtr; |
921 | delete pNode; |
922 | } |
923 | # if BOOST_WORKAROUND(BOOST_MSVC, < 1600 ) |
924 | #undef _Next |
925 | #undef _MemPtr |
926 | #endif |
927 | # endif |
928 | } |
929 | |
930 | //____________________________________________________________________________// |
931 | |
932 | // ************************************************************************** // |
933 | // ************** register_test_unit ************** // |
934 | // ************************************************************************** // |
935 | |
936 | void |
937 | register_test_unit( test_case* tc ) |
938 | { |
939 | BOOST_TEST_SETUP_ASSERT( tc->p_id == INV_TEST_UNIT_ID, BOOST_TEST_L( "test case already registered" ) ); |
940 | |
941 | test_unit_id new_id = impl::s_frk_state().m_next_test_case_id; |
942 | |
943 | BOOST_TEST_SETUP_ASSERT( new_id != MAX_TEST_CASE_ID, BOOST_TEST_L( "too many test cases" ) ); |
944 | |
945 | typedef state::test_unit_store::value_type map_value_type; |
946 | |
947 | impl::s_frk_state().m_test_units.insert( x: map_value_type( new_id, tc ) ); |
948 | impl::s_frk_state().m_next_test_case_id++; |
949 | |
950 | impl::s_frk_state().set_tu_id( tu&: *tc, id: new_id ); |
951 | } |
952 | |
953 | //____________________________________________________________________________// |
954 | |
955 | // ************************************************************************** // |
956 | // ************** register_test_unit ************** // |
957 | // ************************************************************************** // |
958 | |
959 | void |
960 | register_test_unit( test_suite* ts ) |
961 | { |
962 | BOOST_TEST_SETUP_ASSERT( ts->p_id == INV_TEST_UNIT_ID, BOOST_TEST_L( "test suite already registered" ) ); |
963 | |
964 | test_unit_id new_id = impl::s_frk_state().m_next_test_suite_id; |
965 | |
966 | BOOST_TEST_SETUP_ASSERT( new_id != MAX_TEST_SUITE_ID, BOOST_TEST_L( "too many test suites" ) ); |
967 | |
968 | typedef state::test_unit_store::value_type map_value_type; |
969 | |
970 | impl::s_frk_state().m_test_units.insert( x: map_value_type( new_id, ts ) ); |
971 | impl::s_frk_state().m_next_test_suite_id++; |
972 | |
973 | impl::s_frk_state().set_tu_id( tu&: *ts, id: new_id ); |
974 | } |
975 | |
976 | //____________________________________________________________________________// |
977 | |
978 | // ************************************************************************** // |
979 | // ************** deregister_test_unit ************** // |
980 | // ************************************************************************** // |
981 | |
982 | void |
983 | deregister_test_unit( test_unit* tu ) |
984 | { |
985 | impl::s_frk_state().m_test_units.erase( x: tu->p_id ); |
986 | } |
987 | |
988 | //____________________________________________________________________________// |
989 | |
990 | // ************************************************************************** // |
991 | // ************** clear ************** // |
992 | // ************************************************************************** // |
993 | |
994 | void |
995 | clear() |
996 | { |
997 | impl::s_frk_state().clear(); |
998 | } |
999 | |
1000 | //____________________________________________________________________________// |
1001 | |
1002 | // ************************************************************************** // |
1003 | // ************** register_observer ************** // |
1004 | // ************************************************************************** // |
1005 | |
1006 | void |
1007 | register_observer( test_observer& to ) |
1008 | { |
1009 | impl::s_frk_state().m_observers.insert( x: &to ); |
1010 | } |
1011 | |
1012 | //____________________________________________________________________________// |
1013 | |
1014 | // ************************************************************************** // |
1015 | // ************** deregister_observer ************** // |
1016 | // ************************************************************************** // |
1017 | |
1018 | void |
1019 | deregister_observer( test_observer& to ) |
1020 | { |
1021 | impl::s_frk_state().m_observers.erase( x: &to ); |
1022 | } |
1023 | |
1024 | //____________________________________________________________________________// |
1025 | |
1026 | // ************************************************************************** // |
1027 | // ************** add_context ************** // |
1028 | // ************************************************************************** // |
1029 | |
1030 | int |
1031 | add_context( ::boost::unit_test::lazy_ostream const& context_descr, bool sticky ) |
1032 | { |
1033 | std::stringstream buffer; |
1034 | context_descr( buffer ); |
1035 | int res_idx = impl::s_frk_state().m_context_idx++; |
1036 | |
1037 | impl::s_frk_state().m_context.push_back( x: state::context_frame( buffer.str(), res_idx, sticky ) ); |
1038 | |
1039 | return res_idx; |
1040 | } |
1041 | |
1042 | //____________________________________________________________________________// |
1043 | |
1044 | // ************************************************************************** // |
1045 | // ************** clear_context ************** // |
1046 | // ************************************************************************** // |
1047 | |
1048 | struct frame_with_id { |
1049 | explicit frame_with_id( int id ) : m_id( id ) {} |
1050 | |
1051 | bool operator()( state::context_frame const& f ) |
1052 | { |
1053 | return f.frame_id == m_id; |
1054 | } |
1055 | int m_id; |
1056 | }; |
1057 | |
1058 | //____________________________________________________________________________// |
1059 | |
1060 | void |
1061 | clear_context( int frame_id ) |
1062 | { |
1063 | if( frame_id == -1 ) { // clear all non sticky frames |
1064 | for( int i=static_cast<int>(impl::s_frk_state().m_context.size())-1; i>=0; i-- ) |
1065 | if( !impl::s_frk_state().m_context[i].is_sticky ) |
1066 | impl::s_frk_state().m_context.erase( position: impl::s_frk_state().m_context.begin()+i ); |
1067 | } |
1068 | |
1069 | else { // clear specific frame |
1070 | state::context_data::iterator it = |
1071 | std::find_if( first: impl::s_frk_state().m_context.begin(), last: impl::s_frk_state().m_context.end(), pred: frame_with_id( frame_id ) ); |
1072 | |
1073 | if( it != impl::s_frk_state().m_context.end() ) // really an internal error if this is not true |
1074 | impl::s_frk_state().m_context.erase( position: it ); |
1075 | } |
1076 | } |
1077 | |
1078 | //____________________________________________________________________________// |
1079 | |
1080 | // ************************************************************************** // |
1081 | // ************** get_context ************** // |
1082 | // ************************************************************************** // |
1083 | |
1084 | context_generator |
1085 | get_context() |
1086 | { |
1087 | return context_generator(); |
1088 | } |
1089 | |
1090 | //____________________________________________________________________________// |
1091 | |
1092 | // ************************************************************************** // |
1093 | // ************** context_generator ************** // |
1094 | // ************************************************************************** // |
1095 | |
1096 | bool |
1097 | context_generator::is_empty() const |
1098 | { |
1099 | return impl::s_frk_state().m_context.empty(); |
1100 | } |
1101 | |
1102 | //____________________________________________________________________________// |
1103 | |
1104 | const_string |
1105 | context_generator::next() const |
1106 | { |
1107 | return m_curr_frame < impl::s_frk_state().m_context.size() ? impl::s_frk_state().m_context[m_curr_frame++].descr : const_string(); |
1108 | } |
1109 | |
1110 | //____________________________________________________________________________// |
1111 | |
1112 | // ************************************************************************** // |
1113 | // ************** master_test_suite ************** // |
1114 | // ************************************************************************** // |
1115 | |
1116 | master_test_suite_t& |
1117 | master_test_suite() |
1118 | { |
1119 | if( !impl::s_frk_state().m_master_test_suite ) |
1120 | impl::s_frk_state().m_master_test_suite = new master_test_suite_t; |
1121 | |
1122 | return *impl::s_frk_state().m_master_test_suite; |
1123 | } |
1124 | |
1125 | //____________________________________________________________________________// |
1126 | |
1127 | // ************************************************************************** // |
1128 | // ************** current_auto_test_suite ************** // |
1129 | // ************************************************************************** // |
1130 | |
1131 | test_suite& |
1132 | current_auto_test_suite( test_suite* ts, bool push_or_pop ) |
1133 | { |
1134 | if( impl::s_frk_state().m_auto_test_suites.empty() ) |
1135 | impl::s_frk_state().m_auto_test_suites.push_back( x: &framework::master_test_suite() ); |
1136 | |
1137 | if( !push_or_pop ) |
1138 | impl::s_frk_state().m_auto_test_suites.pop_back(); |
1139 | else if( ts ) |
1140 | impl::s_frk_state().m_auto_test_suites.push_back( x: ts ); |
1141 | |
1142 | return *impl::s_frk_state().m_auto_test_suites.back(); |
1143 | } |
1144 | |
1145 | //____________________________________________________________________________// |
1146 | |
1147 | // ************************************************************************** // |
1148 | // ************** current_test_case ************** // |
1149 | // ************************************************************************** // |
1150 | |
1151 | test_case const& |
1152 | current_test_case() |
1153 | { |
1154 | return get<test_case>( id: impl::s_frk_state().m_curr_test_case ); |
1155 | } |
1156 | |
1157 | //____________________________________________________________________________// |
1158 | |
1159 | test_unit_id |
1160 | current_test_case_id() |
1161 | { |
1162 | return impl::s_frk_state().m_curr_test_case; |
1163 | } |
1164 | |
1165 | //____________________________________________________________________________// |
1166 | |
1167 | // ************************************************************************** // |
1168 | // ************** framework::get ************** // |
1169 | // ************************************************************************** // |
1170 | |
1171 | test_unit& |
1172 | get( test_unit_id id, test_unit_type t ) |
1173 | { |
1174 | test_unit* res = impl::s_frk_state().m_test_units[id]; |
1175 | |
1176 | BOOST_TEST_I_ASSRT( (res->p_type & t) != 0, internal_error( "Invalid test unit type" ) ); |
1177 | |
1178 | return *res; |
1179 | } |
1180 | |
1181 | //____________________________________________________________________________// |
1182 | |
1183 | // ************************************************************************** // |
1184 | // ************** framework::run ************** // |
1185 | // ************************************************************************** // |
1186 | |
1187 | void |
1188 | run( test_unit_id id, bool continue_test ) |
1189 | { |
1190 | if( id == INV_TEST_UNIT_ID ) |
1191 | id = master_test_suite().p_id; |
1192 | |
1193 | // Figure out run status for execution phase |
1194 | impl::s_frk_state().deduce_run_status( master_tu_id: id ); |
1195 | |
1196 | test_case_counter tcc; |
1197 | traverse_test_tree( id, tcc ); |
1198 | |
1199 | BOOST_TEST_SETUP_ASSERT( tcc.p_count != 0 , runtime_config::get<std::vector<std::string> >( runtime_config::RUN_FILTERS ).empty() |
1200 | ? BOOST_TEST_L( "test tree is empty" ) |
1201 | : BOOST_TEST_L( "no test cases matching filter or all test cases were disabled" ) ); |
1202 | |
1203 | bool was_in_progress = framework::test_in_progress(); |
1204 | bool call_start_finish = !continue_test || !was_in_progress; |
1205 | |
1206 | impl::s_frk_state().m_test_in_progress = true; |
1207 | |
1208 | if( call_start_finish ) { |
1209 | BOOST_TEST_FOREACH( test_observer*, to, impl::s_frk_state().m_observers ) { |
1210 | BOOST_TEST_I_TRY { |
1211 | impl::s_frk_state().m_aux_em.vexecute( F: boost::bind( f: &test_observer::test_start, a1: to, a2: tcc.p_count ) ); |
1212 | } |
1213 | BOOST_TEST_I_CATCH( execution_exception, ex ) { |
1214 | BOOST_TEST_SETUP_ASSERT( false, ex.what() ); |
1215 | } |
1216 | } |
1217 | } |
1218 | |
1219 | unsigned seed = runtime_config::get<unsigned>( parameter_name: runtime_config::RANDOM_SEED ); |
1220 | switch( seed ) { |
1221 | case 0: |
1222 | break; |
1223 | case 1: |
1224 | seed = static_cast<unsigned>( std::time( timer: 0 ) ); |
1225 | default: |
1226 | BOOST_TEST_MESSAGE( "Test cases order is shuffled using seed: " << seed ); |
1227 | std::srand( seed: seed ); |
1228 | } |
1229 | |
1230 | impl::s_frk_state().execute_test_tree( tu_id: id ); |
1231 | |
1232 | if( call_start_finish ) { |
1233 | BOOST_TEST_REVERSE_FOREACH( test_observer*, to, impl::s_frk_state().m_observers ) |
1234 | to->test_finish(); |
1235 | } |
1236 | |
1237 | impl::s_frk_state().m_test_in_progress = was_in_progress; |
1238 | } |
1239 | |
1240 | //____________________________________________________________________________// |
1241 | |
1242 | void |
1243 | run( test_unit const* tu, bool continue_test ) |
1244 | { |
1245 | run( id: tu->p_id, continue_test ); |
1246 | } |
1247 | |
1248 | //____________________________________________________________________________// |
1249 | |
1250 | // ************************************************************************** // |
1251 | // ************** assertion_result ************** // |
1252 | // ************************************************************************** // |
1253 | |
1254 | void |
1255 | assertion_result( unit_test::assertion_result ar ) |
1256 | { |
1257 | BOOST_TEST_FOREACH( test_observer*, to, impl::s_frk_state().m_observers ) |
1258 | to->assertion_result( ar ); |
1259 | } |
1260 | |
1261 | //____________________________________________________________________________// |
1262 | |
1263 | // ************************************************************************** // |
1264 | // ************** exception_caught ************** // |
1265 | // ************************************************************************** // |
1266 | |
1267 | void |
1268 | exception_caught( execution_exception const& ex ) |
1269 | { |
1270 | BOOST_TEST_FOREACH( test_observer*, to, impl::s_frk_state().m_observers ) |
1271 | to->exception_caught( ex ); |
1272 | } |
1273 | |
1274 | //____________________________________________________________________________// |
1275 | |
1276 | // ************************************************************************** // |
1277 | // ************** test_unit_aborted ************** // |
1278 | // ************************************************************************** // |
1279 | |
1280 | void |
1281 | test_unit_aborted( test_unit const& tu ) |
1282 | { |
1283 | BOOST_TEST_FOREACH( test_observer*, to, impl::s_frk_state().m_observers ) |
1284 | to->test_unit_aborted( tu ); |
1285 | } |
1286 | |
1287 | //____________________________________________________________________________// |
1288 | |
1289 | } // namespace framework |
1290 | } // namespace unit_test |
1291 | } // namespace boost |
1292 | |
1293 | #include <boost/test/detail/enable_warnings.hpp> |
1294 | |
1295 | #endif // BOOST_TEST_FRAMEWORK_IPP_021005GER |
1296 | |