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