123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301 |
- /*=============================================================================
- 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;
- }
|