summaryrefslogtreecommitdiff
path: root/boost/test/impl/cpp_main.ipp
blob: 23d19e2f31a2fd9aac7dc6fcf877ceb235fc7919 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
//  (C) Copyright Gennadiy Rozental 2001-2008.
//  (C) Copyright Beman Dawes 1995-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 : main function implementation for Program Executon Monitor
// ***************************************************************************

#ifndef BOOST_TEST_CPP_MAIN_IPP_012205GER
#define BOOST_TEST_CPP_MAIN_IPP_012205GER

// Boost.Test
#include <boost/test/execution_monitor.hpp>
#include <boost/test/detail/config.hpp>
#include <boost/test/utils/basic_cstring/io.hpp>

// Boost
#include <boost/cstdlib.hpp>    // for exit codes
#include <boost/config.hpp>     // for workarounds

// STL
#include <iostream>
#include <cstdlib>      // std::getenv
#include <cstring>      // std::strerror

#include <boost/test/detail/suppress_warnings.hpp>

//____________________________________________________________________________//

#ifdef BOOST_NO_STDC_NAMESPACE
namespace std { using ::getenv; using ::strerror; }
#endif

namespace {

struct cpp_main_caller {
    cpp_main_caller( int (*cpp_main_func)( int argc, char* argv[] ), int argc, char** argv ) 
    : m_cpp_main_func( cpp_main_func )
    , m_argc( argc )
    , m_argv( argv ) {}
    
    int operator()() { return (*m_cpp_main_func)( m_argc, m_argv ); }
  
private:
    // Data members    
    int (*m_cpp_main_func)( int argc, char* argv[] );
    int      m_argc;
    char**   m_argv;
};

} // local namespace

// ************************************************************************** //
// **************             prg_exec_monitor_main            ************** //
// ************************************************************************** //

namespace boost {

int BOOST_TEST_DECL
prg_exec_monitor_main( int (*cpp_main)( int argc, char* argv[] ), int argc, char* argv[] )
{
    int result = 0;

    try {
        boost::unit_test::const_string p( std::getenv( "BOOST_TEST_CATCH_SYSTEM_ERRORS" ) );
        ::boost::execution_monitor ex_mon;

        ex_mon.p_catch_system_errors.value = p != "no";
        
        result = ex_mon.execute( 
            ::boost::unit_test::callback0<int>( cpp_main_caller( cpp_main, argc, argv ) ) );
        
        if( result == 0 )
            result = ::boost::exit_success;
        else if( result != ::boost::exit_success ) {
            std::cout << "\n**** error return code: " << result << std::endl;
            result = ::boost::exit_failure;
        }
    }
    catch( ::boost::execution_exception const& exex ) {
        std::cout << "\n**** exception(" << exex.code() << "): " << exex.what() << std::endl;
        result = ::boost::exit_exception_failure;
    }
    catch( ::boost::system_error const& ex ) {
        std::cout << "\n**** failed to initialize execution monitor."
                  << "\n**** expression at fault: " << ex.p_failed_exp 
                  << "\n**** error(" << ex.p_errno << "): " << std::strerror( ex.p_errno ) << std::endl;
        result = ::boost::exit_exception_failure;
    }

    if( result != ::boost::exit_success ) {
        std::cerr << "******** errors detected; see standard output for details ********" << std::endl;
    }
    else {
        //  Some prefer a confirming message when all is well, while others don't
        //  like the clutter.  Use an environment variable to avoid command
        //  line argument modifications; for use in production programs
        //  that's a no-no in some organizations.
        ::boost::unit_test::const_string p( std::getenv( "BOOST_PRG_MON_CONFIRM" ) );
        if( p != "no" ) { 
            std::cerr << std::flush << "no errors detected" << std::endl; 
        }
    }

    return result;
}

} // namespace boost

#if !defined(BOOST_TEST_DYN_LINK) && !defined(BOOST_TEST_NO_MAIN)

// ************************************************************************** //
// **************        main function for tests using lib     ************** //
// ************************************************************************** //

int cpp_main( int argc, char* argv[] );  // prototype for user's cpp_main()

int BOOST_TEST_CALL_DECL
main( int argc, char* argv[] )
{
    return ::boost::prg_exec_monitor_main( &cpp_main, argc, argv );
}

//____________________________________________________________________________//

#endif // !BOOST_TEST_DYN_LINK && !BOOST_TEST_NO_MAIN

//____________________________________________________________________________//

#include <boost/test/detail/enable_warnings.hpp>

#endif // BOOST_TEST_CPP_MAIN_IPP_012205GER