junit_log_formatter.ipp 30 KB

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