• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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_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( 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    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( m_checkpoint_data.m_message, 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( current_logger_data.stream(), l );
177    while( !(frame=context.next()).is_empty() )
178    {
179        current_logger_data.m_log_formatter->log_entry_context( current_logger_data.stream(), l, frame );
180    }
181    current_logger_data.m_log_formatter->entry_context_finish( 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(&*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( current_logger_data.stream(), test_cases_amount );
234      current_logger_data.m_log_formatter->log_build_info(
235          current_logger_data.stream(),
236          runtime_config::get<bool>( 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( 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( 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( 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( 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( current_logger_data.stream(), 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( 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( s_log_impl().m_entry_data.m_file_name, b.m_file_name, 0 );
418
419    // normalize file name
420    std::transform( s_log_impl().m_entry_data.m_file_name.begin(), s_log_impl().m_entry_data.m_file_name.end(),
421                    s_log_impl().m_entry_data.m_file_name.begin(),
422                    &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( 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( current_logger_data.stream(), s_log_impl().m_entry_data,
486                                              unit_test_log_formatter::BOOST_UTL_ET_INFO );
487        break;
488    case log_messages:
489        current_logger_data.m_log_formatter->log_entry_start( current_logger_data.stream(), s_log_impl().m_entry_data,
490                                              unit_test_log_formatter::BOOST_UTL_ET_MESSAGE );
491        break;
492    case log_warnings:
493        current_logger_data.m_log_formatter->log_entry_start( current_logger_data.stream(), s_log_impl().m_entry_data,
494                                              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( current_logger_data.stream(), s_log_impl().m_entry_data,
500                                              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( current_logger_data.stream(), s_log_impl().m_entry_data,
504                                              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( 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( 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( 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( 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)(ret, 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(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( 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(OF_CUSTOM_LOGGER, current_level);
749        set_stream(OF_CUSTOM_LOGGER, *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( ostr, (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