| 1 | // (C) Copyright Gennadiy Rozental 2001. |
| 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 |
| 9 | /// Test results collecting facility. |
| 10 | /// |
| 11 | // *************************************************************************** |
| 12 | |
| 13 | #ifndef BOOST_TEST_RESULTS_COLLECTOR_IPP_021105GER |
| 14 | #define BOOST_TEST_RESULTS_COLLECTOR_IPP_021105GER |
| 15 | |
| 16 | // Boost.Test |
| 17 | #include <boost/test/unit_test_log.hpp> |
| 18 | #include <boost/test/results_collector.hpp> |
| 19 | #include <boost/test/framework.hpp> |
| 20 | #include <boost/test/execution_monitor.hpp> |
| 21 | |
| 22 | #include <boost/test/tree/test_unit.hpp> |
| 23 | #include <boost/test/tree/visitor.hpp> |
| 24 | #include <boost/test/tree/test_case_counter.hpp> |
| 25 | #include <boost/test/tree/traverse.hpp> |
| 26 | |
| 27 | // Boost |
| 28 | #include <boost/cstdlib.hpp> |
| 29 | |
| 30 | // STL |
| 31 | #include <map> |
| 32 | |
| 33 | #include <boost/test/detail/suppress_warnings.hpp> |
| 34 | |
| 35 | //____________________________________________________________________________// |
| 36 | |
| 37 | namespace boost { |
| 38 | namespace unit_test { |
| 39 | |
| 40 | // ************************************************************************** // |
| 41 | // ************** test_results ************** // |
| 42 | // ************************************************************************** // |
| 43 | |
| 44 | test_results::test_results() |
| 45 | { |
| 46 | clear(); |
| 47 | } |
| 48 | |
| 49 | //____________________________________________________________________________// |
| 50 | |
| 51 | bool |
| 52 | test_results::passed() const |
| 53 | { |
| 54 | // if it is skipped, it is not passed. However, if any children is not failed/aborted |
| 55 | // then their skipped status is not taken into account. |
| 56 | return !p_skipped && |
| 57 | p_test_cases_failed == 0 && |
| 58 | p_assertions_failed <= p_expected_failures && |
| 59 | // p_test_cases_skipped == 0 && |
| 60 | !p_timed_out && |
| 61 | p_test_cases_timed_out == 0 && |
| 62 | !aborted(); |
| 63 | } |
| 64 | |
| 65 | //____________________________________________________________________________// |
| 66 | |
| 67 | bool |
| 68 | test_results::aborted() const |
| 69 | { |
| 70 | return p_aborted; |
| 71 | } |
| 72 | |
| 73 | //____________________________________________________________________________// |
| 74 | |
| 75 | bool |
| 76 | test_results::skipped() const |
| 77 | { |
| 78 | return p_skipped; |
| 79 | } |
| 80 | |
| 81 | //____________________________________________________________________________// |
| 82 | |
| 83 | int |
| 84 | test_results::result_code() const |
| 85 | { |
| 86 | return passed() ? exit_success |
| 87 | : ( (p_assertions_failed > p_expected_failures || p_skipped || p_timed_out || p_test_cases_timed_out ) |
| 88 | ? exit_test_failure |
| 89 | : exit_exception_failure ); |
| 90 | } |
| 91 | |
| 92 | //____________________________________________________________________________// |
| 93 | |
| 94 | void |
| 95 | test_results::operator+=( test_results const& tr ) |
| 96 | { |
| 97 | p_test_suites.value += tr.p_test_suites; |
| 98 | p_assertions_passed.value += tr.p_assertions_passed; |
| 99 | p_assertions_failed.value += tr.p_assertions_failed; |
| 100 | p_warnings_failed.value += tr.p_warnings_failed; |
| 101 | p_test_cases_passed.value += tr.p_test_cases_passed; |
| 102 | p_test_cases_warned.value += tr.p_test_cases_warned; |
| 103 | p_test_cases_failed.value += tr.p_test_cases_failed; |
| 104 | p_test_cases_skipped.value += tr.p_test_cases_skipped; |
| 105 | p_test_cases_aborted.value += tr.p_test_cases_aborted; |
| 106 | p_test_cases_timed_out.value += tr.p_test_cases_timed_out; |
| 107 | p_test_suites_timed_out.value += tr.p_test_suites_timed_out; |
| 108 | p_duration_microseconds.value += tr.p_duration_microseconds; |
| 109 | } |
| 110 | |
| 111 | //____________________________________________________________________________// |
| 112 | |
| 113 | void |
| 114 | test_results::clear() |
| 115 | { |
| 116 | p_test_suites.value = 0; |
| 117 | p_assertions_passed.value = 0; |
| 118 | p_assertions_failed.value = 0; |
| 119 | p_warnings_failed.value = 0; |
| 120 | p_expected_failures.value = 0; |
| 121 | p_test_cases_passed.value = 0; |
| 122 | p_test_cases_warned.value = 0; |
| 123 | p_test_cases_failed.value = 0; |
| 124 | p_test_cases_skipped.value = 0; |
| 125 | p_test_cases_aborted.value = 0; |
| 126 | p_test_cases_timed_out.value = 0; |
| 127 | p_test_suites_timed_out.value = 0; |
| 128 | p_duration_microseconds.value= 0; |
| 129 | p_aborted.value = false; |
| 130 | p_skipped.value = false; |
| 131 | p_timed_out.value = false; |
| 132 | } |
| 133 | |
| 134 | //____________________________________________________________________________// |
| 135 | |
| 136 | // ************************************************************************** // |
| 137 | // ************** results_collector ************** // |
| 138 | // ************************************************************************** // |
| 139 | |
| 140 | namespace { |
| 141 | |
| 142 | struct results_collector_impl { |
| 143 | std::map<test_unit_id,test_results> m_results_store; |
| 144 | }; |
| 145 | |
| 146 | results_collector_impl& s_rc_impl() { static results_collector_impl the_inst; return the_inst; } |
| 147 | |
| 148 | // deletes the entries of results_collector_impl |
| 149 | class clear_subtree_result : public test_tree_visitor { |
| 150 | public: |
| 151 | clear_subtree_result(results_collector_impl& store) |
| 152 | : m_store( store ) |
| 153 | {} |
| 154 | |
| 155 | private: |
| 156 | bool visit( test_unit const& tu) BOOST_OVERRIDE |
| 157 | { |
| 158 | typedef std::map<test_unit_id,test_results>::iterator iterator; |
| 159 | iterator found = m_store.m_results_store.find(x: tu.p_id); |
| 160 | if(found != m_store.m_results_store.end()) { |
| 161 | m_store.m_results_store.erase( position: found ); |
| 162 | } |
| 163 | return true; |
| 164 | } |
| 165 | |
| 166 | results_collector_impl& m_store; |
| 167 | }; |
| 168 | |
| 169 | } // local namespace |
| 170 | |
| 171 | //____________________________________________________________________________// |
| 172 | |
| 173 | BOOST_TEST_SINGLETON_CONS_IMPL( results_collector_t ) |
| 174 | |
| 175 | //____________________________________________________________________________// |
| 176 | |
| 177 | void |
| 178 | results_collector_t::test_start( counter_t, test_unit_id id ) |
| 179 | { |
| 180 | // deletes the results under id only |
| 181 | clear_subtree_result tree_clear(s_rc_impl()); |
| 182 | traverse_test_tree( id, tree_clear ); |
| 183 | } |
| 184 | |
| 185 | //____________________________________________________________________________// |
| 186 | |
| 187 | void |
| 188 | results_collector_t::test_unit_start( test_unit const& tu ) |
| 189 | { |
| 190 | // init test_results entry |
| 191 | test_results& tr = s_rc_impl().m_results_store[tu.p_id]; |
| 192 | |
| 193 | tr.clear(); |
| 194 | |
| 195 | tr.p_expected_failures.value = tu.p_expected_failures; |
| 196 | } |
| 197 | |
| 198 | //____________________________________________________________________________// |
| 199 | |
| 200 | class results_collect_helper : public test_tree_visitor { |
| 201 | public: |
| 202 | explicit results_collect_helper( test_results& tr, test_unit const& ts ) : m_tr( tr ), m_ts( ts ) {} |
| 203 | |
| 204 | void visit( test_case const& tc ) BOOST_OVERRIDE |
| 205 | { |
| 206 | test_results const& tr = results_collector.results( tu_id: tc.p_id ); |
| 207 | m_tr += tr; |
| 208 | |
| 209 | if( tr.passed() ) { |
| 210 | if( tr.p_warnings_failed ) |
| 211 | m_tr.p_test_cases_warned.value++; |
| 212 | else |
| 213 | m_tr.p_test_cases_passed.value++; |
| 214 | } |
| 215 | else if( tr.p_timed_out ) { |
| 216 | m_tr.p_test_cases_timed_out.value++; |
| 217 | } |
| 218 | else if( tr.p_skipped || !tc.is_enabled() ) { |
| 219 | m_tr.p_test_cases_skipped.value++; |
| 220 | } |
| 221 | else { |
| 222 | if( tr.p_aborted ) |
| 223 | m_tr.p_test_cases_aborted.value++; |
| 224 | |
| 225 | m_tr.p_test_cases_failed.value++; |
| 226 | } |
| 227 | } |
| 228 | bool test_suite_start( test_suite const& ts ) BOOST_OVERRIDE |
| 229 | { |
| 230 | if( m_ts.p_id == ts.p_id ) |
| 231 | return true; |
| 232 | |
| 233 | m_tr += results_collector.results( tu_id: ts.p_id ); |
| 234 | m_tr.p_test_suites.value++; |
| 235 | |
| 236 | if( results_collector.results( tu_id: ts.p_id ).p_timed_out ) |
| 237 | m_tr.p_test_suites_timed_out.value++; |
| 238 | return false; |
| 239 | } |
| 240 | |
| 241 | private: |
| 242 | // Data members |
| 243 | test_results& m_tr; |
| 244 | test_unit const& m_ts; |
| 245 | }; |
| 246 | |
| 247 | //____________________________________________________________________________// |
| 248 | |
| 249 | void |
| 250 | results_collector_t::test_unit_finish( test_unit const& tu, unsigned long elapsed_in_microseconds ) |
| 251 | { |
| 252 | test_results & tr = s_rc_impl().m_results_store[tu.p_id]; |
| 253 | if( tu.p_type == TUT_SUITE ) { |
| 254 | results_collect_helper ch( tr, tu ); |
| 255 | traverse_test_tree( tu, V&: ch, ignore_status: true ); // true to ignore the status: we need to count the skipped/disabled tests |
| 256 | } |
| 257 | else { |
| 258 | bool num_failures_match = tr.p_aborted || tr.p_assertions_failed >= tr.p_expected_failures; |
| 259 | if( !num_failures_match ) |
| 260 | BOOST_TEST_FRAMEWORK_MESSAGE( "Test case " << tu.full_name() << " has fewer failures than expected" ); |
| 261 | |
| 262 | bool check_any_assertions = tr.p_aborted || (tr.p_assertions_failed != 0) || (tr.p_assertions_passed != 0); |
| 263 | if( !check_any_assertions ) |
| 264 | BOOST_TEST_FRAMEWORK_MESSAGE( "Test case " << tu.full_name() << " did not check any assertions" ); |
| 265 | } |
| 266 | tr.p_duration_microseconds.value = elapsed_in_microseconds; |
| 267 | } |
| 268 | |
| 269 | //____________________________________________________________________________// |
| 270 | |
| 271 | void |
| 272 | results_collector_t::test_unit_skipped( test_unit const& tu, const_string /*reason*/ ) |
| 273 | { |
| 274 | test_results& tr = s_rc_impl().m_results_store[tu.p_id]; |
| 275 | tr.clear(); |
| 276 | |
| 277 | tr.p_skipped.value = true; |
| 278 | |
| 279 | if( tu.p_type == TUT_SUITE ) { |
| 280 | test_case_counter tcc(true); |
| 281 | traverse_test_tree( tu, V&: tcc, ignore_status: true ); // true because need to count the disabled tests/units |
| 282 | |
| 283 | tr.p_test_cases_skipped.value = tcc.p_count; |
| 284 | } |
| 285 | } |
| 286 | |
| 287 | //____________________________________________________________________________// |
| 288 | |
| 289 | void |
| 290 | results_collector_t::test_unit_timed_out(test_unit const& tu) |
| 291 | { |
| 292 | test_results& tr = s_rc_impl().m_results_store[tu.p_id]; |
| 293 | tr.p_timed_out.value = true; |
| 294 | } |
| 295 | |
| 296 | //____________________________________________________________________________// |
| 297 | |
| 298 | void |
| 299 | results_collector_t::assertion_result( unit_test::assertion_result ar ) |
| 300 | { |
| 301 | test_results& tr = s_rc_impl().m_results_store[framework::current_test_case_id()]; |
| 302 | |
| 303 | switch( ar ) { |
| 304 | case AR_PASSED: tr.p_assertions_passed.value++; break; |
| 305 | case AR_FAILED: tr.p_assertions_failed.value++; break; |
| 306 | case AR_TRIGGERED: tr.p_warnings_failed.value++; break; |
| 307 | } |
| 308 | |
| 309 | if( tr.p_assertions_failed == 1 ) |
| 310 | first_failed_assertion(); |
| 311 | } |
| 312 | |
| 313 | //____________________________________________________________________________// |
| 314 | |
| 315 | void |
| 316 | results_collector_t::exception_caught( execution_exception const& ex) |
| 317 | { |
| 318 | test_results& tr = s_rc_impl().m_results_store[framework::current_test_case_id()]; |
| 319 | |
| 320 | tr.p_assertions_failed.value++; |
| 321 | if( ex.code() == execution_exception::timeout_error ) { |
| 322 | tr.p_timed_out.value = true; |
| 323 | } |
| 324 | } |
| 325 | |
| 326 | //____________________________________________________________________________// |
| 327 | |
| 328 | void |
| 329 | results_collector_t::test_unit_aborted( test_unit const& tu ) |
| 330 | { |
| 331 | s_rc_impl().m_results_store[tu.p_id].p_aborted.value = true; |
| 332 | } |
| 333 | |
| 334 | //____________________________________________________________________________// |
| 335 | |
| 336 | test_results const& |
| 337 | results_collector_t::results( test_unit_id id ) const |
| 338 | { |
| 339 | return s_rc_impl().m_results_store[id]; |
| 340 | } |
| 341 | |
| 342 | //____________________________________________________________________________// |
| 343 | |
| 344 | } // namespace unit_test |
| 345 | } // namespace boost |
| 346 | |
| 347 | #include <boost/test/detail/enable_warnings.hpp> |
| 348 | |
| 349 | #endif // BOOST_TEST_RESULTS_COLLECTOR_IPP_021105GER |
| 350 | |