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