junit_log_formatter.ipp 29 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841
  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. // 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. name += "-setup-teardown";
  201. }
  202. m_stream << "<testcase assertions" << utils::attr_value() << nb_assertions;
  203. if(!classname.empty())
  204. m_stream << " classname" << utils::attr_value() << classname;
  205. // test case name and time taken
  206. m_stream
  207. << " name" << utils::attr_value() << name
  208. << " time" << utils::attr_value() << double(tr->p_duration_microseconds) * 1E-6
  209. << ">" << std::endl;
  210. }
  211. void write_testcase_system_out(junit_impl::junit_log_helper const &detailed_log,
  212. test_unit const * tu,
  213. bool skipped) const
  214. {
  215. // system-out + all info/messages, the object skips the empty entries
  216. conditional_cdata_helper system_out_helper(m_stream, "system-out");
  217. // indicate why the test has been skipped first
  218. if( skipped ) {
  219. std::list<std::string> skipping_decision_chain = build_skipping_chain(*tu);
  220. for(list_str_citerator it(skipping_decision_chain.begin()), ite(skipping_decision_chain.end());
  221. it != ite;
  222. ++it)
  223. {
  224. system_out_helper(*it);
  225. }
  226. }
  227. // stdout
  228. for(list_str_citerator it(detailed_log.system_out.begin()), ite(detailed_log.system_out.end());
  229. it != ite;
  230. ++it)
  231. {
  232. system_out_helper(*it);
  233. }
  234. // warning/info message last
  235. for(vect_assertion_entry_citerator it(detailed_log.assertion_entries.begin());
  236. it != detailed_log.assertion_entries.end();
  237. ++it)
  238. {
  239. if(it->log_entry != assertion_entry::log_entry_info)
  240. continue;
  241. system_out_helper(it->output);
  242. }
  243. }
  244. void write_testcase_system_err(junit_impl::junit_log_helper const &detailed_log,
  245. test_unit const * tu,
  246. test_results const *tr) const
  247. {
  248. // system-err output + test case informations
  249. bool has_failed = (tr != 0) ? !tr->p_skipped && !tr->passed() : false;
  250. if(!detailed_log.system_err.empty() || has_failed)
  251. {
  252. std::ostringstream o;
  253. if(has_failed) {
  254. o << "Failures detected in:" << std::endl;
  255. }
  256. else {
  257. o << "ERROR STREAM:" << std::endl;
  258. }
  259. if(tu->p_type == TUT_SUITE) {
  260. if( tu->p_id == m_ts.p_id ) {
  261. o << " boost.test global setup/teardown" << std::endl;
  262. } else {
  263. o << "- test suite: " << tu_name_remove_newlines(tu->full_name()) << std::endl;
  264. }
  265. }
  266. else {
  267. o << "- test case: " << tu_name_remove_newlines(tu->full_name());
  268. if(!tu->p_description.value.empty())
  269. o << " '" << tu->p_description << "'";
  270. o << std::endl
  271. << "- file: " << file_basename(tu->p_file_name) << std::endl
  272. << "- line: " << tu->p_line_num << std::endl
  273. ;
  274. }
  275. if(!detailed_log.system_err.empty())
  276. o << std::endl << "STDERR BEGIN: ------------" << std::endl;
  277. for(list_str_citerator it(detailed_log.system_err.begin()), ite(detailed_log.system_err.end());
  278. it != ite;
  279. ++it)
  280. {
  281. o << *it;
  282. }
  283. if(!detailed_log.system_err.empty())
  284. o << std::endl << "STDERR END ------------" << std::endl;
  285. conditional_cdata_helper system_err_helper(m_stream, "system-err");
  286. system_err_helper(o.str());
  287. }
  288. }
  289. int get_nb_assertions(junit_impl::junit_log_helper const &detailed_log,
  290. test_unit const & tu,
  291. test_results const *tr) const {
  292. int nb_assertions(-1);
  293. if( tu.p_type == TUT_SUITE ) {
  294. nb_assertions = 0;
  295. for(vect_assertion_entry_citerator it(detailed_log.assertion_entries.begin());
  296. it != detailed_log.assertion_entries.end();
  297. ++it)
  298. {
  299. if(it->log_entry != assertion_entry::log_entry_info)
  300. nb_assertions++;
  301. }
  302. }
  303. else {
  304. nb_assertions = tr->p_assertions_passed + tr->p_assertions_failed;
  305. }
  306. return nb_assertions;
  307. }
  308. void output_detailed_logs(junit_impl::junit_log_helper const &detailed_log,
  309. test_unit const & tu,
  310. bool skipped,
  311. test_results const *tr) const
  312. {
  313. int nb_assertions = get_nb_assertions(detailed_log, tu, tr);
  314. if(!nb_assertions && tu.p_type == TUT_SUITE)
  315. return;
  316. write_testcase_header(tu, tr, nb_assertions);
  317. if( skipped ) {
  318. m_stream << "<skipped/>" << std::endl;
  319. }
  320. else {
  321. for(vect_assertion_entry_citerator it(detailed_log.assertion_entries.begin());
  322. it != detailed_log.assertion_entries.end();
  323. ++it)
  324. {
  325. add_log_entry(*it);
  326. }
  327. }
  328. write_testcase_system_out(detailed_log, &tu, skipped);
  329. write_testcase_system_err(detailed_log, &tu, tr);
  330. m_stream << "</testcase>" << std::endl;
  331. }
  332. void visit( test_case const& tc )
  333. {
  334. test_results const& tr = results_collector.results( tc.p_id );
  335. junit_log_formatter::map_trace_t::const_iterator it_find = m_map_test.find(tc.p_id);
  336. if(it_find == m_map_test.end())
  337. {
  338. // test has been skipped and not seen by the logger
  339. output_detailed_logs(junit_impl::junit_log_helper(), tc, true, &tr);
  340. }
  341. else {
  342. output_detailed_logs(it_find->second, tc, tr.p_skipped, &tr);
  343. }
  344. }
  345. bool test_suite_start( test_suite const& ts )
  346. {
  347. test_results const& tr = results_collector.results( ts.p_id );
  348. // unique test suite, without s, nesting not supported in CI
  349. if( m_ts.p_id == ts.p_id ) {
  350. m_stream << "<testsuite";
  351. m_stream
  352. // << "disabled=\"" << tr.p_test_cases_skipped << "\" "
  353. << " tests" << utils::attr_value() << tr.p_test_cases_passed
  354. << " skipped" << utils::attr_value() << tr.p_test_cases_skipped
  355. << " errors" << utils::attr_value() << tr.p_test_cases_aborted
  356. << " failures" << utils::attr_value() << tr.p_test_cases_failed
  357. << " id" << utils::attr_value() << m_id++
  358. << " name" << utils::attr_value() << tu_name_normalize(ts.p_name)
  359. << " time" << utils::attr_value() << (tr.p_duration_microseconds * 1E-6)
  360. << ">" << std::endl;
  361. if(m_display_build_info)
  362. {
  363. m_stream << "<properties>" << std::endl;
  364. m_stream << "<property name=\"platform\" value" << utils::attr_value() << BOOST_PLATFORM << " />" << std::endl;
  365. m_stream << "<property name=\"compiler\" value" << utils::attr_value() << BOOST_COMPILER << " />" << std::endl;
  366. m_stream << "<property name=\"stl\" value" << utils::attr_value() << BOOST_STDLIB << " />" << std::endl;
  367. std::ostringstream o;
  368. o << BOOST_VERSION/100000 << "." << BOOST_VERSION/100 % 1000 << "." << BOOST_VERSION % 100;
  369. m_stream << "<property name=\"boost\" value" << utils::attr_value() << o.str() << " />" << std::endl;
  370. m_stream << "</properties>" << std::endl;
  371. }
  372. }
  373. if( !tr.p_skipped ) {
  374. // if we land here, then this is a chance that we are logging the fixture setup/teardown of a test-suite.
  375. // the setup/teardown logging of a test-case is part of the test case.
  376. // we do not care about the test-suite that were skipped (really??)
  377. junit_log_formatter::map_trace_t::const_iterator it_find = m_map_test.find(ts.p_id);
  378. if(it_find != m_map_test.end()) {
  379. output_detailed_logs(it_find->second, ts, false, &tr);
  380. }
  381. }
  382. return true; // indicates that the children should also be parsed
  383. }
  384. virtual void test_suite_finish( test_suite const& ts )
  385. {
  386. if( m_ts.p_id == ts.p_id ) {
  387. write_testcase_system_out(runner_log, 0, false);
  388. write_testcase_system_err(runner_log, 0, 0);
  389. m_stream << "</testsuite>";
  390. return;
  391. }
  392. }
  393. private:
  394. // Data members
  395. std::ostream& m_stream;
  396. test_unit const& m_ts;
  397. junit_log_formatter::map_trace_t const& m_map_test;
  398. junit_impl::junit_log_helper const& runner_log;
  399. size_t m_id;
  400. bool m_display_build_info;
  401. };
  402. void
  403. junit_log_formatter::log_finish( std::ostream& ostr )
  404. {
  405. ostr << "<?xml version=\"1.0\" encoding=\"UTF-8\"?>" << std::endl;
  406. // getting the root test suite
  407. if(!map_tests.empty()) {
  408. test_unit* root = &boost::unit_test::framework::get( map_tests.begin()->first, TUT_ANY );
  409. // looking for the root of the SUBtree (we stay in the subtree)
  410. while(root->p_parent_id != INV_TEST_UNIT_ID && map_tests.count(root->p_parent_id) > 0) {
  411. root = &boost::unit_test::framework::get( root->p_parent_id, TUT_ANY );
  412. }
  413. junit_result_helper ch( ostr, *root, map_tests, this->runner_log_entry, m_display_build_info );
  414. traverse_test_tree( root->p_id, ch, true ); // last is to ignore disabled suite special handling
  415. }
  416. else {
  417. ostr << "<testsuites errors=\"1\">";
  418. ostr << "<testsuite errors=\"1\" name=\"boost-test-framework\">";
  419. ostr << "<testcase assertions=\"1\" name=\"test-setup\">";
  420. ostr << "<system-out>Incorrect setup: no test case executed</system-out>";
  421. ostr << "</testcase></testsuite></testsuites>";
  422. }
  423. return;
  424. }
  425. //____________________________________________________________________________//
  426. void
  427. junit_log_formatter::log_build_info( std::ostream& /*ostr*/ )
  428. {
  429. m_display_build_info = true;
  430. }
  431. //____________________________________________________________________________//
  432. void
  433. junit_log_formatter::test_unit_start( std::ostream& /*ostr*/, test_unit const& tu )
  434. {
  435. list_path_to_root.push_back( tu.p_id );
  436. map_tests.insert(std::make_pair(tu.p_id, junit_impl::junit_log_helper())); // current_test_case_id not working here
  437. }
  438. //____________________________________________________________________________//
  439. void
  440. junit_log_formatter::test_unit_finish( std::ostream& /*ostr*/, test_unit const& tu, unsigned long /*elapsed*/ )
  441. {
  442. // the time is already stored in the result_reporter
  443. assert( tu.p_id == list_path_to_root.back() );
  444. list_path_to_root.pop_back();
  445. }
  446. void
  447. junit_log_formatter::test_unit_aborted( std::ostream& /*ostr*/, test_unit const& tu )
  448. {
  449. assert( tu.p_id == list_path_to_root.back() );
  450. //list_path_to_root.pop_back();
  451. }
  452. //____________________________________________________________________________//
  453. void
  454. junit_log_formatter::test_unit_skipped( std::ostream& /*ostr*/, test_unit const& tu, const_string reason )
  455. {
  456. // if a test unit is skipped, then the start of this TU has not been called yet.
  457. // we cannot use get_current_log_entry here, but the TU id should appear in the map.
  458. // The "skip" boolean is given by the boost.test framework
  459. junit_impl::junit_log_helper& v = map_tests[tu.p_id]; // not sure if we can use get_current_log_entry()
  460. v.skipping_reason.assign(reason.begin(), reason.end());
  461. }
  462. //____________________________________________________________________________//
  463. void
  464. junit_log_formatter::log_exception_start( std::ostream& /*ostr*/, log_checkpoint_data const& checkpoint_data, execution_exception const& ex )
  465. {
  466. std::ostringstream o;
  467. execution_exception::location const& loc = ex.where();
  468. m_is_last_assertion_or_error = false;
  469. junit_impl::junit_log_helper& last_entry = get_current_log_entry();
  470. junit_impl::junit_log_helper::assertion_entry entry;
  471. entry.logentry_message = "unexpected exception";
  472. entry.log_entry = junit_impl::junit_log_helper::assertion_entry::log_entry_error;
  473. switch(ex.code())
  474. {
  475. case execution_exception::cpp_exception_error:
  476. entry.logentry_type = "uncaught exception";
  477. break;
  478. case execution_exception::timeout_error:
  479. entry.logentry_type = "execution timeout";
  480. break;
  481. case execution_exception::user_error:
  482. entry.logentry_type = "user, assert() or CRT error";
  483. break;
  484. case execution_exception::user_fatal_error:
  485. // Looks like never used
  486. entry.logentry_type = "user fatal error";
  487. break;
  488. case execution_exception::system_error:
  489. entry.logentry_type = "system error";
  490. break;
  491. case execution_exception::system_fatal_error:
  492. entry.logentry_type = "system fatal error";
  493. break;
  494. default:
  495. entry.logentry_type = "no error"; // not sure how to handle this one
  496. break;
  497. }
  498. o << "UNCAUGHT EXCEPTION:" << std::endl;
  499. if( !loc.m_function.is_empty() )
  500. o << "- function: \"" << loc.m_function << "\"" << std::endl;
  501. o << "- file: " << file_basename(loc.m_file_name) << std::endl
  502. << "- line: " << loc.m_line_num << std::endl
  503. << std::endl;
  504. o << "\nEXCEPTION STACK TRACE: --------------\n" << ex.what()
  505. << "\n-------------------------------------";
  506. if( !checkpoint_data.m_file_name.is_empty() ) {
  507. o << std::endl << std::endl
  508. << "Last checkpoint:" << std::endl
  509. << "- message: \"" << checkpoint_data.m_message << "\"" << std::endl
  510. << "- file: " << file_basename(checkpoint_data.m_file_name) << std::endl
  511. << "- line: " << checkpoint_data.m_line_num << std::endl
  512. ;
  513. }
  514. entry.output = o.str();
  515. last_entry.assertion_entries.push_back(entry);
  516. }
  517. //____________________________________________________________________________//
  518. void
  519. junit_log_formatter::log_exception_finish( std::ostream& /*ostr*/ )
  520. {
  521. // sealing the last entry
  522. assert(!get_current_log_entry().assertion_entries.back().sealed);
  523. get_current_log_entry().assertion_entries.back().sealed = true;
  524. }
  525. //____________________________________________________________________________//
  526. void
  527. junit_log_formatter::log_entry_start( std::ostream& /*ostr*/, log_entry_data const& entry_data, log_entry_types let )
  528. {
  529. junit_impl::junit_log_helper& last_entry = get_current_log_entry();
  530. last_entry.skipping = false;
  531. m_is_last_assertion_or_error = true;
  532. switch(let)
  533. {
  534. case unit_test_log_formatter::BOOST_UTL_ET_INFO:
  535. {
  536. if(m_log_level_internal > log_successful_tests) {
  537. last_entry.skipping = true;
  538. break;
  539. }
  540. BOOST_FALLTHROUGH;
  541. }
  542. case unit_test_log_formatter::BOOST_UTL_ET_MESSAGE:
  543. {
  544. if(m_log_level_internal > log_messages) {
  545. last_entry.skipping = true;
  546. break;
  547. }
  548. BOOST_FALLTHROUGH;
  549. }
  550. case unit_test_log_formatter::BOOST_UTL_ET_WARNING:
  551. {
  552. if(m_log_level_internal > log_warnings) {
  553. last_entry.skipping = true;
  554. break;
  555. }
  556. std::ostringstream o;
  557. junit_impl::junit_log_helper::assertion_entry entry;
  558. entry.log_entry = junit_impl::junit_log_helper::assertion_entry::log_entry_info;
  559. entry.logentry_message = "info";
  560. entry.logentry_type = "message";
  561. o << (let == unit_test_log_formatter::BOOST_UTL_ET_WARNING ?
  562. "WARNING:" : (let == unit_test_log_formatter::BOOST_UTL_ET_MESSAGE ?
  563. "MESSAGE:" : "INFO:"))
  564. << std::endl
  565. << "- file : " << file_basename(entry_data.m_file_name) << std::endl
  566. << "- line : " << entry_data.m_line_num << std::endl
  567. << "- message: "; // no CR
  568. entry.output += o.str();
  569. last_entry.assertion_entries.push_back(entry);
  570. break;
  571. }
  572. default:
  573. case unit_test_log_formatter::BOOST_UTL_ET_ERROR:
  574. case unit_test_log_formatter::BOOST_UTL_ET_FATAL_ERROR:
  575. {
  576. std::ostringstream o;
  577. junit_impl::junit_log_helper::assertion_entry entry;
  578. entry.log_entry = junit_impl::junit_log_helper::assertion_entry::log_entry_failure;
  579. entry.logentry_message = "failure";
  580. entry.logentry_type = (let == unit_test_log_formatter::BOOST_UTL_ET_ERROR ? "assertion error" : "fatal error");
  581. o << "ASSERTION FAILURE:" << std::endl
  582. << "- file : " << file_basename(entry_data.m_file_name) << std::endl
  583. << "- line : " << entry_data.m_line_num << std::endl
  584. << "- message: " ; // no CR
  585. entry.output += o.str();
  586. last_entry.assertion_entries.push_back(entry);
  587. break;
  588. }
  589. }
  590. }
  591. //____________________________________________________________________________//
  592. void
  593. junit_log_formatter::log_entry_value( std::ostream& /*ostr*/, const_string value )
  594. {
  595. junit_impl::junit_log_helper& last_entry = get_current_log_entry();
  596. if(last_entry.skipping)
  597. return;
  598. assert(last_entry.assertion_entries.empty() || !last_entry.assertion_entries.back().sealed);
  599. if(!last_entry.assertion_entries.empty())
  600. {
  601. junit_impl::junit_log_helper::assertion_entry& log_entry = last_entry.assertion_entries.back();
  602. log_entry.output += value;
  603. }
  604. else
  605. {
  606. // this may be a message coming from another observer
  607. // the prefix is set in the log_entry_start
  608. last_entry.system_out.push_back(std::string(value.begin(), value.end()));
  609. }
  610. }
  611. //____________________________________________________________________________//
  612. void
  613. junit_log_formatter::log_entry_finish( std::ostream& /*ostr*/ )
  614. {
  615. junit_impl::junit_log_helper& last_entry = get_current_log_entry();
  616. if(!last_entry.skipping)
  617. {
  618. assert(last_entry.assertion_entries.empty() || !last_entry.assertion_entries.back().sealed);
  619. if(!last_entry.assertion_entries.empty()) {
  620. junit_impl::junit_log_helper::assertion_entry& log_entry = last_entry.assertion_entries.back();
  621. log_entry.output += "\n\n"; // quote end, CR
  622. log_entry.sealed = true;
  623. }
  624. else {
  625. last_entry.system_out.push_back("\n\n"); // quote end, CR
  626. }
  627. }
  628. last_entry.skipping = false;
  629. }
  630. //____________________________________________________________________________//
  631. void
  632. junit_log_formatter::entry_context_start( std::ostream& /*ostr*/, log_level )
  633. {
  634. junit_impl::junit_log_helper& last_entry = get_current_log_entry();
  635. if(last_entry.skipping)
  636. return;
  637. std::vector< junit_impl::junit_log_helper::assertion_entry > &v_failure_or_error = last_entry.assertion_entries;
  638. assert(!v_failure_or_error.back().sealed);
  639. junit_impl::junit_log_helper::assertion_entry& last_log_entry = v_failure_or_error.back();
  640. if(m_is_last_assertion_or_error)
  641. {
  642. last_log_entry.output += "\n- context:\n";
  643. }
  644. else
  645. {
  646. last_log_entry.output += "\n\nCONTEXT:\n";
  647. }
  648. }
  649. //____________________________________________________________________________//
  650. void
  651. junit_log_formatter::entry_context_finish( std::ostream& /*ostr*/, log_level )
  652. {
  653. // no op, may be removed
  654. junit_impl::junit_log_helper& last_entry = get_current_log_entry();
  655. if(last_entry.skipping)
  656. return;
  657. assert(!get_current_log_entry().assertion_entries.back().sealed);
  658. }
  659. //____________________________________________________________________________//
  660. void
  661. junit_log_formatter::log_entry_context( std::ostream& /*ostr*/, log_level , const_string context_descr )
  662. {
  663. junit_impl::junit_log_helper& last_entry = get_current_log_entry();
  664. if(last_entry.skipping)
  665. return;
  666. assert(!last_entry.assertion_entries.back().sealed);
  667. junit_impl::junit_log_helper::assertion_entry& last_log_entry = get_current_log_entry().assertion_entries.back();
  668. last_log_entry.output +=
  669. (m_is_last_assertion_or_error ? " - '": "- '") + std::string(context_descr.begin(), context_descr.end()) + "'\n"; // quote end
  670. }
  671. //____________________________________________________________________________//
  672. std::string
  673. junit_log_formatter::get_default_stream_description() const {
  674. std::string name = framework::master_test_suite().p_name.value;
  675. static const std::string to_replace[] = { " ", "\"", "/", "\\", ":"};
  676. static const std::string replacement[] = { "_", "_" , "_", "_" , "_"};
  677. name = unit_test::utils::replace_all_occurrences_of(
  678. name,
  679. to_replace, to_replace + sizeof(to_replace)/sizeof(to_replace[0]),
  680. replacement, replacement + sizeof(replacement)/sizeof(replacement[0]));
  681. std::ifstream check_init((name + ".xml").c_str());
  682. if(!check_init)
  683. return name + ".xml";
  684. int index = 0;
  685. for(; index < 100; index++) {
  686. std::string candidate = name + "_" + utils::string_cast(index) + ".xml";
  687. std::ifstream file(candidate.c_str());
  688. if(!file)
  689. return candidate;
  690. }
  691. return name + ".xml";
  692. }
  693. } // namespace output
  694. } // namespace unit_test
  695. } // namespace boost
  696. #include <boost/test/detail/enable_warnings.hpp>
  697. #endif // BOOST_TEST_junit_log_formatter_IPP_020105GER