File: testwave.cpp

package info (click to toggle)
boost 1.34.1-14
  • links: PTS
  • area: main
  • in suites: lenny
  • size: 116,412 kB
  • ctags: 259,566
  • sloc: cpp: 642,395; xml: 56,450; python: 17,612; ansic: 14,520; sh: 2,265; yacc: 858; perl: 481; makefile: 478; lex: 94; sql: 74; csh: 6
file content (288 lines) | stat: -rw-r--r-- 11,793 bytes parent folder | download
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
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
/*=============================================================================
    Boost.Wave: A Standard compliant C++ preprocessor library
    http://www.boost.org/

    Copyright (c) 2001-2006 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)
=============================================================================*/

// system headers
#include <string>
#include <iostream>
#include <vector>

// include boost
#include <boost/config.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 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)")
            ("debug,d", po::value<int>(), "set the debug level (0...9)")
        ;

    // Hidden options, will be used in in config file analysis to allow to
    // recognise 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 (prepend the cfg file path)
                        fs::path cfgpath = fs::complete(
                            fs::path(*cit, fs::native), fs::current_path());
                        fs::path filepath = 
                            cfgpath.branch_path() / fs::path(*iit, fs::native);
                        
                        if (9 == app.get_debuglevel()) {
                            std::cerr << std::string(79, '-') << std::endl;
                            std::cerr << "executing test: " 
                                      << filepath.native_file_string()
                                      << std::endl;
                        }
                    
                    // execute this unit test case
                        if (!app.test_a_file(filepath.native_file_string())) {
                            if (9 == app.get_debuglevel()) {
                                std::cerr << "failed to execute test: " 
                                          << filepath.native_file_string()
                                          << std::endl;
                            }
                            ++error_count;
                        }
                        else if (9 == app.get_debuglevel()) {
                            std::cerr << "succeeded to execute test: " 
                                      << filepath.native_file_string()
                                      << 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((*arg).value[0], fs::native);

            if (9 == app.get_debuglevel()) {
                std::cerr << std::string(79, '-') << std::endl;
                std::cerr << "executing test: " 
                          << filepath.native_file_string()
                          << std::endl;
            }
                    
            if (!app.test_a_file(filepath.native_file_string())) {
                if (9 == app.get_debuglevel()) {
                    std::cerr << "failed to execute test: " 
                              << filepath.native_file_string()
                              << std::endl;
                }
                ++error_count;
            }
            else if (9 == app.get_debuglevel()) {
                std::cerr << "succeeded to execute test: " 
                          << filepath.native_file_string()
                          << 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;
}