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