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 46namespace std { using ::time; using ::srand; } 47#endif 48 49#include <boost/test/detail/suppress_warnings.hpp> 50 51//____________________________________________________________________________// 52 53namespace boost { 54 55namespace unit_test { 56 57// ************************************************************************** // 58// ************** test_start calls wrapper ************** // 59// ************************************************************************** // 60 61namespace ut_detail { 62 63struct 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 75private: 76 // Data members 77 test_observer* m_to; 78 counter_t m_tc_amount; 79}; 80 81//____________________________________________________________________________// 82 83struct 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 111class framework_impl : public test_tree_visitor { 112public: 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 221namespace { 222 223#if defined(__CYGWIN__) 224framework_impl& s_frk_impl() { static framework_impl* the_inst = 0; if(!the_inst) the_inst = new framework_impl; return *the_inst; } 225#else 226framework_impl& s_frk_impl() { static framework_impl the_inst; return the_inst; } 227#endif 228 229} // local namespace 230 231//____________________________________________________________________________// 232 233namespace framework { 234 235void 236init( 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 279bool 280is_initialized() 281{ 282 return s_frk_impl().m_is_initialized; 283} 284 285//____________________________________________________________________________// 286 287void 288register_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 306void 307register_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 324void 325deregister_test_unit( test_unit* tu ) 326{ 327 s_frk_impl().m_test_units.erase( tu->p_id ); 328} 329 330//____________________________________________________________________________// 331 332void 333clear() 334{ 335 s_frk_impl().clear(); 336} 337 338//____________________________________________________________________________// 339 340void 341register_observer( test_observer& to ) 342{ 343 s_frk_impl().m_observers.insert( &to ); 344} 345 346//____________________________________________________________________________// 347 348void 349deregister_observer( test_observer& to ) 350{ 351 s_frk_impl().m_observers.erase( &to ); 352} 353 354//____________________________________________________________________________// 355 356void 357reset_observers() 358{ 359 s_frk_impl().m_observers.clear(); 360} 361 362//____________________________________________________________________________// 363 364master_test_suite_t& 365master_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 375test_case const& 376current_test_case() 377{ 378 return get<test_case>( s_frk_impl().m_curr_test_case ); 379} 380 381//____________________________________________________________________________// 382 383test_unit& 384get( 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 396void 397run( 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 458void 459run( test_unit const* tu, bool continue_test ) 460{ 461 run( tu->p_id, continue_test ); 462} 463 464//____________________________________________________________________________// 465 466void 467assertion_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 475void 476exception_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 484void 485test_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