exception_txt_test.cpp 29 KB

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