]>
Commit | Line | Data |
---|---|---|
7c673cae FG |
1 | /*============================================================================= |
2 | Boost.Wave: A Standard compliant C++ preprocessor library | |
3 | http://www.boost.org/ | |
4 | ||
5 | Copyright (c) 2001-2012 Hartmut Kaiser. Distributed under the Boost | |
6 | Software License, Version 1.0. (See accompanying file | |
7 | LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) | |
8 | =============================================================================*/ | |
9 | ||
10 | // disable stupid compiler warnings | |
11 | #include <boost/config/warning_disable.hpp> | |
12 | ||
13 | // system headers | |
14 | #include <string> | |
15 | #include <iostream> | |
16 | #include <vector> | |
17 | ||
18 | // include boost | |
19 | #include <boost/config.hpp> | |
20 | #include <boost/wave.hpp> | |
21 | #include <boost/filesystem/path.hpp> | |
22 | #include <boost/filesystem/operations.hpp> | |
23 | ||
24 | // test application related headers | |
25 | #include "cmd_line_utils.hpp" | |
26 | #include "testwave_app.hpp" | |
27 | ||
28 | namespace po = boost::program_options; | |
29 | namespace fs = boost::filesystem; | |
30 | ||
31 | /////////////////////////////////////////////////////////////////////////////// | |
32 | // | |
33 | // The debuglevel command line parameter is used to control the amount of text | |
34 | // printed by the testwave application. | |
35 | // | |
36 | // level 0: prints nothing except serious failures preventing the testwave | |
37 | // executable from running, the return value of the executable is | |
38 | // equal to the number of failed tests | |
39 | // level 1: prints a short summary only | |
40 | // level 2: prints the names of the failed tests only | |
41 | // level 3: prints the expected and real result for failed tests | |
42 | // level 4: prints the outcome of every test | |
43 | // level 5: prints the real result even for succeeded tests | |
44 | // level 6: prints the real hooks information recorded, even for succeeded | |
45 | // tests | |
46 | // | |
47 | // level 9: prints information about almost everything | |
48 | // | |
49 | // The default debug level is 1. | |
50 | // | |
51 | /////////////////////////////////////////////////////////////////////////////// | |
52 | ||
53 | /////////////////////////////////////////////////////////////////////////////// | |
54 | int | |
55 | main(int argc, char *argv[]) | |
56 | { | |
57 | int error_count = 0; | |
58 | int config_file_error_count = 0; | |
59 | try { | |
20effc67 | 60 | // analyze the command line options and arguments |
7c673cae FG |
61 | po::options_description desc_cmdline ("Options allowed on the command line"); |
62 | desc_cmdline.add_options() | |
63 | ("help,h", "print out program usage (this message)") | |
64 | ("version,v", "print the version number") | |
65 | ("copyright,c", "print out the copyright statement") | |
66 | ("config-file", po::value<std::vector<std::string> >()->composing(), | |
67 | "specify a config file (alternatively: @arg)") | |
68 | ("hooks", po::value<bool>()->default_value(true), | |
69 | "test preprocessing hooks") | |
70 | ("debug,d", po::value<int>(), "set the debug level (0...9)") | |
71 | ; | |
72 | ||
20effc67 TL |
73 | // Hidden options, will be used in in config file analysis to allow to |
74 | // recognize positional arguments, will not be shown to the user. | |
7c673cae FG |
75 | po::options_description desc_hidden("Hidden options"); |
76 | desc_hidden.add_options() | |
77 | ("input", po::value<std::vector<std::string> >()->composing(), | |
78 | "inputfile") | |
79 | ; | |
80 | ||
20effc67 | 81 | // this is the test application object |
7c673cae FG |
82 | po::variables_map vm; |
83 | testwave_app app(vm); | |
84 | ||
20effc67 | 85 | // all command line and config file options |
7c673cae FG |
86 | po::options_description cmdline_options; |
87 | cmdline_options.add(desc_cmdline).add(app.common_options()); | |
88 | ||
20effc67 | 89 | // parse command line |
7c673cae FG |
90 | // (the (int) cast is to make the True64 compiler happy) |
91 | using namespace boost::program_options::command_line_style; | |
92 | po::parsed_options opts(po::parse_command_line(argc, argv, | |
93 | cmdline_options, (int)unix_style, cmd_line_utils::at_option_parser)); | |
94 | ||
95 | po::store(opts, vm); | |
96 | po::notify(vm); | |
97 | ||
20effc67 | 98 | // ... act as required |
7c673cae FG |
99 | if (vm.count("help")) { |
100 | po::options_description desc_help ( | |
101 | "Usage: testwave [options] [@config-file(s)] file(s)"); | |
102 | desc_help.add(desc_cmdline).add(app.common_options()); | |
103 | std::cout << desc_help << std::endl; | |
104 | return 0; | |
105 | } | |
106 | ||
20effc67 | 107 | // debug flag |
7c673cae FG |
108 | if (vm.count("debug")) { |
109 | int debug_level = vm["debug"].as<int>(); | |
110 | if (debug_level < 0 || debug_level > 9) { | |
111 | std::cerr | |
112 | << "testwave: please use an integer in the range [0..9] " | |
113 | << "as the parameter to the debug option!" | |
114 | << std::endl; | |
115 | } | |
116 | else { | |
117 | app.set_debuglevel(debug_level); | |
118 | } | |
119 | } | |
120 | ||
121 | if (vm.count("version")) { | |
122 | return app.print_version(); | |
123 | } | |
124 | ||
125 | if (vm.count("copyright")) { | |
126 | return app.print_copyright(); | |
127 | } | |
128 | ||
20effc67 TL |
129 | // If there is specified at least one config file, parse it and add the |
130 | // options to the main variables_map | |
131 | // Each of the config files is parsed into a separate variables_map to | |
132 | // allow correct paths handling. | |
7c673cae FG |
133 | int input_count = 0; |
134 | if (vm.count("config-file")) { | |
135 | std::vector<std::string> const &cfg_files = | |
136 | vm["config-file"].as<std::vector<std::string> >(); | |
137 | ||
138 | if (9 == app.get_debuglevel()) { | |
139 | std::cerr << "found " << (unsigned)cfg_files.size() | |
140 | << " config-file arguments" << std::endl; | |
141 | } | |
142 | ||
143 | std::vector<std::string>::const_iterator end = cfg_files.end(); | |
144 | for (std::vector<std::string>::const_iterator cit = cfg_files.begin(); | |
145 | cit != end; ++cit) | |
146 | { | |
147 | if (9 == app.get_debuglevel()) { | |
148 | std::cerr << "reading config_file: " << *cit << std::endl; | |
149 | } | |
150 | ||
20effc67 TL |
151 | // parse a single config file and store the results, config files |
152 | // may only contain --input and positional arguments | |
7c673cae FG |
153 | po::variables_map cvm; |
154 | if (!cmd_line_utils::read_config_file(app.get_debuglevel(), | |
155 | *cit, desc_hidden, cvm)) | |
156 | { | |
157 | if (9 == app.get_debuglevel()) { | |
158 | std::cerr << "failed to read config_file: " << *cit | |
159 | << std::endl; | |
160 | } | |
161 | ++config_file_error_count; | |
162 | } | |
163 | ||
164 | if (9 == app.get_debuglevel()) { | |
165 | std::cerr << "succeeded to read config_file: " << *cit | |
166 | << std::endl; | |
167 | } | |
168 | ||
20effc67 | 169 | // correct the paths parsed into this variables_map |
7c673cae FG |
170 | if (cvm.count("input")) { |
171 | std::vector<std::string> const &infiles = | |
172 | cvm["input"].as<std::vector<std::string> >(); | |
173 | ||
174 | if (9 == app.get_debuglevel()) { | |
175 | std::cerr << "found " << (unsigned)infiles.size() | |
176 | << " entries" << std::endl; | |
177 | } | |
178 | ||
179 | std::vector<std::string>::const_iterator iend = infiles.end(); | |
180 | for (std::vector<std::string>::const_iterator iit = infiles.begin(); | |
181 | iit != iend; ++iit) | |
182 | { | |
20effc67 | 183 | // correct the file name (pre-pend the config file path) |
7c673cae FG |
184 | fs::path cfgpath = boost::wave::util::complete_path( |
185 | boost::wave::util::create_path(*cit), | |
186 | boost::wave::util::current_path()); | |
187 | fs::path filepath = | |
188 | boost::wave::util::branch_path(cfgpath) / | |
189 | boost::wave::util::create_path(*iit); | |
190 | ||
191 | if (9 == app.get_debuglevel()) { | |
192 | std::cerr << std::string(79, '-') << std::endl; | |
193 | std::cerr << "executing test: " | |
194 | << boost::wave::util::native_file_string(filepath) | |
195 | << std::endl; | |
196 | } | |
197 | ||
20effc67 | 198 | // execute this unit test case |
7c673cae FG |
199 | if (!app.test_a_file( |
200 | boost::wave::util::native_file_string(filepath))) | |
201 | { | |
202 | if (9 == app.get_debuglevel()) { | |
203 | std::cerr << "failed to execute test: " | |
204 | << boost::wave::util::native_file_string(filepath) | |
205 | << std::endl; | |
206 | } | |
207 | ++error_count; | |
208 | } | |
209 | else if (9 == app.get_debuglevel()) { | |
210 | std::cerr << "succeeded to execute test: " | |
211 | << boost::wave::util::native_file_string(filepath) | |
212 | << std::endl; | |
213 | } | |
214 | ++input_count; | |
215 | ||
216 | if (9 == app.get_debuglevel()) { | |
217 | std::cerr << std::string(79, '-') << std::endl; | |
218 | } | |
219 | } | |
220 | } | |
221 | else if (9 == app.get_debuglevel()) { | |
222 | std::cerr << "no entries found" << std::endl; | |
223 | } | |
224 | } | |
225 | } | |
226 | ||
20effc67 | 227 | // extract the arguments from the parsed command line |
7c673cae FG |
228 | std::vector<po::option> arguments; |
229 | std::remove_copy_if(opts.options.begin(), opts.options.end(), | |
230 | std::back_inserter(arguments), cmd_line_utils::is_argument()); | |
231 | ||
232 | if (9 == app.get_debuglevel()) { | |
233 | std::cerr << "found " << (unsigned)arguments.size() | |
234 | << " arguments" << std::endl; | |
235 | } | |
236 | ||
20effc67 | 237 | // iterate over remaining arguments |
7c673cae FG |
238 | std::vector<po::option>::const_iterator arg_end = arguments.end(); |
239 | for (std::vector<po::option>::const_iterator arg = arguments.begin(); | |
240 | arg != arg_end; ++arg) | |
241 | { | |
242 | fs::path filepath(boost::wave::util::create_path((*arg).value[0])); | |
243 | ||
244 | if (9 == app.get_debuglevel()) { | |
245 | std::cerr << std::string(79, '-') << std::endl; | |
246 | std::cerr << "executing test: " | |
247 | << boost::wave::util::native_file_string(filepath) | |
248 | << std::endl; | |
249 | } | |
250 | ||
251 | if (!app.test_a_file(boost::wave::util::native_file_string(filepath))) | |
252 | { | |
253 | if (9 == app.get_debuglevel()) { | |
254 | std::cerr << "failed to execute test: " | |
255 | << boost::wave::util::native_file_string(filepath) | |
256 | << std::endl; | |
257 | } | |
258 | ++error_count; | |
259 | } | |
260 | else if (9 == app.get_debuglevel()) { | |
261 | std::cerr << "succeeded to execute test: " | |
262 | << boost::wave::util::native_file_string(filepath) | |
263 | << std::endl; | |
264 | } | |
265 | ||
266 | if (9 == app.get_debuglevel()) { | |
267 | std::cerr << std::string(79, '-') << std::endl; | |
268 | } | |
269 | ++input_count; | |
270 | } | |
271 | ||
20effc67 | 272 | // print a message if no input is given |
7c673cae FG |
273 | if (0 == input_count) { |
274 | std::cerr | |
275 | << "testwave: no input file specified, " | |
276 | << "try --help to get a hint." | |
277 | << std::endl; | |
278 | return (std::numeric_limits<int>::max)() - 3; | |
279 | } | |
280 | else if (app.get_debuglevel() > 0) { | |
281 | std::cout | |
282 | << "testwave: " << input_count-error_count | |
283 | << " of " << input_count << " test(s) succeeded"; | |
284 | if (0 != error_count) { | |
285 | std::cout | |
286 | << " (" << error_count << " test(s) failed)"; | |
287 | } | |
288 | std::cout << "." << std::endl; | |
289 | } | |
290 | } | |
291 | catch (std::exception const& e) { | |
292 | std::cerr << "testwave: exception caught: " << e.what() << std::endl; | |
293 | return (std::numeric_limits<int>::max)() - 1; | |
294 | } | |
295 | catch (...) { | |
296 | std::cerr << "testwave: unexpected exception caught." << std::endl; | |
297 | return (std::numeric_limits<int>::max)() - 2; | |
298 | } | |
299 | ||
300 | return error_count + config_file_error_count; | |
301 | } |