Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2025-01-30 10:00:59

0001 //  (C) Copyright 2016 Raffi Enficiaud.
0002 //  Distributed under the Boost Software License, Version 1.0.
0003 //  (See accompanying file LICENSE_1_0.txt or copy at
0004 //  http://www.boost.org/LICENSE_1_0.txt)
0005 
0006 //  See http://www.boost.org/libs/test for the library home page.
0007 //
0008 ///@file
0009 ///@brief Contains the implementatoin of the Junit log formatter (OF_JUNIT)
0010 // ***************************************************************************
0011 
0012 #ifndef BOOST_TEST_JUNIT_LOG_FORMATTER_IPP__
0013 #define BOOST_TEST_JUNIT_LOG_FORMATTER_IPP__
0014 
0015 // Boost.Test
0016 #include <boost/test/output/junit_log_formatter.hpp>
0017 #include <boost/test/execution_monitor.hpp>
0018 #include <boost/test/framework.hpp>
0019 #include <boost/test/tree/test_unit.hpp>
0020 #include <boost/test/utils/basic_cstring/io.hpp>
0021 #include <boost/test/utils/xml_printer.hpp>
0022 #include <boost/test/utils/string_cast.hpp>
0023 #include <boost/test/framework.hpp>
0024 
0025 #include <boost/test/tree/visitor.hpp>
0026 #include <boost/test/tree/traverse.hpp>
0027 #include <boost/test/results_collector.hpp>
0028 
0029 #include <boost/test/utils/algorithm.hpp>
0030 #include <boost/test/utils/string_cast.hpp>
0031 
0032 //#include <boost/test/results_reporter.hpp>
0033 
0034 
0035 // Boost
0036 #include <boost/version.hpp>
0037 #include <boost/core/ignore_unused.hpp>
0038 
0039 // STL
0040 #include <iostream>
0041 #include <fstream>
0042 #include <set>
0043 
0044 #include <boost/test/detail/suppress_warnings.hpp>
0045 
0046 
0047 //____________________________________________________________________________//
0048 
0049 namespace boost {
0050 namespace unit_test {
0051 namespace output {
0052 
0053 
0054 struct s_replace_chars {
0055   template <class T>
0056   void operator()(T& to_replace)
0057   {
0058     if(to_replace == '/')
0059       to_replace = '.';
0060     else if(to_replace == ' ')
0061       to_replace = '_';
0062   }
0063 };
0064 
0065 inline std::string tu_name_normalize(std::string full_name)
0066 {
0067   // maybe directly using normalize_test_case_name instead?
0068   std::for_each(full_name.begin(), full_name.end(), s_replace_chars());
0069   return full_name;
0070 }
0071 
0072 inline std::string tu_name_remove_newlines(std::string full_name)
0073 {
0074   full_name.erase(std::remove(full_name.begin(), full_name.end(), '\n'), full_name.end());
0075   return full_name;
0076 }
0077 
0078 const_string file_basename(const_string filename) {
0079 
0080     const_string path_sep( "\\/" );
0081     const_string::iterator it = unit_test::utils::find_last_of( filename.begin(), filename.end(),
0082                                                                 path_sep.begin(), path_sep.end() );
0083     if( it != filename.end() )
0084         filename.trim_left( it + 1 );
0085 
0086     return filename;
0087 
0088 }
0089 
0090 // ************************************************************************** //
0091 // **************               junit_log_formatter              ************** //
0092 // ************************************************************************** //
0093 
0094 void
0095 junit_log_formatter::log_start( std::ostream& /*ostr*/, counter_t /*test_cases_amount*/)
0096 {
0097     map_tests.clear();
0098     list_path_to_root.clear();
0099     runner_log_entry.clear();
0100 }
0101 
0102 //____________________________________________________________________________//
0103 
0104 class junit_result_helper : public test_tree_visitor {
0105 private:
0106     typedef junit_impl::junit_log_helper::assertion_entry assertion_entry;
0107     typedef std::vector< assertion_entry >::const_iterator vect_assertion_entry_citerator;
0108     typedef std::list<std::string>::const_iterator list_str_citerator;
0109 
0110 public:
0111     explicit junit_result_helper(
0112         std::ostream& stream,
0113         test_unit const& ts,
0114         junit_log_formatter::map_trace_t const& mt,
0115         junit_impl::junit_log_helper const& runner_log_,
0116         bool display_build_info )
0117     : m_stream(stream)
0118     , m_ts( ts )
0119     , m_map_test( mt )
0120     , runner_log( runner_log_ )
0121     , m_id( 0 )
0122     , m_display_build_info(display_build_info)
0123     { }
0124 
0125     void add_log_entry(assertion_entry const& log) const
0126     {
0127         std::string entry_type;
0128         if( log.log_entry == assertion_entry::log_entry_failure ) {
0129             entry_type = "failure";
0130         }
0131         else if( log.log_entry == assertion_entry::log_entry_error ) {
0132             entry_type = "error";
0133         }
0134         else {
0135             return;
0136         }
0137 
0138         m_stream
0139             << "<" << entry_type
0140             << " message" << utils::attr_value() << log.logentry_message
0141             << " type" << utils::attr_value() << log.logentry_type
0142             << ">";
0143 
0144         if(!log.output.empty()) {
0145             m_stream << utils::cdata() << "\n" + log.output;
0146         }
0147 
0148         m_stream << "</" << entry_type << ">";
0149     }
0150 
0151     struct conditional_cdata_helper {
0152         std::ostream &ostr;
0153         std::string const field;
0154         bool empty;
0155 
0156         conditional_cdata_helper(std::ostream &ostr_, std::string field_)
0157         : ostr(ostr_)
0158         , field(field_)
0159         , empty(true)
0160         {}
0161 
0162         ~conditional_cdata_helper() {
0163             if(!empty) {
0164                 ostr << BOOST_TEST_L( "]]>" ) << "</" << field << '>' << std::endl;
0165             }
0166         }
0167 
0168         void operator()(const std::string& s) {
0169             bool current_empty = s.empty();
0170             if(empty) {
0171                 if(!current_empty) {
0172                     empty = false;
0173                     ostr << '<' << field << '>' << BOOST_TEST_L( "<![CDATA[" );
0174                 }
0175             }
0176             if(!current_empty) {
0177                 ostr << s;
0178             }
0179         }
0180     };
0181 
0182     std::list<std::string> build_skipping_chain(test_unit const & tu) const
0183     {
0184         // we enter here because we know that the tu has been skipped.
0185         // either junit has not seen this tu, or it is indicated as disabled
0186         assert(m_map_test.count(tu.p_id) == 0 || results_collector.results( tu.p_id ).p_skipped);
0187 
0188         std::list<std::string> out;
0189 
0190         test_unit_id id(tu.p_id);
0191         while( id != m_ts.p_id && id != INV_TEST_UNIT_ID) {
0192             test_unit const& tu_hierarchy = boost::unit_test::framework::get( id, TUT_ANY );
0193             out.push_back("- disabled test unit: '" + tu_name_remove_newlines(tu_hierarchy.full_name()) + "'\n");
0194             if(m_map_test.count(id) > 0)
0195             {
0196                 // junit has seen the reason: this is enough for constructing the chain
0197                 break;
0198             }
0199             id = tu_hierarchy.p_parent_id;
0200         }
0201         junit_log_formatter::map_trace_t::const_iterator it_element_stack(m_map_test.find(id));
0202         if( it_element_stack != m_map_test.end() )
0203         {
0204             out.push_back("- reason: '" + it_element_stack->second.skipping_reason + "'");
0205             out.push_front("Test case disabled because of the following chain of decision:\n");
0206         }
0207 
0208         return out;
0209     }
0210 
0211     std::string get_class_name(test_unit const & tu_class) const {
0212         std::string classname;
0213         test_unit_id id(tu_class.p_parent_id);
0214         while( id != m_ts.p_id && id != INV_TEST_UNIT_ID ) {
0215             test_unit const& tu = boost::unit_test::framework::get( id, TUT_ANY );
0216             classname = tu_name_normalize(tu.p_name) + "." + classname;
0217             id = tu.p_parent_id;
0218         }
0219 
0220         // removes the trailing dot
0221         if(!classname.empty() && *classname.rbegin() == '.') {
0222             classname.erase(classname.size()-1);
0223         }
0224 
0225         return classname;
0226     }
0227 
0228     void    write_testcase_header(test_unit const & tu,
0229                                   test_results const *tr,
0230                                   int nb_assertions) const
0231     {
0232         std::string name;
0233         std::string classname;
0234 
0235         if(tu.p_id == m_ts.p_id ) {
0236             name = "boost_test";
0237         }
0238         else {
0239             classname = get_class_name(tu);
0240             name = tu_name_normalize(tu.p_name);
0241         }
0242 
0243         if( tu.p_type == TUT_SUITE ) {
0244             if(tr->p_timed_out)
0245               name += "-timed-execution";
0246             else
0247               name += "-setup-teardown";
0248         }
0249 
0250         m_stream << "<testcase assertions" << utils::attr_value() << nb_assertions;
0251         if(!classname.empty())
0252             m_stream << " classname" << utils::attr_value() << classname;
0253 
0254         // test case name and time taken
0255         m_stream
0256             << " name"      << utils::attr_value() << name
0257             << " time"      << utils::attr_value() << double(tr->p_duration_microseconds) * 1E-6
0258             << ">" << std::endl;
0259     }
0260 
0261     void    write_testcase_system_out(junit_impl::junit_log_helper const &detailed_log,
0262                                       test_unit const * tu,
0263                                       bool skipped) const
0264     {
0265         // system-out + all info/messages, the object skips the empty entries
0266         conditional_cdata_helper system_out_helper(m_stream, "system-out");
0267 
0268         // indicate why the test has been skipped first
0269         if( skipped ) {
0270             std::list<std::string> skipping_decision_chain = build_skipping_chain(*tu);
0271             for(list_str_citerator it(skipping_decision_chain.begin()), ite(skipping_decision_chain.end());
0272                 it != ite;
0273                 ++it)
0274             {
0275               system_out_helper(*it);
0276             }
0277         }
0278 
0279         // stdout
0280         for(list_str_citerator it(detailed_log.system_out.begin()), ite(detailed_log.system_out.end());
0281             it != ite;
0282             ++it)
0283         {
0284           system_out_helper(*it);
0285         }
0286 
0287         // warning/info message last
0288         for(vect_assertion_entry_citerator it(detailed_log.assertion_entries.begin());
0289             it != detailed_log.assertion_entries.end();
0290             ++it)
0291         {
0292             if(it->log_entry != assertion_entry::log_entry_info)
0293                 continue;
0294             system_out_helper(it->output);
0295         }
0296     }
0297 
0298     void    write_testcase_system_err(junit_impl::junit_log_helper const &detailed_log,
0299                                       test_unit const * tu,
0300                                       test_results const *tr) const
0301     {
0302         // system-err output + test case informations
0303         bool has_failed = (tr != 0) ? !tr->p_skipped && !tr->passed() : false;
0304         if(!detailed_log.system_err.empty() || has_failed)
0305         {
0306             std::ostringstream o;
0307             if(has_failed) {
0308                 o << "Failures detected in:" << std::endl;
0309             }
0310             else {
0311                 o << "ERROR STREAM:" << std::endl;
0312             }
0313 
0314             if(tu->p_type == TUT_SUITE) {
0315                 if( tu->p_id == m_ts.p_id ) {
0316                     o << " boost.test global setup/teardown" << std::endl;
0317                 } else {
0318                     o << "- test suite: " << tu_name_remove_newlines(tu->full_name()) << std::endl;
0319                 }
0320             }
0321             else {
0322               o << "- test case: " << tu_name_remove_newlines(tu->full_name());
0323               if(!tu->p_description.value.empty())
0324                   o << " '" << tu->p_description << "'";
0325 
0326               o << std::endl
0327                   << "- file: " << file_basename(tu->p_file_name) << std::endl
0328                   << "- line: " << tu->p_line_num << std::endl
0329                   ;
0330             }
0331 
0332             if(!detailed_log.system_err.empty())
0333                 o << std::endl << "STDERR BEGIN: ------------" << std::endl;
0334 
0335             for(list_str_citerator it(detailed_log.system_err.begin()), ite(detailed_log.system_err.end());
0336                 it != ite;
0337                 ++it)
0338             {
0339               o << *it;
0340             }
0341 
0342             if(!detailed_log.system_err.empty())
0343                 o << std::endl << "STDERR END    ------------" << std::endl;
0344 
0345             conditional_cdata_helper system_err_helper(m_stream, "system-err");
0346             system_err_helper(o.str());
0347         }
0348     }
0349 
0350     int     get_nb_assertions(junit_impl::junit_log_helper const &detailed_log,
0351                               test_unit const & tu,
0352                               test_results const *tr) const {
0353         int nb_assertions(-1);
0354         if( tu.p_type == TUT_SUITE ) {
0355             nb_assertions = 0;
0356             for(vect_assertion_entry_citerator it(detailed_log.assertion_entries.begin());
0357                 it != detailed_log.assertion_entries.end();
0358                 ++it)
0359             {
0360                 if(it->log_entry != assertion_entry::log_entry_info)
0361                     nb_assertions++;
0362             }
0363         }
0364         else {
0365             nb_assertions = static_cast<int>(tr->p_assertions_passed + tr->p_assertions_failed);
0366         }
0367 
0368         return nb_assertions;
0369     }
0370 
0371     void    output_detailed_logs(junit_impl::junit_log_helper const &detailed_log,
0372                                  test_unit const & tu,
0373                                  bool skipped,
0374                                  test_results const *tr) const
0375     {
0376         int nb_assertions = get_nb_assertions(detailed_log, tu, tr);
0377         if(!nb_assertions && tu.p_type == TUT_SUITE)
0378             return;
0379 
0380         write_testcase_header(tu, tr, nb_assertions);
0381 
0382         if( skipped ) {
0383             m_stream << "<skipped/>" << std::endl;
0384         }
0385         else {
0386 
0387           for(vect_assertion_entry_citerator it(detailed_log.assertion_entries.begin());
0388               it != detailed_log.assertion_entries.end();
0389               ++it)
0390           {
0391               add_log_entry(*it);
0392           }
0393         }
0394 
0395         write_testcase_system_out(detailed_log, &tu, skipped);
0396         write_testcase_system_err(detailed_log, &tu, tr);
0397         m_stream << "</testcase>" << std::endl;
0398     }
0399 
0400     void    visit( test_case const& tc ) BOOST_OVERRIDE
0401     {
0402 
0403         test_results const& tr = results_collector.results( tc.p_id );
0404         junit_log_formatter::map_trace_t::const_iterator it_find = m_map_test.find(tc.p_id);
0405         if(it_find == m_map_test.end())
0406         {
0407             // test has been skipped and not seen by the logger
0408             output_detailed_logs(junit_impl::junit_log_helper(), tc, true, &tr);
0409         }
0410         else {
0411             output_detailed_logs(it_find->second, tc, tr.p_skipped, &tr);
0412         }
0413     }
0414 
0415     bool    test_suite_start( test_suite const& ts ) BOOST_OVERRIDE
0416     {
0417         test_results const& tr = results_collector.results( ts.p_id );
0418 
0419         // unique test suite, without s, nesting not supported in CI
0420         if( m_ts.p_id == ts.p_id ) {
0421             m_stream << "<testsuite";
0422 
0423             // think about: maybe we should add the number of fixtures of a test_suite as
0424             // independent tests (field p_fixtures).
0425             // same goes for the timed-execution: we can think of that as a separate test-unit
0426             // in the suite.
0427             // see https://llg.cubic.org/docs/junit/ and
0428             // http://svn.apache.org/viewvc/ant/core/trunk/src/main/org/apache/tools/ant/taskdefs/optional/junit/XMLJUnitResultFormatter.java?view=markup
0429             m_stream
0430               // << "disabled=\"" << tr.p_test_cases_skipped << "\" "
0431               << " tests"     << utils::attr_value()
0432                   << tr.p_test_cases_passed
0433                      + tr.p_test_cases_failed
0434                      // + tr.p_test_cases_aborted // aborted is also failed, we avoid counting it twice
0435               << " skipped"   << utils::attr_value() << tr.p_test_cases_skipped
0436               << " errors"    << utils::attr_value() << tr.p_test_cases_aborted
0437               << " failures"  << utils::attr_value()
0438                   << tr.p_test_cases_failed
0439                      + tr.p_test_suites_timed_out
0440                      + tr.p_test_cases_timed_out
0441                      - tr.p_test_cases_aborted // failed is not aborted in the Junit sense
0442               << " id"        << utils::attr_value() << m_id++
0443               << " name"      << utils::attr_value() << tu_name_normalize(ts.p_name)
0444               << " time"      << utils::attr_value() << (tr.p_duration_microseconds * 1E-6)
0445               << ">" << std::endl;
0446 
0447             if(m_display_build_info)
0448             {
0449                 m_stream  << "<properties>" << std::endl;
0450                 m_stream  << "<property name=\"platform\" value" << utils::attr_value() << BOOST_PLATFORM << " />" << std::endl;
0451                 m_stream  << "<property name=\"compiler\" value" << utils::attr_value() << BOOST_COMPILER << " />" << std::endl;
0452                 m_stream  << "<property name=\"stl\" value" << utils::attr_value() << BOOST_STDLIB << " />" << std::endl;
0453 
0454                 std::ostringstream o;
0455                 o << BOOST_VERSION/100000 << "." << BOOST_VERSION/100 % 1000 << "." << BOOST_VERSION % 100;
0456                 m_stream  << "<property name=\"boost\" value" << utils::attr_value() << o.str() << " />" << std::endl;
0457                 m_stream  << "</properties>" << std::endl;
0458             }
0459         }
0460 
0461         if( !tr.p_skipped ) {
0462             // if we land here, then this is a chance that we are logging the fixture setup/teardown of a test-suite.
0463             // the setup/teardown logging of a test-case is part of the test case.
0464             // we do not care about the test-suite that were skipped (really??)
0465             junit_log_formatter::map_trace_t::const_iterator it_find = m_map_test.find(ts.p_id);
0466             if(it_find != m_map_test.end()) {
0467                 output_detailed_logs(it_find->second, ts, false, &tr);
0468             }
0469         }
0470 
0471         return true; // indicates that the children should also be parsed
0472     }
0473 
0474     void    test_suite_finish( test_suite const& ts ) BOOST_OVERRIDE
0475     {
0476         if( m_ts.p_id == ts.p_id ) {
0477             write_testcase_system_out(runner_log, 0, false);
0478             write_testcase_system_err(runner_log, 0, 0);
0479 
0480             m_stream << "</testsuite>";
0481             return;
0482         }
0483     }
0484 
0485 private:
0486     // Data members
0487     std::ostream& m_stream;
0488     test_unit const& m_ts;
0489     junit_log_formatter::map_trace_t const& m_map_test;
0490     junit_impl::junit_log_helper const& runner_log;
0491     size_t m_id;
0492     bool m_display_build_info;
0493 };
0494 
0495 
0496 
0497 void
0498 junit_log_formatter::log_finish( std::ostream& ostr )
0499 {
0500     ostr << "<?xml version=\"1.0\" encoding=\"UTF-8\"?>" << std::endl;
0501 
0502     // getting the root test suite
0503     if(!map_tests.empty()) {
0504         test_unit* root = &boost::unit_test::framework::get( map_tests.begin()->first, TUT_ANY );
0505 
0506         // looking for the root of the SUBtree (we stay in the subtree)
0507         while(root->p_parent_id != INV_TEST_UNIT_ID && map_tests.count(root->p_parent_id) > 0) {
0508             root = &boost::unit_test::framework::get( root->p_parent_id, TUT_ANY );
0509         }
0510         junit_result_helper ch( ostr, *root, map_tests, this->runner_log_entry, m_display_build_info );
0511         traverse_test_tree( root->p_id, ch, true ); // last is to ignore disabled suite special handling
0512     }
0513     else {
0514         ostr << "<testsuites errors=\"1\">";
0515         ostr << "<testsuite errors=\"1\" name=\"boost-test-framework\">";
0516         ostr << "<testcase assertions=\"1\" name=\"test-setup\">";
0517         ostr << "<system-out>Incorrect setup: no test case executed</system-out>";
0518         ostr << "</testcase></testsuite></testsuites>";
0519     }
0520     return;
0521 }
0522 
0523 //____________________________________________________________________________//
0524 
0525 void
0526 junit_log_formatter::log_build_info( std::ostream& /*ostr*/, bool log_build_info )
0527 {
0528     m_display_build_info = log_build_info;
0529 }
0530 
0531 //____________________________________________________________________________//
0532 
0533 void
0534 junit_log_formatter::test_unit_start( std::ostream& /*ostr*/, test_unit const& tu )
0535 {
0536     list_path_to_root.push_back( tu.p_id );
0537     map_tests.insert(std::make_pair(tu.p_id, junit_impl::junit_log_helper())); // current_test_case_id not working here
0538 }
0539 
0540 
0541 
0542 //____________________________________________________________________________//
0543 
0544 
0545 void
0546 junit_log_formatter::test_unit_finish( std::ostream& /*ostr*/, test_unit const& tu, unsigned long /*elapsed*/ )
0547 {
0548     // the time is already stored in the result_reporter
0549     boost::ignore_unused( tu );
0550     assert( tu.p_id == list_path_to_root.back() );
0551     list_path_to_root.pop_back();
0552 }
0553 
0554 void
0555 junit_log_formatter::test_unit_aborted( std::ostream& /*ostr*/, test_unit const& tu )
0556 {
0557     boost::ignore_unused( tu );
0558     assert( tu.p_id == list_path_to_root.back() );
0559     //list_path_to_root.pop_back();
0560 }
0561 
0562 //____________________________________________________________________________//
0563 
0564 void
0565 junit_log_formatter::test_unit_timed_out( std::ostream& /*os*/, test_unit const& tu)
0566 {
0567     if(tu.p_type == TUT_SUITE)
0568     {
0569         // if we reach this call, it means that the test has already started and
0570         // test_unit_start has already been called on the tu.
0571         junit_impl::junit_log_helper& last_entry = get_current_log_entry();
0572         junit_impl::junit_log_helper::assertion_entry entry;
0573         entry.logentry_message = "test-suite time out";
0574         entry.logentry_type = "execution timeout";
0575         entry.log_entry = junit_impl::junit_log_helper::assertion_entry::log_entry_error;
0576         entry.output = "the current suite exceeded the allocated execution time";
0577         last_entry.assertion_entries.push_back(entry);
0578     }
0579 }
0580 
0581 //____________________________________________________________________________//
0582 
0583 void
0584 junit_log_formatter::test_unit_skipped( std::ostream& /*ostr*/, test_unit const& tu, const_string reason )
0585 {
0586     // if a test unit is skipped, then the start of this TU has not been called yet.
0587     // we cannot use get_current_log_entry here, but the TU id should appear in the map.
0588     // The "skip" boolean is given by the boost.test framework
0589     junit_impl::junit_log_helper& v = map_tests[tu.p_id]; // not sure if we can use get_current_log_entry()
0590     v.skipping_reason.assign(reason.begin(), reason.end());
0591 }
0592 
0593 //____________________________________________________________________________//
0594 
0595 void
0596 junit_log_formatter::log_exception_start( std::ostream& /*ostr*/, log_checkpoint_data const& checkpoint_data, execution_exception const& ex )
0597 {
0598     std::ostringstream o;
0599     execution_exception::location const& loc = ex.where();
0600 
0601     m_is_last_assertion_or_error = false;
0602 
0603     junit_impl::junit_log_helper& last_entry = get_current_log_entry();
0604 
0605     junit_impl::junit_log_helper::assertion_entry entry;
0606 
0607     entry.logentry_message = "unexpected exception";
0608     entry.log_entry = junit_impl::junit_log_helper::assertion_entry::log_entry_error;
0609 
0610     switch(ex.code())
0611     {
0612     case execution_exception::cpp_exception_error:
0613         entry.logentry_type = "uncaught exception";
0614         break;
0615     case execution_exception::timeout_error:
0616         entry.logentry_type = "execution timeout";
0617         break;
0618     case execution_exception::user_error:
0619         entry.logentry_type = "user, assert() or CRT error";
0620         break;
0621     case execution_exception::user_fatal_error:
0622         // Looks like never used
0623         entry.logentry_type = "user fatal error";
0624         break;
0625     case execution_exception::system_error:
0626         entry.logentry_type = "system error";
0627         break;
0628     case execution_exception::system_fatal_error:
0629         entry.logentry_type = "system fatal error";
0630         break;
0631     default:
0632         entry.logentry_type = "no error"; // not sure how to handle this one
0633         break;
0634     }
0635 
0636     o << "UNCAUGHT EXCEPTION:" << std::endl;
0637     if( !loc.m_function.is_empty() )
0638         o << "- function: \""   << loc.m_function << "\"" << std::endl;
0639 
0640     o << "- file: " << file_basename(loc.m_file_name) << std::endl
0641       << "- line: " << loc.m_line_num << std::endl
0642       << std::endl;
0643 
0644     o << "\nEXCEPTION STACK TRACE: --------------\n" << ex.what()
0645       << "\n-------------------------------------";
0646 
0647     if( !checkpoint_data.m_file_name.is_empty() ) {
0648         o << std::endl << std::endl
0649           << "Last checkpoint:" << std::endl
0650           << "- message: \"" << checkpoint_data.m_message << "\"" << std::endl
0651           << "- file: " << file_basename(checkpoint_data.m_file_name) << std::endl
0652           << "- line: " << checkpoint_data.m_line_num << std::endl
0653         ;
0654     }
0655 
0656     entry.output = o.str();
0657 
0658     last_entry.assertion_entries.push_back(entry);
0659 }
0660 
0661 //____________________________________________________________________________//
0662 
0663 void
0664 junit_log_formatter::log_exception_finish( std::ostream& /*ostr*/ )
0665 {
0666     // sealing the last entry
0667     assert(!get_current_log_entry().assertion_entries.back().sealed);
0668     get_current_log_entry().assertion_entries.back().sealed = true;
0669 }
0670 
0671 //____________________________________________________________________________//
0672 
0673 void
0674 junit_log_formatter::log_entry_start( std::ostream& /*ostr*/, log_entry_data const& entry_data, log_entry_types let )
0675 {
0676     junit_impl::junit_log_helper& last_entry = get_current_log_entry();
0677     last_entry.skipping = false;
0678     m_is_last_assertion_or_error = true;
0679     switch(let)
0680     {
0681       case unit_test_log_formatter::BOOST_UTL_ET_INFO:
0682       {
0683         if(m_log_level_internal > log_successful_tests) {
0684           last_entry.skipping = true;
0685           break;
0686         }
0687         BOOST_FALLTHROUGH;
0688       }
0689       case unit_test_log_formatter::BOOST_UTL_ET_MESSAGE:
0690       {
0691         if(m_log_level_internal > log_messages) {
0692           last_entry.skipping = true;
0693           break;
0694         }
0695         BOOST_FALLTHROUGH;
0696       }
0697       case unit_test_log_formatter::BOOST_UTL_ET_WARNING:
0698       {
0699         if(m_log_level_internal > log_warnings) {
0700           last_entry.skipping = true;
0701           break;
0702         }
0703         std::ostringstream o;
0704         junit_impl::junit_log_helper::assertion_entry entry;
0705 
0706         entry.log_entry = junit_impl::junit_log_helper::assertion_entry::log_entry_info;
0707         entry.logentry_message = "info";
0708         entry.logentry_type = "message";
0709 
0710         o << (let == unit_test_log_formatter::BOOST_UTL_ET_WARNING ?
0711               "WARNING:" : (let == unit_test_log_formatter::BOOST_UTL_ET_MESSAGE ?
0712                             "MESSAGE:" : "INFO:"))
0713              << std::endl
0714           << "- file   : " << file_basename(entry_data.m_file_name) << std::endl
0715           << "- line   : " << entry_data.m_line_num << std::endl
0716           << "- message: "; // no CR
0717 
0718         entry.output += o.str();
0719         last_entry.assertion_entries.push_back(entry);
0720         break;
0721       }
0722       default:
0723       case unit_test_log_formatter::BOOST_UTL_ET_ERROR:
0724       case unit_test_log_formatter::BOOST_UTL_ET_FATAL_ERROR:
0725       {
0726         std::ostringstream o;
0727         junit_impl::junit_log_helper::assertion_entry entry;
0728         entry.log_entry = junit_impl::junit_log_helper::assertion_entry::log_entry_failure;
0729         entry.logentry_message = "failure";
0730         entry.logentry_type = (let == unit_test_log_formatter::BOOST_UTL_ET_ERROR ? "assertion error" : "fatal error");
0731 
0732         o << "ASSERTION FAILURE:" << std::endl
0733           << "- file   : " << file_basename(entry_data.m_file_name) << std::endl
0734           << "- line   : " << entry_data.m_line_num << std::endl
0735           << "- message: " ; // no CR
0736 
0737         entry.output += o.str();
0738         last_entry.assertion_entries.push_back(entry);
0739         break;
0740       }
0741     }
0742 }
0743 
0744 //____________________________________________________________________________//
0745 
0746 void
0747 junit_log_formatter::log_entry_value( std::ostream& /*ostr*/, const_string value )
0748 {
0749     junit_impl::junit_log_helper& last_entry = get_current_log_entry();
0750     if(last_entry.skipping)
0751         return;
0752 
0753     assert(last_entry.assertion_entries.empty() || !last_entry.assertion_entries.back().sealed);
0754 
0755     if(!last_entry.assertion_entries.empty())
0756     {
0757         junit_impl::junit_log_helper::assertion_entry& log_entry = last_entry.assertion_entries.back();
0758         log_entry.output += value;
0759     }
0760     else
0761     {
0762         // this may be a message coming from another observer
0763         // the prefix is set in the log_entry_start
0764         last_entry.system_out.push_back(std::string(value.begin(), value.end()));
0765     }
0766 }
0767 
0768 //____________________________________________________________________________//
0769 
0770 void
0771 junit_log_formatter::log_entry_finish( std::ostream& /*ostr*/ )
0772 {
0773     junit_impl::junit_log_helper& last_entry = get_current_log_entry();
0774     if(!last_entry.skipping)
0775     {
0776         assert(last_entry.assertion_entries.empty() || !last_entry.assertion_entries.back().sealed);
0777 
0778         if(!last_entry.assertion_entries.empty()) {
0779             junit_impl::junit_log_helper::assertion_entry& log_entry = last_entry.assertion_entries.back();
0780             log_entry.output += "\n\n"; // quote end, CR
0781             log_entry.sealed = true;
0782         }
0783         else {
0784             last_entry.system_out.push_back("\n\n"); // quote end, CR
0785         }
0786     }
0787 
0788     last_entry.skipping = false;
0789 }
0790 
0791 //____________________________________________________________________________//
0792 
0793 void
0794 junit_log_formatter::entry_context_start( std::ostream& /*ostr*/, log_level )
0795 {
0796     junit_impl::junit_log_helper& last_entry = get_current_log_entry();
0797     if(last_entry.skipping)
0798         return;
0799 
0800     std::vector< junit_impl::junit_log_helper::assertion_entry > &v_failure_or_error = last_entry.assertion_entries;
0801     assert(!v_failure_or_error.back().sealed);
0802 
0803     junit_impl::junit_log_helper::assertion_entry& last_log_entry = v_failure_or_error.back();
0804     if(m_is_last_assertion_or_error)
0805     {
0806         last_log_entry.output += "\n- context:\n";
0807     }
0808     else
0809     {
0810         last_log_entry.output += "\n\nCONTEXT:\n";
0811     }
0812 }
0813 
0814 //____________________________________________________________________________//
0815 
0816 void
0817 junit_log_formatter::entry_context_finish( std::ostream& /*ostr*/, log_level )
0818 {
0819     // no op, may be removed
0820     junit_impl::junit_log_helper& last_entry = get_current_log_entry();
0821     if(last_entry.skipping)
0822         return;
0823     assert(!get_current_log_entry().assertion_entries.back().sealed);
0824 }
0825 
0826 //____________________________________________________________________________//
0827 
0828 void
0829 junit_log_formatter::log_entry_context( std::ostream& /*ostr*/, log_level , const_string context_descr )
0830 {
0831     junit_impl::junit_log_helper& last_entry = get_current_log_entry();
0832     if(last_entry.skipping)
0833         return;
0834 
0835     assert(!last_entry.assertion_entries.back().sealed);
0836     junit_impl::junit_log_helper::assertion_entry& last_log_entry = get_current_log_entry().assertion_entries.back();
0837 
0838     last_log_entry.output +=
0839         (m_is_last_assertion_or_error ? "  - '": "- '") + std::string(context_descr.begin(), context_descr.end()) + "'\n"; // quote end
0840 }
0841 
0842 //____________________________________________________________________________//
0843 
0844 
0845 std::string
0846 junit_log_formatter::get_default_stream_description() const {
0847     std::string name = framework::master_test_suite().p_name.value;
0848 
0849     static const std::string to_replace[] =  { " ", "\"", "/", "\\", ":"};
0850     static const std::string replacement[] = { "_", "_" , "_", "_" , "_"};
0851 
0852     name = unit_test::utils::replace_all_occurrences_of(
0853         name,
0854         to_replace, to_replace + sizeof(to_replace)/sizeof(to_replace[0]),
0855         replacement, replacement + sizeof(replacement)/sizeof(replacement[0]));
0856 
0857     std::ifstream check_init((name + ".xml").c_str());
0858     if(!check_init)
0859         return name + ".xml";
0860 
0861     int index = 0;
0862     for(; index < 100; index++) {
0863       std::string candidate = name + "_" + utils::string_cast(index) + ".xml";
0864       std::ifstream file(candidate.c_str());
0865       if(!file)
0866           return candidate;
0867     }
0868 
0869     return name + ".xml";
0870 }
0871 
0872 } // namespace output
0873 } // namespace unit_test
0874 } // namespace boost
0875 
0876 #include <boost/test/detail/enable_warnings.hpp>
0877 
0878 #endif // BOOST_TEST_junit_log_formatter_IPP_020105GER