Home | History | Annotate | Download | only in impl
      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