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>
35typedef ::boost::io::ios_base_all_saver io_saver_type;
36
37#include <boost/test/detail/suppress_warnings.hpp>
38
39//____________________________________________________________________________//
40
41namespace boost {
42namespace unit_test {
43
44// ************************************************************************** //
45// ************** entry_value_collector ************** //
46// ************************************************************************** //
47
48namespace ut_detail {
49
50entry_value_collector const&
51entry_value_collector::operator<<( lazy_ostream const& v ) const
52{
53 unit_test_log << v;
54
55 return *this;
56}
57
58//____________________________________________________________________________//
59
60entry_value_collector const&
61entry_value_collector::operator<<( const_string v ) const
62{
63 unit_test_log << v;
64
65 return *this;
66}
67
68//____________________________________________________________________________//
69
70entry_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
84namespace {
85
86// log data
87struct 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: 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
122struct unit_test_log_impl {
123 // Constructor
124 unit_test_log_impl()
125 {
126 m_log_formatter_data.push_back( x: 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( x: unit_test_log_data_helper_impl(new output::xml_log_formatter, OF_XML, false) );
128 m_log_formatter_data.push_back( x: 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 typedef std::vector<unit_test_log_data_helper_impl*> vp_formatter_data_t;
135 vp_formatter_data_t m_active_log_formatter_data;
136
137 // entry data
138 log_entry_data m_entry_data;
139
140 bool has_entry_in_progress() const {
141 for( vp_formatter_data_t::const_iterator it(m_active_log_formatter_data.begin()), ite(m_active_log_formatter_data.end());
142 it < ite;
143 ++it)
144 {
145 unit_test_log_data_helper_impl& current_logger_data = **it;
146 if( current_logger_data.m_entry_in_progress )
147 return true;
148 }
149 return false;
150 }
151
152 // check point data
153 log_checkpoint_data m_checkpoint_data;
154
155 void set_checkpoint( const_string file, std::size_t line_num, const_string msg )
156 {
157 assign_op( target&: m_checkpoint_data.m_message, src: msg, 0 );
158 m_checkpoint_data.m_file_name = file;
159 m_checkpoint_data.m_line_num = line_num;
160 }
161};
162
163unit_test_log_impl& s_log_impl() { static unit_test_log_impl the_inst; return the_inst; }
164
165
166//____________________________________________________________________________//
167
168void
169log_entry_context( log_level l, unit_test_log_data_helper_impl& current_logger_data)
170{
171 framework::context_generator const& context = framework::get_context();
172 if( context.is_empty() )
173 return;
174
175 const_string frame;
176 current_logger_data.m_log_formatter->entry_context_start( os&: current_logger_data.stream(), l );
177 while( !(frame=context.next()).is_empty() )
178 {
179 current_logger_data.m_log_formatter->log_entry_context( os&: current_logger_data.stream(), l, value: frame );
180 }
181 current_logger_data.m_log_formatter->entry_context_finish( os&: current_logger_data.stream(), l );
182}
183
184//____________________________________________________________________________//
185
186void
187clear_entry_context()
188{
189 framework::clear_context();
190}
191
192// convenience
193typedef unit_test_log_impl::vp_formatter_data_t vp_logger_t;
194typedef unit_test_log_impl::v_formatter_data_t v_logger_t;
195
196} // local namespace
197
198//____________________________________________________________________________//
199
200BOOST_TEST_SINGLETON_CONS_IMPL( unit_test_log_t )
201
202void
203unit_test_log_t::configure( )
204{
205 // configure is not test_start:
206 // test_start pushes the necessary log information when the test module is starting, and implies configure.
207 // configure: should be called each time the set of loggers, stream or configuration is changed.
208 s_log_impl().m_active_log_formatter_data.clear();
209 for( unit_test_log_impl::v_formatter_data_t::iterator it(s_log_impl().m_log_formatter_data.begin()),
210 ite(s_log_impl().m_log_formatter_data.end());
211 it < ite;
212 ++it)
213 {
214 if( !it->m_enabled || it->get_log_level() == log_nothing )
215 continue;
216
217 s_log_impl().m_active_log_formatter_data.push_back(x: &*it);
218 it->m_entry_in_progress = false;
219 }
220}
221
222//____________________________________________________________________________//
223
224void
225unit_test_log_t::test_start( counter_t test_cases_amount, test_unit_id )
226{
227 configure();
228 vp_logger_t& vloggers = s_log_impl().m_active_log_formatter_data;
229 for( vp_logger_t::iterator it(vloggers.begin()), ite(vloggers.end()); it < ite; ++it)
230 {
231 unit_test_log_data_helper_impl& current_logger_data = **it;
232
233 current_logger_data.m_log_formatter->log_start( os&: current_logger_data.stream(), test_cases_amount );
234 current_logger_data.m_log_formatter->log_build_info(
235 os&: current_logger_data.stream(),
236 log_build_info: runtime_config::get<bool>( parameter_name: runtime_config::btrt_build_info ));
237
238 //current_logger_data.stream().flush();
239 }
240}
241
242//____________________________________________________________________________//
243
244void
245unit_test_log_t::test_finish()
246{
247 vp_logger_t& vloggers = s_log_impl().m_active_log_formatter_data;
248 for( vp_logger_t::iterator it(vloggers.begin()), ite(vloggers.end()); it < ite; ++it)
249 {
250 unit_test_log_data_helper_impl& current_logger_data = **it;
251 current_logger_data.m_log_formatter->log_finish( os&: current_logger_data.stream() );
252 current_logger_data.stream().flush();
253 }
254}
255
256//____________________________________________________________________________//
257
258void
259unit_test_log_t::test_aborted()
260{
261 BOOST_TEST_LOG_ENTRY( log_messages ) << "Test is aborted";
262}
263
264//____________________________________________________________________________//
265
266void
267unit_test_log_t::test_unit_start( test_unit const& tu )
268{
269 if( s_log_impl().has_entry_in_progress() )
270 *this << log::end();
271
272 vp_logger_t& vloggers = s_log_impl().m_active_log_formatter_data;
273 for( vp_logger_t::iterator it(vloggers.begin()), ite(vloggers.end()); it < ite; ++it)
274 {
275 unit_test_log_data_helper_impl& current_logger_data = **it;
276 if( current_logger_data.get_log_level() > log_test_units )
277 continue;
278 current_logger_data.m_log_formatter->test_unit_start( os&: current_logger_data.stream(), tu );
279 }
280}
281
282//____________________________________________________________________________//
283
284void
285unit_test_log_t::test_unit_finish( test_unit const& tu, unsigned long elapsed )
286{
287 s_log_impl().m_checkpoint_data.clear();
288
289 if( s_log_impl().has_entry_in_progress() )
290 *this << log::end();
291
292 vp_logger_t& vloggers = s_log_impl().m_active_log_formatter_data;
293 for( vp_logger_t::iterator it(vloggers.begin()), ite(vloggers.end()); it < ite; ++it)
294 {
295 unit_test_log_data_helper_impl& current_logger_data = **it;
296 if( current_logger_data.get_log_level() > log_test_units )
297 continue;
298
299 current_logger_data.m_log_formatter->test_unit_finish( os&: current_logger_data.stream(), tu, elapsed );
300 }
301}
302
303//____________________________________________________________________________//
304
305void
306unit_test_log_t::test_unit_skipped( test_unit const& tu, const_string reason )
307{
308 if( s_log_impl().has_entry_in_progress() )
309 *this << log::end();
310
311 vp_logger_t& vloggers = s_log_impl().m_active_log_formatter_data;
312 for( vp_logger_t::iterator it(vloggers.begin()), ite(vloggers.end()); it < ite; ++it)
313 {
314 unit_test_log_data_helper_impl& current_logger_data = **it;
315 if( current_logger_data.get_log_level() > log_test_units )
316 continue;
317
318 current_logger_data.m_log_formatter->test_unit_skipped( os&: current_logger_data.stream(), tu, reason );
319 }
320}
321
322void
323unit_test_log_t::test_unit_aborted( test_unit const& tu )
324{
325 if( s_log_impl().has_entry_in_progress() )
326 *this << log::end();
327
328 vp_logger_t& vloggers = s_log_impl().m_active_log_formatter_data;
329 for( vp_logger_t::iterator it(vloggers.begin()), ite(vloggers.end()); it < ite; ++it)
330 {
331 unit_test_log_data_helper_impl& current_logger_data = **it;
332 if( current_logger_data.get_log_level() > log_test_units )
333 continue;
334
335 current_logger_data.m_log_formatter->test_unit_aborted(current_logger_data.stream(), tu );
336 }
337}
338
339void
340unit_test_log_t::test_unit_timed_out( test_unit const& tu )
341{
342 if( s_log_impl().has_entry_in_progress() )
343 *this << log::end();
344
345 vp_logger_t& vloggers = s_log_impl().m_active_log_formatter_data;
346 for( vp_logger_t::iterator it(vloggers.begin()), ite(vloggers.end()); it < ite; ++it)
347 {
348 unit_test_log_data_helper_impl& current_logger_data = **it;
349 if( current_logger_data.get_log_level() > log_test_units )
350 continue;
351
352 current_logger_data.m_log_formatter->test_unit_timed_out(current_logger_data.stream(), tu );
353 }
354}
355
356//____________________________________________________________________________//
357
358void
359unit_test_log_t::exception_caught( execution_exception const& ex )
360{
361 log_level l =
362 ex.code() <= execution_exception::cpp_exception_error ? log_cpp_exception_errors :
363 (ex.code() <= execution_exception::timeout_error ? log_system_errors
364 : log_fatal_errors );
365
366 if( s_log_impl().has_entry_in_progress() )
367 *this << log::end();
368
369 vp_logger_t& vloggers = s_log_impl().m_active_log_formatter_data;
370 for( vp_logger_t::iterator it(vloggers.begin()), ite(vloggers.end()); it < ite; ++it)
371 {
372 unit_test_log_data_helper_impl& current_logger_data = **it;
373
374 if( l >= current_logger_data.get_log_level() ) {
375
376 current_logger_data.m_log_formatter->log_exception_start( os&: current_logger_data.stream(), lcd: s_log_impl().m_checkpoint_data, ex );
377
378 log_entry_context( l, current_logger_data );
379
380 current_logger_data.m_log_formatter->log_exception_finish( os&: current_logger_data.stream() );
381 }
382 }
383 clear_entry_context();
384}
385
386//____________________________________________________________________________//
387
388void
389unit_test_log_t::set_checkpoint( const_string file, std::size_t line_num, const_string msg )
390{
391 s_log_impl().set_checkpoint( file, line_num, msg );
392}
393
394//____________________________________________________________________________//
395
396char
397set_unix_slash( char in )
398{
399 return in == '\\' ? '/' : in;
400}
401
402unit_test_log_t&
403unit_test_log_t::operator<<( log::begin const& b )
404{
405 if( s_log_impl().has_entry_in_progress() )
406 *this << log::end();
407
408 vp_logger_t& vloggers = s_log_impl().m_active_log_formatter_data;
409 for( vp_logger_t::iterator it(vloggers.begin()), ite(vloggers.end()); it < ite; ++it)
410 {
411 unit_test_log_data_helper_impl& current_logger_data = **it;
412 current_logger_data.m_stream_state_saver->restore();
413 }
414
415 s_log_impl().m_entry_data.clear();
416
417 assign_op( target&: s_log_impl().m_entry_data.m_file_name, src: b.m_file_name, 0 );
418
419 // normalize file name
420 std::transform( first: s_log_impl().m_entry_data.m_file_name.begin(), last: s_log_impl().m_entry_data.m_file_name.end(),
421 result: s_log_impl().m_entry_data.m_file_name.begin(),
422 unary_op: &set_unix_slash );
423
424 s_log_impl().m_entry_data.m_line_num = b.m_line_num;
425
426 return *this;
427}
428
429//____________________________________________________________________________//
430
431unit_test_log_t&
432unit_test_log_t::operator<<( log::end const& )
433{
434 if( s_log_impl().has_entry_in_progress() ) {
435 vp_logger_t& vloggers = s_log_impl().m_active_log_formatter_data;
436 log_level l = s_log_impl().m_entry_data.m_level;
437 for( vp_logger_t::iterator it(vloggers.begin()), ite(vloggers.end()); it < ite; ++it)
438 {
439 unit_test_log_data_helper_impl& current_logger_data = **it;
440 if( current_logger_data.m_entry_in_progress ) {
441 if( l >= current_logger_data.get_log_level() ) {
442 log_entry_context( l, current_logger_data );
443 }
444 current_logger_data.m_log_formatter->log_entry_finish( os&: current_logger_data.stream() );
445 }
446 current_logger_data.m_entry_in_progress = false;
447 }
448 }
449
450 clear_entry_context();
451
452 return *this;
453}
454
455//____________________________________________________________________________//
456
457unit_test_log_t&
458unit_test_log_t::operator<<( log_level l )
459{
460 s_log_impl().m_entry_data.m_level = l;
461
462 return *this;
463}
464
465//____________________________________________________________________________//
466
467ut_detail::entry_value_collector
468unit_test_log_t::operator()( log_level l )
469{
470 *this << l;
471
472 return ut_detail::entry_value_collector();
473}
474
475//____________________________________________________________________________//
476
477bool
478log_entry_start(unit_test_log_data_helper_impl &current_logger_data)
479{
480 if( current_logger_data.m_entry_in_progress )
481 return true;
482
483 switch( s_log_impl().m_entry_data.m_level ) {
484 case log_successful_tests:
485 current_logger_data.m_log_formatter->log_entry_start( os&: current_logger_data.stream(), led: s_log_impl().m_entry_data,
486 let: unit_test_log_formatter::BOOST_UTL_ET_INFO );
487 break;
488 case log_messages:
489 current_logger_data.m_log_formatter->log_entry_start( os&: current_logger_data.stream(), led: s_log_impl().m_entry_data,
490 let: unit_test_log_formatter::BOOST_UTL_ET_MESSAGE );
491 break;
492 case log_warnings:
493 current_logger_data.m_log_formatter->log_entry_start( os&: current_logger_data.stream(), led: s_log_impl().m_entry_data,
494 let: unit_test_log_formatter::BOOST_UTL_ET_WARNING );
495 break;
496 case log_all_errors:
497 case log_cpp_exception_errors:
498 case log_system_errors:
499 current_logger_data.m_log_formatter->log_entry_start( os&: current_logger_data.stream(), led: s_log_impl().m_entry_data,
500 let: unit_test_log_formatter::BOOST_UTL_ET_ERROR );
501 break;
502 case log_fatal_errors:
503 current_logger_data.m_log_formatter->log_entry_start( os&: current_logger_data.stream(), led: s_log_impl().m_entry_data,
504 let: unit_test_log_formatter::BOOST_UTL_ET_FATAL_ERROR );
505 break;
506 case log_nothing:
507 case log_test_units:
508 case invalid_log_level:
509 return false;
510 }
511
512 current_logger_data.m_entry_in_progress = true;
513 return true;
514}
515
516//____________________________________________________________________________//
517
518unit_test_log_t&
519unit_test_log_t::operator<<( const_string value )
520{
521 if(value.empty()) {
522 return *this;
523 }
524
525 vp_logger_t& vloggers = s_log_impl().m_active_log_formatter_data;
526 for( vp_logger_t::iterator it(vloggers.begin()), ite(vloggers.end()); it < ite; ++it)
527 {
528 unit_test_log_data_helper_impl& current_logger_data = **it;
529 if( s_log_impl().m_entry_data.m_level >= current_logger_data.get_log_level() )
530 if( log_entry_start(current_logger_data) ) {
531 current_logger_data.m_log_formatter->log_entry_value( os&: current_logger_data.stream(), value );
532 }
533 }
534 return *this;
535}
536
537//____________________________________________________________________________//
538
539unit_test_log_t&
540unit_test_log_t::operator<<( lazy_ostream const& value )
541{
542 if(value.empty()) {
543 return *this;
544 }
545
546 vp_logger_t& vloggers = s_log_impl().m_active_log_formatter_data;
547 for( vp_logger_t::iterator it(vloggers.begin()), ite(vloggers.end()); it < ite; ++it)
548 {
549 unit_test_log_data_helper_impl& current_logger_data = **it;
550 if( s_log_impl().m_entry_data.m_level >= current_logger_data.get_log_level() ) {
551 if( log_entry_start(current_logger_data) ) {
552 current_logger_data.m_log_formatter->log_entry_value( os&: current_logger_data.stream(), value );
553 }
554 }
555 }
556 return *this;
557}
558
559//____________________________________________________________________________//
560
561void
562unit_test_log_t::set_stream( std::ostream& str )
563{
564 if( s_log_impl().has_entry_in_progress() )
565 return;
566
567 v_logger_t& vloggers = s_log_impl().m_log_formatter_data;
568 for( v_logger_t::iterator it(vloggers.begin()), ite(vloggers.end()); it < ite; ++it)
569 {
570 unit_test_log_data_helper_impl& current_logger_data = *it;
571
572 current_logger_data.m_stream = &str;
573 current_logger_data.m_stream_state_saver.reset( p: new io_saver_type( str ) );
574 }
575}
576
577//____________________________________________________________________________//
578
579void
580unit_test_log_t::set_stream( output_format log_format, std::ostream& str )
581{
582 if( s_log_impl().has_entry_in_progress() )
583 return;
584
585 v_logger_t& vloggers = s_log_impl().m_log_formatter_data;
586 for( v_logger_t::iterator it(vloggers.begin()), ite(vloggers.end()); it < ite; ++it)
587 {
588 unit_test_log_data_helper_impl& current_logger_data = *it;
589 if( current_logger_data.m_format == log_format) {
590 current_logger_data.m_stream = &str;
591 current_logger_data.m_stream_state_saver.reset( p: new io_saver_type( str ) );
592 break;
593 }
594 }
595}
596
597std::ostream*
598unit_test_log_t::get_stream( output_format log_format ) const
599{
600 v_logger_t& vloggers = s_log_impl().m_log_formatter_data;
601 for( v_logger_t::iterator it(vloggers.begin()), ite(vloggers.end()); it < ite; ++it)
602 {
603 unit_test_log_data_helper_impl& current_logger_data = *it;
604 if( current_logger_data.m_format == log_format) {
605 return current_logger_data.m_stream;
606 }
607 }
608 return 0;
609}
610
611//____________________________________________________________________________//
612
613log_level
614unit_test_log_t::set_threshold_level( log_level lev )
615{
616 if( s_log_impl().has_entry_in_progress() || lev == invalid_log_level )
617 return invalid_log_level;
618
619 log_level ret = log_nothing;
620 v_logger_t& vloggers = s_log_impl().m_log_formatter_data;
621 for( v_logger_t::iterator it(vloggers.begin()), ite(vloggers.end()); it < ite; ++it)
622 {
623 unit_test_log_data_helper_impl& current_logger_data = *it;
624 ret = (std::min)(a: ret, b: current_logger_data.m_log_formatter->get_log_level());
625 current_logger_data.m_log_formatter->set_log_level( lev );
626 }
627 return ret;
628}
629
630//____________________________________________________________________________//
631
632log_level
633unit_test_log_t::set_threshold_level( output_format log_format, log_level lev )
634{
635 if( s_log_impl().has_entry_in_progress() || lev == invalid_log_level )
636 return invalid_log_level;
637
638 log_level ret = log_nothing;
639 v_logger_t& vloggers = s_log_impl().m_log_formatter_data;
640 for( v_logger_t::iterator it(vloggers.begin()), ite(vloggers.end()); it < ite; ++it)
641 {
642 unit_test_log_data_helper_impl& current_logger_data = *it;
643 if( current_logger_data.m_format == log_format) {
644 ret = current_logger_data.m_log_formatter->get_log_level();
645 current_logger_data.m_log_formatter->set_log_level( lev );
646 break;
647 }
648 }
649 return ret;
650}
651
652//____________________________________________________________________________//
653
654void
655unit_test_log_t::set_format( output_format log_format )
656{
657 if( s_log_impl().has_entry_in_progress() )
658 return;
659
660 v_logger_t& vloggers = s_log_impl().m_log_formatter_data;
661 for( v_logger_t::iterator it(vloggers.begin()), ite(vloggers.end()); it < ite; ++it)
662 {
663 unit_test_log_data_helper_impl& current_logger_data = *it;
664 current_logger_data.m_enabled = current_logger_data.m_format == log_format;
665 }
666}
667
668//____________________________________________________________________________//
669
670void
671unit_test_log_t::add_format( output_format log_format )
672{
673 if( s_log_impl().has_entry_in_progress() )
674 return;
675
676 v_logger_t& vloggers = s_log_impl().m_log_formatter_data;
677 for( v_logger_t::iterator it(vloggers.begin()), ite(vloggers.end()); it < ite; ++it)
678 {
679 unit_test_log_data_helper_impl& current_logger_data = *it;
680 if( current_logger_data.m_format == log_format) {
681 current_logger_data.m_enabled = true;
682 break;
683 }
684 }
685}
686
687//____________________________________________________________________________//
688
689unit_test_log_formatter*
690unit_test_log_t::get_formatter( output_format log_format ) {
691
692 v_logger_t& vloggers = s_log_impl().m_log_formatter_data;
693 for( v_logger_t::iterator it(vloggers.begin()), ite(vloggers.end()); it < ite; ++it)
694 {
695 unit_test_log_data_helper_impl& current_logger_data = *it;
696 if( current_logger_data.m_format == log_format) {
697 return current_logger_data.m_log_formatter.get();
698 }
699 }
700 return 0;
701}
702
703
704void
705unit_test_log_t::add_formatter( unit_test_log_formatter* the_formatter )
706{
707 // remove only user defined logger
708 v_logger_t& vloggers = s_log_impl().m_log_formatter_data;
709 for(v_logger_t::iterator it(vloggers.begin()), ite(vloggers.end()); it < ite; ++it)
710 {
711 if( it->m_format == OF_CUSTOM_LOGGER) {
712 s_log_impl().m_log_formatter_data.erase(position: it);
713 break;
714 }
715 }
716
717 if( the_formatter ) {
718 s_log_impl().m_active_log_formatter_data.clear(); // otherwise dandling references
719 vloggers.push_back( x: unit_test_log_data_helper_impl(the_formatter, OF_CUSTOM_LOGGER, true) );
720 }
721}
722
723void
724unit_test_log_t::set_formatter( unit_test_log_formatter* the_formatter )
725{
726 if( s_log_impl().has_entry_in_progress() )
727 return;
728
729 // remove only user defined logger
730 log_level current_level = invalid_log_level;
731 std::ostream *current_stream = 0;
732 output_format previous_format = OF_INVALID;
733 v_logger_t& vloggers = s_log_impl().m_log_formatter_data;
734 for(v_logger_t::iterator it(vloggers.begin()), ite(vloggers.end()); it < ite; ++it)
735 {
736 if( it->m_enabled ) {
737 if( current_level == invalid_log_level || it->m_format < previous_format || it->m_format == OF_CUSTOM_LOGGER) {
738 current_level = it->get_log_level();
739 current_stream = &(it->stream());
740 previous_format = it->m_format;
741 }
742 }
743 }
744
745 if( the_formatter ) {
746 add_formatter(the_formatter);
747 set_format(OF_CUSTOM_LOGGER);
748 set_threshold_level(log_format: OF_CUSTOM_LOGGER, lev: current_level);
749 set_stream(log_format: OF_CUSTOM_LOGGER, str&: *current_stream);
750 }
751
752 configure();
753}
754
755//____________________________________________________________________________//
756
757// ************************************************************************** //
758// ************** unit_test_log_formatter ************** //
759// ************************************************************************** //
760
761void
762unit_test_log_formatter::log_entry_value( std::ostream& ostr, lazy_ostream const& value )
763{
764 log_entry_value( os&: ostr, value: (wrap_stringstream().ref() << value).str() );
765}
766
767void
768unit_test_log_formatter::set_log_level(log_level new_log_level)
769{
770 m_log_level = new_log_level;
771}
772
773log_level
774unit_test_log_formatter::get_log_level() const
775{
776 return m_log_level;
777}
778
779//____________________________________________________________________________//
780
781} // namespace unit_test
782} // namespace boost
783
784#include <boost/test/detail/enable_warnings.hpp>
785
786#endif // BOOST_TEST_UNIT_TEST_LOG_IPP_012205GER
787
788

source code of include/boost/test/impl/unit_test_log.ipp