Imported Upstream version 1.64.0
[platform/upstream/boost.git] / boost / test / impl / unit_test_log.ipp
1 //  (C) Copyright Gennadiy Rozental 2001.
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        : $RCSfile$
9 //
10 //  Version     : $Revision$
11 //
12 //  Description : implemets Unit Test Log
13 // ***************************************************************************
14
15 #ifndef BOOST_TEST_UNIT_TEST_LOG_IPP_012205GER
16 #define BOOST_TEST_UNIT_TEST_LOG_IPP_012205GER
17
18 // Boost.Test
19 #include <boost/test/unit_test_log.hpp>
20 #include <boost/test/unit_test_log_formatter.hpp>
21 #include <boost/test/execution_monitor.hpp>
22 #include <boost/test/framework.hpp>
23 #include <boost/test/unit_test_parameters.hpp>
24
25 #include <boost/test/utils/basic_cstring/compare.hpp>
26 #include <boost/test/utils/foreach.hpp>
27
28 #include <boost/test/output/compiler_log_formatter.hpp>
29 #include <boost/test/output/xml_log_formatter.hpp>
30 #include <boost/test/output/junit_log_formatter.hpp>
31
32 // Boost
33 #include <boost/shared_ptr.hpp>
34 #include <boost/io/ios_state.hpp>
35 typedef ::boost::io::ios_base_all_saver io_saver_type;
36
37 #include <boost/test/detail/suppress_warnings.hpp>
38
39 //____________________________________________________________________________//
40
41 namespace boost {
42 namespace unit_test {
43
44 // ************************************************************************** //
45 // **************             entry_value_collector            ************** //
46 // ************************************************************************** //
47
48 namespace ut_detail {
49
50 entry_value_collector const&
51 entry_value_collector::operator<<( lazy_ostream const& v ) const
52 {
53     unit_test_log << v;
54
55     return *this;
56 }
57
58 //____________________________________________________________________________//
59
60 entry_value_collector const&
61 entry_value_collector::operator<<( const_string v ) const
62 {
63     unit_test_log << v;
64
65     return *this;
66 }
67
68 //____________________________________________________________________________//
69
70 entry_value_collector::~entry_value_collector()
71 {
72     if( m_last )
73         unit_test_log << log::end();
74 }
75
76 //____________________________________________________________________________//
77
78 } // namespace ut_detail
79
80 // ************************************************************************** //
81 // **************                 unit_test_log                ************** //
82 // ************************************************************************** //
83
84 namespace {
85
86 // log data
87 struct unit_test_log_data_helper_impl {
88   typedef boost::shared_ptr<unit_test_log_formatter> formatter_ptr;
89   typedef boost::shared_ptr<io_saver_type>           saver_ptr;
90
91   bool                m_enabled;
92   output_format       m_format;
93   std::ostream*       m_stream;
94   saver_ptr           m_stream_state_saver;
95   formatter_ptr       m_log_formatter;
96   bool                m_entry_in_progress;
97
98   unit_test_log_data_helper_impl(unit_test_log_formatter* p_log_formatter, output_format format, bool enabled = false)
99     : m_enabled( enabled )
100     , m_format( format )
101     , m_stream( &std::cout )
102     , m_stream_state_saver( new io_saver_type( std::cout ) )
103     , m_log_formatter()
104     , m_entry_in_progress( false )
105   {
106     m_log_formatter.reset(p_log_formatter);
107     m_log_formatter->set_log_level(log_all_errors);
108   }
109
110   // helper functions
111   std::ostream&       stream()
112   {
113       return *m_stream;
114   }
115
116   log_level get_log_level() const
117   {
118       return m_log_formatter->get_log_level();
119   }
120 };
121
122 struct unit_test_log_impl {
123     // Constructor
124     unit_test_log_impl()
125     {
126       m_log_formatter_data.push_back( unit_test_log_data_helper_impl(new output::compiler_log_formatter, OF_CLF, true) ); // only this one is active by default,
127       m_log_formatter_data.push_back( unit_test_log_data_helper_impl(new output::xml_log_formatter, OF_XML, false) );
128       m_log_formatter_data.push_back( unit_test_log_data_helper_impl(new output::junit_log_formatter, OF_JUNIT, false) );
129     }
130
131     typedef std::vector<unit_test_log_data_helper_impl> v_formatter_data_t;
132     v_formatter_data_t m_log_formatter_data;
133
134     // entry data
135     log_entry_data      m_entry_data;
136
137     bool has_entry_in_progress() const {
138         BOOST_TEST_FOREACH( unit_test_log_data_helper_impl const&, current_logger_data, m_log_formatter_data ) {
139             if( current_logger_data.m_entry_in_progress )
140                 return true;
141         }
142         return false;
143     }
144
145     // check point data
146     log_checkpoint_data m_checkpoint_data;
147
148     void                set_checkpoint( const_string file, std::size_t line_num, const_string msg )
149     {
150         assign_op( m_checkpoint_data.m_message, msg, 0 );
151         m_checkpoint_data.m_file_name   = file;
152         m_checkpoint_data.m_line_num    = line_num;
153     }
154 };
155
156 unit_test_log_impl& s_log_impl() { static unit_test_log_impl the_inst; return the_inst; }
157
158 } // local namespace
159
160 //____________________________________________________________________________//
161
162 void
163 unit_test_log_t::test_start( counter_t test_cases_amount )
164 {
165     BOOST_TEST_FOREACH( unit_test_log_data_helper_impl&, current_logger_data, s_log_impl().m_log_formatter_data ) {
166       if( !current_logger_data.m_enabled || current_logger_data.get_log_level() == log_nothing )
167           continue;
168
169       current_logger_data.m_log_formatter->log_start( current_logger_data.stream(), test_cases_amount );
170
171       if( runtime_config::get<bool>( runtime_config::btrt_build_info ) )
172           current_logger_data.m_log_formatter->log_build_info( current_logger_data.stream() );
173
174       current_logger_data.m_entry_in_progress = false;
175     }
176 }
177
178 //____________________________________________________________________________//
179
180 void
181 unit_test_log_t::test_finish()
182 {
183     BOOST_TEST_FOREACH( unit_test_log_data_helper_impl&, current_logger_data, s_log_impl().m_log_formatter_data ) {
184       if( !current_logger_data.m_enabled || current_logger_data.get_log_level() == log_nothing )
185           continue;
186
187       current_logger_data.m_log_formatter->log_finish( current_logger_data.stream() );
188
189       current_logger_data.stream().flush();
190     }
191 }
192
193 //____________________________________________________________________________//
194
195 void
196 unit_test_log_t::test_aborted()
197 {
198     BOOST_TEST_LOG_ENTRY( log_messages ) << "Test is aborted";
199 }
200
201 //____________________________________________________________________________//
202
203 void
204 unit_test_log_t::test_unit_start( test_unit const& tu )
205 {
206     if( s_log_impl().has_entry_in_progress() )
207         *this << log::end();
208     BOOST_TEST_FOREACH( unit_test_log_data_helper_impl&, current_logger_data, s_log_impl().m_log_formatter_data ) {
209         if( !current_logger_data.m_enabled || current_logger_data.get_log_level() > log_test_units )
210             continue;
211         current_logger_data.m_log_formatter->test_unit_start( current_logger_data.stream(), tu );
212     }
213 }
214
215 //____________________________________________________________________________//
216
217 void
218 unit_test_log_t::test_unit_finish( test_unit const& tu, unsigned long elapsed )
219 {
220     s_log_impl().m_checkpoint_data.clear();
221
222     if( s_log_impl().has_entry_in_progress() )
223         *this << log::end();
224
225     BOOST_TEST_FOREACH( unit_test_log_data_helper_impl&, current_logger_data, s_log_impl().m_log_formatter_data ) {
226
227         if( !current_logger_data.m_enabled || current_logger_data.get_log_level() > log_test_units )
228             continue;
229
230         current_logger_data.m_log_formatter->test_unit_finish( current_logger_data.stream(), tu, elapsed );
231     }
232 }
233
234 //____________________________________________________________________________//
235
236 void
237 unit_test_log_t::test_unit_skipped( test_unit const& tu, const_string reason )
238 {
239     if( s_log_impl().has_entry_in_progress() )
240         *this << log::end();
241
242     BOOST_TEST_FOREACH( unit_test_log_data_helper_impl&, current_logger_data, s_log_impl().m_log_formatter_data ) {
243         if( !current_logger_data.m_enabled || current_logger_data.get_log_level() > log_test_units )
244             continue;
245
246         current_logger_data.m_log_formatter->test_unit_skipped( current_logger_data.stream(), tu, reason );
247     }
248 }
249
250 void
251 unit_test_log_t::test_unit_aborted( test_unit const& tu )
252 {
253     if( s_log_impl().has_entry_in_progress() )
254         *this << log::end();
255
256     BOOST_TEST_FOREACH( unit_test_log_data_helper_impl&, current_logger_data, s_log_impl().m_log_formatter_data ) {
257         if( !current_logger_data.m_enabled || current_logger_data.get_log_level() > log_test_units )
258             continue;
259
260         current_logger_data.m_log_formatter->test_unit_aborted(current_logger_data.stream(), tu );
261     }
262 }
263
264 //____________________________________________________________________________//
265
266 void
267 unit_test_log_t::exception_caught( execution_exception const& ex )
268 {
269     log_level l =
270         ex.code() <= execution_exception::cpp_exception_error   ? log_cpp_exception_errors :
271         (ex.code() <= execution_exception::timeout_error        ? log_system_errors
272                                                                 : log_fatal_errors );
273
274     if( s_log_impl().has_entry_in_progress() )
275         *this << log::end();
276
277     BOOST_TEST_FOREACH( unit_test_log_data_helper_impl&, current_logger_data, s_log_impl().m_log_formatter_data ) {
278
279       if( current_logger_data.m_enabled && l >= current_logger_data.get_log_level() ) {
280
281           current_logger_data.m_log_formatter->log_exception_start( current_logger_data.stream(), s_log_impl().m_checkpoint_data, ex );
282
283           log_entry_context( l );
284
285           current_logger_data.m_log_formatter->log_exception_finish( current_logger_data.stream() );
286       }
287     }
288     clear_entry_context();
289 }
290
291 //____________________________________________________________________________//
292
293 void
294 unit_test_log_t::set_checkpoint( const_string file, std::size_t line_num, const_string msg )
295 {
296     s_log_impl().set_checkpoint( file, line_num, msg );
297 }
298
299 //____________________________________________________________________________//
300
301 char
302 set_unix_slash( char in )
303 {
304     return in == '\\' ? '/' : in;
305 }
306
307 unit_test_log_t&
308 unit_test_log_t::operator<<( log::begin const& b )
309 {
310     if( s_log_impl().has_entry_in_progress() )
311         *this << log::end();
312
313     BOOST_TEST_FOREACH( unit_test_log_data_helper_impl&, current_logger_data, s_log_impl().m_log_formatter_data ) {
314         if( current_logger_data.m_enabled ) {
315             current_logger_data.m_stream_state_saver->restore();
316         }
317     }
318
319     s_log_impl().m_entry_data.clear();
320
321     assign_op( s_log_impl().m_entry_data.m_file_name, b.m_file_name, 0 );
322
323     // normalize file name
324     std::transform( s_log_impl().m_entry_data.m_file_name.begin(), s_log_impl().m_entry_data.m_file_name.end(),
325                     s_log_impl().m_entry_data.m_file_name.begin(),
326                     &set_unix_slash );
327
328     s_log_impl().m_entry_data.m_line_num = b.m_line_num;
329
330     return *this;
331 }
332
333 //____________________________________________________________________________//
334
335 unit_test_log_t&
336 unit_test_log_t::operator<<( log::end const& )
337 {
338     if( s_log_impl().has_entry_in_progress() ) {
339         log_entry_context( s_log_impl().m_entry_data.m_level );
340
341         BOOST_TEST_FOREACH( unit_test_log_data_helper_impl&, current_logger_data, s_log_impl().m_log_formatter_data ) {
342             if( current_logger_data.m_enabled && current_logger_data.m_entry_in_progress ) {
343                 current_logger_data.m_log_formatter->log_entry_finish( current_logger_data.stream() );
344             }
345             current_logger_data.m_entry_in_progress = false;
346         }
347     }
348
349     clear_entry_context();
350
351     return *this;
352 }
353
354 //____________________________________________________________________________//
355
356 unit_test_log_t&
357 unit_test_log_t::operator<<( log_level l )
358 {
359     s_log_impl().m_entry_data.m_level = l;
360
361     return *this;
362 }
363
364 //____________________________________________________________________________//
365
366 ut_detail::entry_value_collector
367 unit_test_log_t::operator()( log_level l )
368 {
369     *this << l;
370
371     return ut_detail::entry_value_collector();
372 }
373
374 //____________________________________________________________________________//
375
376 bool
377 unit_test_log_t::log_entry_start(output_format log_format)
378 {
379     BOOST_TEST_FOREACH( unit_test_log_data_helper_impl&, current_logger_data, s_log_impl().m_log_formatter_data ) {
380
381         if( current_logger_data.m_format != log_format )
382             continue;
383
384         if( current_logger_data.m_entry_in_progress )
385             return true;
386
387         if( !current_logger_data.m_enabled )
388             return false;
389
390         switch( s_log_impl().m_entry_data.m_level ) {
391         case log_successful_tests:
392             current_logger_data.m_log_formatter->log_entry_start( current_logger_data.stream(), s_log_impl().m_entry_data,
393                                                   unit_test_log_formatter::BOOST_UTL_ET_INFO );
394             break;
395         case log_messages:
396             current_logger_data.m_log_formatter->log_entry_start( current_logger_data.stream(), s_log_impl().m_entry_data,
397                                                   unit_test_log_formatter::BOOST_UTL_ET_MESSAGE );
398             break;
399         case log_warnings:
400             current_logger_data.m_log_formatter->log_entry_start( current_logger_data.stream(), s_log_impl().m_entry_data,
401                                                   unit_test_log_formatter::BOOST_UTL_ET_WARNING );
402             break;
403         case log_all_errors:
404         case log_cpp_exception_errors:
405         case log_system_errors:
406             current_logger_data.m_log_formatter->log_entry_start( current_logger_data.stream(), s_log_impl().m_entry_data,
407                                                   unit_test_log_formatter::BOOST_UTL_ET_ERROR );
408             break;
409         case log_fatal_errors:
410             current_logger_data.m_log_formatter->log_entry_start( current_logger_data.stream(), s_log_impl().m_entry_data,
411                                                   unit_test_log_formatter::BOOST_UTL_ET_FATAL_ERROR );
412             break;
413         case log_nothing:
414         case log_test_units:
415         case invalid_log_level:
416             return false;
417         }
418
419         current_logger_data.m_entry_in_progress = true;
420         return true;
421     }
422
423     return false;
424 }
425
426 //____________________________________________________________________________//
427
428 unit_test_log_t&
429 unit_test_log_t::operator<<( const_string value )
430 {
431     BOOST_TEST_FOREACH( unit_test_log_data_helper_impl&, current_logger_data, s_log_impl().m_log_formatter_data ) {
432         if( current_logger_data.m_enabled && s_log_impl().m_entry_data.m_level >= current_logger_data.get_log_level() && !value.empty() && log_entry_start(current_logger_data.m_format) )
433             current_logger_data.m_log_formatter->log_entry_value( current_logger_data.stream(), value );
434
435     }
436     return *this;
437 }
438
439 //____________________________________________________________________________//
440
441 unit_test_log_t&
442 unit_test_log_t::operator<<( lazy_ostream const& value )
443 {
444     BOOST_TEST_FOREACH( unit_test_log_data_helper_impl&, current_logger_data, s_log_impl().m_log_formatter_data ) {
445         if( current_logger_data.m_enabled && s_log_impl().m_entry_data.m_level >= current_logger_data.get_log_level() && !value.empty() ) {
446             if( log_entry_start(current_logger_data.m_format) ) {
447                 current_logger_data.m_log_formatter->log_entry_value( current_logger_data.stream(), value );
448             }
449         }
450     }
451     return *this;
452 }
453
454 //____________________________________________________________________________//
455
456 void
457 unit_test_log_t::log_entry_context( log_level l )
458 {
459     framework::context_generator const& context = framework::get_context();
460     if( context.is_empty() )
461         return;
462
463     const_string frame;
464
465     BOOST_TEST_FOREACH( unit_test_log_data_helper_impl&, current_logger_data, s_log_impl().m_log_formatter_data ) {
466         if( current_logger_data.m_enabled ) {
467             current_logger_data.m_log_formatter->entry_context_start( current_logger_data.stream(), l );
468         }
469     }
470
471     while( !(frame=context.next()).is_empty() )
472     {
473         BOOST_TEST_FOREACH( unit_test_log_data_helper_impl&, current_logger_data, s_log_impl().m_log_formatter_data ) {
474             if( current_logger_data.m_enabled ) {
475                 current_logger_data.m_log_formatter->log_entry_context( current_logger_data.stream(), frame );
476             }
477         }
478     }
479
480     BOOST_TEST_FOREACH( unit_test_log_data_helper_impl&, current_logger_data, s_log_impl().m_log_formatter_data ) {
481         if( current_logger_data.m_enabled ) {
482             current_logger_data.m_log_formatter->entry_context_finish( current_logger_data.stream() );
483         }
484     }
485 }
486
487 //____________________________________________________________________________//
488
489 void
490 unit_test_log_t::clear_entry_context()
491 {
492     framework::clear_context();
493 }
494
495 //____________________________________________________________________________//
496
497 void
498 unit_test_log_t::set_stream( std::ostream& str )
499 {
500     if( s_log_impl().has_entry_in_progress() )
501         return;
502
503     BOOST_TEST_FOREACH( unit_test_log_data_helper_impl&, current_logger_data, s_log_impl().m_log_formatter_data ) {
504         current_logger_data.m_stream = &str;
505         current_logger_data.m_stream_state_saver.reset( new io_saver_type( str ) );
506     }
507 }
508
509 //____________________________________________________________________________//
510
511 void
512 unit_test_log_t::set_stream( output_format log_format, std::ostream& str )
513 {
514     if( s_log_impl().has_entry_in_progress() )
515         return;
516
517     BOOST_TEST_FOREACH( unit_test_log_data_helper_impl&, current_logger_data, s_log_impl().m_log_formatter_data ) {
518         if( current_logger_data.m_format == log_format) {
519             current_logger_data.m_stream = &str;
520             current_logger_data.m_stream_state_saver.reset( new io_saver_type( str ) );
521             break;
522         }
523     }
524 }
525
526 //____________________________________________________________________________//
527
528 void
529 unit_test_log_t::set_threshold_level( log_level lev )
530 {
531     if( s_log_impl().has_entry_in_progress() || lev == invalid_log_level )
532         return;
533
534     BOOST_TEST_FOREACH( unit_test_log_data_helper_impl&, current_logger_data, s_log_impl().m_log_formatter_data ) {
535         current_logger_data.m_log_formatter->set_log_level( lev );
536     }
537 }
538
539 //____________________________________________________________________________//
540
541 void
542 unit_test_log_t::set_threshold_level( output_format log_format, log_level lev )
543 {
544     if( s_log_impl().has_entry_in_progress() || lev == invalid_log_level )
545         return;
546
547     BOOST_TEST_FOREACH( unit_test_log_data_helper_impl&, current_logger_data, s_log_impl().m_log_formatter_data ) {
548         if( current_logger_data.m_format == log_format) {
549             current_logger_data.m_log_formatter->set_log_level( lev );
550             break;
551         }
552     }
553 }
554
555 //____________________________________________________________________________//
556
557 void
558 unit_test_log_t::set_format( output_format log_format )
559 {
560     if( s_log_impl().has_entry_in_progress() )
561         return;
562
563     BOOST_TEST_FOREACH( unit_test_log_data_helper_impl&, current_logger_data, s_log_impl().m_log_formatter_data ) {
564         current_logger_data.m_enabled = current_logger_data.m_format == log_format;
565     }
566 }
567
568 //____________________________________________________________________________//
569
570 void
571 unit_test_log_t::add_format( output_format log_format )
572 {
573     if( s_log_impl().has_entry_in_progress() )
574         return;
575
576     BOOST_TEST_FOREACH( unit_test_log_data_helper_impl&, current_logger_data, s_log_impl().m_log_formatter_data ) {
577         if( current_logger_data.m_format == log_format) {
578             current_logger_data.m_enabled = true;
579             break;
580         }
581     }
582 }
583
584 //____________________________________________________________________________//
585
586 unit_test_log_formatter*
587 unit_test_log_t::get_formatter( output_format log_format ) {
588     BOOST_TEST_FOREACH( unit_test_log_data_helper_impl&, current_logger_data, s_log_impl().m_log_formatter_data ) {
589         if( current_logger_data.m_format == log_format) {
590             return current_logger_data.m_log_formatter.get();
591         }
592     }
593     return 0;
594 }
595
596
597 void
598 unit_test_log_t::add_formatter( unit_test_log_formatter* the_formatter )
599 {
600     // remove only user defined logger
601     for(unit_test_log_impl::v_formatter_data_t::iterator it(s_log_impl().m_log_formatter_data.begin()),
602             ite(s_log_impl().m_log_formatter_data.end());
603         it != ite;
604         ++it)
605     {
606         if( it->m_format == OF_CUSTOM_LOGGER) {
607             s_log_impl().m_log_formatter_data.erase(it);
608             break;
609         }
610     }
611
612     if( the_formatter ) {
613         s_log_impl().m_log_formatter_data.push_back( unit_test_log_data_helper_impl(the_formatter, OF_CUSTOM_LOGGER, true) );
614     }
615 }
616
617 void
618 unit_test_log_t::set_formatter( unit_test_log_formatter* the_formatter )
619 {
620     // remove only user defined logger
621     log_level current_level = invalid_log_level;
622     std::ostream *current_stream = 0;
623     output_format previous_format = OF_INVALID;
624     for(unit_test_log_impl::v_formatter_data_t::iterator it(s_log_impl().m_log_formatter_data.begin()),
625             ite(s_log_impl().m_log_formatter_data.end());
626         it != ite;
627         ++it)
628     {
629         if( it->m_enabled ) {
630             if( current_level == invalid_log_level || it->m_format < previous_format || it->m_format == OF_CUSTOM_LOGGER) {
631                 current_level = it->get_log_level();
632                 current_stream = &(it->stream());
633                 previous_format = it->m_format;
634             }
635         }
636     }
637
638     if( the_formatter ) {
639         add_formatter(the_formatter);
640         set_format(OF_CUSTOM_LOGGER);
641         set_threshold_level(OF_CUSTOM_LOGGER, current_level);
642         set_stream(OF_CUSTOM_LOGGER, *current_stream);
643     }
644 }
645
646 //____________________________________________________________________________//
647
648 // ************************************************************************** //
649 // **************            unit_test_log_formatter           ************** //
650 // ************************************************************************** //
651
652 void
653 unit_test_log_formatter::log_entry_value( std::ostream& ostr, lazy_ostream const& value )
654 {
655     log_entry_value( ostr, (wrap_stringstream().ref() << value).str() );
656 }
657
658 void
659 unit_test_log_formatter::set_log_level(log_level new_log_level)
660 {
661     m_log_level = new_log_level;
662 }
663
664 log_level
665 unit_test_log_formatter::get_log_level() const
666 {
667     return m_log_level;
668 }
669
670 //____________________________________________________________________________//
671
672 } // namespace unit_test
673 } // namespace boost
674
675 #include <boost/test/detail/enable_warnings.hpp>
676
677 #endif // BOOST_TEST_UNIT_TEST_LOG_IPP_012205GER
678