// (C) Copyright Gennadiy Rozental 2001-2003. // Use, modification, and distribution are subject to 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 // BOOST #include #include // STL #include # ifdef BOOST_NO_STDC_NAMESPACE namespace std { using ::strcmp; } # endif namespace boost { namespace unit_test_framework { // ************************************************************************** // // ************** 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 ) { m_checkpoint_data.m_message = cp.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 ) return; m_pimpl->m_threshold_level = lev; } //____________________________________________________________________________// void unit_test_log::set_log_threshold_level_by_name( std::string const& lev ) { if( m_pimpl->m_entry_in_progress ) return; struct my_pair { c_string_literal level_name; log_level level_value; }; static const my_pair name_value_map[] = { { "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 }, }; static int const map_size = sizeof(name_value_map)/sizeof(my_pair); if( lev.empty() ) return; for( int i=0; i < map_size; i++ ) { if( lev == name_value_map[i].level_name ) { set_log_threshold_level( name_value_map[i].level_value ); return; } } } //____________________________________________________________________________// 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 ) { m_pimpl->m_entry_data.m_file = f.m_file_name; // 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<<( std::string const& 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: return *this; } } m_pimpl->m_log_formatter->log_entry_value( m_pimpl->stream(), value ); m_pimpl->m_entry_has_value = true; } return *this; } //____________________________________________________________________________// unit_test_log& unit_test_log::operator<<( c_string_literal value ) { return *this << std::string( value ? value : "" ); } //____________________________________________________________________________// 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( std::string const& logformat ) { if( m_pimpl->m_entry_in_progress ) return; struct my_pair { c_string_literal format_name; output_format format_value; }; static const my_pair name_value_map[] = { { "HRF" , HRF }, { "XML" , XML }, }; static int const map_size = sizeof(name_value_map)/sizeof(my_pair); output_format of = HRF; for( int i=0; i < map_size; i++ ) { if( logformat == name_value_map[i].format_name ) { of = name_value_map[i].format_value; break; } } if( of == 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_framework } // namespace boost // *************************************************************************** // Revision History : // // $Log$ // Revision 1.19 2003/12/01 00:42:37 rogeeff // prerelease cleaning // // *************************************************************************** // EOF