]> git.proxmox.com Git - ceph.git/blob - ceph/src/boost/libs/test/include/boost/test/impl/junit_log_formatter.ipp
bump version to 12.2.2-pve1
[ceph.git] / ceph / src / boost / libs / test / include / boost / test / impl / junit_log_formatter.ipp
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
6 // See http://www.boost.org/libs/test for the library home page.
7 //
8 ///@file
9 ///@brief Contains the implementatoin of the Junit log formatter (OF_JUNIT)
10 // ***************************************************************************
11
12 #ifndef BOOST_TEST_JUNIT_LOG_FORMATTER_IPP__
13 #define BOOST_TEST_JUNIT_LOG_FORMATTER_IPP__
14
15 // Boost.Test
16 #include <boost/test/output/junit_log_formatter.hpp>
17 #include <boost/test/execution_monitor.hpp>
18 #include <boost/test/framework.hpp>
19 #include <boost/test/tree/test_unit.hpp>
20 #include <boost/test/utils/basic_cstring/io.hpp>
21 #include <boost/test/utils/xml_printer.hpp>
22 #include <boost/test/utils/string_cast.hpp>
23 #include <boost/test/framework.hpp>
24
25 #include <boost/test/tree/visitor.hpp>
26 #include <boost/test/tree/test_case_counter.hpp>
27 #include <boost/test/tree/traverse.hpp>
28 #include <boost/test/results_collector.hpp>
29
30 #include <boost/test/utils/algorithm.hpp>
31 #include <boost/test/utils/string_cast.hpp>
32
33 //#include <boost/test/results_reporter.hpp>
34
35
36 // Boost
37 #include <boost/version.hpp>
38
39 // STL
40 #include <iostream>
41 #include <fstream>
42 #include <set>
43
44 #include <boost/test/detail/suppress_warnings.hpp>
45
46
47 //____________________________________________________________________________//
48
49 namespace boost {
50 namespace unit_test {
51 namespace output {
52
53
54 struct s_replace_chars {
55 template <class T>
56 void operator()(T& to_replace)
57 {
58 if(to_replace == '/')
59 to_replace = '.';
60 else if(to_replace == ' ')
61 to_replace = '_';
62 }
63 };
64
65 inline std::string tu_name_normalize(std::string full_name)
66 {
67 // maybe directly using normalize_test_case_name instead?
68 std::for_each(full_name.begin(), full_name.end(), s_replace_chars());
69 return full_name;
70 }
71
72 const_string file_basename(const_string filename) {
73
74 const_string path_sep( "\\/" );
75 const_string::iterator it = unit_test::utils::find_last_of( filename.begin(), filename.end(),
76 path_sep.begin(), path_sep.end() );
77 if( it != filename.end() )
78 filename.trim_left( it + 1 );
79
80 return filename;
81
82 }
83
84 // ************************************************************************** //
85 // ************** junit_log_formatter ************** //
86 // ************************************************************************** //
87
88 void
89 junit_log_formatter::log_start( std::ostream& ostr, counter_t test_cases_amount)
90 {
91 map_tests.clear();
92 list_path_to_root.clear();
93 root_id = INV_TEST_UNIT_ID;
94 }
95
96 //____________________________________________________________________________//
97
98 class junit_result_helper : public test_tree_visitor {
99 public:
100 explicit junit_result_helper(
101 std::ostream& stream,
102 test_unit const& ts,
103 junit_log_formatter::map_trace_t const& mt,
104 bool display_build_info )
105 : m_stream(stream)
106 , m_ts( ts )
107 , m_map_test( mt )
108 , m_id( 0 )
109 , m_display_build_info(display_build_info)
110 { }
111
112 void add_log_entry(std::string const& entry_type,
113 test_case const& tc,
114 junit_impl::junit_log_helper::assertion_entry const& log) const
115 {
116 m_stream
117 << "<" << entry_type
118 << " message" << utils::attr_value() << log.logentry_message
119 << " type" << utils::attr_value() << log.logentry_type
120 << ">";
121
122 if(!log.output.empty()) {
123 m_stream << utils::cdata() << "\n" + log.output;
124 }
125
126 m_stream << "</" << entry_type << ">";
127 }
128
129 void visit( test_case const& tc )
130 {
131 test_results const& tr = results_collector.results( tc.p_id );
132
133 junit_impl::junit_log_helper detailed_log;
134 bool need_skipping_reason = false;
135 bool skipped = false;
136
137 junit_log_formatter::map_trace_t::const_iterator it_element(m_map_test.find(tc.p_id));
138 if( it_element != m_map_test.end() )
139 {
140 detailed_log = it_element->second;
141 }
142 else
143 {
144 need_skipping_reason = true;
145 }
146
147 std::string classname;
148 test_unit_id id(tc.p_parent_id);
149 while( id != m_ts.p_id ) {
150 test_unit const& tu = boost::unit_test::framework::get( id, TUT_ANY );
151
152 if(need_skipping_reason)
153 {
154 test_results const& tr_parent = results_collector.results( id );
155 if( tr_parent.p_skipped )
156 {
157 skipped = true;
158 detailed_log.system_out+= "- disabled: " + tu.full_name() + "\n";
159 }
160 junit_log_formatter::map_trace_t::const_iterator it_element_stack(m_map_test.find(id));
161 if( it_element_stack != m_map_test.end() )
162 {
163 detailed_log.system_out+= "- skipping decision: '" + it_element_stack->second.system_out + "'";
164 detailed_log.system_out = "SKIPPING decision stack:\n" + detailed_log.system_out;
165 need_skipping_reason = false;
166 }
167 }
168
169 classname = tu_name_normalize(tu.p_name) + "." + classname;
170 id = tu.p_parent_id;
171 }
172
173 // removes the trailing dot
174 if(!classname.empty() && *classname.rbegin() == '.') {
175 classname.erase(classname.size()-1);
176 }
177
178 //
179 // test case header
180
181 // total number of assertions
182 m_stream << "<testcase assertions" << utils::attr_value() << tr.p_assertions_passed + tr.p_assertions_failed;
183
184 // class name
185 if(!classname.empty())
186 m_stream << " classname" << utils::attr_value() << classname;
187
188 // test case name and time taken
189 m_stream
190 << " name" << utils::attr_value() << tu_name_normalize(tc.p_name)
191 << " time" << utils::attr_value() << double(tr.p_duration_microseconds) * 1E-6
192 << ">" << std::endl;
193
194 if( tr.p_skipped || skipped ) {
195 m_stream << "<skipped/>" << std::endl;
196 }
197 else {
198
199 for(std::vector< junit_impl::junit_log_helper::assertion_entry >::const_iterator it(detailed_log.assertion_entries.begin());
200 it != detailed_log.assertion_entries.end();
201 ++it)
202 {
203 if(it->log_entry == junit_impl::junit_log_helper::assertion_entry::log_entry_failure) {
204 add_log_entry("failure", tc, *it);
205 }
206 else if(it->log_entry == junit_impl::junit_log_helper::assertion_entry::log_entry_error) {
207 add_log_entry("error", tc, *it);
208 }
209 }
210 }
211
212 // system-out + all info/messages
213 std::string system_out = detailed_log.system_out;
214 for(std::vector< junit_impl::junit_log_helper::assertion_entry >::const_iterator it(detailed_log.assertion_entries.begin());
215 it != detailed_log.assertion_entries.end();
216 ++it)
217 {
218 if(it->log_entry != junit_impl::junit_log_helper::assertion_entry::log_entry_info)
219 continue;
220 system_out += it->output;
221 }
222
223 if(!system_out.empty()) {
224 m_stream
225 << "<system-out>"
226 << utils::cdata() << system_out
227 << "</system-out>"
228 << std::endl;
229 }
230
231 // system-err output + test case informations
232 std::string system_err = detailed_log.system_err;
233 {
234 // test case information (redundant but useful)
235 std::ostringstream o;
236 o << "Test case:" << std::endl
237 << "- name: " << tc.full_name() << std::endl
238 << "- description: '" << tc.p_description << "'" << std::endl
239 << "- file: " << file_basename(tc.p_file_name) << std::endl
240 << "- line: " << tc.p_line_num << std::endl
241 ;
242 system_err = o.str() + system_err;
243 }
244 m_stream
245 << "<system-err>"
246 << utils::cdata() << system_err
247 << "</system-err>"
248 << std::endl;
249
250 m_stream << "</testcase>" << std::endl;
251 }
252
253 bool test_suite_start( test_suite const& ts )
254 {
255 // unique test suite, without s, nesting not supported in CI
256 if( m_ts.p_id != ts.p_id )
257 return true;
258
259 test_results const& tr = results_collector.results( ts.p_id );
260
261 m_stream << "<?xml version=\"1.0\" encoding=\"UTF-8\"?>" << std::endl;
262 m_stream << "<testsuite";
263
264 m_stream
265 // << "disabled=\"" << tr.p_test_cases_skipped << "\" "
266 << " tests" << utils::attr_value() << tr.p_test_cases_passed
267 << " skipped" << utils::attr_value() << tr.p_test_cases_skipped
268 << " errors" << utils::attr_value() << tr.p_test_cases_aborted
269 << " failures" << utils::attr_value() << tr.p_test_cases_failed
270 << " id" << utils::attr_value() << m_id++
271 << " name" << utils::attr_value() << tu_name_normalize(ts.p_name)
272 << " time" << utils::attr_value() << (tr.p_duration_microseconds * 1E-6)
273 << ">" << std::endl;
274
275 if(m_display_build_info)
276 {
277 m_stream << "<properties>" << std::endl;
278 m_stream << "<property name=\"platform\" value" << utils::attr_value() << BOOST_PLATFORM << std::endl;
279 m_stream << "<property name=\"compiler\" value" << utils::attr_value() << BOOST_COMPILER << std::endl;
280 m_stream << "<property name=\"stl\" value" << utils::attr_value() << BOOST_STDLIB << std::endl;
281
282 std::ostringstream o;
283 o << BOOST_VERSION/100000 << "." << BOOST_VERSION/100 % 1000 << "." << BOOST_VERSION % 100;
284 m_stream << "<property name=\"boost\" value" << utils::attr_value() << o.str() << std::endl;
285 m_stream << "</properties>" << std::endl;
286 }
287
288 return true; // indicates that the children should also be parsed
289 }
290
291 virtual void test_suite_finish( test_suite const& ts )
292 {
293 if( m_ts.p_id != ts.p_id )
294 return;
295 m_stream << "</testsuite>";
296 }
297
298 private:
299 // Data members
300 std::ostream& m_stream;
301 test_unit const& m_ts;
302 junit_log_formatter::map_trace_t const& m_map_test;
303 size_t m_id;
304 bool m_display_build_info;
305 };
306
307
308
309 void
310 junit_log_formatter::log_finish( std::ostream& ostr )
311 {
312 junit_result_helper ch( ostr, boost::unit_test::framework::get( root_id, TUT_SUITE ), map_tests, m_display_build_info );
313 traverse_test_tree( root_id, ch, true ); // last is to ignore disabled suite special handling
314
315 return;
316 }
317
318 //____________________________________________________________________________//
319
320 void
321 junit_log_formatter::log_build_info( std::ostream& ostr )
322 {
323 m_display_build_info = true;
324 }
325
326 //____________________________________________________________________________//
327
328 void
329 junit_log_formatter::test_unit_start( std::ostream& ostr, test_unit const& tu )
330 {
331 if(list_path_to_root.empty())
332 root_id = tu.p_id;
333 list_path_to_root.push_back( tu.p_id );
334 map_tests.insert(std::make_pair(tu.p_id, junit_impl::junit_log_helper())); // current_test_case_id not working here
335 }
336
337
338
339 //____________________________________________________________________________//
340
341 void
342 junit_log_formatter::test_unit_finish( std::ostream& ostr, test_unit const& tu, unsigned long elapsed )
343 {
344 // the time is already stored in the result_reporter
345 assert( tu.p_id == list_path_to_root.back() );
346 list_path_to_root.pop_back();
347 }
348
349 void
350 junit_log_formatter::test_unit_aborted( std::ostream& os, test_unit const& tu )
351 {
352 assert( tu.p_id == list_path_to_root.back() );
353 //list_path_to_root.pop_back();
354 }
355
356 //____________________________________________________________________________//
357
358 void
359 junit_log_formatter::test_unit_skipped( std::ostream& ostr, test_unit const& tu, const_string reason )
360 {
361 if(tu.p_type == TUT_CASE)
362 {
363 junit_impl::junit_log_helper& v = map_tests[tu.p_id];
364 v.system_out.assign(reason.begin(), reason.end());
365 }
366 else
367 {
368 junit_impl::junit_log_helper& v = map_tests[tu.p_id];
369 v.system_out.assign(reason.begin(), reason.end());
370 }
371 }
372
373 //____________________________________________________________________________//
374
375 void
376 junit_log_formatter::log_exception_start( std::ostream& ostr, log_checkpoint_data const& checkpoint_data, execution_exception const& ex )
377 {
378 std::ostringstream o;
379 execution_exception::location const& loc = ex.where();
380
381 m_is_last_assertion_or_error = false;
382
383 if(!list_path_to_root.empty())
384 {
385 junit_impl::junit_log_helper& last_entry = map_tests[list_path_to_root.back()];
386
387 junit_impl::junit_log_helper::assertion_entry entry;
388
389 entry.logentry_message = "unexpected exception";
390 entry.log_entry = junit_impl::junit_log_helper::assertion_entry::log_entry_error;
391
392 switch(ex.code())
393 {
394 case execution_exception::cpp_exception_error:
395 entry.logentry_type = "uncaught exception";
396 break;
397 case execution_exception::timeout_error:
398 entry.logentry_type = "execution timeout";
399 break;
400 case execution_exception::user_error:
401 entry.logentry_type = "user, assert() or CRT error";
402 break;
403 case execution_exception::user_fatal_error:
404 // Looks like never used
405 entry.logentry_type = "user fatal error";
406 break;
407 case execution_exception::system_error:
408 entry.logentry_type = "system error";
409 break;
410 case execution_exception::system_fatal_error:
411 entry.logentry_type = "system fatal error";
412 break;
413 default:
414 entry.logentry_type = "no error"; // not sure how to handle this one
415 break;
416 }
417
418 o << "UNCAUGHT EXCEPTION:" << std::endl;
419 if( !loc.m_function.is_empty() )
420 o << "- function: \"" << loc.m_function << "\"" << std::endl;
421
422 o << "- file: " << file_basename(loc.m_file_name) << std::endl
423 << "- line: " << loc.m_line_num << std::endl
424 << std::endl;
425
426 o << "\nEXCEPTION STACK TRACE: --------------\n" << ex.what()
427 << "\n-------------------------------------";
428
429 if( !checkpoint_data.m_file_name.is_empty() ) {
430 o << std::endl << std::endl
431 << "Last checkpoint:" << std::endl
432 << "- message: \"" << checkpoint_data.m_message << "\"" << std::endl
433 << "- file: " << file_basename(checkpoint_data.m_file_name) << std::endl
434 << "- line: " << checkpoint_data.m_line_num << std::endl
435 ;
436 }
437
438 entry.output = o.str();
439
440 last_entry.assertion_entries.push_back(entry);
441 }
442
443 // check what to do with this one
444 }
445
446 //____________________________________________________________________________//
447
448 void
449 junit_log_formatter::log_exception_finish( std::ostream& ostr )
450 {
451 // sealing the last entry
452 assert(!map_tests[list_path_to_root.back()].assertion_entries.back().sealed);
453 map_tests[list_path_to_root.back()].assertion_entries.back().sealed = true;
454 }
455
456 //____________________________________________________________________________//
457
458 void
459 junit_log_formatter::log_entry_start( std::ostream& ostr, log_entry_data const& entry_data, log_entry_types let )
460 {
461 junit_impl::junit_log_helper& last_entry = map_tests[list_path_to_root.back()];
462 m_is_last_assertion_or_error = true;
463 switch(let)
464 {
465 case unit_test_log_formatter::BOOST_UTL_ET_INFO:
466 case unit_test_log_formatter::BOOST_UTL_ET_MESSAGE:
467 case unit_test_log_formatter::BOOST_UTL_ET_WARNING:
468 {
469 std::ostringstream o;
470
471 junit_impl::junit_log_helper::assertion_entry entry;
472 entry.log_entry = junit_impl::junit_log_helper::assertion_entry::log_entry_info;
473 entry.logentry_message = "info";
474 entry.logentry_type = "message";
475
476 o << (let == unit_test_log_formatter::BOOST_UTL_ET_WARNING ?
477 "WARNING:" : (let == unit_test_log_formatter::BOOST_UTL_ET_MESSAGE ?
478 "MESSAGE:" : "INFO:"))
479 << std::endl
480 << "- file : " << file_basename(entry_data.m_file_name) << std::endl
481 << "- line : " << entry_data.m_line_num << std::endl
482 << "- message: "; // no CR
483
484 entry.output += o.str();
485 last_entry.assertion_entries.push_back(entry);
486 break;
487 }
488 default:
489 case unit_test_log_formatter::BOOST_UTL_ET_ERROR:
490 case unit_test_log_formatter::BOOST_UTL_ET_FATAL_ERROR:
491 {
492 std::ostringstream o;
493 junit_impl::junit_log_helper::assertion_entry entry;
494 entry.log_entry = junit_impl::junit_log_helper::assertion_entry::log_entry_failure;
495 entry.logentry_message = "failure";
496 entry.logentry_type = (let == unit_test_log_formatter::BOOST_UTL_ET_ERROR ? "assertion error" : "fatal error");
497
498 o << "ASSERTION FAILURE:" << std::endl
499 << "- file : " << file_basename(entry_data.m_file_name) << std::endl
500 << "- line : " << entry_data.m_line_num << std::endl
501 << "- message: " ; // no CR
502
503 entry.output += o.str();
504 last_entry.assertion_entries.push_back(entry);
505 break;
506 }
507 }
508
509 }
510
511 //____________________________________________________________________________//
512
513
514
515 //____________________________________________________________________________//
516
517 void
518 junit_log_formatter::log_entry_value( std::ostream& ostr, const_string value )
519 {
520 assert(map_tests[list_path_to_root.back()].assertion_entries.empty() || !map_tests[list_path_to_root.back()].assertion_entries.back().sealed);
521 junit_impl::junit_log_helper& last_entry = map_tests[list_path_to_root.back()];
522 std::ostringstream o;
523 utils::print_escaped_cdata( o, value );
524
525 if(!last_entry.assertion_entries.empty())
526 {
527 junit_impl::junit_log_helper::assertion_entry& log_entry = last_entry.assertion_entries.back();
528 log_entry.output += value;
529 }
530 else
531 {
532 // this may be a message coming from another observer
533 // the prefix is set in the log_entry_start
534 last_entry.system_out += value;
535 }
536 }
537
538 //____________________________________________________________________________//
539
540 void
541 junit_log_formatter::log_entry_finish( std::ostream& ostr )
542 {
543 assert(map_tests[list_path_to_root.back()].assertion_entries.empty() || !map_tests[list_path_to_root.back()].assertion_entries.back().sealed);
544 junit_impl::junit_log_helper& last_entry = map_tests[list_path_to_root.back()];
545 if(!last_entry.assertion_entries.empty()) {
546 junit_impl::junit_log_helper::assertion_entry& log_entry = last_entry.assertion_entries.back();
547 log_entry.output += "\n\n"; // quote end, CR
548 log_entry.sealed = true;
549 }
550 else {
551 last_entry.system_out += "\n\n"; // quote end, CR
552 }
553 }
554
555 //____________________________________________________________________________//
556
557 void
558 junit_log_formatter::entry_context_start( std::ostream& ostr, log_level )
559 {
560 std::vector< junit_impl::junit_log_helper::assertion_entry > &v_failure_or_error = map_tests[list_path_to_root.back()].assertion_entries;
561 assert(!v_failure_or_error.back().sealed);
562
563 if(m_is_last_assertion_or_error)
564 {
565 v_failure_or_error.back().output += "\n- context:\n";
566 }
567 else
568 {
569 v_failure_or_error.back().output += "\n\nCONTEXT:\n";
570 }
571 }
572
573 //____________________________________________________________________________//
574
575 void
576 junit_log_formatter::entry_context_finish( std::ostream& ostr )
577 {
578 // no op, may be removed
579 assert(!map_tests[list_path_to_root.back()].assertion_entries.back().sealed);
580 }
581
582 //____________________________________________________________________________//
583
584 void
585 junit_log_formatter::log_entry_context( std::ostream& ostr, const_string context_descr )
586 {
587 assert(!map_tests[list_path_to_root.back()].assertion_entries.back().sealed);
588 map_tests[list_path_to_root.back()].assertion_entries.back().output += (m_is_last_assertion_or_error ? " - '": "- '") + std::string(context_descr.begin(), context_descr.end()) + "'\n"; // quote end
589 }
590
591 //____________________________________________________________________________//
592
593
594 std::string
595 junit_log_formatter::get_default_stream_description() const {
596 std::string name = framework::master_test_suite().p_name.value;
597
598 static const std::string to_replace[] = { " ", "\"", "/", "\\", ":"};
599 static const std::string replacement[] = { "_", "_" , "_", "_" , "_"};
600
601 name = unit_test::utils::replace_all_occurrences_of(
602 name,
603 to_replace, to_replace + sizeof(to_replace)/sizeof(to_replace[0]),
604 replacement, replacement + sizeof(replacement)/sizeof(replacement[0]));
605
606 std::ifstream check_init((name + ".xml").c_str());
607 if(!check_init)
608 return name + ".xml";
609
610 int index = 0;
611 for(; index < 100; index++) {
612 std::string candidate = name + "_" + utils::string_cast(index) + ".xml";
613 std::ifstream file(candidate.c_str());
614 if(!file)
615 return candidate;
616 }
617
618 return name + ".xml";
619 }
620
621 } // namespace output
622 } // namespace unit_test
623 } // namespace boost
624
625 #include <boost/test/detail/enable_warnings.hpp>
626
627 #endif // BOOST_TEST_junit_log_formatter_IPP_020105GER