update boost on linux

This commit is contained in:
Bassem Girgis
2019-08-10 16:06:25 -05:00
parent 76ad52be58
commit 861b918727
5363 changed files with 483306 additions and 116507 deletions

View File

@@ -52,7 +52,7 @@ namespace {
std::string
test_phase_identifier()
{
return framework::test_in_progress() ? framework::current_test_case().full_name() : std::string( "Test setup" );
return framework::test_in_progress() ? framework::current_test_unit().full_name() : std::string( "Test setup" );
}
} // local namespace
@@ -80,14 +80,16 @@ compiler_log_formatter::log_finish( std::ostream& ostr )
//____________________________________________________________________________//
void
compiler_log_formatter::log_build_info( std::ostream& output )
compiler_log_formatter::log_build_info( std::ostream& output, bool log_build_info )
{
output << "Platform: " << BOOST_PLATFORM << '\n'
<< "Compiler: " << BOOST_COMPILER << '\n'
<< "STL : " << BOOST_STDLIB << '\n'
<< "Boost : " << BOOST_VERSION/100000 << "."
<< BOOST_VERSION/100 % 1000 << "."
<< BOOST_VERSION % 100 << std::endl;
if(log_build_info) {
output << "Platform: " << BOOST_PLATFORM << '\n'
<< "Compiler: " << BOOST_COMPILER << '\n'
<< "STL : " << BOOST_STDLIB << '\n'
<< "Boost : " << BOOST_VERSION/100000 << "."
<< BOOST_VERSION/100 % 1000 << "."
<< BOOST_VERSION % 100 << std::endl;
}
}
//____________________________________________________________________________//
@@ -182,30 +184,25 @@ compiler_log_formatter::log_entry_start( std::ostream& output, log_entry_data co
switch( let ) {
case BOOST_UTL_ET_INFO:
print_prefix( output, entry_data.m_file_name, entry_data.m_line_num );
if( m_color_output )
output << setcolor( term_attr::BRIGHT, term_color::GREEN );
output << setcolor( m_color_output, term_attr::BRIGHT, term_color::GREEN );
output << "info: ";
break;
case BOOST_UTL_ET_MESSAGE:
if( m_color_output )
output << setcolor( term_attr::BRIGHT, term_color::CYAN );
output << setcolor( m_color_output, term_attr::BRIGHT, term_color::CYAN );
break;
case BOOST_UTL_ET_WARNING:
print_prefix( output, entry_data.m_file_name, entry_data.m_line_num );
if( m_color_output )
output << setcolor( term_attr::BRIGHT, term_color::YELLOW );
output << setcolor( m_color_output, term_attr::BRIGHT, term_color::YELLOW );
output << "warning: in \"" << test_phase_identifier() << "\": ";
break;
case BOOST_UTL_ET_ERROR:
print_prefix( output, entry_data.m_file_name, entry_data.m_line_num );
if( m_color_output )
output << setcolor( term_attr::BRIGHT, term_color::RED );
output << setcolor( m_color_output, term_attr::BRIGHT, term_color::RED );
output << "error: in \"" << test_phase_identifier() << "\": ";
break;
case BOOST_UTL_ET_FATAL_ERROR:
print_prefix( output, entry_data.m_file_name, entry_data.m_line_num );
if( m_color_output )
output << setcolor( term_attr::UNDERLINE, term_color::RED );
output << setcolor( m_color_output, term_attr::UNDERLINE, term_color::RED );
output << "fatal error: in \"" << test_phase_identifier() << "\": ";
break;
}
@@ -233,7 +230,7 @@ void
compiler_log_formatter::log_entry_finish( std::ostream& output )
{
if( m_color_output )
output << utils::setcolor();
output << utils::setcolor(m_color_output);
output << std::endl;
}
@@ -260,21 +257,29 @@ compiler_log_formatter::print_prefix( std::ostream& output, const_string file_na
void
compiler_log_formatter::entry_context_start( std::ostream& output, log_level l )
{
output << (l == log_successful_tests ? "\nAssertion" : "\nFailure" ) << " occurred in a following context:";
if( l == log_messages ) {
output << "\n[context:";
}
else {
output << (l == log_successful_tests ? "\nAssertion" : "\nFailure" ) << " occurred in a following context:";
}
}
//____________________________________________________________________________//
void
compiler_log_formatter::entry_context_finish( std::ostream& output )
compiler_log_formatter::entry_context_finish( std::ostream& output, log_level l )
{
if( l == log_messages ) {
output << "]";
}
output.flush();
}
//____________________________________________________________________________//
void
compiler_log_formatter::log_entry_context( std::ostream& output, const_string context_descr )
compiler_log_formatter::log_entry_context( std::ostream& output, log_level /*l*/, const_string context_descr )
{
output << "\n " << context_descr;
}

View File

@@ -17,12 +17,13 @@
// Boost.Test
#include <boost/test/detail/config.hpp>
#include <boost/test/detail/workaround.hpp>
#include <boost/test/detail/global_typedef.hpp>
#include <boost/test/debug.hpp>
#include <boost/test/debug_config.hpp>
#include <boost/core/ignore_unused.hpp>
// Implementation on Windows
#if defined(_WIN32) && !defined(UNDER_CE) && !defined(BOOST_DISABLE_WIN32) // ******* WIN32
@@ -768,7 +769,7 @@ struct safe_handle_helper
}
}
~safe_handle_helper()
~safe_handle_helper()
{
close_handle();
}
@@ -804,7 +805,7 @@ attach_debugger( bool break_or_continue )
if( !dbg_init_done_ev )
return false;
safe_handle_helper safe_handle_obj( dbg_init_done_ev );
// *************************************************** //
@@ -822,7 +823,7 @@ attach_debugger( bool break_or_continue )
DWORD format_size = MAX_CMD_LINE;
DWORD type = REG_SZ;
bool b_read_key = s_info.m_reg_query_value &&
bool b_read_key = s_info.m_reg_query_value &&
((*s_info.m_reg_query_value)(
reg_key, // handle of open key
"Debugger", // name of subkey to query
@@ -833,7 +834,7 @@ attach_debugger( bool break_or_continue )
if( !s_info.m_reg_close_key || (*s_info.m_reg_close_key)( reg_key ) != ERROR_SUCCESS )
return false;
if( !b_read_key )
return false;
@@ -938,7 +939,7 @@ attach_debugger( bool break_or_continue )
return true;
#else // ****************************************************** default
(void) break_or_continue; // silence 'unused variable' warning
return false;
#endif
@@ -953,7 +954,7 @@ attach_debugger( bool break_or_continue )
void
detect_memory_leaks( bool on_off, unit_test::const_string report_file )
{
unit_test::ut_detail::ignore_unused_variable_warning( on_off );
boost::ignore_unused( on_off );
#ifdef BOOST_MS_CRT_BASED_DEBUG
int flags = _CrtSetDbgFlag( _CRTDBG_REPORT_FLAG );
@@ -975,7 +976,7 @@ detect_memory_leaks( bool on_off, unit_test::const_string report_file )
_CrtSetDbgFlag ( flags );
#else
unit_test::ut_detail::ignore_unused_variable_warning( report_file );
boost::ignore_unused( report_file );
#endif // BOOST_MS_CRT_BASED_DEBUG
}
@@ -989,7 +990,7 @@ detect_memory_leaks( bool on_off, unit_test::const_string report_file )
void
break_memory_alloc( long mem_alloc_order_num )
{
unit_test::ut_detail::ignore_unused_variable_warning( mem_alloc_order_num );
boost::ignore_unused( mem_alloc_order_num );
#ifdef BOOST_MS_CRT_BASED_DEBUG
// only set the value if one was supplied (do not use default used by UTF just as a indicator to enable leak detection)
@@ -1006,4 +1007,3 @@ break_memory_alloc( long mem_alloc_order_num )
#include <boost/test/detail/enable_warnings.hpp>
#endif // BOOST_TEST_DEBUG_API_IPP_112006GER

View File

@@ -5,10 +5,6 @@
// See http://www.boost.org/libs/test for the library home page.
//
// File : $RCSfile$
//
// Version : $Revision$
//
// Description : unit test decorators implementation
// ***************************************************************************
@@ -35,13 +31,17 @@ namespace unit_test {
namespace decorator {
// ************************************************************************** //
// ************** decorator::collector ************** //
// ************** decorator::collector_t ************** //
// ************************************************************************** //
collector&
collector::operator*( base const& d )
// singleton pattern
BOOST_TEST_SINGLETON_CONS_IMPL(collector_t)
collector_t&
collector_t::operator*( base const& d )
{
m_tu_decorators.push_back( d.clone() );
m_tu_decorators_stack.begin()->push_back( d.clone() );
return *this;
}
@@ -49,17 +49,41 @@ collector::operator*( base const& d )
//____________________________________________________________________________//
void
collector::store_in( test_unit& tu )
collector_t::store_in( test_unit& tu )
{
tu.p_decorators.value.insert( tu.p_decorators.value.end(), m_tu_decorators.begin(), m_tu_decorators.end() );
tu.p_decorators.value.insert(
tu.p_decorators.value.end(),
m_tu_decorators_stack.begin()->begin(),
m_tu_decorators_stack.begin()->end() );
}
//____________________________________________________________________________//
void
collector::reset()
collector_t::reset()
{
m_tu_decorators.clear();
if(m_tu_decorators_stack.size() > 1) {
m_tu_decorators_stack.erase(m_tu_decorators_stack.begin());
}
else {
assert(m_tu_decorators_stack.size() == 1);
m_tu_decorators_stack.begin()->clear();
}
}
void
collector_t::stack()
{
assert(m_tu_decorators_stack.size() >= 1);
m_tu_decorators_stack.insert(m_tu_decorators_stack.begin(), std::vector<base_ptr>());
}
//____________________________________________________________________________//
std::vector<base_ptr>
collector_t::get_lazy_decorators() const
{
return *m_tu_decorators_stack.begin();
}
//____________________________________________________________________________//
@@ -68,10 +92,28 @@ collector::reset()
// ************** decorator::base ************** //
// ************************************************************************** //
collector&
collector_t&
base::operator*() const
{
return collector::instance() * *this;
return collector_t::instance() * *this;
}
// ************************************************************************** //
// ************** decorator::stack_decorator ************** //
// ************************************************************************** //
collector_t&
stack_decorator::operator*() const
{
collector_t& instance = collector_t::instance();
instance.stack();
return instance * *this;
}
void
stack_decorator::apply( test_unit& tu )
{
// does nothing by definition
}
// ************************************************************************** //

View File

@@ -23,7 +23,6 @@
// Boost.Test
#include <boost/test/detail/config.hpp>
#include <boost/test/detail/workaround.hpp>
#include <boost/test/detail/throw_exception.hpp>
#include <boost/test/execution_monitor.hpp>
#include <boost/test/debug.hpp>
@@ -35,6 +34,7 @@
#ifndef BOOST_NO_EXCEPTIONS
#include <boost/exception/get_error_info.hpp> // for get_error_info
#include <boost/exception/current_exception_cast.hpp> // for current_exception_cast
#include <boost/exception/diagnostic_information.hpp>
#endif
// STL
@@ -47,28 +47,32 @@
#include <cassert> // for assert
#include <cstddef> // for NULL
#include <cstdio> // for vsnprintf
#include <stdio.h>
#include <cstdarg> // for varargs
#include <stdarg.h>
#include <cmath> // for ceil
#include <iostream> // for varargs
#ifdef BOOST_NO_STDC_NAMESPACE
namespace std { using ::strerror; using ::strlen; using ::strncat; }
namespace std { using ::strerror; using ::strlen; using ::strncat; using ::ceil; }
#endif
// to use vsnprintf
#if defined(__SUNPRO_CC) || defined(__SunOS)
# include <stdio.h>
# include <stdarg.h>
#if defined(__SUNPRO_CC) || defined(__SunOS) || defined(__QNXNTO__) || defined(__VXWORKS__)
using std::va_list;
#endif
// to use vsnprintf
#if defined(__QNXNTO__)
# include <stdio.h>
using std::va_list;
#if defined(__VXWORKS__)
# define BOOST_TEST_LIMITED_SIGNAL_DETAILS
#endif
#ifdef BOOST_SEH_BASED_SIGNAL_HANDLING
# if !defined(_WIN32_WINNT) // WinXP
# define _WIN32_WINNT 0x0501
# endif
# include <windows.h>
# if defined(__MWERKS__) || (defined(_MSC_VER) && !defined(UNDER_CE))
@@ -102,6 +106,10 @@ using std::va_list;
# define BOOST_TEST_CRT_SET_HOOK(H) (void*)(H)
# endif
# if defined(_WIN32_WINNT) && (_WIN32_WINNT >= 0x0501) /* WinXP */
# define BOOST_TEST_WIN32_WAITABLE_TIMERS
# endif
# if (!BOOST_WORKAROUND(_MSC_VER, >= 1400 ) && \
!defined(BOOST_COMO)) || defined(UNDER_CE)
@@ -210,7 +218,8 @@ namespace detail {
# define BOOST_TEST_VSNPRINTF( a1, a2, a3, a4 ) std::vsnprintf( (a1), (a2), (a3), (a4) )
#elif BOOST_WORKAROUND(_MSC_VER, <= 1310) || \
BOOST_WORKAROUND(__MWERKS__, BOOST_TESTED_AT(0x3000)) || \
defined(UNDER_CE)
defined(UNDER_CE) || \
(defined(__MINGW32__) && !defined(__MINGW64_VERSION_MAJOR))
# define BOOST_TEST_VSNPRINTF( a1, a2, a3, a4 ) _vsnprintf( (a1), (a2), (a3), (a4) )
#else
# define BOOST_TEST_VSNPRINTF( a1, a2, a3, a4 ) vsnprintf( (a1), (a2), (a3), (a4) )
@@ -363,11 +372,17 @@ system_signal_exception::report() const
return; // no error actually occur?
switch( m_sig_info->si_code ) {
#ifdef __VXWORKS__
// a bit of a hack to adapt code to small m_sig_info VxWorks uses
#define si_addr si_value.sival_int
#define si_band si_value.sival_int
#else
case SI_USER:
report_error( execution_exception::system_error,
"signal: generated by kill() (or family); uid=%d; pid=%d",
(int)m_sig_info->si_uid, (int)m_sig_info->si_pid );
break;
#endif
case SI_QUEUE:
report_error( execution_exception::system_error,
"signal: sent by sigqueue()" );
@@ -686,7 +701,7 @@ signal_action::~signal_action()
class signal_handler {
public:
// Constructor
explicit signal_handler( bool catch_system_errors, bool detect_fpe, unsigned timeout, bool attach_dbg, char* alt_stack );
explicit signal_handler( bool catch_system_errors, bool detect_fpe, unsigned timeout_microseconds, bool attach_dbg, char* alt_stack );
// Destructor
~signal_handler();
@@ -709,7 +724,7 @@ public:
private:
// Data members
signal_handler* m_prev_handler;
unsigned m_timeout;
unsigned m_timeout_microseconds;
// Note: We intentionality do not catch SIGCHLD. Users have to deal with it themselves
signal_action m_ILL_action;
@@ -733,24 +748,24 @@ signal_handler* signal_handler::s_active_handler = signal_handler_ptr();
//____________________________________________________________________________//
signal_handler::signal_handler( bool catch_system_errors, bool detect_fpe, unsigned timeout, bool attach_dbg, char* alt_stack )
signal_handler::signal_handler( bool catch_system_errors, bool detect_fpe, unsigned timeout_microseconds, bool attach_dbg, char* alt_stack )
: m_prev_handler( s_active_handler )
, m_timeout( timeout )
, m_ILL_action ( SIGILL , catch_system_errors, attach_dbg, alt_stack )
, m_FPE_action ( SIGFPE , detect_fpe , attach_dbg, alt_stack )
, m_SEGV_action( SIGSEGV, catch_system_errors, attach_dbg, alt_stack )
, m_BUS_action ( SIGBUS , catch_system_errors, attach_dbg, alt_stack )
, m_timeout_microseconds( timeout_microseconds )
, m_ILL_action ( SIGILL , catch_system_errors, attach_dbg, alt_stack )
, m_FPE_action ( SIGFPE , detect_fpe , attach_dbg, alt_stack )
, m_SEGV_action( SIGSEGV, catch_system_errors, attach_dbg, alt_stack )
, m_BUS_action ( SIGBUS , catch_system_errors, attach_dbg, alt_stack )
#ifdef BOOST_TEST_CATCH_SIGPOLL
, m_POLL_action( SIGPOLL, catch_system_errors, attach_dbg, alt_stack )
, m_POLL_action( SIGPOLL, catch_system_errors, attach_dbg, alt_stack )
#endif
, m_ABRT_action( SIGABRT, catch_system_errors, attach_dbg, alt_stack )
, m_ALRM_action( SIGALRM, timeout > 0 , attach_dbg, alt_stack )
, m_ABRT_action( SIGABRT, catch_system_errors, attach_dbg, alt_stack )
, m_ALRM_action( SIGALRM, timeout_microseconds > 0, attach_dbg, alt_stack )
{
s_active_handler = this;
if( m_timeout > 0 ) {
if( m_timeout_microseconds > 0 ) {
::alarm( 0 );
::alarm( timeout );
::alarm( static_cast<unsigned int>(std::ceil(timeout_microseconds / 1E6) )); // alarm has a precision to the seconds
}
#ifdef BOOST_TEST_USE_ALT_STACK
@@ -776,7 +791,7 @@ signal_handler::~signal_handler()
{
assert( s_active_handler == this );
if( m_timeout > 0 )
if( m_timeout_microseconds > 0 )
::alarm( 0 );
#ifdef BOOST_TEST_USE_ALT_STACK
@@ -892,8 +907,10 @@ public:
, m_se_id( 0 )
, m_fault_address( 0 )
, m_dir( false )
, m_timeout( false )
{}
void set_timed_out();
void report() const;
int operator()( unsigned id, _EXCEPTION_POINTERS* exps );
@@ -904,6 +921,7 @@ private:
unsigned m_se_id;
void* m_fault_address;
bool m_dir;
bool m_timeout;
};
//____________________________________________________________________________//
@@ -918,6 +936,14 @@ seh_catch_preventer( unsigned /* id */, _EXCEPTION_POINTERS* /* exps */ )
//____________________________________________________________________________//
void
system_signal_exception::set_timed_out()
{
m_timeout = true;
}
//____________________________________________________________________________//
int
system_signal_exception::operator()( unsigned id, _EXCEPTION_POINTERS* exps )
{
@@ -1069,7 +1095,12 @@ system_signal_exception::report() const
break;
default:
detail::report_error( execution_exception::system_error, "unrecognized exception. Id: 0x%08lx", m_se_id );
if( m_timeout ) {
detail::report_error(execution_exception::timeout_error, "timeout while executing function");
}
else {
detail::report_error( execution_exception::system_error, "unrecognized exception. Id: 0x%08lx", m_se_id );
}
break;
}
}
@@ -1128,6 +1159,31 @@ execution_monitor::catch_signals( boost::function<int ()> const& F )
#endif
}
#if defined(BOOST_TEST_WIN32_WAITABLE_TIMERS)
HANDLE htimer = INVALID_HANDLE_VALUE;
BOOL bTimerSuccess = FALSE;
if( p_timeout ) {
htimer = ::CreateWaitableTimer(
NULL,
TRUE,
TEXT("Boost.Test timer"));
if( htimer != INVALID_HANDLE_VALUE ) {
LARGE_INTEGER liDueTime;
liDueTime.QuadPart = - static_cast<signed long int>(p_timeout) * 10; // resolution of 100 ns
bTimerSuccess = ::SetWaitableTimer(
htimer,
&liDueTime,
0,
0,
0,
FALSE); // Do not restore a suspended system
}
}
#endif
detail::system_signal_exception SSE( this );
int ret_val = 0;
@@ -1141,8 +1197,26 @@ execution_monitor::catch_signals( boost::function<int ()> const& F )
__except( SSE( GetExceptionCode(), GetExceptionInformation() ) ) {
throw SSE;
}
// we check for time outs: we do not have any signaling facility on Win32
// however, we signal a timeout as a hard error as for the other operating systems
// and throw the signal error handler
if( bTimerSuccess && htimer != INVALID_HANDLE_VALUE) {
if (::WaitForSingleObject(htimer, 0) == WAIT_OBJECT_0) {
SSE.set_timed_out();
throw SSE;
}
}
}
__finally {
#if defined(BOOST_TEST_WIN32_WAITABLE_TIMERS)
if( htimer != INVALID_HANDLE_VALUE ) {
::CloseHandle(htimer);
}
#endif
if( l_catch_system_errors ) {
BOOST_TEST_CRT_SET_HOOK( old_crt_hook );
@@ -1198,7 +1272,7 @@ execution_monitor::execute( boost::function<int ()> const& F )
BOOST_TEST_I_TRY {
detail::fpe_except_guard G( p_detect_fp_exceptions );
unit_test::ut_detail::ignore_unused_variable_warning( G );
boost::ignore_unused( G );
return catch_signals( F );
}
@@ -1217,6 +1291,16 @@ execution_monitor::execute( boost::function<int ()> const& F )
{ detail::report_error( execution_exception::cpp_exception_error,
"std::string: %s", ex.c_str() ); }
// boost::exception (before std::exception, with extended diagnostic)
catch( boost::exception const& ex )
{ detail::report_error( execution_exception::cpp_exception_error,
&ex,
#if defined(BOOST_NO_TYPEID) || defined(BOOST_NO_RTTI)
"unknown boost::exception" ); }
#else
boost::diagnostic_information(ex).c_str() ); }
#endif
// std:: exceptions
#if defined(BOOST_NO_TYPEID) || defined(BOOST_NO_RTTI)
#define CATCH_AND_REPORT_STD_EXCEPTION( ex_name ) \
@@ -1235,15 +1319,8 @@ execution_monitor::execute( boost::function<int ()> const& F )
#endif
CATCH_AND_REPORT_STD_EXCEPTION( std::bad_alloc )
#if BOOST_WORKAROUND(__BORLANDC__, <= 0x0551)
CATCH_AND_REPORT_STD_EXCEPTION( std::bad_cast )
CATCH_AND_REPORT_STD_EXCEPTION( std::bad_typeid )
#else
CATCH_AND_REPORT_STD_EXCEPTION( std::bad_cast )
CATCH_AND_REPORT_STD_EXCEPTION( std::bad_typeid )
#endif
CATCH_AND_REPORT_STD_EXCEPTION( std::bad_exception )
CATCH_AND_REPORT_STD_EXCEPTION( std::domain_error )
CATCH_AND_REPORT_STD_EXCEPTION( std::invalid_argument )
@@ -1257,15 +1334,6 @@ execution_monitor::execute( boost::function<int ()> const& F )
CATCH_AND_REPORT_STD_EXCEPTION( std::exception )
#undef CATCH_AND_REPORT_STD_EXCEPTION
catch( boost::exception const& ex )
{ detail::report_error( execution_exception::cpp_exception_error,
&ex,
#if defined(BOOST_NO_TYPEID) || defined(BOOST_NO_RTTI)
"unknown boost::exception" ); }
#else
typeid(ex).name() ); }
#endif
// system errors
catch( system_error const& ex )
{ detail::report_error( execution_exception::cpp_exception_error,
@@ -1342,6 +1410,12 @@ execution_exception::location::location( char const* file_name, size_t line_num,
, m_function( func )
{}
execution_exception::location::location(const_string file_name, size_t line_num, char const* func )
: m_file_name( file_name )
, m_line_num( line_num )
, m_function( func )
{}
//____________________________________________________________________________//
// ************************************************************************** //

View File

@@ -27,12 +27,14 @@
#include <boost/test/results_collector.hpp>
#include <boost/test/progress_monitor.hpp>
#include <boost/test/results_reporter.hpp>
#include <boost/test/test_framework_init_observer.hpp>
#include <boost/test/tree/observer.hpp>
#include <boost/test/tree/test_unit.hpp>
#include <boost/test/tree/visitor.hpp>
#include <boost/test/tree/traverse.hpp>
#include <boost/test/tree/test_case_counter.hpp>
#include <boost/test/tree/global_fixture.hpp>
#if BOOST_TEST_SUPPORT_TOKEN_ITERATOR
#include <boost/test/utils/iterator/token_iterator.hpp>
@@ -46,7 +48,7 @@
#include <boost/test/detail/throw_exception.hpp>
// Boost
#include <boost/timer.hpp>
#include <boost/test/utils/timer.hpp>
#include <boost/bind.hpp>
// STL
@@ -56,6 +58,10 @@
#include <cstdlib>
#include <ctime>
#include <numeric>
#include <cmath>
#ifdef BOOST_NO_CXX98_RANDOM_SHUFFLE
#include <iterator>
#endif
#ifdef BOOST_NO_STDC_NAMESPACE
namespace std { using ::time; using ::srand; }
@@ -68,6 +74,7 @@ namespace std { using ::time; using ::srand; }
namespace boost {
namespace unit_test {
namespace framework {
namespace impl {
// ************************************************************************** //
@@ -342,12 +349,10 @@ public:
, m_dep_collector( dep_collector )
{}
private:
// test_tree_visitor interface
virtual bool visit( test_unit const& tu )
{
const_cast<test_unit&>(tu).p_run_status.value = m_new_status == test_unit::RS_INVALID ? tu.p_default_status : m_new_status;
if( m_dep_collector ) {
BOOST_TEST_FOREACH( test_unit_id, dep_id, tu.p_dependencies.get() ) {
test_unit const& dep = framework::get( dep_id, TUT_ANY );
@@ -364,6 +369,7 @@ private:
return true;
}
private:
// Data members
test_unit::run_status m_new_status;
test_unit_id_list* m_dep_collector;
@@ -435,18 +441,59 @@ parse_filters( test_unit_id master_tu_id, test_unit_id_list& tu_to_enable, test_
//____________________________________________________________________________//
#ifdef BOOST_NO_CXX98_RANDOM_SHUFFLE
// a poor man's implementation of random_shuffle
template< class RandomIt, class RandomFunc >
void random_shuffle( RandomIt first, RandomIt last, RandomFunc &r )
{
typedef typename std::iterator_traits<RandomIt>::difference_type difference_type;
difference_type n = last - first;
for (difference_type i = n-1; i > 0; --i) {
difference_type j = r(i+1);
if (j != i) {
using std::swap;
swap(first[i], first[j]);
}
}
}
#endif
// A simple handle for registering the global fixtures to the master test suite
// without deleting an existing static object (the global fixture itself) when the program
// terminates (shared_ptr).
class global_fixture_handle : public test_unit_fixture {
public:
global_fixture_handle(test_unit_fixture* fixture) : m_global_fixture(fixture) {}
~global_fixture_handle() {}
virtual void setup() {
m_global_fixture->setup();
}
virtual void teardown() {
m_global_fixture->teardown();
}
private:
test_unit_fixture* m_global_fixture;
};
} // namespace impl
// ************************************************************************** //
// ************** framework::state ************** //
// ************************************************************************** //
unsigned const TIMEOUT_EXCEEDED = static_cast<unsigned>( -1 );
unsigned long int const TIMEOUT_EXCEEDED = static_cast<unsigned long int>( -1 );
class state {
public:
state()
: m_curr_test_case( INV_TEST_UNIT_ID )
: m_master_test_suite( 0 )
, m_curr_test_unit( INV_TEST_UNIT_ID )
, m_next_test_case_id( MIN_TEST_CASE_ID )
, m_next_test_suite_id( MIN_TEST_SUITE_ID )
, m_test_in_progress( false )
@@ -565,13 +612,27 @@ public:
tu_to_enable.pop_back();
// 35. Ignore test units which already enabled
// 35. Ignore test units which are already enabled
if( tu.is_enabled() )
continue;
// set new status and add all dependencies into tu_to_enable
set_run_status enabler( test_unit::RS_ENABLED, &tu_to_enable );
traverse_test_tree( tu.p_id, enabler, true );
// Add the dependencies of the parent suites, see trac #13149
test_unit_id parent_id = tu.p_parent_id;
while( parent_id != INV_TEST_UNIT_ID
&& parent_id != master_tu_id )
{
// we do not use the traverse_test_tree as otherwise it would enable the sibblings and subtree
// of the test case we want to enable (we need to enable the parent suites and their dependencies only)
// the parent_id needs to be enabled in order to be properly parsed by finalize_run_status, the visit
// does the job
test_unit& tu_parent = framework::get( parent_id, TUT_ANY );
enabler.visit( tu_parent );
parent_id = tu_parent.p_parent_id;
}
}
// 40. Apply all disablers
@@ -603,9 +664,9 @@ public:
}
};
// Executed the test tree with the root at specified test unit
// Executes the test tree with the root at specified test unit
execution_result execute_test_tree( test_unit_id tu_id,
unsigned timeout = 0,
unsigned long int timeout_microseconds = 0,
random_generator_helper const * const p_random_generator = 0)
{
test_unit const& tu = framework::get( tu_id, TUT_ANY );
@@ -617,15 +678,16 @@ public:
// 10. Check preconditions, including zero time left for execution and
// successful execution of all dependencies
if( timeout == TIMEOUT_EXCEEDED ) {
if( timeout_microseconds == TIMEOUT_EXCEEDED ) {
// notify all observers about skipped test unit
BOOST_TEST_FOREACH( test_observer*, to, m_observers )
to->test_unit_skipped( tu, "timeout for the test unit is exceeded" );
return unit_test_monitor_t::os_timeout;
}
else if( timeout == 0 || timeout > tu.p_timeout ) // deduce timeout for this test unit
timeout = tu.p_timeout;
else if( timeout_microseconds == 0 || (tu.p_timeout > 0 && timeout_microseconds > (tu.p_timeout * 1000000) ) ) // deduce timeout for this test unit
timeout_microseconds = tu.p_timeout * 1000000;
test_tools::assertion_result const precondition_res = tu.check_preconditions();
if( !precondition_res ) {
@@ -633,7 +695,10 @@ public:
BOOST_TEST_FOREACH( test_observer*, to, m_observers )
to->test_unit_skipped( tu, precondition_res.message() );
return unit_test_monitor_t::precondition_failure;
// It is not an error to skip the test if any of the parent tests
// have failed. This one should be reported as skipped as if it was
// disabled
return unit_test_monitor_t::test_ok;
}
// 20. Notify all observers about the start of the test unit
@@ -642,17 +707,27 @@ public:
// 30. Execute setup fixtures if any; any failure here leads to test unit abortion
BOOST_TEST_FOREACH( test_unit_fixture_ptr, F, tu.p_fixtures.get() ) {
ut_detail::test_unit_id_restore restore_current_test_unit(m_curr_test_unit, tu.p_id);
result = unit_test_monitor.execute_and_translate( boost::bind( &test_unit_fixture::setup, F ) );
if( result != unit_test_monitor_t::test_ok )
break;
test_results const& test_rslt = unit_test::results_collector.results( m_curr_test_unit );
if( test_rslt.aborted() ) {
result = unit_test_monitor_t::test_setup_failure;
break;
}
}
// This is the time we are going to spend executing the test unit
unsigned long elapsed = 0;
// This is the time we are going to spend executing the test unit (in microseconds
// as expected by test_observer::test_unit_finish)
unsigned long elapsed_microseconds = 0;
if( result == unit_test_monitor_t::test_ok ) {
// 40. We are going to time the execution
boost::timer tu_timer;
boost::unit_test::timer::timer tu_timer;
// we pass the random generator
const random_generator_helper& rand_gen = p_random_generator ? *p_random_generator : random_generator_helper();
if( tu.p_type == TUT_SUITE ) {
test_suite const& ts = static_cast<test_suite const&>( tu );
@@ -661,16 +736,33 @@ public:
typedef std::pair<counter_t,test_unit_id> value_type;
BOOST_TEST_FOREACH( value_type, chld, ts.m_ranked_children ) {
unsigned chld_timeout = child_timeout( timeout, tu_timer.elapsed() );
// tu_timer.elapsed() returns nanosec, timeout and child_timeout in microsec
unsigned long int chld_timeout = child_timeout(
timeout_microseconds,
static_cast<unsigned long int>( microsecond_wall_time(tu_timer.elapsed()) ));
result = (std::min)( result, execute_test_tree( chld.second, chld_timeout ) );
result = (std::min)( result, execute_test_tree( chld.second, chld_timeout, &rand_gen ) );
if( unit_test_monitor.is_critical_error( result ) )
break;
// we check for the time elapsed. If this is too high, we fail the current suite and return from here
elapsed_microseconds = static_cast<unsigned long int>( microsecond_wall_time(tu_timer.elapsed()) );
if( (timeout_microseconds > 0) && (elapsed_microseconds > timeout_microseconds) && (timeout_microseconds != TIMEOUT_EXCEEDED ) ) {
BOOST_TEST_FOREACH( test_observer*, to, m_observers ) {
to->test_unit_timed_out(tu);
}
result = (std::min)( result, unit_test_monitor_t::os_timeout );
timeout_microseconds = TIMEOUT_EXCEEDED;
//break;
// we continue to explore the children, such that we can at least update their
// status to skipped
}
}
}
else {
// Go through ranges of chldren with the same dependency rank and shuffle them
// Go through ranges of children with the same dependency rank and shuffle them
// independently. Execute each subtree in this order
test_unit_id_list children_with_the_same_rank;
@@ -686,22 +778,37 @@ public:
it++;
}
const random_generator_helper& rand_gen = p_random_generator ? *p_random_generator : random_generator_helper();
#ifdef BOOST_NO_CXX98_RANDOM_SHUFFLE
impl::random_shuffle( children_with_the_same_rank.begin(), children_with_the_same_rank.end(), rand_gen );
#else
std::random_shuffle( children_with_the_same_rank.begin(), children_with_the_same_rank.end(), rand_gen );
#endif
BOOST_TEST_FOREACH( test_unit_id, chld, children_with_the_same_rank ) {
unsigned chld_timeout = child_timeout( timeout, tu_timer.elapsed() );
unsigned long int chld_timeout = child_timeout(
timeout_microseconds,
static_cast<unsigned long int>(microsecond_wall_time(tu_timer.elapsed())) );
result = (std::min)( result, execute_test_tree( chld, chld_timeout, &rand_gen ) );
if( unit_test_monitor.is_critical_error( result ) )
break;
// we check for the time elapsed. If this is too high, we fail the current suite and return from here
elapsed_microseconds = static_cast<unsigned long int>( microsecond_wall_time(tu_timer.elapsed()) );
if( (timeout_microseconds > 0) && (elapsed_microseconds > timeout_microseconds) && (timeout_microseconds != TIMEOUT_EXCEEDED ) ) {
BOOST_TEST_FOREACH( test_observer*, to, m_observers ) {
to->test_unit_timed_out(tu);
}
result = (std::min)( result, unit_test_monitor_t::os_timeout );
timeout_microseconds = TIMEOUT_EXCEEDED;
//break;
// we continue to explore the children, such that we can at least update their
// status to skipped
}
}
}
}
elapsed = static_cast<unsigned long>( tu_timer.elapsed() * 1e6 );
}
else { // TUT_CASE
test_case const& tc = static_cast<test_case const&>( tu );
@@ -710,18 +817,16 @@ public:
m_context_idx = 0;
// setup current test case
test_unit_id bkup = m_curr_test_case;
m_curr_test_case = tc.p_id;
ut_detail::test_unit_id_restore restore_current_test_unit(m_curr_test_unit, tc.p_id);
// execute the test case body
result = unit_test_monitor.execute_and_translate( tc.p_test_func, timeout );
elapsed = static_cast<unsigned long>( tu_timer.elapsed() * 1e6 );
// execute the test case body, transforms the time out to seconds
result = unit_test_monitor.execute_and_translate( tc.p_test_func, timeout_microseconds );
elapsed_microseconds = static_cast<unsigned long int>( microsecond_wall_time(tu_timer.elapsed()) );
// cleanup leftover context
m_context.clear();
// restore state and abort if necessary
m_curr_test_case = bkup;
// restore state (scope exit) and abort if necessary
}
}
@@ -729,6 +834,7 @@ public:
if( !unit_test_monitor.is_critical_error( result ) ) {
// execute teardown fixtures if any in reverse order
BOOST_TEST_REVERSE_FOREACH( test_unit_fixture_ptr, F, tu.p_fixtures.get() ) {
ut_detail::test_unit_id_restore restore_current_test_unit(m_curr_test_unit, tu.p_id);
result = (std::min)( result, unit_test_monitor.execute_and_translate( boost::bind( &test_unit_fixture::teardown, F ), 0 ) );
if( unit_test_monitor.is_critical_error( result ) )
@@ -744,21 +850,21 @@ public:
// notify all observers about completion
BOOST_TEST_REVERSE_FOREACH( test_observer*, to, m_observers )
to->test_unit_finish( tu, elapsed );
to->test_unit_finish( tu, elapsed_microseconds );
return result;
}
//////////////////////////////////////////////////////////////////
unsigned child_timeout( unsigned tu_timeout, double elapsed )
unsigned long int child_timeout( unsigned long tu_timeout_microseconds, unsigned long elpsed_microsec )
{
if( tu_timeout == 0U )
return 0U;
if( tu_timeout_microseconds == 0UL || tu_timeout_microseconds == TIMEOUT_EXCEEDED)
return tu_timeout_microseconds;
unsigned elpsed_sec = static_cast<unsigned>(elapsed); // rounding to number of whole seconds
return tu_timeout > elpsed_sec ? tu_timeout - elpsed_sec : TIMEOUT_EXCEEDED;
return tu_timeout_microseconds > elpsed_microsec ?
tu_timeout_microseconds - elpsed_microsec
: TIMEOUT_EXCEEDED;
}
struct priority_order {
@@ -787,7 +893,7 @@ public:
master_test_suite_t* m_master_test_suite;
std::vector<test_suite*> m_auto_test_suites;
test_unit_id m_curr_test_case;
test_unit_id m_curr_test_unit;
test_unit_store m_test_units;
test_unit_id m_next_test_case_id;
@@ -799,6 +905,8 @@ public:
context_data m_context;
int m_context_idx;
std::set<global_fixture*> m_global_fixtures;
boost::execution_monitor m_aux_em;
std::map<output_format, runtime_config::stream_holder> m_log_sinks;
@@ -838,6 +946,30 @@ struct sum_to_first_only {
bool is_first;
};
void
shutdown_loggers_and_reports()
{
s_frk_state().m_log_sinks.clear();
s_frk_state().m_report_sink.setup( "stderr" );
}
void
unregister_global_fixture_and_configuration()
{
// we make a copy as the set will change in the iteration
std::set<global_fixture*> gfixture_copy(s_frk_state().m_global_fixtures);
BOOST_TEST_FOREACH( global_fixture*, tuf, gfixture_copy ) {
tuf->unregister_from_framework();
}
s_frk_state().m_global_fixtures.clear();
state::observer_store gobserver_copy(s_frk_state().m_observers);
BOOST_TEST_FOREACH( test_observer*, to, gobserver_copy ) {
framework::deregister_observer( *to );
}
s_frk_state().m_observers.clear();
}
void
setup_loggers()
{
@@ -857,8 +989,15 @@ setup_loggers()
unit_test_log.set_format( format );
runtime_config::stream_holder& stream_logger = s_frk_state().m_log_sinks[format];
if( runtime_config::has( runtime_config::btrt_log_sink ) )
stream_logger.setup( runtime_config::get<std::string>( runtime_config::btrt_log_sink ) );
if( runtime_config::has( runtime_config::btrt_log_sink ) ) {
// we remove all streams in this case, so we do not specify the format
boost::function< void () > log_cleaner = boost::bind( &unit_test_log_t::set_stream,
&unit_test_log,
boost::ref(std::cout)
);
stream_logger.setup( runtime_config::get<std::string>( runtime_config::btrt_log_sink ),
log_cleaner );
}
unit_test_log.set_stream( stream_logger.ref() );
}
else
@@ -970,7 +1109,6 @@ setup_loggers()
}
}
BOOST_TEST_I_ASSRT( formatter_log_level != invalid_log_level,
boost::runtime::access_to_missing_argument()
<< "Unable to determine the log level from '"
@@ -985,12 +1123,18 @@ setup_loggers()
unit_test_log.set_threshold_level( format, formatter_log_level );
runtime_config::stream_holder& stream_logger = s_frk_state().m_log_sinks[format];
boost::function< void () > log_cleaner = boost::bind( &unit_test_log_t::set_stream,
&unit_test_log,
format,
boost::ref(std::cout) );
if( ++current_format_specs != utils::string_token_iterator() &&
current_format_specs->size() ) {
stream_logger.setup( *current_format_specs );
stream_logger.setup( *current_format_specs,
log_cleaner );
}
else {
stream_logger.setup( formatter->get_default_stream_description() );
stream_logger.setup( formatter->get_default_stream_description(),
log_cleaner );
}
unit_test_log.set_stream( format, stream_logger.ref() );
}
@@ -1036,13 +1180,20 @@ init( init_unit_test_func init_func, int argc, char* argv[] )
results_reporter::set_level( runtime_config::get<report_level>( runtime_config::btrt_report_level ) );
results_reporter::set_format( runtime_config::get<output_format>( runtime_config::btrt_report_format ) );
if( runtime_config::has( runtime_config::btrt_report_sink ) )
s_frk_state().m_report_sink.setup( runtime_config::get<std::string>( runtime_config::btrt_report_sink ) );
if( runtime_config::has( runtime_config::btrt_report_sink ) ) {
boost::function< void () > report_cleaner = boost::bind( &results_reporter::set_stream,
boost::ref(std::cerr)
);
s_frk_state().m_report_sink.setup( runtime_config::get<std::string>( runtime_config::btrt_report_sink ),
report_cleaner );
}
results_reporter::set_stream( s_frk_state().m_report_sink.ref() );
// 40. Register default test observers
register_observer( results_collector );
register_observer( unit_test_log );
register_observer( framework_init_observer );
if( runtime_config::get<bool>( runtime_config::btrt_show_progress ) ) {
progress_monitor.set_stream( std::cout ); // defaults to stdout
@@ -1078,9 +1229,18 @@ finalize_setup_phase( test_unit_id master_tu_id )
master_tu_id = master_test_suite().p_id;
// 10. Apply all decorators to the auto test units
// 10. checks for consistency (duplicate names, etc)
class apply_decorators : public test_tree_visitor {
private:
// test_tree_visitor interface
virtual bool test_suite_start( test_suite const& ts)
{
const_cast<test_suite&>(ts).generate();
const_cast<test_suite&>(ts).check_for_duplicate_test_cases();
return test_tree_visitor::test_suite_start(ts);
}
virtual bool visit( test_unit const& tu )
{
BOOST_TEST_FOREACH( decorator::base_ptr, d, tu.p_decorators.get() )
@@ -1116,6 +1276,13 @@ test_in_progress()
void
shutdown()
{
// shuts down the loggers singleton to avoid any further reference to the
// framework during the destruction of those
impl::shutdown_loggers_and_reports();
// unregisters any global fixture and configuration object
impl::unregister_global_fixture_and_configuration();
// eliminating some fake memory leak reports. See for more details:
// http://connect.microsoft.com/VisualStudio/feedback/details/106937/memory-leaks-reported-by-debug-crt-inside-typeinfo-name
@@ -1235,6 +1402,30 @@ deregister_observer( test_observer& to )
//____________________________________________________________________________//
// ************************************************************************** //
// ************** register_global_fixture ************** //
// ************************************************************************** //
void
register_global_fixture( global_fixture& tuf )
{
impl::s_frk_state().m_global_fixtures.insert( &tuf );
}
//____________________________________________________________________________//
// ************************************************************************** //
// ************** deregister_global_fixture ************** //
// ************************************************************************** //
void
deregister_global_fixture( global_fixture &tuf )
{
impl::s_frk_state().m_global_fixtures.erase( &tuf );
}
//____________________________________________________________________________//
// ************************************************************************** //
// ************** add_context ************** //
// ************************************************************************** //
@@ -1363,7 +1554,14 @@ current_auto_test_suite( test_suite* ts, bool push_or_pop )
test_case const&
current_test_case()
{
return get<test_case>( impl::s_frk_state().m_curr_test_case );
return get<test_case>( impl::s_frk_state().m_curr_test_unit );
}
test_unit const&
current_test_unit()
{
return *impl::s_frk_state().m_test_units[impl::s_frk_state().m_curr_test_unit];
}
//____________________________________________________________________________//
@@ -1371,7 +1569,7 @@ current_test_case()
test_unit_id
current_test_case_id()
{
return impl::s_frk_state().m_curr_test_case;
return impl::s_frk_state().m_curr_test_unit;
}
//____________________________________________________________________________//
@@ -1396,6 +1594,17 @@ get( test_unit_id id, test_unit_type t )
// ************** framework::run ************** //
// ************************************************************************** //
template <class Cont>
struct swap_on_delete {
swap_on_delete(Cont& c1, Cont& c2) : m_c1(c1), m_c2(c2){}
~swap_on_delete() {
m_c1.swap(m_c2);
}
Cont& m_c1;
Cont& m_c2;
};
void
run( test_unit_id id, bool continue_test )
{
@@ -1414,39 +1623,93 @@ run( test_unit_id id, bool continue_test )
bool was_in_progress = framework::test_in_progress();
bool call_start_finish = !continue_test || !was_in_progress;
impl::s_frk_state().m_test_in_progress = true;
bool init_ok = true;
const_string setup_error;
if( call_start_finish ) {
// indicates the framework that no test is in progress now if observers need to be notified
impl::s_frk_state().m_test_in_progress = false;
// unit_test::framework_init_observer will get cleared first
BOOST_TEST_FOREACH( test_observer*, to, impl::s_frk_state().m_observers ) {
BOOST_TEST_I_TRY {
impl::s_frk_state().m_aux_em.vexecute( boost::bind( &test_observer::test_start, to, tcc.p_count ) );
ut_detail::test_unit_id_restore restore_current_test_unit(impl::s_frk_state().m_curr_test_unit, id);
unit_test_monitor_t::error_level result = unit_test_monitor.execute_and_translate( boost::bind( &test_observer::test_start, to, tcc.p_count ) );
if( init_ok ) {
if( result != unit_test_monitor_t::test_ok ) {
init_ok = false;
}
else {
if( unit_test::framework_init_observer.has_failed() ) {
init_ok = false;
}
}
}
}
BOOST_TEST_I_CATCH( execution_exception, ex ) {
BOOST_TEST_SETUP_ASSERT( false, ex.what() );
if( init_ok ) {
// log only the first error
init_ok = false;
setup_error = ex.what();
}
// break; // we should continue otherwise loggers may have improper structure (XML start missing for instance)
}
}
}
unsigned seed = runtime_config::get<unsigned>( runtime_config::btrt_random_seed );
switch( seed ) {
case 0:
break;
case 1:
seed = static_cast<unsigned>( std::rand() ^ std::time( 0 ) ); // better init using std::rand() ^ ...
default:
BOOST_TEST_FRAMEWORK_MESSAGE( "Test cases order is shuffled using seed: " << seed );
std::srand( seed );
if( init_ok ) {
// attaching the global fixtures to the main entry point
test_unit& entry_test_unit = framework::get( id, TUT_ANY );
std::vector<test_unit_fixture_ptr> v_saved_fixture(entry_test_unit.p_fixtures.value.begin(),
entry_test_unit.p_fixtures.value.end());
BOOST_TEST_FOREACH( test_unit_fixture*, tuf, impl::s_frk_state().m_global_fixtures ) {
entry_test_unit.p_fixtures.value.insert( entry_test_unit.p_fixtures.value.begin(),
test_unit_fixture_ptr(new impl::global_fixture_handle(tuf)) );
}
swap_on_delete< std::vector<test_unit_fixture_ptr> > raii_fixture(v_saved_fixture, entry_test_unit.p_fixtures.value);
// now work in progress
impl::s_frk_state().m_test_in_progress = true;
unsigned seed = runtime_config::get<unsigned>( runtime_config::btrt_random_seed );
switch( seed ) {
case 0:
break;
case 1:
seed = static_cast<unsigned>( std::rand() ^ std::time( 0 ) ); // better init using std::rand() ^ ...
BOOST_FALLTHROUGH;
default:
BOOST_TEST_FRAMEWORK_MESSAGE( "Test cases order is shuffled using seed: " << seed );
std::srand( seed );
}
// executing the test tree
impl::s_frk_state().execute_test_tree( id );
// removing previously added global fixtures: dtor raii_fixture
}
impl::s_frk_state().execute_test_tree( id );
impl::s_frk_state().m_test_in_progress = false;
results_reporter::make_report( INV_REPORT_LEVEL, id );
unit_test::framework_init_observer.clear();
if( call_start_finish ) {
BOOST_TEST_REVERSE_FOREACH( test_observer*, to, impl::s_frk_state().m_observers )
// indicates the framework that no test is in progress anymore if observers need to be notified
// and this is a teardown, so assertions should not raise any exception otherwise an exception
// might be raised in a dtor of a global fixture
impl::s_frk_state().m_test_in_progress = false;
BOOST_TEST_REVERSE_FOREACH( test_observer*, to, impl::s_frk_state().m_observers ) {
ut_detail::test_unit_id_restore restore_current_test_unit(impl::s_frk_state().m_curr_test_unit, id);
to->test_finish();
}
}
impl::s_frk_state().m_test_in_progress = was_in_progress;
// propagates the init/teardown error if any
BOOST_TEST_SETUP_ASSERT( init_ok && !unit_test::framework_init_observer.has_failed(), setup_error );
}
//____________________________________________________________________________//
@@ -1496,6 +1759,18 @@ test_unit_aborted( test_unit const& tu )
to->test_unit_aborted( tu );
}
// ************************************************************************** //
// ************** test_aborted ************** //
// ************************************************************************** //
void
test_aborted( )
{
BOOST_TEST_FOREACH( test_observer*, to, impl::s_frk_state().m_observers )
to->test_aborted( );
}
//____________________________________________________________________________//
} // namespace framework

View File

@@ -35,6 +35,7 @@
// Boost
#include <boost/version.hpp>
#include <boost/core/ignore_unused.hpp>
// STL
#include <iostream>
@@ -69,6 +70,12 @@ inline std::string tu_name_normalize(std::string full_name)
return full_name;
}
inline std::string tu_name_remove_newlines(std::string full_name)
{
full_name.erase(std::remove(full_name.begin(), full_name.end(), '\n'), full_name.end());
return full_name;
}
const_string file_basename(const_string filename) {
const_string path_sep( "\\/" );
@@ -86,7 +93,7 @@ const_string file_basename(const_string filename) {
// ************************************************************************** //
void
junit_log_formatter::log_start( std::ostream& ostr, counter_t test_cases_amount)
junit_log_formatter::log_start( std::ostream& /*ostr*/, counter_t /*test_cases_amount*/)
{
map_tests.clear();
list_path_to_root.clear();
@@ -96,6 +103,11 @@ junit_log_formatter::log_start( std::ostream& ostr, counter_t test_cases_amount)
//____________________________________________________________________________//
class junit_result_helper : public test_tree_visitor {
private:
typedef junit_impl::junit_log_helper::assertion_entry assertion_entry;
typedef std::vector< assertion_entry >::const_iterator vect_assertion_entry_citerator;
typedef std::list<std::string>::const_iterator list_str_citerator;
public:
explicit junit_result_helper(
std::ostream& stream,
@@ -111,10 +123,19 @@ public:
, m_display_build_info(display_build_info)
{ }
void add_log_entry(std::string const& entry_type,
test_case const& tc,
junit_impl::junit_log_helper::assertion_entry const& log) const
void add_log_entry(assertion_entry const& log) const
{
std::string entry_type;
if( log.log_entry == assertion_entry::log_entry_failure ) {
entry_type = "failure";
}
else if( log.log_entry == assertion_entry::log_entry_error ) {
entry_type = "error";
}
else {
return;
}
m_stream
<< "<" << entry_type
<< " message" << utils::attr_value() << log.logentry_message
@@ -159,24 +180,24 @@ public:
}
};
std::list<std::string> build_skipping_chain(test_case const & tc) const
std::list<std::string> build_skipping_chain(test_unit const & tu) const
{
// we enter here because we know that the tc has been skipped.
// either junit has not seen this tc, or it is indicated as disabled
assert(m_map_test.count(tc.p_id) == 0 || results_collector.results( tc.p_id ).p_skipped);
// we enter here because we know that the tu has been skipped.
// either junit has not seen this tu, or it is indicated as disabled
assert(m_map_test.count(tu.p_id) == 0 || results_collector.results( tu.p_id ).p_skipped);
std::list<std::string> out;
test_unit_id id(tc.p_id);
test_unit_id id(tu.p_id);
while( id != m_ts.p_id && id != INV_TEST_UNIT_ID) {
test_unit const& tu = boost::unit_test::framework::get( id, TUT_ANY );
out.push_back("- disabled test unit: '" + tu.full_name() + "'\n");
test_unit const& tu_hierarchy = boost::unit_test::framework::get( id, TUT_ANY );
out.push_back("- disabled test unit: '" + tu_name_remove_newlines(tu_hierarchy.full_name()) + "'\n");
if(m_map_test.count(id) > 0)
{
// junit has seen the reason: this is enough for constructing the chain
break;
}
id = tu.p_parent_id;
id = tu_hierarchy.p_parent_id;
}
junit_log_formatter::map_trace_t::const_iterator it_element_stack(m_map_test.find(id));
if( it_element_stack != m_map_test.end() )
@@ -188,9 +209,9 @@ public:
return out;
}
std::string get_class_name(test_case const & tc) const {
std::string get_class_name(test_unit const & tu_class) const {
std::string classname;
test_unit_id id(tc.p_parent_id);
test_unit_id id(tu_class.p_parent_id);
while( id != m_ts.p_id && id != INV_TEST_UNIT_ID ) {
test_unit const& tu = boost::unit_test::framework::get( id, TUT_ANY );
classname = tu_name_normalize(tu.p_name) + "." + classname;
@@ -205,39 +226,50 @@ public:
return classname;
}
void write_testcase_header(test_case const & tc,
test_results const *tr = 0) const
void write_testcase_header(test_unit const & tu,
test_results const *tr,
int nb_assertions) const
{
//
// test case header
std::string name;
std::string classname;
// total number of assertions
m_stream << "<testcase assertions" << utils::attr_value() << tr->p_assertions_passed + tr->p_assertions_failed;
if(tu.p_id == m_ts.p_id ) {
name = "boost_test";
}
else {
classname = get_class_name(tu);
name = tu_name_normalize(tu.p_name);
}
// class name
const std::string classname = get_class_name(tc);
if( tu.p_type == TUT_SUITE ) {
if(tr->p_timed_out)
name += "-timed-execution";
else
name += "-setup-teardown";
}
m_stream << "<testcase assertions" << utils::attr_value() << nb_assertions;
if(!classname.empty())
m_stream << " classname" << utils::attr_value() << classname;
// test case name and time taken
m_stream
<< " name" << utils::attr_value() << tu_name_normalize(tc.p_name)
<< " name" << utils::attr_value() << name
<< " time" << utils::attr_value() << double(tr->p_duration_microseconds) * 1E-6
<< ">" << std::endl;
}
void write_testcase_system_out(junit_impl::junit_log_helper const &detailed_log,
test_case const * tc,
bool skipped,
test_results const *tr = 0) const
test_unit const * tu,
bool skipped) const
{
// system-out + all info/messages, the object skips the empty entries
conditional_cdata_helper system_out_helper(m_stream, "system-out");
// indicate why the test has been skipped first
if( skipped ) {
std::list<std::string> skipping_decision_chain = build_skipping_chain(*tc);
for(std::list<std::string>::const_iterator it(skipping_decision_chain.begin()), ite(skipping_decision_chain.end());
std::list<std::string> skipping_decision_chain = build_skipping_chain(*tu);
for(list_str_citerator it(skipping_decision_chain.begin()), ite(skipping_decision_chain.end());
it != ite;
++it)
{
@@ -246,7 +278,7 @@ public:
}
// stdout
for(std::list<std::string>::const_iterator it(detailed_log.system_out.begin()), ite(detailed_log.system_out.end());
for(list_str_citerator it(detailed_log.system_out.begin()), ite(detailed_log.system_out.end());
it != ite;
++it)
{
@@ -254,25 +286,24 @@ public:
}
// warning/info message last
for(std::vector< junit_impl::junit_log_helper::assertion_entry >::const_iterator it(detailed_log.assertion_entries.begin());
for(vect_assertion_entry_citerator it(detailed_log.assertion_entries.begin());
it != detailed_log.assertion_entries.end();
++it)
{
if(it->log_entry != junit_impl::junit_log_helper::assertion_entry::log_entry_info)
if(it->log_entry != assertion_entry::log_entry_info)
continue;
system_out_helper(it->output);
}
}
void write_testcase_system_err(junit_impl::junit_log_helper const &detailed_log,
test_case const * tc,
test_results const *tr = 0) const
test_unit const * tu,
test_results const *tr) const
{
// system-err output + test case informations
bool has_failed = (tr != 0) ? !tr->passed() : false;
bool has_failed = (tr != 0) ? !tr->p_skipped && !tr->passed() : false;
if(!detailed_log.system_err.empty() || has_failed)
{
conditional_cdata_helper system_err_helper(m_stream, "system-err");
std::ostringstream o;
if(has_failed) {
o << "Failures detected in:" << std::endl;
@@ -281,58 +312,89 @@ public:
o << "ERROR STREAM:" << std::endl;
}
o << "- test case: " << tc->full_name() << std::endl;
if(!tc->p_description.value.empty())
o << " '" << tc->p_description << "'";
if(tu->p_type == TUT_SUITE) {
if( tu->p_id == m_ts.p_id ) {
o << " boost.test global setup/teardown" << std::endl;
} else {
o << "- test suite: " << tu_name_remove_newlines(tu->full_name()) << std::endl;
}
}
else {
o << "- test case: " << tu_name_remove_newlines(tu->full_name());
if(!tu->p_description.value.empty())
o << " '" << tu->p_description << "'";
o << std::endl
<< "- file: " << file_basename(tc->p_file_name) << std::endl
<< "- line: " << tc->p_line_num << std::endl
;
o << std::endl
<< "- file: " << file_basename(tu->p_file_name) << std::endl
<< "- line: " << tu->p_line_num << std::endl
;
}
if(!detailed_log.system_err.empty())
o << std::endl << "STDERR BEGIN: ------------" << std::endl;
system_err_helper(o.str());
for(std::list<std::string>::const_iterator it(detailed_log.system_err.begin()), ite(detailed_log.system_err.end());
for(list_str_citerator it(detailed_log.system_err.begin()), ite(detailed_log.system_err.end());
it != ite;
++it)
{
system_err_helper(*it);
o << *it;
}
if(!detailed_log.system_err.empty())
o << std::endl << "STDERR END ------------" << std::endl;
conditional_cdata_helper system_err_helper(m_stream, "system-err");
system_err_helper(o.str());
}
}
int get_nb_assertions(junit_impl::junit_log_helper const &detailed_log,
test_unit const & tu,
test_results const *tr) const {
int nb_assertions(-1);
if( tu.p_type == TUT_SUITE ) {
nb_assertions = 0;
for(vect_assertion_entry_citerator it(detailed_log.assertion_entries.begin());
it != detailed_log.assertion_entries.end();
++it)
{
if(it->log_entry != assertion_entry::log_entry_info)
nb_assertions++;
}
}
else {
nb_assertions = static_cast<int>(tr->p_assertions_passed + tr->p_assertions_failed);
}
return nb_assertions;
}
void output_detailed_logs(junit_impl::junit_log_helper const &detailed_log,
test_case const & tc,
test_unit const & tu,
bool skipped,
test_results const *tr = 0) const
test_results const *tr) const
{
write_testcase_header(tc, tr);
int nb_assertions = get_nb_assertions(detailed_log, tu, tr);
if(!nb_assertions && tu.p_type == TUT_SUITE)
return;
write_testcase_header(tu, tr, nb_assertions);
if( skipped ) {
m_stream << "<skipped/>" << std::endl;
}
else {
for(std::vector< junit_impl::junit_log_helper::assertion_entry >::const_iterator it(detailed_log.assertion_entries.begin());
for(vect_assertion_entry_citerator it(detailed_log.assertion_entries.begin());
it != detailed_log.assertion_entries.end();
++it)
{
if(it->log_entry == junit_impl::junit_log_helper::assertion_entry::log_entry_failure) {
add_log_entry("failure", tc, *it);
}
else if(it->log_entry == junit_impl::junit_log_helper::assertion_entry::log_entry_error) {
add_log_entry("error", tc, *it);
}
add_log_entry(*it);
}
}
write_testcase_system_out(detailed_log, &tc, skipped, tr);
write_testcase_system_err(detailed_log, &tc, tr);
write_testcase_system_out(detailed_log, &tu, skipped);
write_testcase_system_err(detailed_log, &tu, tr);
m_stream << "</testcase>" << std::endl;
}
@@ -353,35 +415,58 @@ public:
bool test_suite_start( test_suite const& ts )
{
// unique test suite, without s, nesting not supported in CI
if( m_ts.p_id != ts.p_id )
return true;
test_results const& tr = results_collector.results( ts.p_id );
m_stream << "<testsuite";
m_stream
// << "disabled=\"" << tr.p_test_cases_skipped << "\" "
<< " tests" << utils::attr_value() << tr.p_test_cases_passed
<< " skipped" << utils::attr_value() << tr.p_test_cases_skipped
<< " errors" << utils::attr_value() << tr.p_test_cases_aborted
<< " failures" << utils::attr_value() << tr.p_test_cases_failed
<< " id" << utils::attr_value() << m_id++
<< " name" << utils::attr_value() << tu_name_normalize(ts.p_name)
<< " time" << utils::attr_value() << (tr.p_duration_microseconds * 1E-6)
<< ">" << std::endl;
// unique test suite, without s, nesting not supported in CI
if( m_ts.p_id == ts.p_id ) {
m_stream << "<testsuite";
if(m_display_build_info)
{
m_stream << "<properties>" << std::endl;
m_stream << "<property name=\"platform\" value" << utils::attr_value() << BOOST_PLATFORM << std::endl;
m_stream << "<property name=\"compiler\" value" << utils::attr_value() << BOOST_COMPILER << std::endl;
m_stream << "<property name=\"stl\" value" << utils::attr_value() << BOOST_STDLIB << std::endl;
// think about: maybe we should add the number of fixtures of a test_suite as
// independant tests (field p_fixtures).
// same goes for the timed-execution: we can think of that as a separate test-unit
// in the suite.
// see https://llg.cubic.org/docs/junit/ and
// http://svn.apache.org/viewvc/ant/core/trunk/src/main/org/apache/tools/ant/taskdefs/optional/junit/XMLJUnitResultFormatter.java?view=markup
m_stream
// << "disabled=\"" << tr.p_test_cases_skipped << "\" "
<< " tests" << utils::attr_value()
<< tr.p_test_cases_passed
+ tr.p_test_cases_failed
// + tr.p_test_cases_aborted // aborted is also failed, we avoid counting it twice
<< " skipped" << utils::attr_value() << tr.p_test_cases_skipped
<< " errors" << utils::attr_value() << tr.p_test_cases_aborted
<< " failures" << utils::attr_value()
<< tr.p_test_cases_failed
+ tr.p_test_suites_timed_out
+ tr.p_test_cases_timed_out
- tr.p_test_cases_aborted // failed is not aborted in the Junit sense
<< " id" << utils::attr_value() << m_id++
<< " name" << utils::attr_value() << tu_name_normalize(ts.p_name)
<< " time" << utils::attr_value() << (tr.p_duration_microseconds * 1E-6)
<< ">" << std::endl;
std::ostringstream o;
o << BOOST_VERSION/100000 << "." << BOOST_VERSION/100 % 1000 << "." << BOOST_VERSION % 100;
m_stream << "<property name=\"boost\" value" << utils::attr_value() << o.str() << std::endl;
m_stream << "</properties>" << std::endl;
if(m_display_build_info)
{
m_stream << "<properties>" << std::endl;
m_stream << "<property name=\"platform\" value" << utils::attr_value() << BOOST_PLATFORM << " />" << std::endl;
m_stream << "<property name=\"compiler\" value" << utils::attr_value() << BOOST_COMPILER << " />" << std::endl;
m_stream << "<property name=\"stl\" value" << utils::attr_value() << BOOST_STDLIB << " />" << std::endl;
std::ostringstream o;
o << BOOST_VERSION/100000 << "." << BOOST_VERSION/100 % 1000 << "." << BOOST_VERSION % 100;
m_stream << "<property name=\"boost\" value" << utils::attr_value() << o.str() << " />" << std::endl;
m_stream << "</properties>" << std::endl;
}
}
if( !tr.p_skipped ) {
// if we land here, then this is a chance that we are logging the fixture setup/teardown of a test-suite.
// the setup/teardown logging of a test-case is part of the test case.
// we do not care about the test-suite that were skipped (really??)
junit_log_formatter::map_trace_t::const_iterator it_find = m_map_test.find(ts.p_id);
if(it_find != m_map_test.end()) {
output_detailed_logs(it_find->second, ts, false, &tr);
}
}
return true; // indicates that the children should also be parsed
@@ -389,13 +474,13 @@ public:
virtual void test_suite_finish( test_suite const& ts )
{
if( m_ts.p_id != ts.p_id )
if( m_ts.p_id == ts.p_id ) {
write_testcase_system_out(runner_log, 0, false);
write_testcase_system_err(runner_log, 0, 0);
m_stream << "</testsuite>";
return;
write_testcase_system_out(runner_log, 0, false, 0);
write_testcase_system_err(runner_log, 0, 0);
m_stream << "</testsuite>";
}
}
private:
@@ -439,15 +524,15 @@ junit_log_formatter::log_finish( std::ostream& ostr )
//____________________________________________________________________________//
void
junit_log_formatter::log_build_info( std::ostream& ostr )
junit_log_formatter::log_build_info( std::ostream& /*ostr*/, bool log_build_info )
{
m_display_build_info = true;
m_display_build_info = log_build_info;
}
//____________________________________________________________________________//
void
junit_log_formatter::test_unit_start( std::ostream& ostr, test_unit const& tu )
junit_log_formatter::test_unit_start( std::ostream& /*ostr*/, test_unit const& tu )
{
list_path_to_root.push_back( tu.p_id );
map_tests.insert(std::make_pair(tu.p_id, junit_impl::junit_log_helper())); // current_test_case_id not working here
@@ -457,17 +542,20 @@ junit_log_formatter::test_unit_start( std::ostream& ostr, test_unit const& tu )
//____________________________________________________________________________//
void
junit_log_formatter::test_unit_finish( std::ostream& ostr, test_unit const& tu, unsigned long elapsed )
junit_log_formatter::test_unit_finish( std::ostream& /*ostr*/, test_unit const& tu, unsigned long /*elapsed*/ )
{
// the time is already stored in the result_reporter
boost::ignore_unused( tu );
assert( tu.p_id == list_path_to_root.back() );
list_path_to_root.pop_back();
}
void
junit_log_formatter::test_unit_aborted( std::ostream& os, test_unit const& tu )
junit_log_formatter::test_unit_aborted( std::ostream& /*ostr*/, test_unit const& tu )
{
boost::ignore_unused( tu );
assert( tu.p_id == list_path_to_root.back() );
//list_path_to_root.pop_back();
}
@@ -475,7 +563,26 @@ junit_log_formatter::test_unit_aborted( std::ostream& os, test_unit const& tu )
//____________________________________________________________________________//
void
junit_log_formatter::test_unit_skipped( std::ostream& ostr, test_unit const& tu, const_string reason )
junit_log_formatter::test_unit_timed_out( std::ostream& /*os*/, test_unit const& tu)
{
if(tu.p_type == TUT_SUITE)
{
// if we reach this call, it means that the test has already started and
// test_unit_start has already been called on the tu.
junit_impl::junit_log_helper& last_entry = get_current_log_entry();
junit_impl::junit_log_helper::assertion_entry entry;
entry.logentry_message = "test-suite time out";
entry.logentry_type = "execution timeout";
entry.log_entry = junit_impl::junit_log_helper::assertion_entry::log_entry_error;
entry.output = "the current suite exceeded the allocated execution time";
last_entry.assertion_entries.push_back(entry);
}
}
//____________________________________________________________________________//
void
junit_log_formatter::test_unit_skipped( std::ostream& /*ostr*/, test_unit const& tu, const_string reason )
{
// if a test unit is skipped, then the start of this TU has not been called yet.
// we cannot use get_current_log_entry here, but the TU id should appear in the map.
@@ -487,7 +594,7 @@ junit_log_formatter::test_unit_skipped( std::ostream& ostr, test_unit const& tu,
//____________________________________________________________________________//
void
junit_log_formatter::log_exception_start( std::ostream& ostr, log_checkpoint_data const& checkpoint_data, execution_exception const& ex )
junit_log_formatter::log_exception_start( std::ostream& /*ostr*/, log_checkpoint_data const& checkpoint_data, execution_exception const& ex )
{
std::ostringstream o;
execution_exception::location const& loc = ex.where();
@@ -555,7 +662,7 @@ junit_log_formatter::log_exception_start( std::ostream& ostr, log_checkpoint_dat
//____________________________________________________________________________//
void
junit_log_formatter::log_exception_finish( std::ostream& ostr )
junit_log_formatter::log_exception_finish( std::ostream& /*ostr*/ )
{
// sealing the last entry
assert(!get_current_log_entry().assertion_entries.back().sealed);
@@ -565,7 +672,7 @@ junit_log_formatter::log_exception_finish( std::ostream& ostr )
//____________________________________________________________________________//
void
junit_log_formatter::log_entry_start( std::ostream& ostr, log_entry_data const& entry_data, log_entry_types let )
junit_log_formatter::log_entry_start( std::ostream& /*ostr*/, log_entry_data const& entry_data, log_entry_types let )
{
junit_impl::junit_log_helper& last_entry = get_current_log_entry();
last_entry.skipping = false;
@@ -578,7 +685,7 @@ junit_log_formatter::log_entry_start( std::ostream& ostr, log_entry_data const&
last_entry.skipping = true;
break;
}
// no break on purpose
BOOST_FALLTHROUGH;
}
case unit_test_log_formatter::BOOST_UTL_ET_MESSAGE:
{
@@ -586,7 +693,7 @@ junit_log_formatter::log_entry_start( std::ostream& ostr, log_entry_data const&
last_entry.skipping = true;
break;
}
// no break on purpose
BOOST_FALLTHROUGH;
}
case unit_test_log_formatter::BOOST_UTL_ET_WARNING:
{
@@ -638,7 +745,7 @@ junit_log_formatter::log_entry_start( std::ostream& ostr, log_entry_data const&
//____________________________________________________________________________//
void
junit_log_formatter::log_entry_value( std::ostream& ostr, const_string value )
junit_log_formatter::log_entry_value( std::ostream& /*ostr*/, const_string value )
{
junit_impl::junit_log_helper& last_entry = get_current_log_entry();
if(last_entry.skipping)
@@ -662,7 +769,7 @@ junit_log_formatter::log_entry_value( std::ostream& ostr, const_string value )
//____________________________________________________________________________//
void
junit_log_formatter::log_entry_finish( std::ostream& ostr )
junit_log_formatter::log_entry_finish( std::ostream& /*ostr*/ )
{
junit_impl::junit_log_helper& last_entry = get_current_log_entry();
if(!last_entry.skipping)
@@ -685,7 +792,7 @@ junit_log_formatter::log_entry_finish( std::ostream& ostr )
//____________________________________________________________________________//
void
junit_log_formatter::entry_context_start( std::ostream& ostr, log_level )
junit_log_formatter::entry_context_start( std::ostream& /*ostr*/, log_level )
{
junit_impl::junit_log_helper& last_entry = get_current_log_entry();
if(last_entry.skipping)
@@ -708,7 +815,7 @@ junit_log_formatter::entry_context_start( std::ostream& ostr, log_level )
//____________________________________________________________________________//
void
junit_log_formatter::entry_context_finish( std::ostream& ostr )
junit_log_formatter::entry_context_finish( std::ostream& /*ostr*/, log_level )
{
// no op, may be removed
junit_impl::junit_log_helper& last_entry = get_current_log_entry();
@@ -720,7 +827,7 @@ junit_log_formatter::entry_context_finish( std::ostream& ostr )
//____________________________________________________________________________//
void
junit_log_formatter::log_entry_context( std::ostream& ostr, const_string context_descr )
junit_log_formatter::log_entry_context( std::ostream& /*ostr*/, log_level , const_string context_descr )
{
junit_impl::junit_log_helper& last_entry = get_current_log_entry();
if(last_entry.skipping)

View File

@@ -108,6 +108,8 @@ plain_report_formatter::test_unit_report_start( test_unit const& tu, std::ostrea
descr = "has passed";
else if( tr.p_skipped )
descr = "was skipped";
else if( tr.p_timed_out )
descr = "has timed out";
else if( tr.p_aborted )
descr = "was aborted";
else
@@ -122,8 +124,9 @@ plain_report_formatter::test_unit_report_start( test_unit const& tu, std::ostrea
return;
}
// aborted test case within failed ones, timed-out TC exclusive with failed/aborted
counter_t total_assertions = tr.p_assertions_passed + tr.p_assertions_failed;
counter_t total_tc = tr.p_test_cases_passed + tr.p_test_cases_warned + tr.p_test_cases_failed + tr.p_test_cases_skipped;
counter_t total_tc = tr.p_test_cases_passed + tr.p_test_cases_warned + tr.p_test_cases_failed + tr.p_test_cases_skipped + tr.p_test_cases_timed_out;
if( total_assertions > 0 || total_tc > 0 || tr.p_warnings_failed > 0)
ostr << " with:";
@@ -134,6 +137,8 @@ plain_report_formatter::test_unit_report_start( test_unit const& tu, std::ostrea
print_stat_value( ostr, tr.p_test_cases_passed , m_indent, total_tc , "test case", "passed" );
print_stat_value( ostr, tr.p_test_cases_warned , m_indent, total_tc , "test case", "passed with warnings" );
print_stat_value( ostr, tr.p_test_cases_failed , m_indent, total_tc , "test case", "failed" );
print_stat_value( ostr, tr.p_test_cases_timed_out, m_indent, total_tc , "test case", "timed-out" );
print_stat_value( ostr, tr.p_test_suites_timed_out, m_indent, tr.p_test_suites, "test suite", "timed-out" );
print_stat_value( ostr, tr.p_test_cases_skipped, m_indent, total_tc , "test case", "skipped" );
print_stat_value( ostr, tr.p_test_cases_aborted, m_indent, total_tc , "test case", "aborted" );
print_stat_value( ostr, tr.p_assertions_passed , m_indent, total_assertions, "assertion", "passed" );
@@ -174,6 +179,12 @@ plain_report_formatter::do_confirmation_report( test_unit const& tu, std::ostrea
return;
}
if( tr.p_timed_out ) {
ostr << "*** The test " << tu.p_type_name << ' ' << quote() << tu.full_name() << " has timed out"
<< "; see standard output for details\n";
return;
}
if( tr.p_aborted ) {
ostr << "*** The test " << tu.p_type_name << ' ' << quote() << tu.full_name() << " was aborted"
<< "; see standard output for details\n";

View File

@@ -52,7 +52,7 @@ struct progress_display {
<< "\n|----|----|----|----|----|----|----|----|----|----|"
<< std::endl;
if( !m_expected_count )
if( !m_expected_count )
m_expected_count = 1; // prevent divide by zero
}
@@ -63,7 +63,7 @@ struct progress_display {
// use of floating point ensures that both large and small counts
// work correctly. static_cast<>() is also used several places
// to suppress spurious compiler warnings.
// to suppress spurious compiler warnings.
unsigned int tics_needed = static_cast<unsigned int>(
(static_cast<double>(m_count)/m_expected_count)*50.0 );
@@ -121,6 +121,10 @@ progress_monitor_impl& s_pm_impl() { static progress_monitor_impl the_inst; retu
//____________________________________________________________________________//
BOOST_TEST_SINGLETON_CONS_IMPL(progress_monitor_t)
//____________________________________________________________________________//
void
progress_monitor_t::test_start( counter_t test_cases_amount )
{

View File

@@ -5,11 +5,9 @@
// See http://www.boost.org/libs/test for the library home page.
//
// File : $RCSfile$
//
// Version : $Revision$
//
// Description : implements Unit Test results collecting facility.
/// @file
/// Test results collecting facility.
///
// ***************************************************************************
#ifndef BOOST_TEST_RESULTS_COLLECTOR_IPP_021105GER
@@ -19,6 +17,7 @@
#include <boost/test/unit_test_log.hpp>
#include <boost/test/results_collector.hpp>
#include <boost/test/framework.hpp>
#include <boost/test/execution_monitor.hpp>
#include <boost/test/tree/test_unit.hpp>
#include <boost/test/tree/visitor.hpp>
@@ -52,11 +51,31 @@ test_results::test_results()
bool
test_results::passed() const
{
// if it is skipped, it is not passed. However, if any children is not failed/aborted
// then their skipped status is not taken into account.
return !p_skipped &&
p_test_cases_failed == 0 &&
p_assertions_failed <= p_expected_failures &&
p_test_cases_skipped == 0 &&
!p_aborted;
// p_test_cases_skipped == 0 &&
!p_timed_out &&
p_test_cases_timed_out == 0 &&
!aborted();
}
//____________________________________________________________________________//
bool
test_results::aborted() const
{
return p_aborted;
}
//____________________________________________________________________________//
bool
test_results::skipped() const
{
return p_skipped;
}
//____________________________________________________________________________//
@@ -65,7 +84,7 @@ int
test_results::result_code() const
{
return passed() ? exit_success
: ( (p_assertions_failed > p_expected_failures || p_skipped )
: ( (p_assertions_failed > p_expected_failures || p_skipped || p_timed_out || p_test_cases_timed_out )
? exit_test_failure
: exit_exception_failure );
}
@@ -75,6 +94,7 @@ test_results::result_code() const
void
test_results::operator+=( test_results const& tr )
{
p_test_suites.value += tr.p_test_suites;
p_assertions_passed.value += tr.p_assertions_passed;
p_assertions_failed.value += tr.p_assertions_failed;
p_warnings_failed.value += tr.p_warnings_failed;
@@ -83,6 +103,8 @@ test_results::operator+=( test_results const& tr )
p_test_cases_failed.value += tr.p_test_cases_failed;
p_test_cases_skipped.value += tr.p_test_cases_skipped;
p_test_cases_aborted.value += tr.p_test_cases_aborted;
p_test_cases_timed_out.value += tr.p_test_cases_timed_out;
p_test_suites_timed_out.value += tr.p_test_suites_timed_out;
p_duration_microseconds.value += tr.p_duration_microseconds;
}
@@ -91,6 +113,7 @@ test_results::operator+=( test_results const& tr )
void
test_results::clear()
{
p_test_suites.value = 0;
p_assertions_passed.value = 0;
p_assertions_failed.value = 0;
p_warnings_failed.value = 0;
@@ -100,9 +123,12 @@ test_results::clear()
p_test_cases_failed.value = 0;
p_test_cases_skipped.value = 0;
p_test_cases_aborted.value = 0;
p_test_cases_timed_out.value = 0;
p_test_suites_timed_out.value = 0;
p_duration_microseconds.value= 0;
p_aborted.value = false;
p_skipped.value = false;
p_timed_out.value = false;
}
//____________________________________________________________________________//
@@ -123,6 +149,10 @@ results_collector_impl& s_rc_impl() { static results_collector_impl the_inst; re
//____________________________________________________________________________//
BOOST_TEST_SINGLETON_CONS_IMPL( results_collector_t )
//____________________________________________________________________________//
void
results_collector_t::test_start( counter_t )
{
@@ -159,6 +189,8 @@ public:
else
m_tr.p_test_cases_passed.value++;
}
else if( tr.p_timed_out )
m_tr.p_test_cases_timed_out.value++;
else if( tr.p_skipped )
m_tr.p_test_cases_skipped.value++;
else {
@@ -174,6 +206,10 @@ public:
return true;
m_tr += results_collector.results( ts.p_id );
m_tr.p_test_suites.value++;
if( results_collector.results( ts.p_id ).p_timed_out )
m_tr.p_test_suites_timed_out.value++;
return false;
}
@@ -192,6 +228,8 @@ results_collector_t::test_unit_finish( test_unit const& tu, unsigned long elapse
results_collect_helper ch( s_rc_impl().m_results_store[tu.p_id], tu );
traverse_test_tree( tu, ch );
s_rc_impl().m_results_store[tu.p_id].p_duration_microseconds.value = elapsed_in_microseconds;
}
else {
test_results & tr = s_rc_impl().m_results_store[tu.p_id];
@@ -213,7 +251,6 @@ void
results_collector_t::test_unit_skipped( test_unit const& tu, const_string /*reason*/ )
{
test_results& tr = s_rc_impl().m_results_store[tu.p_id];
tr.clear();
tr.p_skipped.value = true;
@@ -228,6 +265,15 @@ results_collector_t::test_unit_skipped( test_unit const& tu, const_string /*reas
//____________________________________________________________________________//
void
results_collector_t::test_unit_timed_out(test_unit const& tu)
{
test_results& tr = s_rc_impl().m_results_store[tu.p_id];
tr.p_timed_out.value = true;
}
//____________________________________________________________________________//
void
results_collector_t::assertion_result( unit_test::assertion_result ar )
{
@@ -246,11 +292,14 @@ results_collector_t::assertion_result( unit_test::assertion_result ar )
//____________________________________________________________________________//
void
results_collector_t::exception_caught( execution_exception const& )
results_collector_t::exception_caught( execution_exception const& ex)
{
test_results& tr = s_rc_impl().m_results_store[framework::current_test_case_id()];
tr.p_assertions_failed.value++;
if( ex.code() == execution_exception::timeout_error ) {
tr.p_timed_out.value = true;
}
}
//____________________________________________________________________________//

View File

@@ -0,0 +1,117 @@
// (c) Copyright Raffi Enficiaud 2017.
// 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
//! An observer for monitoring the success/failure of the other observers
// ***************************************************************************
#ifndef BOOST_TEST_FRAMEWORK_INIT_OBSERVER_IPP_021105GER
#define BOOST_TEST_FRAMEWORK_INIT_OBSERVER_IPP_021105GER
// Boost.Test
#include <boost/test/test_framework_init_observer.hpp>
#include <boost/test/framework.hpp>
#include <boost/test/detail/suppress_warnings.hpp>
//____________________________________________________________________________//
namespace boost {
namespace unit_test {
//____________________________________________________________________________//
// ************************************************************************** //
// ************** framework_init_observer_t ************** //
// ************************************************************************** //
namespace {
struct test_init_observer_check {
bool has_failure;
void clear()
{
has_failure = false;
}
};
test_init_observer_check& s_tioc_impl() { static test_init_observer_check the_inst; return the_inst; }
} // local namespace
//____________________________________________________________________________//
// singleton pattern
BOOST_TEST_SINGLETON_CONS_IMPL(framework_init_observer_t)
//____________________________________________________________________________//
void
framework_init_observer_t::clear()
{
if(!framework::test_in_progress())
s_tioc_impl().clear();
}
//____________________________________________________________________________//
void
framework_init_observer_t::test_start( counter_t )
{
clear();
}
//____________________________________________________________________________//
void
framework_init_observer_t::assertion_result( unit_test::assertion_result ar )
{
test_init_observer_check& tr = s_tioc_impl();
switch( ar ) {
case AR_TRIGGERED: break;
case AR_PASSED: break;
case AR_FAILED: tr.has_failure = true; break;
default:
break;
}
}
//____________________________________________________________________________//
void
framework_init_observer_t::exception_caught( execution_exception const& )
{
test_init_observer_check& tr = s_tioc_impl();
tr.has_failure = true;
}
void
framework_init_observer_t::test_aborted()
{
s_tioc_impl().has_failure = true;
}
//____________________________________________________________________________//
bool
framework_init_observer_t::has_failed() const
{
return s_tioc_impl().has_failure;
}
//____________________________________________________________________________//
} // namespace unit_test
} // namespace boost
#include <boost/test/detail/enable_warnings.hpp>
#endif // BOOST_TEST_FRAMEWORK_INIT_OBSERVER_IPP_021105GER

View File

@@ -16,6 +16,7 @@
#define BOOST_TEST_TEST_TOOLS_IPP_012205GER
// Boost.Test
#include <boost/test/test_tools.hpp>
#include <boost/test/unit_test_log.hpp>
#include <boost/test/tools/context.hpp>
#include <boost/test/tools/output_test_stream.hpp>
@@ -59,6 +60,13 @@ namespace std { using ::wcscmp; }
#endif
# endif
namespace boost {
namespace unit_test {
// local static variable, needed here for visibility reasons
lazy_ostream lazy_ostream::inst = lazy_ostream();
}}
namespace boost {
namespace test_tools {
namespace tt_detail {
@@ -119,14 +127,6 @@ print_log_value<wchar_t const*>::operator()( std::ostream& ostr, wchar_t const*
ostr << ( t ? t : L"null string" );
}
#if !defined(BOOST_NO_CXX11_NULLPTR)
void
print_log_value<std::nullptr_t>::operator()( std::ostream& ostr, std::nullptr_t p )
{
ostr << "nullptr";
}
#endif
//____________________________________________________________________________//
// ************************************************************************** //
@@ -310,8 +310,19 @@ report_assertion( assertion_result const& ar,
{
using namespace unit_test;
BOOST_TEST_I_ASSRT( framework::current_test_case_id() != INV_TEST_UNIT_ID,
std::runtime_error( "Can't use testing tools outside of test case implementation." ) );
if( !framework::test_in_progress() ) {
// in case no test is in progress, we do not throw anything:
// raising an exception here may result in raising an exception in a destructor of a global fixture
// which will abort the process
// We flag this as aborted instead
//BOOST_TEST_I_ASSRT( framework::current_test_case_id() != INV_TEST_UNIT_ID,
// std::runtime_error( "Can't use testing tools outside of test case implementation." ) );
framework::test_aborted();
return false;
}
if( !!ar )
tl = PASS;
@@ -369,10 +380,11 @@ report_assertion( assertion_result const& ar,
case REQUIRE:
framework::assertion_result( AR_FAILED );
framework::test_unit_aborted( framework::current_test_case() );
framework::test_unit_aborted( framework::current_test_unit() );
BOOST_TEST_I_THROW( execution_aborted() );
// the previous line either throws or aborts and the return below is not reached
// return false;
BOOST_UNREACHABLE_RETURN(false);
}
return true;
@@ -493,7 +505,7 @@ struct output_test_stream::Impl
char get_char()
{
char res;
char res = 0;
do {
m_pattern.get( res );
} while( m_text_or_binary && res == '\r' && !m_pattern.fail() && !m_pattern.eof() );
@@ -619,6 +631,7 @@ output_test_stream::match_pattern( bool flush_stream )
int offset = 0;
std::vector<char> last_elements;
for ( std::string::size_type i = 0; static_cast<int>(i + offset) < static_cast<int>(stream_string_repr.length()); ++i ) {
char c = m_pimpl->get_char();
if( last_elements.size() <= n_chars_presuffix ) {
@@ -698,7 +711,7 @@ output_test_stream::match_pattern( bool flush_stream )
if( last_elements_ordered[pattern_start_index + k] == sub_str_suffix[stream_start_index + k] )
nb_char_in_common ++;
else
break; // we take fully macthing substring only
break; // we take fully matching substring only
}
if( nb_char_in_common > max_nb_char_in_common ) {
@@ -709,20 +722,32 @@ output_test_stream::match_pattern( bool flush_stream )
}
}
// indicates with more precision the location of the mismatchs in ascii arts ...
// indicates with more precision the location of the mismatchs in "ascii arts" ...
result.message() << " ...\n... ";
for( std::string::size_type j = 0; j < sub_str_prefix.size(); j++) {
result.message() << ' ';
}
for( std::size_t k = 0; k < (std::max)(best_pattern_start_index, best_stream_start_index); k++ ) { // 1 is for the current char c
result.message() << '~'; // places the first tilde at the current char that mismatches
for( std::size_t k = 1; k < (std::max)(best_pattern_start_index, best_stream_start_index); k++ ) { // 1 is for the current char c
std::string s1(pretty_print_log(std::string(1, last_elements_ordered[(std::min)(k, best_pattern_start_index)])));
std::string s2(pretty_print_log(std::string(1, sub_str_suffix[(std::min)(k, best_stream_start_index)])));
for( int h = (std::max)(s1.size(), s2.size()); h > 0; h--)
result.message() << "~";
result.message() << "~";
}
if( m_pimpl->m_pattern.eof() ) {
result.message() << " (reference string shorter than current stream)";
}
result.message() << "\n";
// no need to continue if the EOF is reached
if( m_pimpl->m_pattern.eof() ) {
break;
}
// first char is a replicat of c, so we do not copy it.
for(std::string::size_type counter = 0; counter < last_elements_ordered.size() - 1 ; counter++)
last_elements[ (i + 1 + counter) % last_elements.size() ] = last_elements_ordered[counter + 1];

View File

@@ -30,12 +30,10 @@
#include <boost/test/unit_test_parameters.hpp>
// Boost
#include <boost/timer.hpp>
// STL
#include <algorithm>
#include <vector>
#include <set>
#include <boost/test/detail/suppress_warnings.hpp>
@@ -124,7 +122,7 @@ test_unit::check_preconditions() const
test_results const& test_rslt = unit_test::results_collector.results( dep_id );
if( !test_rslt.passed() ) {
test_tools::assertion_result res(false);
res.message() << "dependency test " << dep.p_type_name << " \"" << dep.full_name() << "\" has failed";
res.message() << "dependency test " << dep.p_type_name << " \"" << dep.full_name() << (test_rslt.skipped() ? "\" was skipped":"\" has failed");
return res;
}
@@ -223,7 +221,7 @@ test_case::test_case( const_string name, const_string file_name, std::size_t lin
//____________________________________________________________________________//
test_suite::test_suite( const_string name, const_string file_name, std::size_t line_num )
: test_unit( name, file_name, line_num, static_cast<test_unit_type>(type) )
: test_unit( ut_detail::normalize_test_case_name( name ), file_name, line_num, static_cast<test_unit_type>(type) )
{
framework::register_test_unit( this );
}
@@ -266,19 +264,80 @@ test_suite::add( test_unit_generator const& gen, unsigned timeout )
//____________________________________________________________________________//
void
test_suite::add( test_unit_generator const& gen, decorator::collector& decorators )
test_suite::add( test_unit_generator const& gen, decorator::collector_t& decorators )
{
test_unit* tu;
while((tu = gen.next()) != 0) {
decorators.store_in( *tu );
add( tu, 0 );
}
decorators.reset();
}
//____________________________________________________________________________//
void
test_suite::add( boost::shared_ptr<test_unit_generator> gen_ptr, decorator::collector_t& decorators )
{
std::pair<boost::shared_ptr<test_unit_generator>, std::vector<decorator::base_ptr> > tmp_p(gen_ptr, decorators.get_lazy_decorators() );
m_generators.push_back(tmp_p);
decorators.reset();
}
//____________________________________________________________________________//
void
test_suite::generate( )
{
typedef std::pair<boost::shared_ptr<test_unit_generator>, std::vector<decorator::base_ptr> > element_t;
for(std::vector<element_t>::iterator it(m_generators.begin()), ite(m_generators.end());
it < ite;
++it)
{
test_unit* tu;
while((tu = it->first->next()) != 0) {
tu->p_decorators.value.insert( tu->p_decorators.value.end(), it->second.begin(), it->second.end() );
//it->second.store_in( *tu );
add( tu, 0 );
}
}
m_generators.clear();
#if 0
test_unit* tu;
while((tu = gen.next()) != 0) {
decorators.store_in( *tu );
add( tu, 0 );
}
#endif
}
//____________________________________________________________________________//
void
test_suite::check_for_duplicate_test_cases() {
// check for clashing names #12597
std::set<std::string> names;
for( test_unit_id_list::const_iterator it(m_children.begin()), ite(m_children.end());
it < ite;
++it) {
std::string name = framework::get(*it, TUT_ANY).p_name;
std::pair<std::set<std::string>::iterator, bool> ret = names.insert(name);
BOOST_TEST_SETUP_ASSERT(ret.second,
"test unit with name '"
+ name
+ std::string("' registered multiple times in the test suite '")
+ this->p_name.value
+ "'");
}
return;
}
//____________________________________________________________________________//
void
test_suite::remove( test_unit_id id )
{
@@ -380,9 +439,25 @@ normalize_test_case_name( const_string name )
if( name[0] == '&' )
norm_name = norm_name.substr( 1 );
std::replace(norm_name.begin(), norm_name.end(), ' ', '_');
std::replace(norm_name.begin(), norm_name.end(), ':', '_');
// trim spaces
std::size_t first_not_space = norm_name.find_first_not_of(' ');
if( first_not_space ) {
norm_name.erase(0, first_not_space);
}
std::size_t last_not_space = norm_name.find_last_not_of(' ');
if( last_not_space !=std::string::npos ) {
norm_name.erase(last_not_space + 1);
}
// sanitize all chars that might be used in runtime filters
static const char to_replace[] = { ':', '*', '@', '+', '!', '/' };
for(std::size_t index = 0;
index < sizeof(to_replace)/sizeof(to_replace[0]);
index++) {
std::replace(norm_name.begin(), norm_name.end(), to_replace[index], '_');
}
return norm_name;
}
@@ -393,7 +468,7 @@ normalize_test_case_name( const_string name )
// ************** auto_test_unit_registrar ************** //
// ************************************************************************** //
auto_test_unit_registrar::auto_test_unit_registrar( test_case* tc, decorator::collector& decorators, counter_t exp_fail )
auto_test_unit_registrar::auto_test_unit_registrar( test_case* tc, decorator::collector_t& decorators, counter_t exp_fail )
{
framework::current_auto_test_suite().add( tc, exp_fail );
@@ -403,7 +478,7 @@ auto_test_unit_registrar::auto_test_unit_registrar( test_case* tc, decorator::co
//____________________________________________________________________________//
auto_test_unit_registrar::auto_test_unit_registrar( const_string ts_name, const_string ts_file, std::size_t ts_line, decorator::collector& decorators )
auto_test_unit_registrar::auto_test_unit_registrar( const_string ts_name, const_string ts_file, std::size_t ts_line, decorator::collector_t& decorators )
{
test_unit_id id = framework::current_auto_test_suite().get( ts_name );
@@ -426,11 +501,19 @@ auto_test_unit_registrar::auto_test_unit_registrar( const_string ts_name, const_
//____________________________________________________________________________//
auto_test_unit_registrar::auto_test_unit_registrar( test_unit_generator const& tc_gen, decorator::collector& decorators )
auto_test_unit_registrar::auto_test_unit_registrar( test_unit_generator const& tc_gen, decorator::collector_t& decorators )
{
framework::current_auto_test_suite().add( tc_gen, decorators );
}
//____________________________________________________________________________//
auto_test_unit_registrar::auto_test_unit_registrar( boost::shared_ptr<test_unit_generator> tc_gen, decorator::collector_t& decorators )
{
framework::current_auto_test_suite().add( tc_gen, decorators );
}
//____________________________________________________________________________//
auto_test_unit_registrar::auto_test_unit_registrar( int )
@@ -446,9 +529,49 @@ auto_test_unit_registrar::auto_test_unit_registrar( int )
// ************** global_fixture ************** //
// ************************************************************************** //
global_fixture::global_fixture()
global_fixture::global_fixture(): registered(false)
{
framework::register_global_fixture( *this );
registered = true;
}
void global_fixture::unregister_from_framework() {
// not accessing the framework singleton after deregistering -> release
// of the observer from the framework
if(registered) {
framework::deregister_global_fixture( *this );
}
registered = false;
}
global_fixture::~global_fixture()
{
this->unregister_from_framework();
}
// ************************************************************************** //
// ************** global_configuration ************** //
// ************************************************************************** //
global_configuration::global_configuration(): registered(false)
{
framework::register_observer( *this );
registered = true;
}
void global_configuration::unregister_from_framework()
{
// not accessing the framework singleton after deregistering -> release
// of the observer from the framework
if(registered) {
framework::deregister_observer( *this );
}
registered = false;
}
global_configuration::~global_configuration()
{
this->unregister_from_framework();
}
//____________________________________________________________________________//

View File

@@ -159,6 +159,10 @@ unit_test_log_impl& s_log_impl() { static unit_test_log_impl the_inst; return th
//____________________________________________________________________________//
BOOST_TEST_SINGLETON_CONS_IMPL( unit_test_log_t )
//____________________________________________________________________________//
void
unit_test_log_t::test_start( counter_t test_cases_amount )
{
@@ -168,8 +172,11 @@ unit_test_log_t::test_start( counter_t test_cases_amount )
current_logger_data.m_log_formatter->log_start( current_logger_data.stream(), test_cases_amount );
if( runtime_config::get<bool>( runtime_config::btrt_build_info ) )
current_logger_data.m_log_formatter->log_build_info( current_logger_data.stream() );
current_logger_data.m_log_formatter->log_build_info(
current_logger_data.stream(),
runtime_config::get<bool>( runtime_config::btrt_build_info ));
//current_logger_data.stream().flush();
current_logger_data.m_entry_in_progress = false;
}
@@ -261,6 +268,20 @@ unit_test_log_t::test_unit_aborted( test_unit const& tu )
}
}
void
unit_test_log_t::test_unit_timed_out( test_unit const& tu )
{
if( s_log_impl().has_entry_in_progress() )
*this << log::end();
BOOST_TEST_FOREACH( unit_test_log_data_helper_impl&, current_logger_data, s_log_impl().m_log_formatter_data ) {
if( !current_logger_data.m_enabled || current_logger_data.get_log_level() > log_test_units )
continue;
current_logger_data.m_log_formatter->test_unit_timed_out(current_logger_data.stream(), tu );
}
}
//____________________________________________________________________________//
void
@@ -472,14 +493,14 @@ unit_test_log_t::log_entry_context( log_level l )
{
BOOST_TEST_FOREACH( unit_test_log_data_helper_impl&, current_logger_data, s_log_impl().m_log_formatter_data ) {
if( current_logger_data.m_enabled ) {
current_logger_data.m_log_formatter->log_entry_context( current_logger_data.stream(), frame );
current_logger_data.m_log_formatter->log_entry_context( current_logger_data.stream(), l, frame );
}
}
}
BOOST_TEST_FOREACH( unit_test_log_data_helper_impl&, current_logger_data, s_log_impl().m_log_formatter_data ) {
if( current_logger_data.m_enabled ) {
current_logger_data.m_log_formatter->entry_context_finish( current_logger_data.stream() );
current_logger_data.m_log_formatter->entry_context_finish( current_logger_data.stream(), l );
}
}
}
@@ -523,6 +544,17 @@ unit_test_log_t::set_stream( output_format log_format, std::ostream& str )
}
}
std::ostream*
unit_test_log_t::get_stream( output_format log_format ) const
{
BOOST_TEST_FOREACH( unit_test_log_data_helper_impl&, current_logger_data, s_log_impl().m_log_formatter_data ) {
if( current_logger_data.m_format == log_format) {
return current_logger_data.m_stream;
}
}
return 0;
}
//____________________________________________________________________________//
void

View File

@@ -37,6 +37,7 @@
#include <stdexcept>
#include <iostream>
#include <iomanip>
#include <iterator>
#include <set>
#include <boost/test/detail/suppress_warnings.hpp>
@@ -174,18 +175,34 @@ private:
std::set<std::string> m_labels;
};
struct framework_shutdown_helper {
~framework_shutdown_helper() {
try {
framework::shutdown();
}
catch(...) {
std::cerr << "Boost.Test shutdown exception caught" << std::endl;
}
}
};
} // namespace ut_detail
// ************************************************************************** //
// ************** unit_test_main ************** //
// ************************************************************************** //
int BOOST_TEST_DECL
unit_test_main( init_unit_test_func init_func, int argc, char* argv[] )
{
int result_code = 0;
ut_detail::framework_shutdown_helper shutdown_helper;
BOOST_TEST_I_TRY {
framework::init( init_func, argc, argv );
if( runtime_config::get<bool>( runtime_config::btrt_wait_for_debugger ) ) {
@@ -230,8 +247,6 @@ unit_test_main( init_unit_test_func init_func, int argc, char* argv[] )
framework::run();
results_reporter::make_report();
result_code = !runtime_config::get<bool>( runtime_config::btrt_result_code )
? boost::exit_success
: results_collector.results( framework::master_test_suite().p_id ).result_code();
@@ -249,14 +264,17 @@ unit_test_main( init_unit_test_func init_func, int argc, char* argv[] )
result_code = boost::exit_exception_failure;
}
BOOST_TEST_I_CATCH( std::logic_error, ex ) {
results_reporter::get_stream() << "Test setup error: " << ex.what() << std::endl;
result_code = boost::exit_exception_failure;
}
BOOST_TEST_I_CATCHALL() {
results_reporter::get_stream() << "Boost.Test framework internal error: unknown reason" << std::endl;
result_code = boost::exit_exception_failure;
}
framework::shutdown();
return result_code;
}

View File

@@ -29,16 +29,19 @@
namespace boost {
namespace unit_test {
// singleton pattern
BOOST_TEST_SINGLETON_CONS_IMPL(unit_test_monitor_t)
// ************************************************************************** //
// ************** unit_test_monitor ************** //
// ************************************************************************** //
unit_test_monitor_t::error_level
unit_test_monitor_t::execute_and_translate( boost::function<void ()> const& func, unsigned timeout )
unit_test_monitor_t::execute_and_translate( boost::function<void ()> const& func, unsigned long int timeout_microseconds )
{
BOOST_TEST_I_TRY {
p_catch_system_errors.value = runtime_config::get<bool>( runtime_config::btrt_catch_sys_errors );
p_timeout.value = timeout;
p_timeout.value = timeout_microseconds;
p_auto_start_dbg.value = runtime_config::get<bool>( runtime_config::btrt_auto_start_dbg );
p_use_alt_stack.value = runtime_config::get<bool>( runtime_config::btrt_use_alt_stack );
p_detect_fp_exceptions.value = runtime_config::get<bool>( runtime_config::btrt_detect_fp_except );
@@ -47,7 +50,7 @@ unit_test_monitor_t::execute_and_translate( boost::function<void ()> const& func
}
BOOST_TEST_I_CATCH( execution_exception, ex ) {
framework::exception_caught( ex );
framework::test_unit_aborted( framework::current_test_case() );
framework::test_unit_aborted( framework::current_test_unit() );
// translate execution_exception::error_code to error_level
switch( ex.code() ) {

View File

@@ -43,7 +43,6 @@
#include <boost/config.hpp>
#include <boost/test/detail/suppress_warnings.hpp>
#include <boost/test/detail/enable_warnings.hpp>
#include <boost/optional.hpp>
#include <boost/cstdlib.hpp>
// STL
@@ -112,7 +111,7 @@ register_parameters( rt::parameters_store& store )
rt::description = "Automatically attaches debugger in case of system level failure (signal).",
rt::env_var = "BOOST_TEST_AUTO_START_DBG",
rt::help = "Option " + btrt_auto_start_dbg + " specifies whether Boost.Test should attempt "
rt::help = "Specifies whether Boost.Test should attempt "
"to attach a debugger when fatal system error occurs. At the moment this feature "
"is only available on a few selected platforms: Win32 and *nix. There is a "
"default debugger configured for these platforms. You can manually configure "
@@ -145,7 +144,7 @@ register_parameters( rt::parameters_store& store )
rt::option build_info( btrt_build_info, (
rt::description = "Displays library build information.",
rt::env_var = "BOOST_TEST_BUILD_INFO",
rt::help = "Option " + btrt_build_info + " displays library build information, including: platform, "
rt::help = "Displays library build information, including: platform, "
"compiler, STL version and Boost version."
));
@@ -164,7 +163,7 @@ register_parameters( rt::parameters_store& store )
#else
true,
#endif
rt::help = "If option " + btrt_catch_sys_errors + " has value no the frameworks does not attempt to catch "
rt::help = "If option " + btrt_catch_sys_errors + " has value 'no' the frameworks does not attempt to catch "
"asynchronous system failure events (signals on *NIX platforms or structured exceptions on Windows). "
" Default value is "
#ifdef BOOST_TEST_DEFAULTS_TO_CORE_DUMP
@@ -183,9 +182,9 @@ register_parameters( rt::parameters_store& store )
rt::option color_output( btrt_color_output, (
rt::description = "Enables color output of the framework log and report messages.",
rt::env_var = "BOOST_TEST_COLOR_OUTPUT",
rt::help = "The framework is able to produce color output on systems which supports it. "
"To enable this behavior set this option to yes. By default the framework "
"does not produces color output."
rt::default_value = true,
rt::help = "Produces color output for logs, reports and help. "
"Defaults to true. "
));
color_output.add_cla_id( "--", btrt_color_output, "=", true );
@@ -197,7 +196,7 @@ register_parameters( rt::parameters_store& store )
rt::option detect_fp_except( btrt_detect_fp_except, (
rt::description = "Enables/disables floating point exceptions traps.",
rt::env_var = "BOOST_TEST_DETECT_FP_EXCEPTIONS",
rt::help = "Option " + btrt_detect_fp_except + " enables/disables hardware traps for the floating "
rt::help = "Enables/disables hardware traps for the floating "
"point exceptions (if supported on your platfrom)."
));
@@ -212,7 +211,7 @@ register_parameters( rt::parameters_store& store )
rt::default_value = 1L,
rt::optional_value = 1L,
rt::value_hint = "<alloc order number>",
rt::help = "Parameter " + btrt_detect_mem_leaks + " enables/disables memory leaks detection. "
rt::help = "Enables/disables memory leaks detection. "
"This parameter has optional long integer value. The default value is 1, which "
"enables the memory leak detection. The value 0 disables memory leak detection. "
"Any value N greater than 1 is treated as leak allocation number and tells the "
@@ -242,9 +241,9 @@ register_parameters( rt::parameters_store& store )
( "DOT", OF_DOT )
,
#endif
rt::help = "Parameter " + btrt_list_content + " instructs the framework to list the content "
"of the test module instead of executing the test cases. Parameter accepts "
"optional string value indicating the format of the output. Currently the "
rt::help = "Lists the test suites and cases "
"of the test module instead of executing the test cases. The format of the "
"desired output can be passed to the command. Currently the "
"framework supports two formats: human readable format (HRF) and dot graph "
"format (DOT). If value is omitted HRF value is assumed."
));
@@ -285,7 +284,7 @@ register_parameters( rt::parameters_store& store )
( "JUNIT", OF_JUNIT )
,
#endif
rt::help = "Parameter " + btrt_log_format + " allows to set the frameowrk's log format to one "
rt::help = "Set the frameowrk's log format to one "
"of the formats supplied by the framework. The only acceptable values for this "
"parameter are the names of the output formats supplied by the framework. By "
"default the framework uses human readable format (HRF) for testing log. This "
@@ -300,7 +299,7 @@ register_parameters( rt::parameters_store& store )
///////////////////////////////////////////////
rt::enum_parameter<unit_test::log_level> log_level( btrt_log_level, (
rt::description = "Specifies log level.",
rt::description = "Specifies the logging level of the test execution.",
rt::env_var = "BOOST_TEST_LOG_LEVEL",
rt::default_value = log_all_errors,
rt::enum_values<unit_test::log_level>::value =
@@ -333,8 +332,8 @@ register_parameters( rt::parameters_store& store )
( "nothing" , log_nothing )
,
#endif
rt::help = "Parameter " + btrt_log_level + " allows to set the framework's log level. "
"Log level defines the verbosity of testing log produced by a testing "
rt::help = "Set the framework's log level. "
"The log level defines the verbosity of the testing logs produced by a test "
"module. The verbosity ranges from a complete log, when all assertions "
"(both successful and failing) are reported, all notifications about "
"test units start and finish are included, to an empty log when nothing "
@@ -348,11 +347,11 @@ register_parameters( rt::parameters_store& store )
///////////////////////////////////////////////
rt::parameter<std::string> log_sink( btrt_log_sink, (
rt::description = "Specifies log sink: stdout(default), stderr or file name.",
rt::description = "Specifies log sink: stdout (default), stderr or file name.",
rt::env_var = "BOOST_TEST_LOG_SINK",
rt::value_hint = "<stderr|stdout|file name>",
rt::help = "Parameter " + btrt_log_sink + " allows to set the log sink - location "
"where we report the log to, thus it allows to easily redirect the "
rt::help = "Sets the log sink - the location "
"where Boost.Test writes the logs of the test execution. It allows to easily redirect the "
"test logs to file or standard streams. By default testing log is "
"directed to standard output."
));
@@ -380,9 +379,8 @@ register_parameters( rt::parameters_store& store )
( "XML", OF_XML )
,
#endif
rt::help = "Parameter " + btrt_output_format + " combines an effect of " + btrt_report_format +
" and " + btrt_log_format + " parameters. This parameter has higher priority "
"than either one of them. In other words if this parameter is specified "
rt::help = "Combines an effect of " + btrt_report_format +
" and " + btrt_log_format + " parameters. If this parameter is specified, "
"it overrides the value of other two parameters. This parameter does not "
"have a default value. The only acceptable values are string names of "
"output formats: HRF - human readable format and XML - XML formats for "
@@ -398,9 +396,12 @@ register_parameters( rt::parameters_store& store )
rt::parameter<std::string,rt::REPEATABLE_PARAM> combined_logger( btrt_combined_logger, (
rt::description = "Specifies log level and sink for one or several log format",
rt::env_var = "BOOST_TEST_LOGGER",
rt::value_hint = "log_format:log_level:log_sink",
rt::help = "Parameter " + btrt_combined_logger + " allows to specify the logger type, level and sink\n"
"in one command."
rt::value_hint = "log_format,log_level,log_sink[:log_format,log_level,log_sink]",
rt::help = "Specify one or more logging definition, which include the logger type, level and sink. "
"The log format, level and sink follow the same format as for the argument '--" + btrt_log_format +
"', '--" + btrt_log_level + "' and '--" + btrt_log_sink + "' respetively. "
"This command can take several logging definition separated by a ':', or be repeated "
"on the command line."
));
combined_logger.add_cla_id( "--", btrt_combined_logger, "=" );
@@ -415,14 +416,14 @@ register_parameters( rt::parameters_store& store )
rt::default_value = 0U,
rt::optional_value = 1U,
rt::value_hint = "<seed>",
rt::help = "Parameter " + btrt_random_seed + " instructs the framework to execute the "
"test cases in random order. This parameter accepts optional unsigned "
"integer argument. By default test cases are executed in some specific "
"order defined by order of test units in test files and dependency between "
"test units. If parameter is specified without the argument value testing "
rt::help = "Instructs the framework to execute the "
"test cases in random order. This parameter accepts an optional unsigned "
"integer argument. If parameter is specified without the argument value testing "
"order is randomized based on current time. Alternatively you can specify "
"any positive value greater than 1 and it will be used as random seed for "
"the run."
"the run. "
"By default, the test cases are executed in an "
"order defined by their declaration and the optional dependencies among the test units."
));
random_seed.add_cla_id( "--", btrt_random_seed, "=" );
@@ -431,7 +432,7 @@ register_parameters( rt::parameters_store& store )
///////////////////////////////////////////////
rt::enum_parameter<unit_test::output_format> report_format( btrt_report_format, (
rt::description = "Specifies report format.",
rt::description = "Specifies the test report format.",
rt::env_var = "BOOST_TEST_REPORT_FORMAT",
rt::default_value = OF_CLF,
rt::enum_values<unit_test::output_format>::value =
@@ -448,7 +449,7 @@ register_parameters( rt::parameters_store& store )
( "XML", OF_XML )
,
#endif
rt::help = "Parameter " + btrt_report_format + " allows to set the framework's report format "
rt::help = "Set the framework's report format "
"to one of the formats supplied by the framework. The only acceptable values "
"for this parameter are the names of the output formats. By default the framework "
"uses human readable format (HRF) for results reporting. Alternatively you can "
@@ -463,7 +464,7 @@ register_parameters( rt::parameters_store& store )
///////////////////////////////////////////////
rt::enum_parameter<unit_test::report_level> report_level( btrt_report_level, (
rt::description = "Specifies report level.",
rt::description = "Specifies test report level.",
rt::env_var = "BOOST_TEST_REPORT_LEVEL",
rt::default_value = CONFIRMATION_REPORT,
rt::enum_values<unit_test::report_level>::value =
@@ -482,9 +483,9 @@ register_parameters( rt::parameters_store& store )
( "no", NO_REPORT )
,
#endif
rt::help = "Parameter " + btrt_report_level + " allows to set the verbosity level of the "
"testing result report generated by the framework. Use value 'no' to "
"eliminate the results report completely."
rt::help = "Set the verbosity level of the "
"result report generated by the testing framework. Use value 'no' to "
"disable the results report completely."
));
report_level.add_cla_id( "--", btrt_report_level, "=" );
@@ -512,10 +513,10 @@ register_parameters( rt::parameters_store& store )
rt::description = "Specifies report sink: stderr(default), stdout or file name.",
rt::env_var = "BOOST_TEST_REPORT_SINK",
rt::value_hint = "<stderr|stdout|file name>",
rt::help = "Parameter " + btrt_report_sink + " allows to set the result report sink - "
"the location where the framework writes the result report to, thus it "
"allows to easily redirect the result report to a file or a standard "
"stream. By default the testing result report is directed to the "
rt::help = "Sets the result report sink - "
"the location where the framework writes the result report to. "
"The sink may be a a file or a standard "
"stream. The default is 'stderr': the "
"standard error stream."
));
@@ -541,13 +542,13 @@ register_parameters( rt::parameters_store& store )
///////////////////////////////////////////////
rt::parameter<std::string,rt::REPEATABLE_PARAM> tests_to_run( btrt_run_filters, (
rt::description = "Filters, which test units to include or exclude from test module execution.",
rt::description = "Filters which tests to execute.",
rt::env_var = "BOOST_TEST_RUN_FILTERS",
rt::value_hint = "<test unit filter>",
rt::help = "Parameter " + btrt_run_filters + " allows to filter which test units to execute during "
"testing. The framework supports both 'selection filters', which allow to select "
rt::help = "Filters which test units to execute. "
"The framework supports both 'selection filters', which allow to select "
"which test units to enable from the set of available test units, and 'disabler "
"filters', which allow to disable some test units. The __UTF__ also supports "
"filters', which allow to disable some test units. Boost.test also supports "
"enabling/disabling test units at compile time. These settings identify the default "
"set of test units to run. Parameter " + btrt_run_filters + " is used to change this default. "
"This parameter is repeatable, so you can specify more than one filter if necessary."
@@ -576,8 +577,8 @@ register_parameters( rt::parameters_store& store )
rt::option show_progress( btrt_show_progress, (
rt::description = "Turns on progress display.",
rt::env_var = "BOOST_TEST_SHOW_PROGRESS",
rt::help = "Parameter " + btrt_show_progress + " instructs the framework to display test progress "
"information. By default the test progress is not shown."
rt::help = "Instructs the framework to display the progress of the tests. "
"This feature is turned off by default."
));
show_progress.add_cla_id( "--", btrt_show_progress, "=" );
@@ -590,9 +591,9 @@ register_parameters( rt::parameters_store& store )
rt::description = "Turns on/off usage of an alternative stack for signal handling.",
rt::env_var = "BOOST_TEST_USE_ALT_STACK",
rt::default_value = true,
rt::help = "Parameter " + btrt_use_alt_stack + " instructs the framework to use alternative "
"stack for signals processing, on platforms where they are supported. The feature "
"is enabled by default, but can be disabled using this parameter."
rt::help = "Instructs the framework to use an alternative "
"stack for operating system's signals handling (on platforms where this is supported). "
"The feature is enabled by default, but can be disabled using this command line switch."
));
use_alt_stack.add_cla_id( "--", btrt_use_alt_stack, "=", true );
@@ -603,9 +604,9 @@ register_parameters( rt::parameters_store& store )
rt::option wait_for_debugger( btrt_wait_for_debugger, (
rt::description = "Forces test module to wait for button to be pressed before starting test run.",
rt::env_var = "BOOST_TEST_WAIT_FOR_DEBUGGER",
rt::help = "Parameter " + btrt_wait_for_debugger + " instructs the framework to pause before starting "
"test units execution, so that you can attach a debugger to running test module. By "
"default this parameters turned off."
rt::help = "Instructs the framework to pause before starting "
"test units execution, so that you can attach a debugger to the test module process. "
"This feature is turned off by default."
));
wait_for_debugger.add_cla_id( "--", btrt_wait_for_debugger, "=" );
@@ -618,10 +619,10 @@ register_parameters( rt::parameters_store& store )
rt::description = "Help for framework parameters.",
rt::optional_value = std::string(),
rt::value_hint = "<parameter name>",
rt::help = "Parameter " + btrt_help + " displays help on the framework's parameters. "
rt::help = "Displays help on the framework's parameters. "
"The parameter accepts an optional argument value. If present, an argument value is "
"interpreted as a parameter name (name guessing works as well, so for example "
"--help=rand displays help on the parameter random). If the parameter name is unknown "
"'--help=rand' displays help on the parameter 'random'). If the parameter name is unknown "
"or ambiguous error is reported. If argument value is absent, a summary of all "
"framework's parameter is displayed."
));
@@ -675,17 +676,26 @@ init( int& argc, char** argv )
// Set arguments to default values if defined and perform all the validations
rt::finalize_arguments( s_parameters_store, s_arguments_store );
// check if colorized output is enabled
bool use_color = true;
if( s_arguments_store.has(btrt_color_output ) ) {
use_color = runtime_config::get<bool>(runtime_config::btrt_color_output);
}
// Report help if requested
if( runtime_config::get<bool>( btrt_version ) ) {
parser->version( std::cerr );
BOOST_TEST_I_THROW( framework::nothing_to_test( boost::exit_success ) );
}
else if( runtime_config::get<bool>( btrt_usage ) ) {
parser->usage( std::cerr );
parser->usage( std::cerr, runtime::cstring(), use_color );
BOOST_TEST_I_THROW( framework::nothing_to_test( boost::exit_success ) );
}
else if( s_arguments_store.has( btrt_help ) ) {
parser->help( std::cerr, s_parameters_store, runtime_config::get<std::string>( btrt_help ) );
parser->help(std::cerr,
s_parameters_store,
runtime_config::get<std::string>( btrt_help ),
use_color );
BOOST_TEST_I_THROW( framework::nothing_to_test( boost::exit_success ) );
}

View File

@@ -63,16 +63,18 @@ xml_log_formatter::log_finish( std::ostream& ostr )
//____________________________________________________________________________//
void
xml_log_formatter::log_build_info( std::ostream& ostr )
xml_log_formatter::log_build_info( std::ostream& ostr, bool log_build_info )
{
ostr << "<BuildInfo"
<< " platform" << utils::attr_value() << BOOST_PLATFORM
<< " compiler" << utils::attr_value() << BOOST_COMPILER
<< " stl" << utils::attr_value() << BOOST_STDLIB
<< " boost=\"" << BOOST_VERSION/100000 << "."
<< BOOST_VERSION/100 % 1000 << "."
<< BOOST_VERSION % 100 << '\"'
<< "/>";
if( log_build_info ) {
ostr << "<BuildInfo"
<< " platform" << utils::attr_value() << BOOST_PLATFORM
<< " compiler" << utils::attr_value() << BOOST_COMPILER
<< " stl" << utils::attr_value() << BOOST_STDLIB
<< " boost=\"" << BOOST_VERSION/100000 << "."
<< BOOST_VERSION/100 % 1000 << "."
<< BOOST_VERSION % 100 << '\"'
<< "/>";
}
}
//____________________________________________________________________________//
@@ -199,7 +201,7 @@ xml_log_formatter::entry_context_start( std::ostream& ostr, log_level )
//____________________________________________________________________________//
void
xml_log_formatter::entry_context_finish( std::ostream& ostr )
xml_log_formatter::entry_context_finish( std::ostream& ostr, log_level )
{
ostr << BOOST_TEST_L( "</Context>" );
}
@@ -207,7 +209,7 @@ xml_log_formatter::entry_context_finish( std::ostream& ostr )
//____________________________________________________________________________//
void
xml_log_formatter::log_entry_context( std::ostream& ostr, const_string context_descr )
xml_log_formatter::log_entry_context( std::ostream& ostr, log_level, const_string context_descr )
{
ostr << BOOST_TEST_L( "<Frame>" ) << utils::cdata() << context_descr << BOOST_TEST_L( "</Frame>" );
}

View File

@@ -59,6 +59,8 @@ xml_report_formatter::test_unit_report_start( test_unit const& tu, std::ostream&
descr = "passed";
else if( tr.p_skipped )
descr = "skipped";
else if( tr.p_timed_out )
descr = "timed-out";
else if( tr.p_aborted )
descr = "aborted";
else
@@ -70,14 +72,18 @@ xml_report_formatter::test_unit_report_start( test_unit const& tu, std::ostream&
<< " assertions_passed" << utils::attr_value() << tr.p_assertions_passed
<< " assertions_failed" << utils::attr_value() << tr.p_assertions_failed
<< " warnings_failed" << utils::attr_value() << tr.p_warnings_failed
<< " expected_failures" << utils::attr_value() << tr.p_expected_failures;
<< " expected_failures" << utils::attr_value() << tr.p_expected_failures
;
if( tu.p_type == TUT_SUITE ) {
ostr << " test_cases_passed" << utils::attr_value() << tr.p_test_cases_passed
<< " test_cases_passed_with_warnings" << utils::attr_value() << tr.p_test_cases_warned
<< " test_cases_failed" << utils::attr_value() << tr.p_test_cases_failed
<< " test_cases_skipped" << utils::attr_value() << tr.p_test_cases_skipped
<< " test_cases_aborted" << utils::attr_value() << tr.p_test_cases_aborted;
<< " test_cases_aborted" << utils::attr_value() << tr.p_test_cases_aborted
<< " test_cases_timed_out" << utils::attr_value() << tr.p_test_cases_timed_out
<< " test_suites_timed_out"<< utils::attr_value() << tr.p_test_suites_timed_out
;
}
ostr << '>';