1//  (C) Copyright Gennadiy Rozental 2005-2008.
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: 57992 $
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/unit_test_suite_impl.hpp>
22#include <boost/test/execution_monitor.hpp>
23
24#include <boost/test/detail/unit_test_parameters.hpp>
25
26#include <boost/test/utils/basic_cstring/compare.hpp>
27
28#include <boost/test/output/compiler_log_formatter.hpp>
29#include <boost/test/output/xml_log_formatter.hpp>
30
31// Boost
32#include <boost/scoped_ptr.hpp>
33#include <boost/io/ios_state.hpp>
34typedef ::boost::io::ios_base_all_saver io_saver_type;
35
36#include <boost/test/detail/suppress_warnings.hpp>
37
38//____________________________________________________________________________//
39
40namespace boost {
41
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
86struct unit_test_log_impl {
87    // Constructor
88    unit_test_log_impl()
89    : m_stream( runtime_config::log_sink() )
90    , m_stream_state_saver( new io_saver_type( *m_stream ) )
91    , m_threshold_level( log_all_errors )
92    , m_log_formatter( new output::compiler_log_formatter )
93    {
94    }
95
96    // log data
97    typedef scoped_ptr<unit_test_log_formatter> formatter_ptr;
98    typedef scoped_ptr<io_saver_type>           saver_ptr;
99
100    std::ostream*       m_stream;
101    saver_ptr           m_stream_state_saver;
102    log_level           m_threshold_level;
103    formatter_ptr       m_log_formatter;
104
105    // entry data
106    bool                m_entry_in_progress;
107    bool                m_entry_started;
108    log_entry_data      m_entry_data;
109
110    // check point data
111    log_checkpoint_data m_checkpoint_data;
112
113    // helper functions
114    std::ostream&       stream()            { return *m_stream; }
115    void                set_checkpoint( const_string file, std::size_t line_num, const_string msg )
116    {
117        assign_op( m_checkpoint_data.m_message, msg, 0 );
118        m_checkpoint_data.m_file_name    = file;
119        m_checkpoint_data.m_line_num    = line_num;
120    }
121};
122
123unit_test_log_impl& s_log_impl() { static unit_test_log_impl the_inst; return the_inst; }
124
125} // local namespace
126
127//____________________________________________________________________________//
128
129void
130unit_test_log_t::test_start( counter_t test_cases_amount )
131{
132    if( s_log_impl().m_threshold_level == log_nothing )
133        return;
134
135    s_log_impl().m_log_formatter->log_start( s_log_impl().stream(), test_cases_amount );
136
137    if( runtime_config::show_build_info() )
138        s_log_impl().m_log_formatter->log_build_info( s_log_impl().stream() );
139
140    s_log_impl().m_entry_in_progress = false;
141}
142
143//____________________________________________________________________________//
144
145void
146unit_test_log_t::test_finish()
147{
148    if( s_log_impl().m_threshold_level == log_nothing )
149        return;
150
151    s_log_impl().m_log_formatter->log_finish( s_log_impl().stream() );
152
153    s_log_impl().stream().flush();
154}
155
156//____________________________________________________________________________//
157
158void
159unit_test_log_t::test_aborted()
160{
161    BOOST_TEST_LOG_ENTRY( log_messages ) << "Test is aborted";
162}
163
164//____________________________________________________________________________//
165
166void
167unit_test_log_t::test_unit_start( test_unit const& tu )
168{
169    if( s_log_impl().m_threshold_level > log_test_units )
170        return;
171
172    if( s_log_impl().m_entry_in_progress )
173        *this << log::end();
174
175    s_log_impl().m_log_formatter->test_unit_start( s_log_impl().stream(), tu );
176}
177
178//____________________________________________________________________________//
179
180void
181unit_test_log_t::test_unit_finish( test_unit const& tu, unsigned long elapsed )
182{
183    if( s_log_impl().m_threshold_level > log_test_units )
184        return;
185
186    s_log_impl().m_checkpoint_data.clear();
187
188    if( s_log_impl().m_entry_in_progress )
189        *this << log::end();
190
191    s_log_impl().m_log_formatter->test_unit_finish( s_log_impl().stream(), tu, elapsed );
192}
193
194//____________________________________________________________________________//
195
196void
197unit_test_log_t::test_unit_skipped( test_unit const& tu )
198{
199    if( s_log_impl().m_threshold_level > log_test_units )
200        return;
201
202    if( s_log_impl().m_entry_in_progress )
203        *this << log::end();
204
205    s_log_impl().m_log_formatter->test_unit_skipped( s_log_impl().stream(), tu );
206}
207
208//____________________________________________________________________________//
209
210void
211unit_test_log_t::test_unit_aborted( test_unit const& )
212{
213    // do nothing
214}
215
216//____________________________________________________________________________//
217
218void
219unit_test_log_t::assertion_result( bool )
220{
221    // do nothing
222}
223
224//____________________________________________________________________________//
225
226void
227unit_test_log_t::exception_caught( execution_exception const& ex )
228{
229    log_level l =
230        ex.code() <= execution_exception::cpp_exception_error   ? log_cpp_exception_errors :
231        (ex.code() <= execution_exception::timeout_error        ? log_system_errors
232                                                                : log_fatal_errors );
233
234    if( l >= s_log_impl().m_threshold_level ) {
235        if( s_log_impl().m_entry_in_progress )
236            *this << log::end();
237
238        s_log_impl().m_log_formatter->log_exception( s_log_impl().stream(), s_log_impl().m_checkpoint_data, ex );
239    }
240}
241
242//____________________________________________________________________________//
243
244void
245unit_test_log_t::set_checkpoint( const_string file, std::size_t line_num, const_string msg )
246{
247    s_log_impl().set_checkpoint( file, line_num, msg );
248}
249
250//____________________________________________________________________________//
251
252char
253set_unix_slash( char in )
254{
255    return in == '\\' ? '/' : in;
256}
257
258unit_test_log_t&
259unit_test_log_t::operator<<( log::begin const& b )
260{
261    if( s_log_impl().m_entry_in_progress )
262        *this << log::end();
263
264    s_log_impl().m_stream_state_saver->restore();
265
266    s_log_impl().m_entry_data.clear();
267
268    assign_op( s_log_impl().m_entry_data.m_file_name, b.m_file_name, 0 );
269
270    // normalize file name
271    std::transform( s_log_impl().m_entry_data.m_file_name.begin(), s_log_impl().m_entry_data.m_file_name.end(),
272                    s_log_impl().m_entry_data.m_file_name.begin(),
273                    &set_unix_slash );
274
275    s_log_impl().m_entry_data.m_line_num = b.m_line_num;
276
277    return *this;
278}
279
280//____________________________________________________________________________//
281
282unit_test_log_t&
283unit_test_log_t::operator<<( log::end const& )
284{
285    if( s_log_impl().m_entry_in_progress )
286        s_log_impl().m_log_formatter->log_entry_finish( s_log_impl().stream() );
287
288    s_log_impl().m_entry_in_progress = false;
289
290    return *this;
291}
292
293//____________________________________________________________________________//
294
295unit_test_log_t&
296unit_test_log_t::operator<<( log_level l )
297{
298    s_log_impl().m_entry_data.m_level = l;
299
300    return *this;
301}
302
303//____________________________________________________________________________//
304
305ut_detail::entry_value_collector
306unit_test_log_t::operator()( log_level l )
307{
308    *this << l;
309
310    return ut_detail::entry_value_collector();
311}
312
313//____________________________________________________________________________//
314
315bool
316unit_test_log_t::log_entry_start()
317{
318    if( s_log_impl().m_entry_in_progress )
319        return true;
320
321    switch( s_log_impl().m_entry_data.m_level ) {
322    case log_successful_tests:
323        s_log_impl().m_log_formatter->log_entry_start( s_log_impl().stream(), s_log_impl().m_entry_data,
324                                                       unit_test_log_formatter::BOOST_UTL_ET_INFO );
325        break;
326    case log_messages:
327        s_log_impl().m_log_formatter->log_entry_start( s_log_impl().stream(), s_log_impl().m_entry_data,
328                                                       unit_test_log_formatter::BOOST_UTL_ET_MESSAGE );
329        break;
330    case log_warnings:
331        s_log_impl().m_log_formatter->log_entry_start( s_log_impl().stream(), s_log_impl().m_entry_data,
332                                                       unit_test_log_formatter::BOOST_UTL_ET_WARNING );
333        break;
334    case log_all_errors:
335    case log_cpp_exception_errors:
336    case log_system_errors:
337        s_log_impl().m_log_formatter->log_entry_start( s_log_impl().stream(), s_log_impl().m_entry_data,
338                                                       unit_test_log_formatter::BOOST_UTL_ET_ERROR );
339        break;
340    case log_fatal_errors:
341        s_log_impl().m_log_formatter->log_entry_start( s_log_impl().stream(), s_log_impl().m_entry_data,
342                                                       unit_test_log_formatter::BOOST_UTL_ET_FATAL_ERROR );
343        break;
344    case log_nothing:
345    case log_test_units:
346    case invalid_log_level:
347        return false;
348    }
349
350    s_log_impl().m_entry_in_progress = true;
351
352    return true;
353}
354
355//____________________________________________________________________________//
356
357unit_test_log_t&
358unit_test_log_t::operator<<( const_string value )
359{
360    if( s_log_impl().m_entry_data.m_level >= s_log_impl().m_threshold_level && !value.empty() && log_entry_start() )
361        s_log_impl().m_log_formatter->log_entry_value( s_log_impl().stream(), value );
362
363    return *this;
364}
365
366//____________________________________________________________________________//
367
368unit_test_log_t&
369unit_test_log_t::operator<<( lazy_ostream const& value )
370{
371    if( s_log_impl().m_entry_data.m_level >= s_log_impl().m_threshold_level && !value.empty() && log_entry_start() )
372        s_log_impl().m_log_formatter->log_entry_value( s_log_impl().stream(), value );
373
374    return *this;
375}
376
377//____________________________________________________________________________//
378
379void
380unit_test_log_t::set_stream( std::ostream& str )
381{
382    if( s_log_impl().m_entry_in_progress )
383        return;
384
385    s_log_impl().m_stream = &str;
386    s_log_impl().m_stream_state_saver.reset( new io_saver_type( str ) );
387}
388
389//____________________________________________________________________________//
390
391void
392unit_test_log_t::set_threshold_level( log_level lev )
393{
394    if( s_log_impl().m_entry_in_progress || lev == invalid_log_level )
395        return;
396
397    s_log_impl().m_threshold_level = lev;
398}
399
400//____________________________________________________________________________//
401
402void
403unit_test_log_t::set_format( output_format log_format )
404{
405    if( s_log_impl().m_entry_in_progress )
406        return;
407
408    if( log_format == CLF )
409        set_formatter( new output::compiler_log_formatter );
410    else
411        set_formatter( new output::xml_log_formatter );
412}
413
414//____________________________________________________________________________//
415
416void
417unit_test_log_t::set_formatter( unit_test_log_formatter* the_formatter )
418{
419    s_log_impl().m_log_formatter.reset( the_formatter );
420}
421
422//____________________________________________________________________________//
423
424// ************************************************************************** //
425// **************            unit_test_log_formatter           ************** //
426// ************************************************************************** //
427
428void
429unit_test_log_formatter::log_entry_value( std::ostream& ostr, lazy_ostream const& value )
430{
431    log_entry_value( ostr, (wrap_stringstream().ref() << value).str() );
432}
433
434//____________________________________________________________________________//
435
436} // namespace unit_test
437
438} // namespace boost
439
440//____________________________________________________________________________//
441
442#include <boost/test/detail/enable_warnings.hpp>
443
444#endif // BOOST_TEST_UNIT_TEST_LOG_IPP_012205GER
445