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