Boost.Test > Components > The Program Execution Monitor
Boost Test logo

Boost Test Library: The Program Execution Monitor

Introduction
Usage
Configuration
Implementation
Compilation
Examples and tests

Introduction

The components of a C++ program may report user-detected errors in several ways, such as via a return value or throwing an exception. System-detected errors such as dereferencing an invalid pointer are reported in other ways, totally operating system and compiler dependent.

Yet many C++ programs, both production and test, must run in an environment where uniform reporting of errors is necessary. For example, converting otherwise uncaught exceptions to non-zero program return codes allows many command line, script, or batch environments to continue processing in a controlled manner. Even some GUI environments benefit from the unification of errors into program return codes.

The Boost Test Library's Program Execution Monitor relieves users from messy error detection and reporting duties by providing a replacement function main() which calls a user-supplied cpp_main() function within a monitored environment. The supplied main() then uniformly detects and reports the occurrence of several types of errors, reducing them to a uniform return code which is returned to the host environment.

Uniform error reporting is particularly useful for programs running unattended under control of scripts or batch files. Some operating systems pop up message boxes if an uncaught exception occurs, and this requires operator intervention. By converting such exceptions to non-zero program return codes, the library makes the program a better citizen. More uniform reporting of errors isn't a benefit to some programs, particularly programs always run by hand by a knowledgeable person. So the Program Execution Monitor wouldn't be worth using in that environment.

Uniform error reporting could be also useful in test environments such as the Boost regression tests. Be aware though in such case it might be preferable to use the Unit Test Framework, cause they allows one to use the Test Tools and generate more detailed error information.

Usage

Using the Program Execution Monitor, the traditional Hello World program becomes:

#include <iostream>
#include <boost/test/included/prg_exec_monitor.hpp> 

int cpp_main( int, char* [] ) // note name cpp_main, not main.
{
    std::cout << "Hello, world\n";

    return 0;
}

It really is that simple - just change the name of your initial function from main() to cpp_main(). Do make sure the argc and argv parameters are specified (although you don't have to name them if you don't use them). Now you can compile it. When the above program executes, the output will be:

Hello, world
no errors detected

The Program Execution Monitor treat as errors:

So what if some function had thrown a runtime_error with the message "big trouble" and it's not trapped by any catch clause? Like in a following example:

#include <stdexcept>
#include <boost/test/included/prg_exec_monitor.hpp> 

int foo() { throw std::runtime_exception( "big trouble" ); }

int cpp_main( int, char* [] ) // note the name
{
    foo();

    return 0;
}
  

Then the output would look something like this:

**** exception(205): std::runtime_error: big trouble
******** errors detected; see standard output for details ********

Note that in both examples above we used inlined version of the Program Execution Monitor. Alternatively we could compile it into standalone library and link with it during program build. In this case we usually don't need to include anything at all (see below for more details). Lets consider an example where function cpp_main() had bubbled up a return code of 5:

#include <boost/test/prg_exec_monitor.hpp> // this header is optional
  
int cpp_main( int, char* [] ) // note the name
{
    return 5;
}

Once we build this program and linked with prebuilt Program Execution Monitor, the output would look something like this:

**** error return code: 5
******** errors detected; see standard output for details ********

The Program Execution Monitor reports errors to both cout (details) and cerr (summary). Primary detailed error messages appear on standard output stream so that it is properly interlaced with other output, thus aiding error analysis. While the final error notification message appears on standard error stream. This increases the visibility of error notification if standard output and error streams are directed to different devices or files.

The Program Execution Monitor's supplied main() will return following result codes:

Configuration

There are two aspects of the Program Execution Monitor behavior that you can customize at runtime. Customization performed using environment variables.

BOOST_TEST_CATCH_SYSTEM_ERRORS - allows to customize behavior of the Program Execution Monitor in regards of catching system errors. For more details about the meaning of this option see the Execution Monitor documentation. If you want to prevent the Program Execution Monitor from catching system exception, set the value of this variable to "no". The default value is "yes".


BOOST_PRG_MON_CONFIRM - allows to avoid success confirmation message. Some users prefer to see a confirmation message in case if program successfully executed. While others don't like the clutter or any output is prohibited by organization standards. To avoid the message set the value of this variable to "no". The default value is "yes".

Implementation

To monitor execution of user supplied function cpp_main() the Program Execution Monitor relies on the Boost.Test's Execution Monitor . Also the Program Execution Monitor supply function main(). For the program to link successfully user is required to supply a function cpp_main() with same interface as the main().

You could use either header-only inlined version of the Program Execution Monitor implemented in <boost/test/included/prg_exec_monitor.hpp> of build standalone library and link with it during program build in which case nothing needs to be included. Bur If you wish to link with dynamic version of prebuilt library or employ auto-lining feature available for Microsoft compilers you need an extra support implemented in <boost/test/prg_exec_monitor.hpp>.

Following files are used in the Program Execution Monitor implementation:

libs/test/execution_monitor.cpp:

The Execution Monitor implementation.

libs/test/cpp_main.cpp:

Supply function main() for static library build

boost/test/included/prg_exec_monitor.hpp:

Combine all implementation files into single header to be use as inlined version of component

boost/test/prg_exec_monitor.hpp:

Contains definitions for main() function for dynamic library build and pragmas for auto-linking feature support.

Examples and tests

prg_exec_example
prg_exec_fail1
prg_exec_fail2
prg_exec_fail3
prg_exec_fail4