1 // (C) Copyright Gennadiy Rozental 2005-2008. 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: 57991 $ 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_suite_impl.hpp> 23 #include <boost/test/unit_test_log.hpp> 24 #include <boost/test/unit_test_monitor.hpp> 25 #include <boost/test/test_observer.hpp> 26 #include <boost/test/results_collector.hpp> 27 #include <boost/test/progress_monitor.hpp> 28 #include <boost/test/results_reporter.hpp> 29 #include <boost/test/test_tools.hpp> 30 31 #include <boost/test/detail/unit_test_parameters.hpp> 32 #include <boost/test/detail/global_typedef.hpp> 33 34 #include <boost/test/utils/foreach.hpp> 35 36 // Boost 37 #include <boost/timer.hpp> 38 39 // STL 40 #include <map> 41 #include <set> 42 #include <cstdlib> 43 #include <ctime> 44 45 #ifdef BOOST_NO_STDC_NAMESPACE 46 namespace std { using ::time; using ::srand; } 47 #endif 48 49 #include <boost/test/detail/suppress_warnings.hpp> 50 51 //____________________________________________________________________________// 52 53 namespace boost { 54 55 namespace unit_test { 56 57 // ************************************************************************** // 58 // ************** test_start calls wrapper ************** // 59 // ************************************************************************** // 60 61 namespace ut_detail { 62 63 struct test_start_caller { 64 test_start_caller( test_observer* to, counter_t tc_amount ) 65 : m_to( to ) 66 , m_tc_amount( tc_amount ) 67 {} 68 69 int operator()() 70 { 71 m_to->test_start( m_tc_amount ); 72 return 0; 73 } 74 75 private: 76 // Data members 77 test_observer* m_to; 78 counter_t m_tc_amount; 79 }; 80 81 //____________________________________________________________________________// 82 83 struct test_init_caller { 84 explicit test_init_caller( init_unit_test_func init_func ) 85 : m_init_func( init_func ) 86 {} 87 int operator()() 88 { 89 #ifdef BOOST_TEST_ALTERNATIVE_INIT_API 90 if( !(*m_init_func)() ) 91 throw std::runtime_error( "test module initialization failed" ); 92 #else 93 test_suite* manual_test_units = (*m_init_func)( framework::master_test_suite().argc, framework::master_test_suite().argv ); 94 95 if( manual_test_units ) 96 framework::master_test_suite().add( manual_test_units ); 97 #endif 98 return 0; 99 } 100 101 // Data members 102 init_unit_test_func m_init_func; 103 }; 104 105 } 106 107 // ************************************************************************** // 108 // ************** framework ************** // 109 // ************************************************************************** // 110 111 class framework_impl : public test_tree_visitor { 112 public: 113 framework_impl() 114 : m_master_test_suite( 0 ) 115 , m_curr_test_case( INV_TEST_UNIT_ID ) 116 , m_next_test_case_id( MIN_TEST_CASE_ID ) 117 , m_next_test_suite_id( MIN_TEST_SUITE_ID ) 118 , m_is_initialized( false ) 119 , m_test_in_progress( false ) 120 {} 121 122 ~framework_impl() { clear(); } 123 124 void clear() 125 { 126 while( !m_test_units.empty() ) { 127 test_unit_store::value_type const& tu = *m_test_units.begin(); 128 test_unit* tu_ptr = tu.second; 129 130 // the delete will erase this element from map 131 if( ut_detail::test_id_2_unit_type( tu.second->p_id ) == tut_suite ) 132 delete (test_suite const*)tu_ptr; 133 else 134 delete (test_case const*)tu_ptr; 135 } 136 } 137 138 void set_tu_id( test_unit& tu, test_unit_id id ) { tu.p_id.value = id; } 139 140 // test_tree_visitor interface implementation 141 void visit( test_case const& tc ) 142 { 143 if( !tc.check_dependencies() ) { 144 BOOST_TEST_FOREACH( test_observer*, to, m_observers ) 145 to->test_unit_skipped( tc ); 146 147 return; 148 } 149 150 BOOST_TEST_FOREACH( test_observer*, to, m_observers ) 151 to->test_unit_start( tc ); 152 153 boost::timer tc_timer; 154 test_unit_id bkup = m_curr_test_case; 155 m_curr_test_case = tc.p_id; 156 unit_test_monitor_t::error_level run_result = unit_test_monitor.execute_and_translate( tc ); 157 158 unsigned long elapsed = static_cast<unsigned long>( tc_timer.elapsed() * 1e6 ); 159 160 if( unit_test_monitor.is_critical_error( run_result ) ) { 161 BOOST_TEST_FOREACH( test_observer*, to, m_observers ) 162 to->test_aborted(); 163 } 164 165 BOOST_TEST_FOREACH( test_observer*, to, m_observers ) 166 to->test_unit_finish( tc, elapsed ); 167 168 m_curr_test_case = bkup; 169 170 if( unit_test_monitor.is_critical_error( run_result ) ) 171 throw test_being_aborted(); 172 } 173 174 bool test_suite_start( test_suite const& ts ) 175 { 176 if( !ts.check_dependencies() ) { 177 BOOST_TEST_FOREACH( test_observer*, to, m_observers ) 178 to->test_unit_skipped( ts ); 179 180 return false; 181 } 182 183 BOOST_TEST_FOREACH( test_observer*, to, m_observers ) 184 to->test_unit_start( ts ); 185 186 return true; 187 } 188 189 void test_suite_finish( test_suite const& ts ) 190 { 191 BOOST_TEST_FOREACH( test_observer*, to, m_observers ) 192 to->test_unit_finish( ts, 0 ); 193 } 194 195 ////////////////////////////////////////////////////////////////// 196 struct priority_order { 197 bool operator()( test_observer* lhs, test_observer* rhs ) const 198 { 199 return (lhs->priority() < rhs->priority()) || ((lhs->priority() == rhs->priority()) && (lhs < rhs)); 200 } 201 }; 202 203 typedef std::map<test_unit_id,test_unit*> test_unit_store; 204 typedef std::set<test_observer*,priority_order> observer_store; 205 206 master_test_suite_t* m_master_test_suite; 207 test_unit_id m_curr_test_case; 208 test_unit_store m_test_units; 209 210 test_unit_id m_next_test_case_id; 211 test_unit_id m_next_test_suite_id; 212 213 bool m_is_initialized; 214 bool m_test_in_progress; 215 216 observer_store m_observers; 217 }; 218 219 //____________________________________________________________________________// 220 221 namespace { 222 223 #if defined(__CYGWIN__) 224 framework_impl& s_frk_impl() { static framework_impl* the_inst = 0; if(!the_inst) the_inst = new framework_impl; return *the_inst; } 225 #else 226 framework_impl& s_frk_impl() { static framework_impl the_inst; return the_inst; } 227 #endif 228 229 } // local namespace 230 231 //____________________________________________________________________________// 232 233 namespace framework { 234 235 void 236 init( init_unit_test_func init_func, int argc, char* argv[] ) 237 { 238 runtime_config::init( argc, argv ); 239 240 // set the log level and format 241 unit_test_log.set_threshold_level( runtime_config::log_level() ); 242 unit_test_log.set_format( runtime_config::log_format() ); 243 244 // set the report level and format 245 results_reporter::set_level( runtime_config::report_level() ); 246 results_reporter::set_format( runtime_config::report_format() ); 247 248 register_observer( results_collector ); 249 register_observer( unit_test_log ); 250 251 if( runtime_config::show_progress() ) 252 register_observer( progress_monitor ); 253 254 if( runtime_config::detect_memory_leaks() > 0 ) { 255 debug::detect_memory_leaks( true ); 256 debug::break_memory_alloc( runtime_config::detect_memory_leaks() ); 257 } 258 259 // init master unit test suite 260 master_test_suite().argc = argc; 261 master_test_suite().argv = argv; 262 263 try { 264 boost::execution_monitor em; 265 266 ut_detail::test_init_caller tic( init_func ); 267 268 em.execute( tic ); 269 } 270 catch( execution_exception const& ex ) { 271 throw setup_error( ex.what() ); 272 } 273 274 s_frk_impl().m_is_initialized = true; 275 } 276 277 //____________________________________________________________________________// 278 279 bool 280 is_initialized() 281 { 282 return s_frk_impl().m_is_initialized; 283 } 284 285 //____________________________________________________________________________// 286 287 void 288 register_test_unit( test_case* tc ) 289 { 290 BOOST_TEST_SETUP_ASSERT( tc->p_id == INV_TEST_UNIT_ID, BOOST_TEST_L( "test case already registered" ) ); 291 292 test_unit_id new_id = s_frk_impl().m_next_test_case_id; 293 294 BOOST_TEST_SETUP_ASSERT( new_id != MAX_TEST_CASE_ID, BOOST_TEST_L( "too many test cases" ) ); 295 296 typedef framework_impl::test_unit_store::value_type map_value_type; 297 298 s_frk_impl().m_test_units.insert( map_value_type( new_id, tc ) ); 299 s_frk_impl().m_next_test_case_id++; 300 301 s_frk_impl().set_tu_id( *tc, new_id ); 302 } 303 304 //____________________________________________________________________________// 305 306 void 307 register_test_unit( test_suite* ts ) 308 { 309 BOOST_TEST_SETUP_ASSERT( ts->p_id == INV_TEST_UNIT_ID, BOOST_TEST_L( "test suite already registered" ) ); 310 311 test_unit_id new_id = s_frk_impl().m_next_test_suite_id; 312 313 BOOST_TEST_SETUP_ASSERT( new_id != MAX_TEST_SUITE_ID, BOOST_TEST_L( "too many test suites" ) ); 314 315 typedef framework_impl::test_unit_store::value_type map_value_type; 316 s_frk_impl().m_test_units.insert( map_value_type( new_id, ts ) ); 317 s_frk_impl().m_next_test_suite_id++; 318 319 s_frk_impl().set_tu_id( *ts, new_id ); 320 } 321 322 //____________________________________________________________________________// 323 324 void 325 deregister_test_unit( test_unit* tu ) 326 { 327 s_frk_impl().m_test_units.erase( tu->p_id ); 328 } 329 330 //____________________________________________________________________________// 331 332 void 333 clear() 334 { 335 s_frk_impl().clear(); 336 } 337 338 //____________________________________________________________________________// 339 340 void 341 register_observer( test_observer& to ) 342 { 343 s_frk_impl().m_observers.insert( &to ); 344 } 345 346 //____________________________________________________________________________// 347 348 void 349 deregister_observer( test_observer& to ) 350 { 351 s_frk_impl().m_observers.erase( &to ); 352 } 353 354 //____________________________________________________________________________// 355 356 void 357 reset_observers() 358 { 359 s_frk_impl().m_observers.clear(); 360 } 361 362 //____________________________________________________________________________// 363 364 master_test_suite_t& 365 master_test_suite() 366 { 367 if( !s_frk_impl().m_master_test_suite ) 368 s_frk_impl().m_master_test_suite = new master_test_suite_t; 369 370 return *s_frk_impl().m_master_test_suite; 371 } 372 373 //____________________________________________________________________________// 374 375 test_case const& 376 current_test_case() 377 { 378 return get<test_case>( s_frk_impl().m_curr_test_case ); 379 } 380 381 //____________________________________________________________________________// 382 383 test_unit& 384 get( test_unit_id id, test_unit_type t ) 385 { 386 test_unit* res = s_frk_impl().m_test_units[id]; 387 388 if( (res->p_type & t) == 0 ) 389 throw internal_error( "Invalid test unit type" ); 390 391 return *res; 392 } 393 394 //____________________________________________________________________________// 395 396 void 397 run( test_unit_id id, bool continue_test ) 398 { 399 if( id == INV_TEST_UNIT_ID ) 400 id = master_test_suite().p_id; 401 402 test_case_counter tcc; 403 traverse_test_tree( id, tcc ); 404 405 BOOST_TEST_SETUP_ASSERT( tcc.p_count != 0 , runtime_config::test_to_run().is_empty() 406 ? BOOST_TEST_L( "test tree is empty" ) 407 : BOOST_TEST_L( "no test cases matching filter" ) ); 408 409 bool call_start_finish = !continue_test || !s_frk_impl().m_test_in_progress; 410 bool was_in_progress = s_frk_impl().m_test_in_progress; 411 412 s_frk_impl().m_test_in_progress = true; 413 414 if( call_start_finish ) { 415 BOOST_TEST_FOREACH( test_observer*, to, s_frk_impl().m_observers ) { 416 boost::execution_monitor em; 417 418 try { 419 em.execute( ut_detail::test_start_caller( to, tcc.p_count ) ); 420 } 421 catch( execution_exception const& ex ) { 422 throw setup_error( ex.what() ); 423 } 424 } 425 } 426 427 switch( runtime_config::random_seed() ) { 428 case 0: 429 break; 430 case 1: { 431 unsigned int seed = static_cast<unsigned int>( std::time( 0 ) ); 432 BOOST_TEST_MESSAGE( "Test cases order is shuffled using seed: " << seed ); 433 std::srand( seed ); 434 break; 435 } 436 default: 437 BOOST_TEST_MESSAGE( "Test cases order is shuffled using seed: " << runtime_config::random_seed() ); 438 std::srand( runtime_config::random_seed() ); 439 } 440 441 try { 442 traverse_test_tree( id, s_frk_impl() ); 443 } 444 catch( test_being_aborted const& ) { 445 // abort already reported 446 } 447 448 if( call_start_finish ) { 449 BOOST_TEST_FOREACH( test_observer*, to, s_frk_impl().m_observers ) 450 to->test_finish(); 451 } 452 453 s_frk_impl().m_test_in_progress = was_in_progress; 454 } 455 456 //____________________________________________________________________________// 457 458 void 459 run( test_unit const* tu, bool continue_test ) 460 { 461 run( tu->p_id, continue_test ); 462 } 463 464 //____________________________________________________________________________// 465 466 void 467 assertion_result( bool passed ) 468 { 469 BOOST_TEST_FOREACH( test_observer*, to, s_frk_impl().m_observers ) 470 to->assertion_result( passed ); 471 } 472 473 //____________________________________________________________________________// 474 475 void 476 exception_caught( execution_exception const& ex ) 477 { 478 BOOST_TEST_FOREACH( test_observer*, to, s_frk_impl().m_observers ) 479 to->exception_caught( ex ); 480 } 481 482 //____________________________________________________________________________// 483 484 void 485 test_unit_aborted( test_unit const& tu ) 486 { 487 BOOST_TEST_FOREACH( test_observer*, to, s_frk_impl().m_observers ) 488 to->test_unit_aborted( tu ); 489 } 490 491 //____________________________________________________________________________// 492 493 } // namespace framework 494 495 } // namespace unit_test 496 497 } // namespace boost 498 499 //____________________________________________________________________________// 500 501 #include <boost/test/detail/enable_warnings.hpp> 502 503 #endif // BOOST_TEST_FRAMEWORK_IPP_021005GER 504