// (C) Copyright Gennadiy Rozental 2001-2004. // Distributed under the Boost Software License, Version 1.0. // (See accompanying file LICENSE_1_0.txt or copy at // http://www.boost.org/LICENSE_1_0.txt) // See http://www.boost.org/libs/test for the library home page. // // File : $RCSfile$ // // Version : $Revision$ // // Description : implemets Unit Test Log, Majority of implementation details // are hidden in this file with use of pimpl idiom. // *************************************************************************** // Boost.Test #include #include #include #include #include #include #include // BOOST #include #include // STL #include #include # ifdef BOOST_NO_STDC_NAMESPACE namespace std { using ::strcmp; } # endif namespace boost { namespace unit_test { // ************************************************************************** // // ************** unit_test_log ************** // // ************************************************************************** // struct unit_test_log::Impl { // Constructor Impl() : m_stream( &std::cout ) {} // log data std::ostream* m_stream; log_level m_threshold_level; boost::scoped_ptr m_progress_display; boost::scoped_ptr m_log_formatter; // entry data bool m_entry_in_progress; bool m_entry_has_value; log_entry_data m_entry_data; // checkpoint data log_checkpoint_data m_checkpoint_data; // helper functions std::ostream& stream() { return *m_stream; } void flush_entry() { stream() << std::endl; } void clear_entry_data() { m_entry_data.clear(); m_entry_in_progress = false; m_entry_has_value = false; } void set_checkpoint( checkpoint const& cp ) { cp.m_message.assign_to( m_checkpoint_data.m_message ); m_checkpoint_data.m_file = m_entry_data.m_file; m_checkpoint_data.m_line = m_entry_data.m_line; } void clear_checkpoint() { m_checkpoint_data.clear(); } }; //____________________________________________________________________________// unit_test_log::unit_test_log() : m_pimpl( new Impl() ) { m_pimpl->m_threshold_level = log_all_errors; m_pimpl->m_log_formatter.reset( new detail::msvc65_like_log_formatter( *this ) ); m_pimpl->clear_entry_data(); m_pimpl->clear_checkpoint(); } //____________________________________________________________________________// unit_test_log& unit_test_log::instance() { static unit_test_log the_instance; return the_instance; } //____________________________________________________________________________// unit_test_log::~unit_test_log() { delete m_pimpl; } //____________________________________________________________________________// void unit_test_log::set_log_stream( std::ostream& str ) { if( m_pimpl->m_entry_in_progress ) return; m_pimpl->m_stream = &str; } //____________________________________________________________________________// void unit_test_log::set_log_threshold_level( log_level lev ) { if( m_pimpl->m_entry_in_progress || lev == invalid_log_level ) return; m_pimpl->m_threshold_level = lev; } //____________________________________________________________________________// void unit_test_log::set_log_threshold_level_by_name( const_string lev ) { static fixed_mapping log_level_name( "all" , log_successful_tests, "success" , log_successful_tests, "test_suite" , log_test_suites, "messages" , log_messages, "warnings" , log_warnings, "all_errors" , log_all_errors, "cpp_exceptions", log_cpp_exception_errors, "system_errors" , log_system_errors, "fatal_errors" , log_fatal_errors, "progress" , log_progress_only, "nothing" , log_nothing, invalid_log_level ); if( m_pimpl->m_entry_in_progress ) return; set_log_threshold_level( log_level_name[lev] ); } //____________________________________________________________________________// void unit_test_log::clear_checkpoint() { m_pimpl->clear_checkpoint(); } //____________________________________________________________________________// void unit_test_log::track_test_case_scope( test_case const& tc, bool in_out ) { if( m_pimpl->m_threshold_level > log_test_suites ) return; *this << begin(); m_pimpl->m_log_formatter->track_test_case_scope( m_pimpl->stream(), tc, in_out ); m_pimpl->m_entry_has_value = true; *this << end(); } //____________________________________________________________________________// unit_test_log& unit_test_log::operator<<( begin const& ) { if( m_pimpl->m_entry_in_progress ) *this << end(); m_pimpl->m_entry_in_progress = true; return *this; } //____________________________________________________________________________// unit_test_log& unit_test_log::operator<<( end const& ) { if( m_pimpl->m_entry_has_value ) { m_pimpl->m_log_formatter->end_log_entry( m_pimpl->stream() ); m_pimpl->flush_entry(); } m_pimpl->clear_entry_data(); return *this; } //____________________________________________________________________________// char set_unix_slash( char in ) { return in == '\\' ? '/' : in; } unit_test_log& unit_test_log::operator<<( file const& f ) { if( m_pimpl->m_entry_in_progress ) { f.m_file_name.assign_to( m_pimpl->m_entry_data.m_file ); // normalize file name std::transform( m_pimpl->m_entry_data.m_file.begin(), m_pimpl->m_entry_data.m_file.end(), m_pimpl->m_entry_data.m_file.begin(), &set_unix_slash ); } return *this; } //____________________________________________________________________________// unit_test_log& unit_test_log::operator<<( line const& l ) { if( m_pimpl->m_entry_in_progress ) m_pimpl->m_entry_data.m_line = l.m_line_num; return *this; } //____________________________________________________________________________// unit_test_log& unit_test_log::operator<<( level const& lev ) { if( m_pimpl->m_entry_in_progress ) m_pimpl->m_entry_data.m_level = lev.m_level; return *this; } //____________________________________________________________________________// unit_test_log& unit_test_log::operator<<( checkpoint const& cp ) { if( m_pimpl->m_entry_in_progress ) m_pimpl->set_checkpoint( cp ); return *this; } //____________________________________________________________________________// unit_test_log& unit_test_log::operator<<( log_exception const& re ) { if( m_pimpl->m_entry_in_progress && m_pimpl->m_entry_data.m_level >= m_pimpl->m_threshold_level ) { m_pimpl->m_log_formatter->log_exception( m_pimpl->stream(), unit_test_result::instance().test_case_name(), re.m_what ); m_pimpl->m_entry_has_value = true; } return *this; } //____________________________________________________________________________// unit_test_log& unit_test_log::operator<<( log_progress const& ) { if( m_pimpl->m_progress_display ) ++(*m_pimpl->m_progress_display); return *this; } //____________________________________________________________________________// unit_test_log& unit_test_log::operator<<( const_string value ) { if( m_pimpl->m_entry_in_progress && m_pimpl->m_entry_data.m_level >= m_pimpl->m_threshold_level && !value.empty() ) { if( !m_pimpl->m_entry_has_value ) { switch( m_pimpl->m_entry_data.m_level ) { case log_successful_tests: m_pimpl->m_log_formatter->begin_log_entry( m_pimpl->stream(), unit_test_log_formatter::BOOST_UTL_ET_INFO ); break; case log_messages: m_pimpl->m_log_formatter->begin_log_entry( m_pimpl->stream(), unit_test_log_formatter::BOOST_UTL_ET_MESSAGE ); break; case log_warnings: m_pimpl->m_log_formatter->begin_log_entry( m_pimpl->stream(), unit_test_log_formatter::BOOST_UTL_ET_WARNING ); break; case log_all_errors: case log_cpp_exception_errors: case log_system_errors: m_pimpl->m_log_formatter->begin_log_entry( m_pimpl->stream(), unit_test_log_formatter::BOOST_UTL_ET_ERROR ); break; case log_fatal_errors: m_pimpl->m_log_formatter->begin_log_entry( m_pimpl->stream(), unit_test_log_formatter::BOOST_UTL_ET_FATAL_ERROR ); break; case log_progress_only: case log_nothing: case log_test_suites: case invalid_log_level: return *this; } } m_pimpl->m_log_formatter->log_entry_value( m_pimpl->stream(), value ); m_pimpl->m_entry_has_value = true; } return *this; } //____________________________________________________________________________// void unit_test_log::start( bool print_build_info ) { m_pimpl->m_log_formatter->start_log( m_pimpl->stream(), print_build_info ); } //____________________________________________________________________________// void unit_test_log::header( unit_test_counter test_cases_amount ) { if( m_pimpl->m_threshold_level != log_nothing && test_cases_amount > 0 ) m_pimpl->m_log_formatter->log_header( m_pimpl->stream(), test_cases_amount ); if( m_pimpl->m_threshold_level == log_progress_only ) m_pimpl->m_progress_display.reset( new boost::progress_display( test_cases_amount, m_pimpl->stream() ) ); else m_pimpl->m_progress_display.reset(); } //____________________________________________________________________________// void unit_test_log::finish( unit_test_counter test_cases_amount ) { if( test_cases_amount == 1 ) *this << log_progress(); m_pimpl->m_log_formatter->finish_log( m_pimpl->stream() ); } //____________________________________________________________________________// void unit_test_log::set_log_format( const_string log_format_name ) { if( m_pimpl->m_entry_in_progress ) return; static fixed_mapping > log_format( "HRF", HRF, "XML", XML, HRF ); if( log_format[log_format_name] == HRF ) set_log_formatter( new detail::msvc65_like_log_formatter( *this ) ); else set_log_formatter( new detail::xml_log_formatter( *this ) ); } //____________________________________________________________________________// void unit_test_log::set_log_formatter( unit_test_log_formatter* the_formatter ) { m_pimpl->m_log_formatter.reset( the_formatter ); } //____________________________________________________________________________// log_entry_data const& unit_test_log::entry_data() const { return m_pimpl->m_entry_data; } //____________________________________________________________________________// log_checkpoint_data const& unit_test_log::checkpoint_data() const { return m_pimpl->m_checkpoint_data; } //____________________________________________________________________________// } // namespace unit_test } // namespace boost // *************************************************************************** // Revision History : // // $Log$ // Revision 1.23 2004/05/27 06:29:59 rogeeff // eliminate warnings // // Revision 1.22 2004/05/21 06:26:09 rogeeff // licence update // // Revision 1.21 2004/05/13 09:04:43 rogeeff // added fixed_mapping // // Revision 1.20 2004/05/11 11:04:44 rogeeff // basic_cstring introduced and used everywhere // class properties reworked // namespace names shortened // // Revision 1.19 2003/12/01 00:42:37 rogeeff // prerelease cleaning // // *************************************************************************** // EOF