junit_log_formatter.ipp 30 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878
  1. // (C) Copyright 2016 Raffi Enficiaud.
  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. // See http://www.boost.org/libs/test for the library home page.
  6. //
  7. ///@file
  8. ///@brief Contains the implementatoin of the Junit log formatter (OF_JUNIT)
  9. // ***************************************************************************
  10. #ifndef BOOST_TEST_JUNIT_LOG_FORMATTER_IPP__
  11. #define BOOST_TEST_JUNIT_LOG_FORMATTER_IPP__
  12. // Boost.Test
  13. #include <boost/test/output/junit_log_formatter.hpp>
  14. #include <boost/test/execution_monitor.hpp>
  15. #include <boost/test/framework.hpp>
  16. #include <boost/test/tree/test_unit.hpp>
  17. #include <boost/test/utils/basic_cstring/io.hpp>
  18. #include <boost/test/utils/xml_printer.hpp>
  19. #include <boost/test/utils/string_cast.hpp>
  20. #include <boost/test/framework.hpp>
  21. #include <boost/test/tree/visitor.hpp>
  22. #include <boost/test/tree/traverse.hpp>
  23. #include <boost/test/results_collector.hpp>
  24. #include <boost/test/utils/algorithm.hpp>
  25. #include <boost/test/utils/string_cast.hpp>
  26. //#include <boost/test/results_reporter.hpp>
  27. // Boost
  28. #include <boost/version.hpp>
  29. #include <boost/core/ignore_unused.hpp>
  30. // STL
  31. #include <iostream>
  32. #include <fstream>
  33. #include <set>
  34. #include <boost/test/detail/suppress_warnings.hpp>
  35. //____________________________________________________________________________//
  36. namespace boost {
  37. namespace unit_test {
  38. namespace output {
  39. struct s_replace_chars {
  40. template <class T>
  41. void operator()(T& to_replace)
  42. {
  43. if(to_replace == '/')
  44. to_replace = '.';
  45. else if(to_replace == ' ')
  46. to_replace = '_';
  47. }
  48. };
  49. inline std::string tu_name_normalize(std::string full_name)
  50. {
  51. // maybe directly using normalize_test_case_name instead?
  52. std::for_each(full_name.begin(), full_name.end(), s_replace_chars());
  53. return full_name;
  54. }
  55. inline std::string tu_name_remove_newlines(std::string full_name)
  56. {
  57. full_name.erase(std::remove(full_name.begin(), full_name.end(), '\n'), full_name.end());
  58. return full_name;
  59. }
  60. const_string file_basename(const_string filename) {
  61. const_string path_sep( "\\/" );
  62. const_string::iterator it = unit_test::utils::find_last_of( filename.begin(), filename.end(),
  63. path_sep.begin(), path_sep.end() );
  64. if( it != filename.end() )
  65. filename.trim_left( it + 1 );
  66. return filename;
  67. }
  68. // ************************************************************************** //
  69. // ************** junit_log_formatter ************** //
  70. // ************************************************************************** //
  71. void
  72. junit_log_formatter::log_start( std::ostream& /*ostr*/, counter_t /*test_cases_amount*/)
  73. {
  74. map_tests.clear();
  75. list_path_to_root.clear();
  76. runner_log_entry.clear();
  77. }
  78. //____________________________________________________________________________//
  79. class junit_result_helper : public test_tree_visitor {
  80. private:
  81. typedef junit_impl::junit_log_helper::assertion_entry assertion_entry;
  82. typedef std::vector< assertion_entry >::const_iterator vect_assertion_entry_citerator;
  83. typedef std::list<std::string>::const_iterator list_str_citerator;
  84. public:
  85. explicit junit_result_helper(
  86. std::ostream& stream,
  87. test_unit const& ts,
  88. junit_log_formatter::map_trace_t const& mt,
  89. junit_impl::junit_log_helper const& runner_log_,
  90. bool display_build_info )
  91. : m_stream(stream)
  92. , m_ts( ts )
  93. , m_map_test( mt )
  94. , runner_log( runner_log_ )
  95. , m_id( 0 )
  96. , m_display_build_info(display_build_info)
  97. { }
  98. void add_log_entry(assertion_entry const& log) const
  99. {
  100. std::string entry_type;
  101. if( log.log_entry == assertion_entry::log_entry_failure ) {
  102. entry_type = "failure";
  103. }
  104. else if( log.log_entry == assertion_entry::log_entry_error ) {
  105. entry_type = "error";
  106. }
  107. else {
  108. return;
  109. }
  110. m_stream
  111. << "<" << entry_type
  112. << " message" << utils::attr_value() << log.logentry_message
  113. << " type" << utils::attr_value() << log.logentry_type
  114. << ">";
  115. if(!log.output.empty()) {
  116. m_stream << utils::cdata() << "\n" + log.output;
  117. }
  118. m_stream << "</" << entry_type << ">";
  119. }
  120. struct conditional_cdata_helper {
  121. std::ostream &ostr;
  122. std::string const field;
  123. bool empty;
  124. conditional_cdata_helper(std::ostream &ostr_, std::string field_)
  125. : ostr(ostr_)
  126. , field(field_)
  127. , empty(true)
  128. {}
  129. ~conditional_cdata_helper() {
  130. if(!empty) {
  131. ostr << BOOST_TEST_L( "]]>" ) << "</" << field << '>' << std::endl;
  132. }
  133. }
  134. void operator()(const std::string& s) {
  135. bool current_empty = s.empty();
  136. if(empty) {
  137. if(!current_empty) {
  138. empty = false;
  139. ostr << '<' << field << '>' << BOOST_TEST_L( "<![CDATA[" );
  140. }
  141. }
  142. if(!current_empty) {
  143. ostr << s;
  144. }
  145. }
  146. };
  147. std::list<std::string> build_skipping_chain(test_unit const & tu) const
  148. {
  149. // we enter here because we know that the tu has been skipped.
  150. // either junit has not seen this tu, or it is indicated as disabled
  151. assert(m_map_test.count(tu.p_id) == 0 || results_collector.results( tu.p_id ).p_skipped);
  152. std::list<std::string> out;
  153. test_unit_id id(tu.p_id);
  154. while( id != m_ts.p_id && id != INV_TEST_UNIT_ID) {
  155. test_unit const& tu_hierarchy = boost::unit_test::framework::get( id, TUT_ANY );
  156. out.push_back("- disabled test unit: '" + tu_name_remove_newlines(tu_hierarchy.full_name()) + "'\n");
  157. if(m_map_test.count(id) > 0)
  158. {
  159. // junit has seen the reason: this is enough for constructing the chain
  160. break;
  161. }
  162. id = tu_hierarchy.p_parent_id;
  163. }
  164. junit_log_formatter::map_trace_t::const_iterator it_element_stack(m_map_test.find(id));
  165. if( it_element_stack != m_map_test.end() )
  166. {
  167. out.push_back("- reason: '" + it_element_stack->second.skipping_reason + "'");
  168. out.push_front("Test case disabled because of the following chain of decision:\n");
  169. }
  170. return out;
  171. }
  172. std::string get_class_name(test_unit const & tu_class) const {
  173. std::string classname;
  174. test_unit_id id(tu_class.p_parent_id);
  175. while( id != m_ts.p_id && id != INV_TEST_UNIT_ID ) {
  176. test_unit const& tu = boost::unit_test::framework::get( id, TUT_ANY );
  177. classname = tu_name_normalize(tu.p_name) + "." + classname;
  178. id = tu.p_parent_id;
  179. }
  180. // removes the trailing dot
  181. if(!classname.empty() && *classname.rbegin() == '.') {
  182. classname.erase(classname.size()-1);
  183. }
  184. return classname;
  185. }
  186. void write_testcase_header(test_unit const & tu,
  187. test_results const *tr,
  188. int nb_assertions) const
  189. {
  190. std::string name;
  191. std::string classname;
  192. if(tu.p_id == m_ts.p_id ) {
  193. name = "boost_test";
  194. }
  195. else {
  196. classname = get_class_name(tu);
  197. name = tu_name_normalize(tu.p_name);
  198. }
  199. if( tu.p_type == TUT_SUITE ) {
  200. if(tr->p_timed_out)
  201. name += "-timed-execution";
  202. else
  203. name += "-setup-teardown";
  204. }
  205. m_stream << "<testcase assertions" << utils::attr_value() << nb_assertions;
  206. if(!classname.empty())
  207. m_stream << " classname" << utils::attr_value() << classname;
  208. // test case name and time taken
  209. m_stream
  210. << " name" << utils::attr_value() << name
  211. << " time" << utils::attr_value() << double(tr->p_duration_microseconds) * 1E-6
  212. << ">" << std::endl;
  213. }
  214. void write_testcase_system_out(junit_impl::junit_log_helper const &detailed_log,
  215. test_unit const * tu,
  216. bool skipped) const
  217. {
  218. // system-out + all info/messages, the object skips the empty entries
  219. conditional_cdata_helper system_out_helper(m_stream, "system-out");
  220. // indicate why the test has been skipped first
  221. if( skipped ) {
  222. std::list<std::string> skipping_decision_chain = build_skipping_chain(*tu);
  223. for(list_str_citerator it(skipping_decision_chain.begin()), ite(skipping_decision_chain.end());
  224. it != ite;
  225. ++it)
  226. {
  227. system_out_helper(*it);
  228. }
  229. }
  230. // stdout
  231. for(list_str_citerator it(detailed_log.system_out.begin()), ite(detailed_log.system_out.end());
  232. it != ite;
  233. ++it)
  234. {
  235. system_out_helper(*it);
  236. }
  237. // warning/info message last
  238. for(vect_assertion_entry_citerator it(detailed_log.assertion_entries.begin());
  239. it != detailed_log.assertion_entries.end();
  240. ++it)
  241. {
  242. if(it->log_entry != assertion_entry::log_entry_info)
  243. continue;
  244. system_out_helper(it->output);
  245. }
  246. }
  247. void write_testcase_system_err(junit_impl::junit_log_helper const &detailed_log,
  248. test_unit const * tu,
  249. test_results const *tr) const
  250. {
  251. // system-err output + test case informations
  252. bool has_failed = (tr != 0) ? !tr->p_skipped && !tr->passed() : false;
  253. if(!detailed_log.system_err.empty() || has_failed)
  254. {
  255. std::ostringstream o;
  256. if(has_failed) {
  257. o << "Failures detected in:" << std::endl;
  258. }
  259. else {
  260. o << "ERROR STREAM:" << std::endl;
  261. }
  262. if(tu->p_type == TUT_SUITE) {
  263. if( tu->p_id == m_ts.p_id ) {
  264. o << " boost.test global setup/teardown" << std::endl;
  265. } else {
  266. o << "- test suite: " << tu_name_remove_newlines(tu->full_name()) << std::endl;
  267. }
  268. }
  269. else {
  270. o << "- test case: " << tu_name_remove_newlines(tu->full_name());
  271. if(!tu->p_description.value.empty())
  272. o << " '" << tu->p_description << "'";
  273. o << std::endl
  274. << "- file: " << file_basename(tu->p_file_name) << std::endl
  275. << "- line: " << tu->p_line_num << std::endl
  276. ;
  277. }
  278. if(!detailed_log.system_err.empty())
  279. o << std::endl << "STDERR BEGIN: ------------" << std::endl;
  280. for(list_str_citerator it(detailed_log.system_err.begin()), ite(detailed_log.system_err.end());
  281. it != ite;
  282. ++it)
  283. {
  284. o << *it;
  285. }
  286. if(!detailed_log.system_err.empty())
  287. o << std::endl << "STDERR END ------------" << std::endl;
  288. conditional_cdata_helper system_err_helper(m_stream, "system-err");
  289. system_err_helper(o.str());
  290. }
  291. }
  292. int get_nb_assertions(junit_impl::junit_log_helper const &detailed_log,
  293. test_unit const & tu,
  294. test_results const *tr) const {
  295. int nb_assertions(-1);
  296. if( tu.p_type == TUT_SUITE ) {
  297. nb_assertions = 0;
  298. for(vect_assertion_entry_citerator it(detailed_log.assertion_entries.begin());
  299. it != detailed_log.assertion_entries.end();
  300. ++it)
  301. {
  302. if(it->log_entry != assertion_entry::log_entry_info)
  303. nb_assertions++;
  304. }
  305. }
  306. else {
  307. nb_assertions = static_cast<int>(tr->p_assertions_passed + tr->p_assertions_failed);
  308. }
  309. return nb_assertions;
  310. }
  311. void output_detailed_logs(junit_impl::junit_log_helper const &detailed_log,
  312. test_unit const & tu,
  313. bool skipped,
  314. test_results const *tr) const
  315. {
  316. int nb_assertions = get_nb_assertions(detailed_log, tu, tr);
  317. if(!nb_assertions && tu.p_type == TUT_SUITE)
  318. return;
  319. write_testcase_header(tu, tr, nb_assertions);
  320. if( skipped ) {
  321. m_stream << "<skipped/>" << std::endl;
  322. }
  323. else {
  324. for(vect_assertion_entry_citerator it(detailed_log.assertion_entries.begin());
  325. it != detailed_log.assertion_entries.end();
  326. ++it)
  327. {
  328. add_log_entry(*it);
  329. }
  330. }
  331. write_testcase_system_out(detailed_log, &tu, skipped);
  332. write_testcase_system_err(detailed_log, &tu, tr);
  333. m_stream << "</testcase>" << std::endl;
  334. }
  335. void visit( test_case const& tc )
  336. {
  337. test_results const& tr = results_collector.results( tc.p_id );
  338. junit_log_formatter::map_trace_t::const_iterator it_find = m_map_test.find(tc.p_id);
  339. if(it_find == m_map_test.end())
  340. {
  341. // test has been skipped and not seen by the logger
  342. output_detailed_logs(junit_impl::junit_log_helper(), tc, true, &tr);
  343. }
  344. else {
  345. output_detailed_logs(it_find->second, tc, tr.p_skipped, &tr);
  346. }
  347. }
  348. bool test_suite_start( test_suite const& ts )
  349. {
  350. test_results const& tr = results_collector.results( ts.p_id );
  351. // unique test suite, without s, nesting not supported in CI
  352. if( m_ts.p_id == ts.p_id ) {
  353. m_stream << "<testsuite";
  354. // think about: maybe we should add the number of fixtures of a test_suite as
  355. // independant tests (field p_fixtures).
  356. // same goes for the timed-execution: we can think of that as a separate test-unit
  357. // in the suite.
  358. // see https://llg.cubic.org/docs/junit/ and
  359. // http://svn.apache.org/viewvc/ant/core/trunk/src/main/org/apache/tools/ant/taskdefs/optional/junit/XMLJUnitResultFormatter.java?view=markup
  360. m_stream
  361. // << "disabled=\"" << tr.p_test_cases_skipped << "\" "
  362. << " tests" << utils::attr_value()
  363. << tr.p_test_cases_passed
  364. + tr.p_test_cases_failed
  365. // + tr.p_test_cases_aborted // aborted is also failed, we avoid counting it twice
  366. << " skipped" << utils::attr_value() << tr.p_test_cases_skipped
  367. << " errors" << utils::attr_value() << tr.p_test_cases_aborted
  368. << " failures" << utils::attr_value()
  369. << tr.p_test_cases_failed
  370. + tr.p_test_suites_timed_out
  371. + tr.p_test_cases_timed_out
  372. - tr.p_test_cases_aborted // failed is not aborted in the Junit sense
  373. << " id" << utils::attr_value() << m_id++
  374. << " name" << utils::attr_value() << tu_name_normalize(ts.p_name)
  375. << " time" << utils::attr_value() << (tr.p_duration_microseconds * 1E-6)
  376. << ">" << std::endl;
  377. if(m_display_build_info)
  378. {
  379. m_stream << "<properties>" << std::endl;
  380. m_stream << "<property name=\"platform\" value" << utils::attr_value() << BOOST_PLATFORM << " />" << std::endl;
  381. m_stream << "<property name=\"compiler\" value" << utils::attr_value() << BOOST_COMPILER << " />" << std::endl;
  382. m_stream << "<property name=\"stl\" value" << utils::attr_value() << BOOST_STDLIB << " />" << std::endl;
  383. std::ostringstream o;
  384. o << BOOST_VERSION/100000 << "." << BOOST_VERSION/100 % 1000 << "." << BOOST_VERSION % 100;
  385. m_stream << "<property name=\"boost\" value" << utils::attr_value() << o.str() << " />" << std::endl;
  386. m_stream << "</properties>" << std::endl;
  387. }
  388. }
  389. if( !tr.p_skipped ) {
  390. // if we land here, then this is a chance that we are logging the fixture setup/teardown of a test-suite.
  391. // the setup/teardown logging of a test-case is part of the test case.
  392. // we do not care about the test-suite that were skipped (really??)
  393. junit_log_formatter::map_trace_t::const_iterator it_find = m_map_test.find(ts.p_id);
  394. if(it_find != m_map_test.end()) {
  395. output_detailed_logs(it_find->second, ts, false, &tr);
  396. }
  397. }
  398. return true; // indicates that the children should also be parsed
  399. }
  400. virtual void test_suite_finish( test_suite const& ts )
  401. {
  402. if( m_ts.p_id == ts.p_id ) {
  403. write_testcase_system_out(runner_log, 0, false);
  404. write_testcase_system_err(runner_log, 0, 0);
  405. m_stream << "</testsuite>";
  406. return;
  407. }
  408. }
  409. private:
  410. // Data members
  411. std::ostream& m_stream;
  412. test_unit const& m_ts;
  413. junit_log_formatter::map_trace_t const& m_map_test;
  414. junit_impl::junit_log_helper const& runner_log;
  415. size_t m_id;
  416. bool m_display_build_info;
  417. };
  418. void
  419. junit_log_formatter::log_finish( std::ostream& ostr )
  420. {
  421. ostr << "<?xml version=\"1.0\" encoding=\"UTF-8\"?>" << std::endl;
  422. // getting the root test suite
  423. if(!map_tests.empty()) {
  424. test_unit* root = &boost::unit_test::framework::get( map_tests.begin()->first, TUT_ANY );
  425. // looking for the root of the SUBtree (we stay in the subtree)
  426. while(root->p_parent_id != INV_TEST_UNIT_ID && map_tests.count(root->p_parent_id) > 0) {
  427. root = &boost::unit_test::framework::get( root->p_parent_id, TUT_ANY );
  428. }
  429. junit_result_helper ch( ostr, *root, map_tests, this->runner_log_entry, m_display_build_info );
  430. traverse_test_tree( root->p_id, ch, true ); // last is to ignore disabled suite special handling
  431. }
  432. else {
  433. ostr << "<testsuites errors=\"1\">";
  434. ostr << "<testsuite errors=\"1\" name=\"boost-test-framework\">";
  435. ostr << "<testcase assertions=\"1\" name=\"test-setup\">";
  436. ostr << "<system-out>Incorrect setup: no test case executed</system-out>";
  437. ostr << "</testcase></testsuite></testsuites>";
  438. }
  439. return;
  440. }
  441. //____________________________________________________________________________//
  442. void
  443. junit_log_formatter::log_build_info( std::ostream& /*ostr*/, bool log_build_info )
  444. {
  445. m_display_build_info = log_build_info;
  446. }
  447. //____________________________________________________________________________//
  448. void
  449. junit_log_formatter::test_unit_start( std::ostream& /*ostr*/, test_unit const& tu )
  450. {
  451. list_path_to_root.push_back( tu.p_id );
  452. map_tests.insert(std::make_pair(tu.p_id, junit_impl::junit_log_helper())); // current_test_case_id not working here
  453. }
  454. //____________________________________________________________________________//
  455. void
  456. junit_log_formatter::test_unit_finish( std::ostream& /*ostr*/, test_unit const& tu, unsigned long /*elapsed*/ )
  457. {
  458. // the time is already stored in the result_reporter
  459. boost::ignore_unused( tu );
  460. assert( tu.p_id == list_path_to_root.back() );
  461. list_path_to_root.pop_back();
  462. }
  463. void
  464. junit_log_formatter::test_unit_aborted( std::ostream& /*ostr*/, test_unit const& tu )
  465. {
  466. boost::ignore_unused( tu );
  467. assert( tu.p_id == list_path_to_root.back() );
  468. //list_path_to_root.pop_back();
  469. }
  470. //____________________________________________________________________________//
  471. void
  472. junit_log_formatter::test_unit_timed_out( std::ostream& /*os*/, test_unit const& tu)
  473. {
  474. if(tu.p_type == TUT_SUITE)
  475. {
  476. // if we reach this call, it means that the test has already started and
  477. // test_unit_start has already been called on the tu.
  478. junit_impl::junit_log_helper& last_entry = get_current_log_entry();
  479. junit_impl::junit_log_helper::assertion_entry entry;
  480. entry.logentry_message = "test-suite time out";
  481. entry.logentry_type = "execution timeout";
  482. entry.log_entry = junit_impl::junit_log_helper::assertion_entry::log_entry_error;
  483. entry.output = "the current suite exceeded the allocated execution time";
  484. last_entry.assertion_entries.push_back(entry);
  485. }
  486. }
  487. //____________________________________________________________________________//
  488. void
  489. junit_log_formatter::test_unit_skipped( std::ostream& /*ostr*/, test_unit const& tu, const_string reason )
  490. {
  491. // if a test unit is skipped, then the start of this TU has not been called yet.
  492. // we cannot use get_current_log_entry here, but the TU id should appear in the map.
  493. // The "skip" boolean is given by the boost.test framework
  494. junit_impl::junit_log_helper& v = map_tests[tu.p_id]; // not sure if we can use get_current_log_entry()
  495. v.skipping_reason.assign(reason.begin(), reason.end());
  496. }
  497. //____________________________________________________________________________//
  498. void
  499. junit_log_formatter::log_exception_start( std::ostream& /*ostr*/, log_checkpoint_data const& checkpoint_data, execution_exception const& ex )
  500. {
  501. std::ostringstream o;
  502. execution_exception::location const& loc = ex.where();
  503. m_is_last_assertion_or_error = false;
  504. junit_impl::junit_log_helper& last_entry = get_current_log_entry();
  505. junit_impl::junit_log_helper::assertion_entry entry;
  506. entry.logentry_message = "unexpected exception";
  507. entry.log_entry = junit_impl::junit_log_helper::assertion_entry::log_entry_error;
  508. switch(ex.code())
  509. {
  510. case execution_exception::cpp_exception_error:
  511. entry.logentry_type = "uncaught exception";
  512. break;
  513. case execution_exception::timeout_error:
  514. entry.logentry_type = "execution timeout";
  515. break;
  516. case execution_exception::user_error:
  517. entry.logentry_type = "user, assert() or CRT error";
  518. break;
  519. case execution_exception::user_fatal_error:
  520. // Looks like never used
  521. entry.logentry_type = "user fatal error";
  522. break;
  523. case execution_exception::system_error:
  524. entry.logentry_type = "system error";
  525. break;
  526. case execution_exception::system_fatal_error:
  527. entry.logentry_type = "system fatal error";
  528. break;
  529. default:
  530. entry.logentry_type = "no error"; // not sure how to handle this one
  531. break;
  532. }
  533. o << "UNCAUGHT EXCEPTION:" << std::endl;
  534. if( !loc.m_function.is_empty() )
  535. o << "- function: \"" << loc.m_function << "\"" << std::endl;
  536. o << "- file: " << file_basename(loc.m_file_name) << std::endl
  537. << "- line: " << loc.m_line_num << std::endl
  538. << std::endl;
  539. o << "\nEXCEPTION STACK TRACE: --------------\n" << ex.what()
  540. << "\n-------------------------------------";
  541. if( !checkpoint_data.m_file_name.is_empty() ) {
  542. o << std::endl << std::endl
  543. << "Last checkpoint:" << std::endl
  544. << "- message: \"" << checkpoint_data.m_message << "\"" << std::endl
  545. << "- file: " << file_basename(checkpoint_data.m_file_name) << std::endl
  546. << "- line: " << checkpoint_data.m_line_num << std::endl
  547. ;
  548. }
  549. entry.output = o.str();
  550. last_entry.assertion_entries.push_back(entry);
  551. }
  552. //____________________________________________________________________________//
  553. void
  554. junit_log_formatter::log_exception_finish( std::ostream& /*ostr*/ )
  555. {
  556. // sealing the last entry
  557. assert(!get_current_log_entry().assertion_entries.back().sealed);
  558. get_current_log_entry().assertion_entries.back().sealed = true;
  559. }
  560. //____________________________________________________________________________//
  561. void
  562. junit_log_formatter::log_entry_start( std::ostream& /*ostr*/, log_entry_data const& entry_data, log_entry_types let )
  563. {
  564. junit_impl::junit_log_helper& last_entry = get_current_log_entry();
  565. last_entry.skipping = false;
  566. m_is_last_assertion_or_error = true;
  567. switch(let)
  568. {
  569. case unit_test_log_formatter::BOOST_UTL_ET_INFO:
  570. {
  571. if(m_log_level_internal > log_successful_tests) {
  572. last_entry.skipping = true;
  573. break;
  574. }
  575. BOOST_FALLTHROUGH;
  576. }
  577. case unit_test_log_formatter::BOOST_UTL_ET_MESSAGE:
  578. {
  579. if(m_log_level_internal > log_messages) {
  580. last_entry.skipping = true;
  581. break;
  582. }
  583. BOOST_FALLTHROUGH;
  584. }
  585. case unit_test_log_formatter::BOOST_UTL_ET_WARNING:
  586. {
  587. if(m_log_level_internal > log_warnings) {
  588. last_entry.skipping = true;
  589. break;
  590. }
  591. std::ostringstream o;
  592. junit_impl::junit_log_helper::assertion_entry entry;
  593. entry.log_entry = junit_impl::junit_log_helper::assertion_entry::log_entry_info;
  594. entry.logentry_message = "info";
  595. entry.logentry_type = "message";
  596. o << (let == unit_test_log_formatter::BOOST_UTL_ET_WARNING ?
  597. "WARNING:" : (let == unit_test_log_formatter::BOOST_UTL_ET_MESSAGE ?
  598. "MESSAGE:" : "INFO:"))
  599. << std::endl
  600. << "- file : " << file_basename(entry_data.m_file_name) << std::endl
  601. << "- line : " << entry_data.m_line_num << std::endl
  602. << "- message: "; // no CR
  603. entry.output += o.str();
  604. last_entry.assertion_entries.push_back(entry);
  605. break;
  606. }
  607. default:
  608. case unit_test_log_formatter::BOOST_UTL_ET_ERROR:
  609. case unit_test_log_formatter::BOOST_UTL_ET_FATAL_ERROR:
  610. {
  611. std::ostringstream o;
  612. junit_impl::junit_log_helper::assertion_entry entry;
  613. entry.log_entry = junit_impl::junit_log_helper::assertion_entry::log_entry_failure;
  614. entry.logentry_message = "failure";
  615. entry.logentry_type = (let == unit_test_log_formatter::BOOST_UTL_ET_ERROR ? "assertion error" : "fatal error");
  616. o << "ASSERTION FAILURE:" << std::endl
  617. << "- file : " << file_basename(entry_data.m_file_name) << std::endl
  618. << "- line : " << entry_data.m_line_num << std::endl
  619. << "- message: " ; // no CR
  620. entry.output += o.str();
  621. last_entry.assertion_entries.push_back(entry);
  622. break;
  623. }
  624. }
  625. }
  626. //____________________________________________________________________________//
  627. void
  628. junit_log_formatter::log_entry_value( std::ostream& /*ostr*/, const_string value )
  629. {
  630. junit_impl::junit_log_helper& last_entry = get_current_log_entry();
  631. if(last_entry.skipping)
  632. return;
  633. assert(last_entry.assertion_entries.empty() || !last_entry.assertion_entries.back().sealed);
  634. if(!last_entry.assertion_entries.empty())
  635. {
  636. junit_impl::junit_log_helper::assertion_entry& log_entry = last_entry.assertion_entries.back();
  637. log_entry.output += value;
  638. }
  639. else
  640. {
  641. // this may be a message coming from another observer
  642. // the prefix is set in the log_entry_start
  643. last_entry.system_out.push_back(std::string(value.begin(), value.end()));
  644. }
  645. }
  646. //____________________________________________________________________________//
  647. void
  648. junit_log_formatter::log_entry_finish( std::ostream& /*ostr*/ )
  649. {
  650. junit_impl::junit_log_helper& last_entry = get_current_log_entry();
  651. if(!last_entry.skipping)
  652. {
  653. assert(last_entry.assertion_entries.empty() || !last_entry.assertion_entries.back().sealed);
  654. if(!last_entry.assertion_entries.empty()) {
  655. junit_impl::junit_log_helper::assertion_entry& log_entry = last_entry.assertion_entries.back();
  656. log_entry.output += "\n\n"; // quote end, CR
  657. log_entry.sealed = true;
  658. }
  659. else {
  660. last_entry.system_out.push_back("\n\n"); // quote end, CR
  661. }
  662. }
  663. last_entry.skipping = false;
  664. }
  665. //____________________________________________________________________________//
  666. void
  667. junit_log_formatter::entry_context_start( std::ostream& /*ostr*/, log_level )
  668. {
  669. junit_impl::junit_log_helper& last_entry = get_current_log_entry();
  670. if(last_entry.skipping)
  671. return;
  672. std::vector< junit_impl::junit_log_helper::assertion_entry > &v_failure_or_error = last_entry.assertion_entries;
  673. assert(!v_failure_or_error.back().sealed);
  674. junit_impl::junit_log_helper::assertion_entry& last_log_entry = v_failure_or_error.back();
  675. if(m_is_last_assertion_or_error)
  676. {
  677. last_log_entry.output += "\n- context:\n";
  678. }
  679. else
  680. {
  681. last_log_entry.output += "\n\nCONTEXT:\n";
  682. }
  683. }
  684. //____________________________________________________________________________//
  685. void
  686. junit_log_formatter::entry_context_finish( std::ostream& /*ostr*/, log_level )
  687. {
  688. // no op, may be removed
  689. junit_impl::junit_log_helper& last_entry = get_current_log_entry();
  690. if(last_entry.skipping)
  691. return;
  692. assert(!get_current_log_entry().assertion_entries.back().sealed);
  693. }
  694. //____________________________________________________________________________//
  695. void
  696. junit_log_formatter::log_entry_context( std::ostream& /*ostr*/, log_level , const_string context_descr )
  697. {
  698. junit_impl::junit_log_helper& last_entry = get_current_log_entry();
  699. if(last_entry.skipping)
  700. return;
  701. assert(!last_entry.assertion_entries.back().sealed);
  702. junit_impl::junit_log_helper::assertion_entry& last_log_entry = get_current_log_entry().assertion_entries.back();
  703. last_log_entry.output +=
  704. (m_is_last_assertion_or_error ? " - '": "- '") + std::string(context_descr.begin(), context_descr.end()) + "'\n"; // quote end
  705. }
  706. //____________________________________________________________________________//
  707. std::string
  708. junit_log_formatter::get_default_stream_description() const {
  709. std::string name = framework::master_test_suite().p_name.value;
  710. static const std::string to_replace[] = { " ", "\"", "/", "\\", ":"};
  711. static const std::string replacement[] = { "_", "_" , "_", "_" , "_"};
  712. name = unit_test::utils::replace_all_occurrences_of(
  713. name,
  714. to_replace, to_replace + sizeof(to_replace)/sizeof(to_replace[0]),
  715. replacement, replacement + sizeof(replacement)/sizeof(replacement[0]));
  716. std::ifstream check_init((name + ".xml").c_str());
  717. if(!check_init)
  718. return name + ".xml";
  719. int index = 0;
  720. for(; index < 100; index++) {
  721. std::string candidate = name + "_" + utils::string_cast(index) + ".xml";
  722. std::ifstream file(candidate.c_str());
  723. if(!file)
  724. return candidate;
  725. }
  726. return name + ".xml";
  727. }
  728. } // namespace output
  729. } // namespace unit_test
  730. } // namespace boost
  731. #include <boost/test/detail/enable_warnings.hpp>
  732. #endif // BOOST_TEST_junit_log_formatter_IPP_020105GER