//  (C) Copyright Gennadiy Rozental 2001-2006.
//  (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: errors_handling_test.cpp,v $
//
//  Version     : $Revision: 1.38 $
//
//  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
#define BOOST_TEST_MAIN
#include <boost/test/unit_test.hpp>
#include <boost/test/output_test_stream.hpp>
#include <boost/test/unit_test_log.hpp>
#include <boost/test/unit_test_suite.hpp>
#include <boost/test/framework.hpp>
#include <boost/test/detail/unit_test_parameters.hpp>
#include <boost/test/output/compiler_log_formatter.hpp>
#include <boost/test/results_reporter.hpp>

// STL
#include <iostream>
#include <stdexcept>

using namespace boost::unit_test;
using namespace boost::test_tools;

#if defined(__GNUC__) || defined(__SUNPRO_CC) || defined(__DECCXX_VER)
#define LIMITED_TEST
#endif

namespace {

struct this_test_log_formatter : public boost::unit_test::output::compiler_log_formatter
{
    void    print_prefix( std::ostream& output, boost::unit_test::const_string, std::size_t line )
    {
        output << line << ": ";
    }

    void test_unit_finish( std::ostream& output, test_unit const& tu, unsigned long elapsed )
    {
        output << "Leaving test " << tu.p_type_name << " \"" << tu.p_name << "\"" << std::endl;
    }

};

//____________________________________________________________________________//

char const* log_level_name[] = {
    "log_successful_tests",
    "log_test_suites",
    "log_messages",
    "log_warnings",
    "log_all_errors",
    "log_cpp_exception_errors",
    "log_system_errors",
    "log_fatal_errors",
    "log_nothing"
};

enum error_type_enum {
    et_begin,
    et_none = et_begin,
    et_message,
    et_warning,
    et_user,
    et_cpp_exception,
#ifdef LIMITED_TEST
    et_fatal_user,
#else
    et_system,
    et_fatal_user,
    et_fatal_system,
#endif
    et_end
} error_type;

char const* error_type_name[] = {
    "no error", "user message", "user warning",
    "user non-fatal error", "cpp exception", " system error",
    "user fatal error", "system fatal error"
};

int divide_by_zero = 0;

void error_on_demand()
{
    switch( error_type ) {
    case et_none:
        BOOST_CHECK_MESSAGE( divide_by_zero == 0, "no error" );
        break;

    case et_message:
        BOOST_TEST_MESSAGE( "message" );
        break;

    case et_warning:
        BOOST_WARN_MESSAGE( divide_by_zero != 0, "warning" );
        break;

    case et_user:
        BOOST_ERROR( "non-fatal error" );
        break;

    case et_fatal_user:
        BOOST_FAIL( "fatal error" );

        BOOST_ERROR( "Should never reach this code!" );
        break;

    case et_cpp_exception:
        BOOST_TEST_CHECKPOINT( "error_on_demand() throw runtime_error" );
        throw std::runtime_error( "test std::runtime error what() message" );

#ifndef LIMITED_TEST
    case et_system:
        BOOST_TEST_CHECKPOINT( "error_on_demand() divide by zero" );
        divide_by_zero = 1 / divide_by_zero;
        break;

    case et_fatal_system:
        BOOST_TEST_CHECKPOINT( "write to an invalid address" );
        {
            int* p = 0;
            *p = 0;

            BOOST_ERROR( "Should never reach this code!" );
        }
        break;
#endif
    default:
        BOOST_ERROR( "Should never reach this code!" );
    }
    return;
}

}  // local namespace

//____________________________________________________________________________//

BOOST_AUTO_TEST_CASE( test_errors_handling )
{
#define PATTERN_FILE_NAME "errors_handling_test.pattern"
    std::string pattern_file_name(
        framework::master_test_suite().argc <= 1 
            ? (runtime_config::save_pattern() ? PATTERN_FILE_NAME : "./test_files/" PATTERN_FILE_NAME)
            : framework::master_test_suite().argv[1] );

#ifdef LIMITED_TEST
    pattern_file_name += "2";
#endif

    output_test_stream test_output( pattern_file_name, !runtime_config::save_pattern() );

    test_case* test = BOOST_TEST_CASE( &error_on_demand );

    // for each log level
    for( log_level level = log_successful_tests;
         level          <= log_nothing;
         level           = static_cast<log_level>(level+1) )
    {
        // for each error type
        for( error_type = et_begin;
             error_type != et_end;
             error_type = static_cast<error_type_enum>(error_type+1) )
        {
            test_output << "\n===========================\n"
                        << "log level: "       << log_level_name[level] << ';'
                        << " error type: "     << error_type_name[error_type] << ";\n" << std::endl;

            unit_test_log.set_stream( test_output );
            unit_test_log.set_formatter( new this_test_log_formatter );
            unit_test_log.set_threshold_level( level );
            framework::run( test );

            unit_test_log.set_stream( std::cout );
            unit_test_log.set_format( runtime_config::log_format() );
            unit_test_log.set_threshold_level( runtime_config::log_level() != invalid_log_level
                                                ? runtime_config::log_level()
                                                : log_all_errors );
            BOOST_CHECK( test_output.match_pattern() );
        }
    }
}

//____________________________________________________________________________//

// ***************************************************************************
//  Revision History :
//
//  $Log: errors_handling_test.cpp,v $
//  Revision 1.38  2006/03/19 11:49:04  rogeeff
//  *** empty log message ***
//
//  Revision 1.37  2006/02/01 08:00:15  rogeeff
//  *** empty log message ***
//
//  Revision 1.36  2005/12/14 06:01:02  rogeeff
//  *** empty log message ***
//
//  Revision 1.35  2005/06/13 11:46:26  schoepflin
//  Use limited tests with Tru64/CXX.
//
//  Revision 1.34  2005/06/11 19:20:58  rogeeff
//  *** empty log message ***
//
//  Revision 1.33  2005/05/11 05:07:56  rogeeff
//  licence update
//
//  Revision 1.32  2005/03/23 21:06:39  rogeeff
//  Sunpro CC 5.3 fixes
//
//  Revision 1.31  2005/03/22 07:14:44  rogeeff
//  no message
//
//  Revision 1.30  2005/02/23 06:36:01  vawjr
//  Deleted - extraneous \r characters in the file
//
//  Revision 1.29  2005/02/20 08:28:34  rogeeff
//  This a major update for Boost.Test framework. See release docs for complete list of fixes/updates
//
// ***************************************************************************

// EOF

