mirror of
https://github.com/boostorg/test.git
synced 2026-01-30 20:32:10 +00:00
293 lines
9.5 KiB
C++
293 lines
9.5 KiB
C++
// (C) Copyright Gennadiy Rozental 2001-2004.
|
|
// (C) Copyright Beman Dawes 2001.
|
|
// Distributed under the Boost Software License, Version 1.0.
|
|
// (See accompanying file LICENSE_1_0.txt or copy at
|
|
// http://www.boost.org/LICENSE_1_0.txt)
|
|
|
|
|
|
// See http://www.boost.org/libs/test for the library home page.
|
|
//
|
|
// File : $RCSfile$
|
|
//
|
|
// Version : $Revision$
|
|
//
|
|
// Description : tests an ability of Unit Test Framework to catch all kinds
|
|
// of test errors in a user code and properly report it.
|
|
// ***************************************************************************
|
|
|
|
// Boost.Test
|
|
#include <boost/test/unit_test.hpp>
|
|
#include <boost/test/unit_test_result.hpp>
|
|
#include <boost/test/detail/unit_test_parameters.hpp>
|
|
#include <boost/test/detail/supplied_log_formatters.hpp>
|
|
using namespace boost::unit_test;
|
|
using namespace boost::test_tools;
|
|
|
|
// STL
|
|
#include <iostream>
|
|
|
|
struct this_test_log_formatter : public boost::unit_test::ut_detail::msvc65_like_log_formatter
|
|
{
|
|
explicit this_test_log_formatter( unit_test_log const& log )
|
|
: boost::unit_test::ut_detail::msvc65_like_log_formatter( log ) {}
|
|
|
|
void print_prefix( std::ostream& output, boost::unit_test::const_string, std::size_t line )
|
|
{
|
|
output << line << ": ";
|
|
}
|
|
};
|
|
|
|
//____________________________________________________________________________//
|
|
|
|
namespace {
|
|
enum error_type_enum {
|
|
et_begin,
|
|
et_none = et_begin,
|
|
et_user,
|
|
et_cpp_exception,
|
|
et_system,
|
|
et_fatal_user,
|
|
et_fatal_system,
|
|
et_end
|
|
} error_type;
|
|
|
|
char const* error_type_name[] = { "no error", "user error", "cpp exception", " system error", "fatal user error", "fatal system error" };
|
|
|
|
int divide_by_zero = 0;
|
|
|
|
// will cause an error coresponding to the current error_type;
|
|
void error_on_demand()
|
|
{
|
|
switch( error_type ) {
|
|
case et_none:
|
|
BOOST_MESSAGE( "error_on_demand() BOOST_MESSAGE" );
|
|
break;
|
|
|
|
case et_user:
|
|
unit_test_result::instance().increase_expected_failures();
|
|
BOOST_ERROR( "error_on_demand() BOOST_ERROR" );
|
|
break;
|
|
|
|
case et_fatal_user:
|
|
unit_test_result::instance().increase_expected_failures();
|
|
BOOST_CRITICAL_ERROR( "error_on_demand() BOOST_CRITICAL_ERROR" );
|
|
|
|
BOOST_ERROR( "Should never reach this code!" );
|
|
break;
|
|
|
|
case et_cpp_exception:
|
|
BOOST_CHECKPOINT( "error_on_demand() throw runtime_error" );
|
|
throw std::runtime_error( "test std::runtime error what() message" );
|
|
|
|
case et_system:
|
|
BOOST_CHECKPOINT( "error_on_demand() divide by zero" );
|
|
divide_by_zero = 1 / divide_by_zero;
|
|
break;
|
|
|
|
case et_fatal_system:
|
|
BOOST_CHECKPOINT( "error_on_demand() write to an invalid address" );
|
|
{
|
|
int* p = 0;
|
|
*p = 0;
|
|
|
|
BOOST_ERROR( "Should never reach this code!" );
|
|
}
|
|
break;
|
|
|
|
default:
|
|
BOOST_ERROR( "Should never reach this code!" );
|
|
}
|
|
return;
|
|
}
|
|
|
|
enum test_case_type_enum {
|
|
tct_begin,
|
|
tct_free_function = tct_begin,
|
|
tct_user_test_case,
|
|
tct_param_free_function,
|
|
tct_param_user_test_case,
|
|
tct_end
|
|
} test_case_type;
|
|
|
|
char const* test_case_type_name[] = { "free function",
|
|
"user test case",
|
|
"parameterized free function",
|
|
"parameterized user test case"
|
|
};
|
|
|
|
// simulated user classes to be tested --------------------------------//
|
|
|
|
// user test cases ----------------------------------------------------//
|
|
|
|
struct bad_test
|
|
{
|
|
void test()
|
|
{
|
|
BOOST_MESSAGE( "(user test case)" );
|
|
error_on_demand();
|
|
}
|
|
void test_param( int )
|
|
{
|
|
BOOST_MESSAGE( "(parameterized user test case)" );
|
|
error_on_demand();
|
|
}
|
|
};
|
|
|
|
// free function tests ---------------------------------------------------//
|
|
|
|
void bad_function()
|
|
{
|
|
BOOST_MESSAGE( "(free function)" );
|
|
error_on_demand();
|
|
}
|
|
|
|
void bad_function_param( int )
|
|
{
|
|
BOOST_MESSAGE( "(parameterized free function)" );
|
|
error_on_demand();
|
|
}
|
|
|
|
int params[] = { 0 };
|
|
|
|
} // unnamed namespace
|
|
|
|
//____________________________________________________________________________//
|
|
|
|
int
|
|
test_main( int argc, char * argv[] )
|
|
{
|
|
|
|
bool match_or_save = retrieve_framework_parameter( SAVE_TEST_PATTERN, &argc, argv ) != "yes";
|
|
|
|
#define PATTERN_FILE_NAME "errors_handling_test.pattern"
|
|
|
|
std::string pattern_file_name( argc == 1
|
|
? (match_or_save ? "./test_files/" PATTERN_FILE_NAME : PATTERN_FILE_NAME)
|
|
: argv[1] );
|
|
|
|
#ifdef __GNUC__
|
|
pattern_file_name.append( "2" );
|
|
#endif
|
|
|
|
output_test_stream output( pattern_file_name, match_or_save );
|
|
|
|
unit_test_log::instance().set_log_stream( output );
|
|
unit_test_log::instance().set_log_formatter( new this_test_log_formatter( unit_test_log::instance() ) );
|
|
|
|
boost::shared_ptr<bad_test> bad_test_instance( new bad_test );
|
|
|
|
// for each log level
|
|
for( log_level level = log_successful_tests;
|
|
level <= log_nothing;
|
|
level = static_cast<log_level>(level+1) )
|
|
{
|
|
unit_test_log::instance().set_log_threshold_level( level );
|
|
|
|
// for each error type
|
|
for( error_type = et_begin;
|
|
error_type != et_end;
|
|
error_type = static_cast<error_type_enum>(error_type+1) )
|
|
{
|
|
#ifdef __GNUC__
|
|
if( error_type == et_system || error_type == et_fatal_system )
|
|
continue;
|
|
#endif
|
|
// for each error location
|
|
for( test_case_type = tct_begin;
|
|
test_case_type != tct_end;
|
|
test_case_type = static_cast<test_case_type_enum>(test_case_type+1) )
|
|
{
|
|
output << "\n===========================\n\n"
|
|
<< "log level: " << int(level) << ';'
|
|
<< " error type: " << error_type_name[error_type] << ';'
|
|
<< " test case type: " << test_case_type_name[test_case_type] << ';'<< std::endl;
|
|
|
|
// In typical user code, multiple test cases would be added to a single
|
|
// test suite. But for testing the unit test code itself, it is easier
|
|
// to isolate each case in its own test suite.
|
|
test_suite test( "Errors handling test" );
|
|
switch( test_case_type ) {
|
|
case tct_free_function:
|
|
test.add( BOOST_TEST_CASE( &bad_function ) );
|
|
break;
|
|
case tct_user_test_case:
|
|
test.add( BOOST_CLASS_TEST_CASE( &bad_test::test, bad_test_instance ) );
|
|
break;
|
|
case tct_param_free_function:
|
|
// Borland bug workaround
|
|
#if BOOST_WORKAROUND(__BORLANDC__, BOOST_TESTED_AT(0x570))
|
|
test.add( boost::unit_test::create_test_case<int*,int>( &bad_function_param, std::string( "bad_function_param" ), (int*)params, params+1 ) );
|
|
#else
|
|
test.add( BOOST_PARAM_TEST_CASE( &bad_function_param, (int*)params, params+1 ) );
|
|
#endif
|
|
break;
|
|
case tct_param_user_test_case:
|
|
#if BOOST_WORKAROUND(__BORLANDC__, BOOST_TESTED_AT(0x570))
|
|
test.add( boost::unit_test::create_test_case<bad_test,int*,int>( &bad_test::test_param, std::string( "bad_test::test_param" ), bad_test_instance, (int*)params, params+1 ) );
|
|
#else
|
|
test.add( BOOST_PARAM_CLASS_TEST_CASE( &bad_test::test_param, bad_test_instance, (int*)params, params+1 ) );
|
|
#endif
|
|
break;
|
|
default:
|
|
continue;
|
|
}
|
|
|
|
{
|
|
unit_test_result_saver saver;
|
|
unit_test_log::instance().start();
|
|
unit_test_log::instance().header( 1 );
|
|
test.run();
|
|
unit_test_log::instance().finish( 1 );
|
|
}
|
|
|
|
unit_test_log::instance().set_log_threshold_level( log_all_errors );
|
|
BOOST_CHECK( output.match_pattern() );
|
|
unit_test_log::instance().set_log_threshold_level( level );
|
|
}
|
|
}
|
|
}
|
|
|
|
unit_test_result::instance().short_report( output );
|
|
output.match_pattern();
|
|
|
|
return 0;
|
|
} // main
|
|
|
|
//____________________________________________________________________________//
|
|
|
|
// ***************************************************************************
|
|
// Revision History :
|
|
//
|
|
// $Log$
|
|
// Revision 1.24 2004/10/05 04:27:09 rogeeff
|
|
// 31 length fix
|
|
//
|
|
// Revision 1.23 2004/10/05 01:32:09 rogeeff
|
|
// file/directory renaming for the sake of CD burning
|
|
//
|
|
// Revision 1.22 2004/10/01 10:55:43 rogeeff
|
|
// some test errors workarrounds
|
|
//
|
|
// Revision 1.21 2004/06/07 07:34:23 rogeeff
|
|
// detail namespace renamed
|
|
//
|
|
// Revision 1.20 2004/05/27 06:30:48 rogeeff
|
|
// no message
|
|
//
|
|
// Revision 1.19 2004/05/21 06:26:10 rogeeff
|
|
// licence update
|
|
//
|
|
// Revision 1.18 2004/05/11 11:05:06 rogeeff
|
|
// basic_cstring introduced and used everywhere
|
|
// class properties reworked
|
|
// namespace names shortened
|
|
//
|
|
// Revision 1.17 2003/12/01 00:42:37 rogeeff
|
|
// prerelease cleaning
|
|
//
|
|
|
|
// ***************************************************************************
|
|
|
|
// EOF
|
|
|