1 // Copyright Leo Goodstadt 2012
2 // Distributed under the Boost Software License, Version 1.0.
3 // (See accompanying file LICENSE_1_0.txt
4 // or copy at http://www.boost.org/LICENSE_1_0.txt)
5 
6 
7 #include <boost/program_options/parsers.hpp>
8 #include <boost/program_options/options_description.hpp>
9 #include <boost/program_options/variables_map.hpp>
10 #include <boost/program_options/cmdline.hpp>
11 using namespace boost::program_options;
12 
13 #include <iostream>
14 #include <sstream>
15 #include <vector>
16 #include <cassert>
17 using namespace std;
18 
19 #include "minitest.hpp"
20 
21 
22 
23 //
24 //  like BOOST_CHECK_EQUAL but with more descriptive error message
25 //
26 #define CHECK_EQUAL(description, a, b) if (a != b) {std::cerr << "\n\nError:\n<<" << \
27         description << ">>\n  Expected text=\"" << b << "\"\n  Actual text  =\"" << a << "\"\n\n"; assert(a == b);}
28 
29 
30 // Uncomment for Debugging, removes asserts so we can see more failures!
31 //#define BOOST_ERROR(description) std::cerr << description; std::cerr << "\n";
32 
33 
34 //8888888888888888888888888888888888888888888888888888888888888888888888888888888888888888
35 //
36 //  Uncomment to print out the complete set of diagnostic messages for the different test cases
37 /*
38 #define CHECK_EQUAL(description, a, b) if (a != b) {std::cerr << "\n\nError:  " << \
39     description << "\n  Expecting\n" << b << "\n  Found\n" << a << "\n\n"; } \
40     else {std::cout << description<< "\t" << b << "\n";}
41 */
42 
43 //8888888888888888888888888888888888888888888888888888888888888888888888888888888888888888
44 
45 
46 //
47 //  test exception for each specified command line style, e.g. short dash or config file
48 //
49 template<typename EXCEPTION>
test_each_exception_message(const string & test_description,const vector<const char * > & argv,options_description & desc,int style,string exception_msg,istream & is=cin)50 void test_each_exception_message(const string& test_description, const vector<const char*>& argv, options_description& desc, int style, string exception_msg, istream& is = cin)
51 {
52     if (exception_msg.length() == 0)
53         return;
54     variables_map vm;
55     unsigned argc = argv.size();
56 
57 
58     try {
59         if (style == -1)
60             store(parse_config_file(is, desc), vm);
61         else
62             store(parse_command_line(argv.size(), &argv[0], desc, style), vm);
63         notify(vm);
64     }
65     catch (EXCEPTION& e)
66     {
67        //cerr << "Correct:\n\t" << e.what() << "\n";
68        CHECK_EQUAL(test_description, e.what(), exception_msg);
69        return;
70     }
71     catch (std::exception& e)
72     {
73         // concatenate argv without boost::algorithm::join
74         string argv_txt;
75         for (unsigned ii = 0; ii < argc - 1; ++ii)
76             argv_txt += argv[ii] + string(" ");
77         if (argc)
78             argv_txt += argv[argc - 1];
79 
80        BOOST_ERROR("\n<<" + test_description +
81                     string(">>\n  Unexpected exception type!\n  Actual text  =\"") + e.what() +
82                     "\"\n  argv         =\"" + argv_txt +
83                     "\"\n  Expected text=\"" + exception_msg + "\"\n");
84        return;
85     }
86     BOOST_ERROR(test_description + ": No exception thrown. ");
87 }
88 
89 
90 
91 
92 //
93 //  test exception messages for all command line styles (unix/long/short/slash/config file)
94 //
95 //      try each command line style in turn
96 const int unix_style = command_line_style::unix_style;
97 const int short_dash = command_line_style::allow_dash_for_short | command_line_style::allow_short | command_line_style::short_allow_adjacent | command_line_style::allow_sticky;
98 const int short_slash = command_line_style::allow_slash_for_short | command_line_style::allow_short | command_line_style::short_allow_adjacent;
99 const int long_dash = command_line_style::allow_long | command_line_style::long_allow_adjacent | command_line_style::allow_guessing;
100 
101 
102 
103 template<typename EXCEPTION>
test_exception_message(const vector<vector<const char * >> & argv,options_description & desc,const string & error_description,const char * expected_message_template[5])104 void test_exception_message(const vector<vector<const char*> >& argv,
105                             options_description& desc,
106                             const string& error_description,
107                             const char* expected_message_template[5])
108 {
109     string expected_message;
110 
111     // unix
112     expected_message = expected_message_template[0];
113     test_each_exception_message<EXCEPTION>(error_description + " -- unix",
114                                   argv[0], desc, unix_style, expected_message);
115 
116     // long dash only
117     expected_message = expected_message_template[1];
118     test_each_exception_message<EXCEPTION>(error_description + " -- long_dash",
119                                   argv[1], desc, long_dash, expected_message);
120 
121 
122     // short dash only
123     expected_message = expected_message_template[2];
124     test_each_exception_message<EXCEPTION>(error_description + " -- short_dash",
125                                   argv[2], desc, short_dash, expected_message);
126 
127     // short slash only
128     expected_message = expected_message_template[3];
129     test_each_exception_message<EXCEPTION>(error_description + " -- short_slash",
130                                   argv[3], desc, short_slash, expected_message);
131 
132     // config file only
133     expected_message = expected_message_template[4];
134     if (expected_message.length())
135     {
136         istringstream istrm(argv[4][0]);
137         test_each_exception_message<EXCEPTION>(error_description + " -- config_file",
138                                           argv[4], desc, -1, expected_message, istrm);
139     }
140 
141 }
142 
143 #define VEC_STR_PUSH_BACK(vec, c_array)  \
144     vec.push_back(vector<const char*>(c_array, c_array + sizeof(c_array) / sizeof(char*)));
145 
146 //________________________________________________________________________________________
147 //
148 //  invalid_option_value
149 //
150 //________________________________________________________________________________________
test_invalid_option_value_exception_msg()151 void test_invalid_option_value_exception_msg()
152 {
153     options_description desc;
154     desc.add_options()
155         ("int-option,d", value< int >(),        "An option taking an integer")
156     ;
157 
158     vector<vector<const char*> > argv;
159     const char* argv0[] = { "program", "-d", "A_STRING"}   ;  VEC_STR_PUSH_BACK(argv, argv0);
160     const char* argv1[] = { "program", "--int", "A_STRING"};  VEC_STR_PUSH_BACK(argv, argv1);
161     const char* argv2[] = { "program", "-d", "A_STRING"}   ;  VEC_STR_PUSH_BACK(argv, argv2);
162     const char* argv3[] = { "program", "/d", "A_STRING"}   ;  VEC_STR_PUSH_BACK(argv, argv3);
163     const char* argv4[] = { "int-option=A_STRING"}         ;  VEC_STR_PUSH_BACK(argv, argv4);
164 
165     const char* expected_msg[5] = {
166                                 "the argument ('A_STRING') for option '--int-option' is invalid",
167                                 "the argument ('A_STRING') for option '--int-option' is invalid",
168                                 "the argument ('A_STRING') for option '-d' is invalid",
169                                 "the argument ('A_STRING') for option '/d' is invalid",
170                                 "the argument ('A_STRING') for option 'int-option' is invalid",
171     };
172 
173 
174     test_exception_message<invalid_option_value>(argv, desc, "invalid_option_value",
175                                                  expected_msg);
176 
177 
178 }
179 
180 //________________________________________________________________________________________
181 //
182 //  missing_value
183 //
184 //________________________________________________________________________________________
test_missing_value_exception_msg()185 void test_missing_value_exception_msg()
186 {
187     options_description desc;
188     desc.add_options()
189         ("cfgfile,e", value<string>(), "the config file")
190         ("output,o", value<string>(), "the output file")
191     ;
192     vector<vector<const char*> > argv;
193     const char* argv0[] = { "program", "-e", "-e", "output.txt"} ; VEC_STR_PUSH_BACK(argv, argv0);
194     const char* argv1[] = { "program", "--cfgfile"}              ; VEC_STR_PUSH_BACK(argv, argv1);
195     const char* argv2[] = { "program", "-e", "-e", "output.txt"} ; VEC_STR_PUSH_BACK(argv, argv2);
196     const char* argv3[] = { "program", "/e", "/e", "output.txt"} ; VEC_STR_PUSH_BACK(argv, argv3);
197     const char* argv4[] = { ""}    ;      VEC_STR_PUSH_BACK(argv, argv4);
198 
199     const char* expected_msg[5] = {
200                                 "the required argument for option '--cfgfile' is missing",
201                                 "the required argument for option '--cfgfile' is missing",
202                                 "the required argument for option '-e' is missing",
203                                 "", // Ignore probable bug in cmdline::finish_option
204                                     //"the required argument for option '/e' is missing",
205                                 "",
206     };
207     test_exception_message<invalid_command_line_syntax>(argv, desc,
208                                                         "invalid_syntax::missing_parameter",
209                                                         expected_msg);
210 }
211 
212 //________________________________________________________________________________________
213 //
214 //  ambiguous_option
215 //
216 //________________________________________________________________________________________
test_ambiguous_option_exception_msg()217 void test_ambiguous_option_exception_msg()
218 {
219     options_description desc;
220     desc.add_options()
221         ("cfgfile1,c", value<string>(), "the config file")
222         ("cfgfile2,o",  value<string>(), "the config file")
223         ("good,g",                          "good option")
224         ("output,c",   value<string>(), "the output file")
225         ("output",     value<string>(), "the output file")
226     ;
227 
228     vector<vector<const char*> > argv;
229     const char* argv0[] = {"program", "-ggc", "file", "-o", "anotherfile"}             ; VEC_STR_PUSH_BACK(argv, argv0);
230     const char* argv1[] = {"program", "--cfgfile", "file", "--cfgfile", "anotherfile"} ; VEC_STR_PUSH_BACK(argv, argv1);
231     const char* argv2[] = {"program", "-ggc", "file", "-o", "anotherfile"}             ; VEC_STR_PUSH_BACK(argv, argv2);
232     const char* argv3[] = {"program", "/c", "file", "/o", "anotherfile"}               ; VEC_STR_PUSH_BACK(argv, argv3);
233     const char* argv4[] = { "output=output.txt\n"}                                     ; VEC_STR_PUSH_BACK(argv, argv4);
234     const char* expected_msg[5] = {
235                                 "option '-c' is ambiguous and matches '--cfgfile1', and '--output'",
236                                 "option '--cfgfile' is ambiguous and matches '--cfgfile1', and '--cfgfile2'",
237                                 "option '-c' is ambiguous",
238                                 "option '/c' is ambiguous",
239                                 "option 'output' is ambiguous and matches different versions of 'output'",
240     };
241     test_exception_message<ambiguous_option>(argv, desc, "ambiguous_option",
242                                              expected_msg);
243 }
244 
245 //________________________________________________________________________________________
246 //
247 //  multiple_occurrences
248 //
249 //________________________________________________________________________________________
test_multiple_occurrences_exception_msg()250 void test_multiple_occurrences_exception_msg()
251 {
252     options_description desc;
253     desc.add_options()
254                 ("cfgfile,c", value<string>(), "the configfile")
255     ;
256 
257     vector<vector<const char*> > argv;
258     const char* argv0[] = {"program", "-c", "file", "-c", "anotherfile"}           ; VEC_STR_PUSH_BACK(argv, argv0);
259     const char* argv1[] = {"program", "--cfgfi", "file", "--cfgfi", "anotherfile"} ; VEC_STR_PUSH_BACK(argv, argv1);
260     const char* argv2[] = {"program", "-c", "file", "-c", "anotherfile"}           ; VEC_STR_PUSH_BACK(argv, argv2);
261     const char* argv3[] = {"program", "/c", "file", "/c", "anotherfile"}           ; VEC_STR_PUSH_BACK(argv, argv3);
262     const char* argv4[] = { "cfgfile=output.txt\ncfgfile=output.txt\n"}            ; VEC_STR_PUSH_BACK(argv, argv4);
263     const char* expected_msg[5] = {
264                                 "option '--cfgfile' cannot be specified more than once",
265                                 "option '--cfgfile' cannot be specified more than once",
266                                 "option '-c' cannot be specified more than once",
267                                 "option '/c' cannot be specified more than once",
268                                 "option 'cfgfile' cannot be specified more than once",
269     };
270     test_exception_message<multiple_occurrences>(argv, desc, "multiple_occurrences",
271                                                 expected_msg);
272 }
273 
274 //________________________________________________________________________________________
275 //
276 //  unknown_option
277 //
278 //________________________________________________________________________________________
test_unknown_option_exception_msg()279 void test_unknown_option_exception_msg()
280 {
281     options_description desc;
282     desc.add_options()
283         ("good,g",                          "good option")
284     ;
285 
286     vector<vector<const char*> > argv;
287     const char* argv0[] = {"program", "-ggc", "file"}      ; VEC_STR_PUSH_BACK(argv, argv0);
288     const char* argv1[] = {"program", "--cfgfile", "file"} ; VEC_STR_PUSH_BACK(argv, argv1);
289     const char* argv2[] = {"program", "-ggc", "file"}      ; VEC_STR_PUSH_BACK(argv, argv2);
290     const char* argv3[] = {"program", "/c", "file"}        ; VEC_STR_PUSH_BACK(argv, argv3);
291     const char* argv4[] = { "cfgfile=output.txt\n"}        ; VEC_STR_PUSH_BACK(argv, argv4);
292     const char* expected_msg[5] = {
293                                 "unrecognised option '-ggc'",
294                                 "unrecognised option '--cfgfile'",
295                                 "unrecognised option '-ggc'",
296                                 "unrecognised option '/c'",
297                                 "unrecognised option 'cfgfile'",
298     };
299     test_exception_message<unknown_option>(argv, desc, "unknown_option", expected_msg);
300 }
301 
302 //________________________________________________________________________________________
303 //
304 //  validation_error::invalid_bool_value
305 //
306 //________________________________________________________________________________________
test_invalid_bool_value_exception_msg()307 void test_invalid_bool_value_exception_msg()
308 {
309     options_description desc;
310     desc.add_options()
311         ("bool_option,b",       value< bool>(), "bool_option")
312         ;
313 
314 
315     vector<vector<const char*> > argv;
316     const char* argv0[] = {"program", "-b", "file"}           ; VEC_STR_PUSH_BACK(argv, argv0);
317     const char* argv1[] = {"program", "--bool_optio", "file"} ; VEC_STR_PUSH_BACK(argv, argv1);
318     const char* argv2[] = {"program", "-b", "file"}           ; VEC_STR_PUSH_BACK(argv, argv2);
319     const char* argv3[] = {"program", "/b", "file"}           ; VEC_STR_PUSH_BACK(argv, argv3);
320     const char* argv4[] = { "bool_option=output.txt\n"}       ; VEC_STR_PUSH_BACK(argv, argv4);
321     const char* expected_msg[5] = {
322                                 "the argument ('file') for option '--bool_option' is invalid. Valid choices are 'on|off', 'yes|no', '1|0' and 'true|false'",
323                                 "the argument ('file') for option '--bool_option' is invalid. Valid choices are 'on|off', 'yes|no', '1|0' and 'true|false'",
324                                 "the argument ('file') for option '-b' is invalid. Valid choices are 'on|off', 'yes|no', '1|0' and 'true|false'",
325                                 "the argument ('file') for option '/b' is invalid. Valid choices are 'on|off', 'yes|no', '1|0' and 'true|false'",
326                                 "the argument ('output.txt') for option 'bool_option' is invalid. Valid choices are 'on|off', 'yes|no', '1|0' and 'true|false'",
327     };
328     test_exception_message<validation_error>(argv,
329                                 desc,
330                                 "validation_error::invalid_bool_value",
331                                 expected_msg);
332 }
333 
334 
335 
336 
337 //________________________________________________________________________________________
338 //
339 //  validation_error::multiple_values_not_allowed
340 //
341 //________________________________________________________________________________________
342 //
343 //  Strange exception: sole purpose seems to be catching multitoken() associated with a scalar
344 //  validation_error::multiple_values_not_allowed seems thus to be a programmer error
345 //
346 //
test_multiple_values_not_allowed_exception_msg()347 void test_multiple_values_not_allowed_exception_msg()
348 {
349     options_description desc;
350     desc.add_options()
351          ("cfgfile,c", value<string>()->multitoken(), "the config file")
352          ("good,g",                                     "good option")
353          ("output,o", value<string>(),                  "the output file")
354        ;
355 
356     vector<vector<const char*> > argv;
357     const char* argv0[] = { "program", "-c", "file", "c", "-o", "fritz", "hugo" }              ;      VEC_STR_PUSH_BACK(argv, argv0);
358     const char* argv1[] = { "program", "--cfgfil", "file", "c", "--outpu", "fritz", "hugo" }   ;      VEC_STR_PUSH_BACK(argv, argv1);
359     const char* argv2[] = { "program", "-c", "file", "c", "-o", "fritz", "hugo"}               ;      VEC_STR_PUSH_BACK(argv, argv2);
360     const char* argv3[] = { "program", "/c", "file", "c", "/o", "fritz", "hugo"}               ;      VEC_STR_PUSH_BACK(argv, argv3);
361     const char* argv4[] = { "" }                                                               ;      VEC_STR_PUSH_BACK(argv, argv4);
362     const char* expected_msg[5] = {
363                                 "option '--cfgfile' only takes a single argument",
364                                 "option '--cfgfile' only takes a single argument",
365                                 "option '-c' only takes a single argument",
366                                 "option '/c' only takes a single argument",
367                                 "",
368     };
369     test_exception_message<validation_error>(argv,
370                                 desc,
371                                 "validation_error::multiple_values_not_allowed",
372                                 expected_msg);
373 }
374 
375 //________________________________________________________________________________________
376 //
377 //  validation_error::at_least_one_value_required
378 //
379 //________________________________________________________________________________________
380 //
381 //  Strange exception: sole purpose seems to be catching zero_tokens() associated with a scalar
382 //  validation_error::multiple_values_not_allowed seems thus to be a programmer error
383 //
384 //
test_at_least_one_value_required_exception_msg()385 void test_at_least_one_value_required_exception_msg()
386 {
387 
388 
389     options_description desc;
390     desc.add_options()
391          ("cfgfile,c", value<int>()->zero_tokens(), "the config file")
392          ("other,o", value<string>(), "other")
393        ;
394 
395     vector<vector<const char*> > argv;
396     const char* argv0[] = { "program", "-c"                       }  ;      VEC_STR_PUSH_BACK(argv, argv0);
397     const char* argv1[] = { "program", "--cfg", "--o", "name"     }  ;      VEC_STR_PUSH_BACK(argv, argv1);
398     const char* argv2[] = { "program", "-c"   , "-o"   , "name"   }  ;      VEC_STR_PUSH_BACK(argv, argv2);
399     const char* argv3[] = { "program", "/c"                       }  ;      VEC_STR_PUSH_BACK(argv, argv3);
400     const char* argv4[] = { ""                                    }  ;      VEC_STR_PUSH_BACK(argv, argv4);
401     const char* expected_msg[5] = {
402                                 "option '--cfgfile' requires at least one argument",
403                                 "option '--cfgfile' requires at least one argument",
404                                 "option '-c' requires at least one argument",
405                                 "option '/c' requires at least one argument",
406                                 "",
407     };
408     test_exception_message<validation_error>(argv,
409                                 desc,
410                                 "validation_error::at_least_one_value_required",
411                                 expected_msg);
412 }
413 
414 
415 //________________________________________________________________________________________
416 //
417 //  required_option
418 //
419 //________________________________________________________________________________________
test_required_option_exception_msg()420 void test_required_option_exception_msg()
421 {
422     options_description desc;
423     desc.add_options()
424          ("cfgfile,c", value<string>()->required(), "the config file")
425          ("good,g",                                 "good option")
426          ("output,o", value<string>()->required(),  "the output file")
427        ;
428 
429     vector<vector<const char*> > argv;
430     const char* argv0[] = { "program", "-g" }    ;      VEC_STR_PUSH_BACK(argv, argv0);
431     const char* argv1[] = { "program", "--g" }   ;      VEC_STR_PUSH_BACK(argv, argv1);
432     const char* argv2[] = { "program", "-g"}     ;      VEC_STR_PUSH_BACK(argv, argv2);
433     const char* argv3[] = { "program", "/g"}     ;      VEC_STR_PUSH_BACK(argv, argv3);
434     const char* argv4[] = { "" }                 ;      VEC_STR_PUSH_BACK(argv, argv4);
435     const char* expected_msg[5] = {
436                                 "the option '--cfgfile' is required but missing",
437                                 "the option '--cfgfile' is required but missing",
438                                 "the option '-c' is required but missing",
439                                 "the option '/c' is required but missing",
440                                 "the option 'cfgfile' is required but missing",
441     };
442     test_exception_message<required_option>(argv,
443                                 desc,
444                                 "required_option",
445                                 expected_msg);
446 }
447 
448 
449 
450 
451 
452 
453 
454 
455 
456 
457 
458 
459 
460 
461 
462 
463 /**
464  * Check if this is the expected exception with the right message is being thrown inside
465  * func
466 */
467 template <typename EXCEPTION, typename FUNC>
test_exception(const string & test_name,const string & exception_txt,FUNC func)468 void test_exception(const string& test_name, const string& exception_txt, FUNC func)
469 {
470 
471     try {
472         options_description desc;
473         variables_map vm;
474         func(desc, vm);
475     }
476     catch (EXCEPTION& e)
477     {
478        CHECK_EQUAL(test_name, e.what(), exception_txt);
479        return;
480     }
481     catch (std::exception& e)
482     {
483        BOOST_ERROR(string(test_name + ":\nUnexpected exception. ") + e.what() +
484                    "\nExpected text:\n" + exception_txt + "\n\n");
485        return;
486     }
487     BOOST_ERROR(test_name + ": No exception thrown. ");
488 }
489 
490 
491 
492 //________________________________________________________________________________________
493 //
494 //  check_reading_file
495 //
496 //________________________________________________________________________________________
check_reading_file(options_description & desc,variables_map & vm)497 void check_reading_file(options_description& desc, variables_map& vm)
498 {
499     desc.add_options()
500          ("output,o", value<string>(), "the output file");
501 
502     const char* file_name = "no_such_file";
503     store(parse_config_file<char>(file_name, desc, true), vm);
504 
505 }
506 
507 
508 //________________________________________________________________________________________
509 //
510 //  config_file_wildcard
511 //
512 //________________________________________________________________________________________
config_file_wildcard(options_description & desc,variables_map & vm)513 void config_file_wildcard(options_description& desc, variables_map& vm)
514 {
515     desc.add_options()
516          ("outpu*", value<string>(), "the output file1")
517          ("outp*",    value<string>(), "the output file2")
518        ;
519     istringstream is("output1=whichone\noutput2=whichone\n");
520     store(parse_config_file(is, desc), vm);
521 }
522 
523 //________________________________________________________________________________________
524 //
525 //  invalid_syntax::unrecognized_line
526 //
527 //________________________________________________________________________________________
unrecognized_line(options_description & desc,variables_map & vm)528 void unrecognized_line(options_description& desc, variables_map& vm)
529 {
530     istringstream is("funny wierd line\n");
531     store(parse_config_file(is, desc), vm);
532 }
533 
534 //________________________________________________________________________________________
535 //
536 //  abbreviated_options_in_config_file
537 //
538 //________________________________________________________________________________________
abbreviated_options_in_config_file(options_description & desc,variables_map & vm)539 void abbreviated_options_in_config_file(options_description& desc, variables_map& vm)
540 {
541     desc.add_options()(",o", value<string>(), "the output file");
542     istringstream is("o=output.txt\n");
543     store(parse_config_file(is, desc), vm);
544 }
545 
546 
547 //________________________________________________________________________________________
548 //
549 //  too_many_positional_options
550 //
551 //________________________________________________________________________________________
too_many_positional_options(options_description & desc,variables_map & vm)552 void too_many_positional_options(options_description& desc, variables_map& vm)
553 {
554     const char* argv[] = {"program", "1", "2", "3"};
555     positional_options_description positional_args;
556     positional_args.add("two_positional_arguments", 2);
557     store(command_line_parser(4, argv).options(desc).positional(positional_args).run(), vm);
558 }
559 
560 
561 //________________________________________________________________________________________
562 //
563 //  invalid_command_line_style
564 //
565 //________________________________________________________________________________________
566 
test_invalid_command_line_style_exception_msg()567 void test_invalid_command_line_style_exception_msg()
568 {
569     string test_name = "invalid_command_line_style";
570     using namespace command_line_style;
571     options_description desc;
572     desc.add_options()("output,o", value<string>(), "the output file");
573 
574     vector<int> invalid_styles;
575     invalid_styles.push_back(allow_short | short_allow_adjacent);
576     invalid_styles.push_back(allow_short | allow_dash_for_short);
577     invalid_styles.push_back(allow_long);
578     vector<string> invalid_diagnostics;
579     invalid_diagnostics.push_back("boost::program_options misconfiguration: choose one "
580                                   "or other of 'command_line_style::allow_slash_for_short' "
581                                   "(slashes) or 'command_line_style::allow_dash_for_short' "
582                                   "(dashes) for short options.");
583     invalid_diagnostics.push_back("boost::program_options misconfiguration: choose one "
584                                   "or other of 'command_line_style::short_allow_next' "
585                                   "(whitespace separated arguments) or "
586                                   "'command_line_style::short_allow_adjacent' ('=' "
587                                   "separated arguments) for short options.");
588     invalid_diagnostics.push_back("boost::program_options misconfiguration: choose one "
589                                   "or other of 'command_line_style::long_allow_next' "
590                                   "(whitespace separated arguments) or "
591                                   "'command_line_style::long_allow_adjacent' ('=' "
592                                   "separated arguments) for long options.");
593 
594 
595     const char* argv[] = {"program"};
596     variables_map vm;
597     for (unsigned ii = 0; ii < 3; ++ii)
598     {
599         bool exception_thrown = false;
600         try
601         {
602             store(parse_command_line(1, argv, desc, invalid_styles[ii]), vm);
603         }
604         catch (invalid_command_line_style& e)
605         {
606            string error_msg("arguments are not allowed for unabbreviated option names");
607            CHECK_EQUAL(test_name, e.what(), invalid_diagnostics[ii]);
608            exception_thrown = true;
609         }
610         catch (std::exception& e)
611         {
612            BOOST_ERROR(string(test_name + ":\nUnexpected exception. ") + e.what() +
613                             "\nExpected text:\n" + invalid_diagnostics[ii] + "\n");
614            exception_thrown = true;
615         }
616         if (!exception_thrown)
617         {
618             BOOST_ERROR(test_name << ": No exception thrown. ");
619         }
620     }
621 }
622 
623 
624 
main(int,char **)625 int main(int /*ac*/, char** /*av*/)
626 {
627    test_ambiguous_option_exception_msg();
628    test_unknown_option_exception_msg();
629    test_multiple_occurrences_exception_msg();
630    test_missing_value_exception_msg();
631    test_invalid_option_value_exception_msg();
632    test_invalid_bool_value_exception_msg();
633    test_multiple_values_not_allowed_exception_msg();
634    test_required_option_exception_msg();
635    test_at_least_one_value_required_exception_msg();
636 
637    string test_name;
638    string expected_message;
639 
640 
641    // check_reading_file
642    test_name        = "check_reading_file";
643    expected_message = "can not read options configuration file 'no_such_file'";
644    test_exception<reading_file>(test_name, expected_message, check_reading_file);
645 
646    // config_file_wildcard
647    test_name        = "config_file_wildcard";
648    expected_message = "options 'outpu*' and 'outp*' will both match the same arguments from the configuration file";
649    test_exception<error>(test_name, expected_message, config_file_wildcard);
650 
651    // unrecognized_line
652    test_name        = "unrecognized_line";
653    expected_message = "the options configuration file contains an invalid line 'funny wierd line'";
654    test_exception<invalid_syntax>(test_name, expected_message, unrecognized_line);
655 
656 
657    // abbreviated_options_in_config_file
658    test_name        = "abbreviated_options_in_config_file";
659    expected_message = "abbreviated option names are not permitted in options configuration files";
660    test_exception<error>(test_name, expected_message, abbreviated_options_in_config_file);
661 
662    test_name        = "too_many_positional_options";
663    expected_message = "too many positional options have been specified on the command line";
664    test_exception<too_many_positional_options_error>(
665                           test_name, expected_message, too_many_positional_options);
666 
667    test_invalid_command_line_style_exception_msg();
668 
669 
670    return 0;
671 }
672 
673