15c01a454c
[SVN r78634]
302 lines
12 KiB
C++
302 lines
12 KiB
C++
/*=============================================================================
|
|
Boost.Wave: A Standard compliant C++ preprocessor library
|
|
http://www.boost.org/
|
|
|
|
Copyright (c) 2001-2012 Hartmut Kaiser. 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)
|
|
=============================================================================*/
|
|
|
|
// disable stupid compiler warnings
|
|
#include <boost/config/warning_disable.hpp>
|
|
|
|
// system headers
|
|
#include <string>
|
|
#include <iostream>
|
|
#include <vector>
|
|
|
|
// include boost
|
|
#include <boost/config.hpp>
|
|
#include <boost/wave.hpp>
|
|
#include <boost/filesystem/path.hpp>
|
|
#include <boost/filesystem/operations.hpp>
|
|
|
|
// test application related headers
|
|
#include "cmd_line_utils.hpp"
|
|
#include "testwave_app.hpp"
|
|
|
|
namespace po = boost::program_options;
|
|
namespace fs = boost::filesystem;
|
|
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// The debuglevel command line parameter is used to control the amount of text
|
|
// printed by the testwave application.
|
|
//
|
|
// level 0: prints nothing except serious failures preventing the testwave
|
|
// executable from running, the return value of the executable is
|
|
// equal to the number of failed tests
|
|
// level 1: prints a short summary only
|
|
// level 2: prints the names of the failed tests only
|
|
// level 3: prints the expected and real result for failed tests
|
|
// level 4: prints the outcome of every test
|
|
// level 5: prints the real result even for succeeded tests
|
|
// level 6: prints the real hooks information recorded, even for succeeded
|
|
// tests
|
|
//
|
|
// level 9: prints information about almost everything
|
|
//
|
|
// The default debug level is 1.
|
|
//
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
int
|
|
main(int argc, char *argv[])
|
|
{
|
|
int error_count = 0;
|
|
int config_file_error_count = 0;
|
|
try {
|
|
// analyze the command line options and arguments
|
|
po::options_description desc_cmdline ("Options allowed on the command line");
|
|
desc_cmdline.add_options()
|
|
("help,h", "print out program usage (this message)")
|
|
("version,v", "print the version number")
|
|
("copyright,c", "print out the copyright statement")
|
|
("config-file", po::value<std::vector<std::string> >()->composing(),
|
|
"specify a config file (alternatively: @arg)")
|
|
("hooks", po::value<bool>()->default_value(true),
|
|
"test preprocessing hooks")
|
|
("debug,d", po::value<int>(), "set the debug level (0...9)")
|
|
;
|
|
|
|
// Hidden options, will be used in in config file analysis to allow to
|
|
// recognize positional arguments, will not be shown to the user.
|
|
po::options_description desc_hidden("Hidden options");
|
|
desc_hidden.add_options()
|
|
("input", po::value<std::vector<std::string> >()->composing(),
|
|
"inputfile")
|
|
;
|
|
|
|
// this is the test application object
|
|
po::variables_map vm;
|
|
testwave_app app(vm);
|
|
|
|
// all command line and config file options
|
|
po::options_description cmdline_options;
|
|
cmdline_options.add(desc_cmdline).add(app.common_options());
|
|
|
|
// parse command line
|
|
// (the (int) cast is to make the True64 compiler happy)
|
|
using namespace boost::program_options::command_line_style;
|
|
po::parsed_options opts(po::parse_command_line(argc, argv,
|
|
cmdline_options, (int)unix_style, cmd_line_utils::at_option_parser));
|
|
|
|
po::store(opts, vm);
|
|
po::notify(vm);
|
|
|
|
// ... act as required
|
|
if (vm.count("help")) {
|
|
po::options_description desc_help (
|
|
"Usage: testwave [options] [@config-file(s)] file(s)");
|
|
desc_help.add(desc_cmdline).add(app.common_options());
|
|
std::cout << desc_help << std::endl;
|
|
return 0;
|
|
}
|
|
|
|
// debug flag
|
|
if (vm.count("debug")) {
|
|
int debug_level = vm["debug"].as<int>();
|
|
if (debug_level < 0 || debug_level > 9) {
|
|
std::cerr
|
|
<< "testwave: please use an integer in the range [0..9] "
|
|
<< "as the parameter to the debug option!"
|
|
<< std::endl;
|
|
}
|
|
else {
|
|
app.set_debuglevel(debug_level);
|
|
}
|
|
}
|
|
|
|
if (vm.count("version")) {
|
|
return app.print_version();
|
|
}
|
|
|
|
if (vm.count("copyright")) {
|
|
return app.print_copyright();
|
|
}
|
|
|
|
// If there is specified at least one config file, parse it and add the
|
|
// options to the main variables_map
|
|
// Each of the config files is parsed into a separate variables_map to
|
|
// allow correct paths handling.
|
|
int input_count = 0;
|
|
if (vm.count("config-file")) {
|
|
std::vector<std::string> const &cfg_files =
|
|
vm["config-file"].as<std::vector<std::string> >();
|
|
|
|
if (9 == app.get_debuglevel()) {
|
|
std::cerr << "found " << (unsigned)cfg_files.size()
|
|
<< " config-file arguments" << std::endl;
|
|
}
|
|
|
|
std::vector<std::string>::const_iterator end = cfg_files.end();
|
|
for (std::vector<std::string>::const_iterator cit = cfg_files.begin();
|
|
cit != end; ++cit)
|
|
{
|
|
if (9 == app.get_debuglevel()) {
|
|
std::cerr << "reading config_file: " << *cit << std::endl;
|
|
}
|
|
|
|
// parse a single config file and store the results, config files
|
|
// may only contain --input and positional arguments
|
|
po::variables_map cvm;
|
|
if (!cmd_line_utils::read_config_file(app.get_debuglevel(),
|
|
*cit, desc_hidden, cvm))
|
|
{
|
|
if (9 == app.get_debuglevel()) {
|
|
std::cerr << "failed to read config_file: " << *cit
|
|
<< std::endl;
|
|
}
|
|
++config_file_error_count;
|
|
}
|
|
|
|
if (9 == app.get_debuglevel()) {
|
|
std::cerr << "succeeded to read config_file: " << *cit
|
|
<< std::endl;
|
|
}
|
|
|
|
// correct the paths parsed into this variables_map
|
|
if (cvm.count("input")) {
|
|
std::vector<std::string> const &infiles =
|
|
cvm["input"].as<std::vector<std::string> >();
|
|
|
|
if (9 == app.get_debuglevel()) {
|
|
std::cerr << "found " << (unsigned)infiles.size()
|
|
<< " entries" << std::endl;
|
|
}
|
|
|
|
std::vector<std::string>::const_iterator iend = infiles.end();
|
|
for (std::vector<std::string>::const_iterator iit = infiles.begin();
|
|
iit != iend; ++iit)
|
|
{
|
|
// correct the file name (pre-pend the config file path)
|
|
fs::path cfgpath = boost::wave::util::complete_path(
|
|
boost::wave::util::create_path(*cit),
|
|
boost::wave::util::current_path());
|
|
fs::path filepath =
|
|
boost::wave::util::branch_path(cfgpath) /
|
|
boost::wave::util::create_path(*iit);
|
|
|
|
if (9 == app.get_debuglevel()) {
|
|
std::cerr << std::string(79, '-') << std::endl;
|
|
std::cerr << "executing test: "
|
|
<< boost::wave::util::native_file_string(filepath)
|
|
<< std::endl;
|
|
}
|
|
|
|
// execute this unit test case
|
|
if (!app.test_a_file(
|
|
boost::wave::util::native_file_string(filepath)))
|
|
{
|
|
if (9 == app.get_debuglevel()) {
|
|
std::cerr << "failed to execute test: "
|
|
<< boost::wave::util::native_file_string(filepath)
|
|
<< std::endl;
|
|
}
|
|
++error_count;
|
|
}
|
|
else if (9 == app.get_debuglevel()) {
|
|
std::cerr << "succeeded to execute test: "
|
|
<< boost::wave::util::native_file_string(filepath)
|
|
<< std::endl;
|
|
}
|
|
++input_count;
|
|
|
|
if (9 == app.get_debuglevel()) {
|
|
std::cerr << std::string(79, '-') << std::endl;
|
|
}
|
|
}
|
|
}
|
|
else if (9 == app.get_debuglevel()) {
|
|
std::cerr << "no entries found" << std::endl;
|
|
}
|
|
}
|
|
}
|
|
|
|
// extract the arguments from the parsed command line
|
|
std::vector<po::option> arguments;
|
|
std::remove_copy_if(opts.options.begin(), opts.options.end(),
|
|
std::back_inserter(arguments), cmd_line_utils::is_argument());
|
|
|
|
if (9 == app.get_debuglevel()) {
|
|
std::cerr << "found " << (unsigned)arguments.size()
|
|
<< " arguments" << std::endl;
|
|
}
|
|
|
|
// iterate over remaining arguments
|
|
std::vector<po::option>::const_iterator arg_end = arguments.end();
|
|
for (std::vector<po::option>::const_iterator arg = arguments.begin();
|
|
arg != arg_end; ++arg)
|
|
{
|
|
fs::path filepath(boost::wave::util::create_path((*arg).value[0]));
|
|
|
|
if (9 == app.get_debuglevel()) {
|
|
std::cerr << std::string(79, '-') << std::endl;
|
|
std::cerr << "executing test: "
|
|
<< boost::wave::util::native_file_string(filepath)
|
|
<< std::endl;
|
|
}
|
|
|
|
if (!app.test_a_file(boost::wave::util::native_file_string(filepath)))
|
|
{
|
|
if (9 == app.get_debuglevel()) {
|
|
std::cerr << "failed to execute test: "
|
|
<< boost::wave::util::native_file_string(filepath)
|
|
<< std::endl;
|
|
}
|
|
++error_count;
|
|
}
|
|
else if (9 == app.get_debuglevel()) {
|
|
std::cerr << "succeeded to execute test: "
|
|
<< boost::wave::util::native_file_string(filepath)
|
|
<< std::endl;
|
|
}
|
|
|
|
if (9 == app.get_debuglevel()) {
|
|
std::cerr << std::string(79, '-') << std::endl;
|
|
}
|
|
++input_count;
|
|
}
|
|
|
|
// print a message if no input is given
|
|
if (0 == input_count) {
|
|
std::cerr
|
|
<< "testwave: no input file specified, "
|
|
<< "try --help to get a hint."
|
|
<< std::endl;
|
|
return (std::numeric_limits<int>::max)() - 3;
|
|
}
|
|
else if (app.get_debuglevel() > 0) {
|
|
std::cout
|
|
<< "testwave: " << input_count-error_count
|
|
<< " of " << input_count << " test(s) succeeded";
|
|
if (0 != error_count) {
|
|
std::cout
|
|
<< " (" << error_count << " test(s) failed)";
|
|
}
|
|
std::cout << "." << std::endl;
|
|
}
|
|
}
|
|
catch (std::exception const& e) {
|
|
std::cerr << "testwave: exception caught: " << e.what() << std::endl;
|
|
return (std::numeric_limits<int>::max)() - 1;
|
|
}
|
|
catch (...) {
|
|
std::cerr << "testwave: unexpected exception caught." << std::endl;
|
|
return (std::numeric_limits<int>::max)() - 2;
|
|
}
|
|
|
|
return error_count + config_file_error_count;
|
|
}
|