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: 57992 $
11//
12//  Description : implements Unit Test results collecting facility.
13// ***************************************************************************
14
15#ifndef BOOST_TEST_RESULTS_COLLECTOR_IPP_021105GER
16#define BOOST_TEST_RESULTS_COLLECTOR_IPP_021105GER
17
18// Boost.Test
19#include <boost/test/unit_test_suite_impl.hpp>
20#include <boost/test/unit_test_log.hpp>
21#include <boost/test/results_collector.hpp>
22#include <boost/test/framework.hpp>
23
24// Boost
25#include <boost/cstdlib.hpp>
26
27// STL
28#include <map>
29
30#include <boost/test/detail/suppress_warnings.hpp>
31
32//____________________________________________________________________________//
33
34namespace boost {
35
36namespace unit_test {
37
38// ************************************************************************** //
39// **************                 test_results                 ************** //
40// ************************************************************************** //
41
42test_results::test_results()
43{
44    clear();
45}
46
47//____________________________________________________________________________//
48
49bool
50test_results::passed() const
51{
52    return  !p_skipped                                  &&
53            p_test_cases_failed == 0                    &&
54            p_assertions_failed <= p_expected_failures  &&
55            !p_aborted;
56}
57
58//____________________________________________________________________________//
59
60int
61test_results::result_code() const
62{
63    return passed() ? exit_success
64           : ( (p_assertions_failed > p_expected_failures || p_skipped )
65                    ? exit_test_failure
66                    : exit_exception_failure );
67}
68
69//____________________________________________________________________________//
70
71void
72test_results::operator+=( test_results const& tr )
73{
74    p_assertions_passed.value   += tr.p_assertions_passed;
75    p_assertions_failed.value   += tr.p_assertions_failed;
76    p_test_cases_passed.value   += tr.p_test_cases_passed;
77    p_test_cases_failed.value   += tr.p_test_cases_failed;
78    p_test_cases_skipped.value  += tr.p_test_cases_skipped;
79    p_test_cases_aborted.value  += tr.p_test_cases_aborted;
80}
81
82//____________________________________________________________________________//
83
84void
85test_results::clear()
86{
87    p_assertions_passed.value    = 0;
88    p_assertions_failed.value    = 0;
89    p_expected_failures.value    = 0;
90    p_test_cases_passed.value    = 0;
91    p_test_cases_failed.value    = 0;
92    p_test_cases_skipped.value   = 0;
93    p_test_cases_aborted.value   = 0;
94    p_aborted.value              = false;
95    p_skipped.value              = true;
96}
97
98//____________________________________________________________________________//
99
100// ************************************************************************** //
101// **************               results_collector              ************** //
102// ************************************************************************** //
103
104#if !BOOST_WORKAROUND(BOOST_MSVC, <1300)
105
106namespace {
107
108struct results_collector_impl {
109    std::map<test_unit_id,test_results> m_results_store;
110};
111
112results_collector_impl& s_rc_impl() { static results_collector_impl the_inst; return the_inst; }
113
114} // local namespace
115
116#else
117
118struct results_collector_impl {
119    std::map<test_unit_id,test_results> m_results_store;
120};
121
122static results_collector_impl& s_rc_impl() { static results_collector_impl the_inst; return the_inst; }
123
124#endif
125
126//____________________________________________________________________________//
127
128void
129results_collector_t::test_start( counter_t )
130{
131    s_rc_impl().m_results_store.clear();
132}
133
134//____________________________________________________________________________//
135
136void
137results_collector_t::test_finish()
138{
139    // do nothing
140}
141
142//____________________________________________________________________________//
143
144void
145results_collector_t::test_aborted()
146{
147    // do nothing
148}
149
150//____________________________________________________________________________//
151
152void
153results_collector_t::test_unit_start( test_unit const& tu )
154{
155    // init test_results entry
156    test_results& tr = s_rc_impl().m_results_store[tu.p_id];
157
158    tr.clear();
159
160    tr.p_expected_failures.value    = tu.p_expected_failures;
161    tr.p_skipped.value              = false;
162}
163
164//____________________________________________________________________________//
165
166class results_collect_helper : public test_tree_visitor {
167public:
168    explicit results_collect_helper( test_results& tr, test_unit const& ts ) : m_tr( tr ), m_ts( ts ) {}
169
170    void    visit( test_case const& tc )
171    {
172        test_results const& tr = results_collector.results( tc.p_id );
173        m_tr += tr;
174
175        if( tr.passed() )
176            m_tr.p_test_cases_passed.value++;
177        else if( tr.p_skipped )
178            m_tr.p_test_cases_skipped.value++;
179        else {
180            if( tr.p_aborted )
181                m_tr.p_test_cases_aborted.value++;
182            m_tr.p_test_cases_failed.value++;
183        }
184    }
185    bool    test_suite_start( test_suite const& ts )
186    {
187        if( m_ts.p_id == ts.p_id )
188            return true;
189        else {
190            m_tr += results_collector.results( ts.p_id );
191            return false;
192        }
193    }
194
195private:
196    // Data members
197    test_results&       m_tr;
198    test_unit const&    m_ts;
199};
200
201//____________________________________________________________________________//
202
203void
204results_collector_t::test_unit_finish( test_unit const& tu, unsigned long )
205{
206    if( tu.p_type == tut_suite ) {
207        results_collect_helper ch( s_rc_impl().m_results_store[tu.p_id], tu );
208
209        traverse_test_tree( tu, ch );
210    }
211    else {
212        test_results const& tr = s_rc_impl().m_results_store[tu.p_id];
213
214        bool num_failures_match = tr.p_aborted || tr.p_assertions_failed >= tr.p_expected_failures;
215        if( !num_failures_match )
216            BOOST_TEST_MESSAGE( "Test case " << tu.p_name << " has fewer failures than expected" );
217
218        bool check_any_assertions = tr.p_aborted || (tr.p_assertions_failed != 0) || (tr.p_assertions_passed != 0);
219        if( !check_any_assertions )
220            BOOST_TEST_MESSAGE( "Test case " << tu.p_name << " did not check any assertions" );
221    }
222}
223
224//____________________________________________________________________________//
225
226void
227results_collector_t::test_unit_skipped( test_unit const& tu )
228{
229    if( tu.p_type == tut_suite ) {
230        test_case_counter tcc;
231        traverse_test_tree( tu, tcc );
232
233        test_results& tr = s_rc_impl().m_results_store[tu.p_id];
234
235        tr.clear();
236
237        tr.p_skipped.value              = true;
238        tr.p_test_cases_skipped.value   = tcc.p_count;
239    }
240}
241
242//____________________________________________________________________________//
243
244void
245results_collector_t::assertion_result( bool passed )
246{
247    test_results& tr = s_rc_impl().m_results_store[framework::current_test_case().p_id];
248
249    if( passed )
250        tr.p_assertions_passed.value++;
251    else
252        tr.p_assertions_failed.value++;
253
254    if( tr.p_assertions_failed == 1 )
255        first_failed_assertion();
256}
257
258//____________________________________________________________________________//
259
260void
261results_collector_t::exception_caught( execution_exception const& )
262{
263    test_results& tr = s_rc_impl().m_results_store[framework::current_test_case().p_id];
264
265    tr.p_assertions_failed.value++;
266}
267
268//____________________________________________________________________________//
269
270void
271results_collector_t::test_unit_aborted( test_unit const& tu )
272{
273    s_rc_impl().m_results_store[tu.p_id].p_aborted.value = true;
274}
275
276//____________________________________________________________________________//
277
278test_results const&
279results_collector_t::results( test_unit_id id ) const
280{
281    return s_rc_impl().m_results_store[id];
282}
283
284//____________________________________________________________________________//
285
286} // namespace unit_test
287
288} // namespace boost
289
290//____________________________________________________________________________//
291
292#include <boost/test/detail/enable_warnings.hpp>
293
294#endif // BOOST_TEST_RESULTS_COLLECTOR_IPP_021105GER
295