🛠️🐜 Antkeeper superbuild with dependencies included https://antkeeper.com
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

832 lines
23 KiB

2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
  1. #include "catch.hpp"
  2. #include <initializer_list>
  3. #include "cxxopts.hpp"
  4. class Argv {
  5. public:
  6. Argv(std::initializer_list<const char*> args)
  7. : m_argv(new const char*[args.size()])
  8. , m_argc(static_cast<int>(args.size()))
  9. {
  10. int i = 0;
  11. auto iter = args.begin();
  12. while (iter != args.end()) {
  13. auto len = strlen(*iter) + 1;
  14. auto ptr = std::unique_ptr<char[]>(new char[len]);
  15. strcpy(ptr.get(), *iter);
  16. m_args.push_back(std::move(ptr));
  17. m_argv.get()[i] = m_args.back().get();
  18. ++iter;
  19. ++i;
  20. }
  21. }
  22. const char** argv() const {
  23. return m_argv.get();
  24. }
  25. int argc() const {
  26. return m_argc;
  27. }
  28. private:
  29. std::vector<std::unique_ptr<char[]>> m_args{};
  30. std::unique_ptr<const char*[]> m_argv;
  31. int m_argc;
  32. };
  33. TEST_CASE("Basic options", "[options]")
  34. {
  35. cxxopts::Options options("tester", " - test basic options");
  36. options.add_options()
  37. ("long", "a long option")
  38. ("s,short", "a short option")
  39. ("value", "an option with a value", cxxopts::value<std::string>())
  40. ("a,av", "a short option with a value", cxxopts::value<std::string>())
  41. ("6,six", "a short number option")
  42. ("p, space", "an option with space between short and long")
  43. ("nothing", "won't exist", cxxopts::value<std::string>())
  44. ;
  45. Argv argv({
  46. "tester",
  47. "--long",
  48. "-s",
  49. "--value",
  50. "value",
  51. "-a",
  52. "b",
  53. "-6",
  54. "-p",
  55. "--space",
  56. });
  57. auto** actual_argv = argv.argv();
  58. auto argc = argv.argc();
  59. auto result = options.parse(argc, actual_argv);
  60. CHECK(result.count("long") == 1);
  61. CHECK(result.count("s") == 1);
  62. CHECK(result.count("value") == 1);
  63. CHECK(result.count("a") == 1);
  64. CHECK(result["value"].as<std::string>() == "value");
  65. CHECK(result["a"].as<std::string>() == "b");
  66. CHECK(result.count("6") == 1);
  67. CHECK(result.count("p") == 2);
  68. CHECK(result.count("space") == 2);
  69. auto& arguments = result.arguments();
  70. REQUIRE(arguments.size() == 7);
  71. CHECK(arguments[0].key() == "long");
  72. CHECK(arguments[0].value() == "true");
  73. CHECK(arguments[0].as<bool>() == true);
  74. CHECK(arguments[1].key() == "short");
  75. CHECK(arguments[2].key() == "value");
  76. CHECK(arguments[3].key() == "av");
  77. CHECK_THROWS_AS(result["nothing"].as<std::string>(), cxxopts::option_has_no_value_exception&);
  78. }
  79. TEST_CASE("Short options", "[options]")
  80. {
  81. cxxopts::Options options("test_short", " - test short options");
  82. options.add_options()
  83. ("a", "a short option", cxxopts::value<std::string>());
  84. Argv argv({"test_short", "-a", "value"});
  85. auto actual_argv = argv.argv();
  86. auto argc = argv.argc();
  87. auto result = options.parse(argc, actual_argv);
  88. CHECK(result.count("a") == 1);
  89. CHECK(result["a"].as<std::string>() == "value");
  90. REQUIRE_THROWS_AS(options.add_options()("", "nothing option"),
  91. cxxopts::invalid_option_format_error&);
  92. }
  93. TEST_CASE("No positional", "[positional]")
  94. {
  95. cxxopts::Options options("test_no_positional",
  96. " - test no positional options");
  97. Argv av({"tester", "a", "b", "def"});
  98. auto** argv = av.argv();
  99. auto argc = av.argc();
  100. auto result = options.parse(argc, argv);
  101. REQUIRE(argc == 4);
  102. CHECK(strcmp(argv[1], "a") == 0);
  103. }
  104. TEST_CASE("All positional", "[positional]")
  105. {
  106. std::vector<std::string> positional;
  107. cxxopts::Options options("test_all_positional", " - test all positional");
  108. options.add_options()
  109. ("positional", "Positional parameters",
  110. cxxopts::value<std::vector<std::string>>(positional))
  111. ;
  112. Argv av({"tester", "a", "b", "c"});
  113. auto argc = av.argc();
  114. auto argv = av.argv();
  115. std::vector<std::string> pos_names = {"positional"};
  116. options.parse_positional(pos_names.begin(), pos_names.end());
  117. auto result = options.parse(argc, argv);
  118. CHECK(result.unmatched().size() == 0);
  119. REQUIRE(positional.size() == 3);
  120. CHECK(positional[0] == "a");
  121. CHECK(positional[1] == "b");
  122. CHECK(positional[2] == "c");
  123. }
  124. TEST_CASE("Some positional explicit", "[positional]")
  125. {
  126. cxxopts::Options options("positional_explicit", " - test positional");
  127. options.add_options()
  128. ("input", "Input file", cxxopts::value<std::string>())
  129. ("output", "Output file", cxxopts::value<std::string>())
  130. ("positional", "Positional parameters",
  131. cxxopts::value<std::vector<std::string>>())
  132. ;
  133. options.parse_positional({"input", "output", "positional"});
  134. Argv av({"tester", "--output", "a", "b", "c", "d"});
  135. auto** argv = av.argv();
  136. auto argc = av.argc();
  137. auto result = options.parse(argc, argv);
  138. CHECK(result.unmatched().size() == 0);
  139. CHECK(result.count("output"));
  140. CHECK(result["input"].as<std::string>() == "b");
  141. CHECK(result["output"].as<std::string>() == "a");
  142. auto& positional = result["positional"].as<std::vector<std::string>>();
  143. REQUIRE(positional.size() == 2);
  144. CHECK(positional[0] == "c");
  145. CHECK(positional[1] == "d");
  146. }
  147. TEST_CASE("No positional with extras", "[positional]")
  148. {
  149. cxxopts::Options options("posargmaster", "shows incorrect handling");
  150. options.add_options()
  151. ("dummy", "oh no", cxxopts::value<std::string>())
  152. ;
  153. Argv av({"extras", "--", "a", "b", "c", "d"});
  154. auto** argv = av.argv();
  155. auto argc = av.argc();
  156. auto old_argv = argv;
  157. auto old_argc = argc;
  158. auto result = options.parse(argc, argv);
  159. auto& unmatched = result.unmatched();
  160. CHECK((unmatched == std::vector<std::string>{"a", "b", "c", "d"}));
  161. }
  162. TEST_CASE("Positional not valid", "[positional]") {
  163. cxxopts::Options options("positional_invalid", "invalid positional argument");
  164. options.add_options()
  165. ("long", "a long option", cxxopts::value<std::string>())
  166. ;
  167. options.parse_positional("something");
  168. Argv av({"foobar", "bar", "baz"});
  169. auto** argv = av.argv();
  170. auto argc = av.argc();
  171. CHECK_THROWS_AS(options.parse(argc, argv), cxxopts::option_not_exists_exception&);
  172. }
  173. TEST_CASE("Positional with empty arguments", "[positional]") {
  174. cxxopts::Options options("positional_with_empty_arguments", "positional with empty argument");
  175. options.add_options()
  176. ("long", "a long option", cxxopts::value<std::string>())
  177. ("program", "program to run", cxxopts::value<std::string>())
  178. ("programArgs", "program arguments", cxxopts::value<std::vector<std::string>>())
  179. ;
  180. options.parse_positional("program", "programArgs");
  181. Argv av({"foobar", "--long", "long_value", "--", "someProgram", "ab", "-c", "d", "--ef", "gh", "--ijk=lm", "n", "", "o", });
  182. std::vector<std::string> expected({"ab", "-c", "d", "--ef", "gh", "--ijk=lm", "n", "", "o", });
  183. auto** argv = av.argv();
  184. auto argc = av.argc();
  185. auto result = options.parse(argc, argv);
  186. auto actual = result["programArgs"].as<std::vector<std::string>>();
  187. REQUIRE(result.count("program") == 1);
  188. REQUIRE(result["program"].as<std::string>() == "someProgram");
  189. REQUIRE(result.count("programArgs") == expected.size());
  190. REQUIRE(actual == expected);
  191. }
  192. TEST_CASE("Empty with implicit value", "[implicit]")
  193. {
  194. cxxopts::Options options("empty_implicit", "doesn't handle empty");
  195. options.add_options()
  196. ("implicit", "Has implicit", cxxopts::value<std::string>()
  197. ->implicit_value("foo"));
  198. Argv av({"implicit", "--implicit="});
  199. auto** argv = av.argv();
  200. auto argc = av.argc();
  201. auto result = options.parse(argc, argv);
  202. REQUIRE(result.count("implicit") == 1);
  203. REQUIRE(result["implicit"].as<std::string>() == "");
  204. }
  205. TEST_CASE("Boolean without implicit value", "[implicit]")
  206. {
  207. cxxopts::Options options("no_implicit", "bool without an implicit value");
  208. options.add_options()
  209. ("bool", "Boolean without implicit", cxxopts::value<bool>()
  210. ->no_implicit_value());
  211. SECTION("When no value provided") {
  212. Argv av({"no_implicit", "--bool"});
  213. auto** argv = av.argv();
  214. auto argc = av.argc();
  215. CHECK_THROWS_AS(options.parse(argc, argv), cxxopts::missing_argument_exception&);
  216. }
  217. SECTION("With equal-separated true") {
  218. Argv av({"no_implicit", "--bool=true"});
  219. auto** argv = av.argv();
  220. auto argc = av.argc();
  221. auto result = options.parse(argc, argv);
  222. CHECK(result.count("bool") == 1);
  223. CHECK(result["bool"].as<bool>() == true);
  224. }
  225. SECTION("With equal-separated false") {
  226. Argv av({"no_implicit", "--bool=false"});
  227. auto** argv = av.argv();
  228. auto argc = av.argc();
  229. auto result = options.parse(argc, argv);
  230. CHECK(result.count("bool") == 1);
  231. CHECK(result["bool"].as<bool>() == false);
  232. }
  233. SECTION("With space-separated true") {
  234. Argv av({"no_implicit", "--bool", "true"});
  235. auto** argv = av.argv();
  236. auto argc = av.argc();
  237. auto result = options.parse(argc, argv);
  238. CHECK(result.count("bool") == 1);
  239. CHECK(result["bool"].as<bool>() == true);
  240. }
  241. SECTION("With space-separated false") {
  242. Argv av({"no_implicit", "--bool", "false"});
  243. auto** argv = av.argv();
  244. auto argc = av.argc();
  245. auto result = options.parse(argc, argv);
  246. CHECK(result.count("bool") == 1);
  247. CHECK(result["bool"].as<bool>() == false);
  248. }
  249. }
  250. TEST_CASE("Default values", "[default]")
  251. {
  252. cxxopts::Options options("defaults", "has defaults");
  253. options.add_options()
  254. ("default", "Has implicit", cxxopts::value<int>()->default_value("42"))
  255. ("v,vector", "Default vector", cxxopts::value<std::vector<int>>()
  256. ->default_value("1,4"))
  257. ;
  258. SECTION("Sets defaults") {
  259. Argv av({"implicit"});
  260. auto** argv = av.argv();
  261. auto argc = av.argc();
  262. auto result = options.parse(argc, argv);
  263. CHECK(result.count("default") == 0);
  264. CHECK(result["default"].as<int>() == 42);
  265. auto& v = result["vector"].as<std::vector<int>>();
  266. REQUIRE(v.size() == 2);
  267. CHECK(v[0] == 1);
  268. CHECK(v[1] == 4);
  269. }
  270. SECTION("When values provided") {
  271. Argv av({"implicit", "--default", "5"});
  272. auto** argv = av.argv();
  273. auto argc = av.argc();
  274. auto result = options.parse(argc, argv);
  275. CHECK(result.count("default") == 1);
  276. CHECK(result["default"].as<int>() == 5);
  277. }
  278. }
  279. TEST_CASE("Parse into a reference", "[reference]")
  280. {
  281. int value = 0;
  282. cxxopts::Options options("into_reference", "parses into a reference");
  283. options.add_options()
  284. ("ref", "A reference", cxxopts::value(value));
  285. Argv av({"into_reference", "--ref", "42"});
  286. auto argv = av.argv();
  287. auto argc = av.argc();
  288. auto result = options.parse(argc, argv);
  289. CHECK(result.count("ref") == 1);
  290. CHECK(value == 42);
  291. }
  292. TEST_CASE("Integers", "[options]")
  293. {
  294. cxxopts::Options options("parses_integers", "parses integers correctly");
  295. options.add_options()
  296. ("positional", "Integers", cxxopts::value<std::vector<int>>());
  297. Argv av({"ints", "--", "5", "6", "-6", "0", "0xab", "0xAf", "0x0"});
  298. auto** argv = av.argv();
  299. auto argc = av.argc();
  300. options.parse_positional("positional");
  301. auto result = options.parse(argc, argv);
  302. REQUIRE(result.count("positional") == 7);
  303. auto& positional = result["positional"].as<std::vector<int>>();
  304. REQUIRE(positional.size() == 7);
  305. CHECK(positional[0] == 5);
  306. CHECK(positional[1] == 6);
  307. CHECK(positional[2] == -6);
  308. CHECK(positional[3] == 0);
  309. CHECK(positional[4] == 0xab);
  310. CHECK(positional[5] == 0xaf);
  311. CHECK(positional[6] == 0x0);
  312. }
  313. TEST_CASE("Leading zero integers", "[options]")
  314. {
  315. cxxopts::Options options("parses_integers", "parses integers correctly");
  316. options.add_options()
  317. ("positional", "Integers", cxxopts::value<std::vector<int>>());
  318. Argv av({"ints", "--", "05", "06", "0x0ab", "0x0001"});
  319. auto** argv = av.argv();
  320. auto argc = av.argc();
  321. options.parse_positional("positional");
  322. auto result = options.parse(argc, argv);
  323. REQUIRE(result.count("positional") == 4);
  324. auto& positional = result["positional"].as<std::vector<int>>();
  325. REQUIRE(positional.size() == 4);
  326. CHECK(positional[0] == 5);
  327. CHECK(positional[1] == 6);
  328. CHECK(positional[2] == 0xab);
  329. CHECK(positional[3] == 0x1);
  330. }
  331. TEST_CASE("Unsigned integers", "[options]")
  332. {
  333. cxxopts::Options options("parses_unsigned", "detects unsigned errors");
  334. options.add_options()
  335. ("positional", "Integers", cxxopts::value<std::vector<unsigned int>>());
  336. Argv av({"ints", "--", "-2"});
  337. auto** argv = av.argv();
  338. auto argc = av.argc();
  339. options.parse_positional("positional");
  340. CHECK_THROWS_AS(options.parse(argc, argv), cxxopts::argument_incorrect_type&);
  341. }
  342. TEST_CASE("Integer bounds", "[integer]")
  343. {
  344. cxxopts::Options options("integer_boundaries", "check min/max integer");
  345. options.add_options()
  346. ("positional", "Integers", cxxopts::value<std::vector<int8_t>>());
  347. SECTION("No overflow")
  348. {
  349. Argv av({"ints", "--", "127", "-128", "0x7f", "-0x80", "0x7e"});
  350. auto argv = av.argv();
  351. auto argc = av.argc();
  352. options.parse_positional("positional");
  353. auto result = options.parse(argc, argv);
  354. REQUIRE(result.count("positional") == 5);
  355. auto& positional = result["positional"].as<std::vector<int8_t>>();
  356. CHECK(positional[0] == 127);
  357. CHECK(positional[1] == -128);
  358. CHECK(positional[2] == 0x7f);
  359. CHECK(positional[3] == -0x80);
  360. CHECK(positional[4] == 0x7e);
  361. }
  362. }
  363. TEST_CASE("Overflow on boundary", "[integer]")
  364. {
  365. using namespace cxxopts::values;
  366. int8_t si;
  367. uint8_t ui;
  368. CHECK_THROWS_AS((integer_parser("128", si)), cxxopts::argument_incorrect_type&);
  369. CHECK_THROWS_AS((integer_parser("-129", si)), cxxopts::argument_incorrect_type&);
  370. CHECK_THROWS_AS((integer_parser("256", ui)), cxxopts::argument_incorrect_type&);
  371. CHECK_THROWS_AS((integer_parser("-0x81", si)), cxxopts::argument_incorrect_type&);
  372. CHECK_THROWS_AS((integer_parser("0x80", si)), cxxopts::argument_incorrect_type&);
  373. CHECK_THROWS_AS((integer_parser("0x100", ui)), cxxopts::argument_incorrect_type&);
  374. }
  375. TEST_CASE("Integer overflow", "[options]")
  376. {
  377. using namespace cxxopts::values;
  378. cxxopts::Options options("reject_overflow", "rejects overflowing integers");
  379. options.add_options()
  380. ("positional", "Integers", cxxopts::value<std::vector<int8_t>>());
  381. Argv av({"ints", "--", "128"});
  382. auto argv = av.argv();
  383. auto argc = av.argc();
  384. options.parse_positional("positional");
  385. CHECK_THROWS_AS(options.parse(argc, argv), cxxopts::argument_incorrect_type&);
  386. int integer = 0;
  387. CHECK_THROWS_AS((integer_parser("23423423423", integer)), cxxopts::argument_incorrect_type&);
  388. CHECK_THROWS_AS((integer_parser("234234234234", integer)), cxxopts::argument_incorrect_type&);
  389. }
  390. TEST_CASE("Floats", "[options]")
  391. {
  392. cxxopts::Options options("parses_floats", "parses floats correctly");
  393. options.add_options()
  394. ("double", "Double precision", cxxopts::value<double>())
  395. ("positional", "Floats", cxxopts::value<std::vector<float>>());
  396. Argv av({"floats", "--double", "0.5", "--", "4", "-4", "1.5e6", "-1.5e6"});
  397. auto** argv = av.argv();
  398. auto argc = av.argc();
  399. options.parse_positional("positional");
  400. auto result = options.parse(argc, argv);
  401. REQUIRE(result.count("double") == 1);
  402. REQUIRE(result.count("positional") == 4);
  403. CHECK(result["double"].as<double>() == 0.5);
  404. auto& positional = result["positional"].as<std::vector<float>>();
  405. CHECK(positional[0] == 4);
  406. CHECK(positional[1] == -4);
  407. CHECK(positional[2] == 1.5e6);
  408. CHECK(positional[3] == -1.5e6);
  409. }
  410. TEST_CASE("Invalid integers", "[integer]") {
  411. cxxopts::Options options("invalid_integers", "rejects invalid integers");
  412. options.add_options()
  413. ("positional", "Integers", cxxopts::value<std::vector<int>>());
  414. Argv av({"ints", "--", "Ae"});
  415. auto** argv = av.argv();
  416. auto argc = av.argc();
  417. options.parse_positional("positional");
  418. CHECK_THROWS_AS(options.parse(argc, argv), cxxopts::argument_incorrect_type&);
  419. }
  420. TEST_CASE("Booleans", "[boolean]") {
  421. cxxopts::Options options("parses_floats", "parses floats correctly");
  422. options.add_options()
  423. ("bool", "A Boolean", cxxopts::value<bool>())
  424. ("debug", "Debugging", cxxopts::value<bool>())
  425. ("timing", "Timing", cxxopts::value<bool>())
  426. ("verbose", "Verbose", cxxopts::value<bool>())
  427. ("dry-run", "Dry Run", cxxopts::value<bool>())
  428. ("noExplicitDefault", "No Explicit Default", cxxopts::value<bool>())
  429. ("defaultTrue", "Timing", cxxopts::value<bool>()->default_value("true"))
  430. ("defaultFalse", "Timing", cxxopts::value<bool>()->default_value("false"))
  431. ("others", "Other arguments", cxxopts::value<std::vector<std::string>>())
  432. ;
  433. options.parse_positional("others");
  434. Argv av({"booleans", "--bool=false", "--debug=true", "--timing", "--verbose=1", "--dry-run=0", "extra"});
  435. auto** argv = av.argv();
  436. auto argc = av.argc();
  437. auto result = options.parse(argc, argv);
  438. REQUIRE(result.count("bool") == 1);
  439. REQUIRE(result.count("debug") == 1);
  440. REQUIRE(result.count("timing") == 1);
  441. REQUIRE(result.count("verbose") == 1);
  442. REQUIRE(result.count("dry-run") == 1);
  443. REQUIRE(result.count("noExplicitDefault") == 0);
  444. REQUIRE(result.count("defaultTrue") == 0);
  445. REQUIRE(result.count("defaultFalse") == 0);
  446. CHECK(result["bool"].as<bool>() == false);
  447. CHECK(result["debug"].as<bool>() == true);
  448. CHECK(result["timing"].as<bool>() == true);
  449. CHECK(result["verbose"].as<bool>() == true);
  450. CHECK(result["dry-run"].as<bool>() == false);
  451. CHECK(result["noExplicitDefault"].as<bool>() == false);
  452. CHECK(result["defaultTrue"].as<bool>() == true);
  453. CHECK(result["defaultFalse"].as<bool>() == false);
  454. REQUIRE(result.count("others") == 1);
  455. }
  456. TEST_CASE("std::vector", "[vector]") {
  457. std::vector<double> vector;
  458. cxxopts::Options options("vector", " - tests vector");
  459. options.add_options()
  460. ("vector", "an vector option", cxxopts::value<std::vector<double>>(vector));
  461. Argv av({"vector", "--vector", "1,-2.1,3,4.5"});
  462. auto** argv = av.argv();
  463. auto argc = av.argc();
  464. options.parse(argc, argv);
  465. REQUIRE(vector.size() == 4);
  466. CHECK(vector[0] == 1);
  467. CHECK(vector[1] == -2.1);
  468. CHECK(vector[2] == 3);
  469. CHECK(vector[3] == 4.5);
  470. }
  471. #ifdef CXXOPTS_HAS_OPTIONAL
  472. TEST_CASE("std::optional", "[optional]") {
  473. std::optional<std::string> optional;
  474. cxxopts::Options options("optional", " - tests optional");
  475. options.add_options()
  476. ("optional", "an optional option", cxxopts::value<std::optional<std::string>>(optional));
  477. Argv av({"optional", "--optional", "foo"});
  478. auto** argv = av.argv();
  479. auto argc = av.argc();
  480. options.parse(argc, argv);
  481. REQUIRE(optional.has_value());
  482. CHECK(*optional == "foo");
  483. }
  484. #endif
  485. TEST_CASE("Unrecognised options", "[options]") {
  486. cxxopts::Options options("unknown_options", " - test unknown options");
  487. options.add_options()
  488. ("long", "a long option")
  489. ("s,short", "a short option");
  490. Argv av({
  491. "unknown_options",
  492. "--unknown",
  493. "--long",
  494. "-su",
  495. "--another_unknown",
  496. "-a",
  497. });
  498. auto** argv = av.argv();
  499. auto argc = av.argc();
  500. SECTION("Default behaviour") {
  501. CHECK_THROWS_AS(options.parse(argc, argv), cxxopts::option_not_exists_exception&);
  502. }
  503. SECTION("After allowing unrecognised options") {
  504. options.allow_unrecognised_options();
  505. auto result = options.parse(argc, argv);
  506. auto& unmatched = result.unmatched();
  507. CHECK((unmatched == std::vector<std::string>{"--unknown", "-u", "--another_unknown", "-a"}));
  508. }
  509. }
  510. TEST_CASE("Allow bad short syntax", "[options]") {
  511. cxxopts::Options options("unknown_options", " - test unknown options");
  512. options.add_options()
  513. ("long", "a long option")
  514. ("s,short", "a short option");
  515. Argv av({
  516. "unknown_options",
  517. "-some_bad_short",
  518. });
  519. auto** argv = av.argv();
  520. auto argc = av.argc();
  521. SECTION("Default behaviour") {
  522. CHECK_THROWS_AS(options.parse(argc, argv), cxxopts::option_syntax_exception&);
  523. }
  524. SECTION("After allowing unrecognised options") {
  525. options.allow_unrecognised_options();
  526. CHECK_NOTHROW(options.parse(argc, argv));
  527. REQUIRE(argc == 2);
  528. CHECK_THAT(argv[1], Catch::Equals("-some_bad_short"));
  529. }
  530. }
  531. TEST_CASE("Invalid option syntax", "[options]") {
  532. cxxopts::Options options("invalid_syntax", " - test invalid syntax");
  533. Argv av({
  534. "invalid_syntax",
  535. "--a",
  536. });
  537. auto** argv = av.argv();
  538. auto argc = av.argc();
  539. SECTION("Default behaviour") {
  540. CHECK_THROWS_AS(options.parse(argc, argv), cxxopts::option_syntax_exception&);
  541. }
  542. }
  543. TEST_CASE("Options empty", "[options]") {
  544. cxxopts::Options options("Options list empty", " - test empty option list");
  545. options.add_options();
  546. options.add_options("");
  547. options.add_options("", {});
  548. options.add_options("test");
  549. Argv argv_({
  550. "test",
  551. "--unknown"
  552. });
  553. auto argc = argv_.argc();
  554. auto** argv = argv_.argv();
  555. CHECK(options.groups().empty());
  556. CHECK_THROWS_AS(options.parse(argc, argv), cxxopts::option_not_exists_exception&);
  557. }
  558. TEST_CASE("Initializer list with group", "[options]") {
  559. cxxopts::Options options("Initializer list group", " - test initializer list with group");
  560. options.add_options("", {
  561. {"a, address", "server address", cxxopts::value<std::string>()->default_value("127.0.0.1")},
  562. {"p, port", "server port", cxxopts::value<std::string>()->default_value("7110"), "PORT"},
  563. });
  564. cxxopts::Option help{"h,help", "Help"};
  565. options.add_options("TEST_GROUP", {
  566. {"t, test", "test option"},
  567. help
  568. });
  569. Argv argv({
  570. "test",
  571. "--address",
  572. "10.0.0.1",
  573. "-p",
  574. "8000",
  575. "-t",
  576. });
  577. auto** actual_argv = argv.argv();
  578. auto argc = argv.argc();
  579. auto result = options.parse(argc, actual_argv);
  580. CHECK(options.groups().size() == 2);
  581. CHECK(result.count("address") == 1);
  582. CHECK(result.count("port") == 1);
  583. CHECK(result.count("test") == 1);
  584. CHECK(result.count("help") == 0);
  585. CHECK(result["address"].as<std::string>() == "10.0.0.1");
  586. CHECK(result["port"].as<std::string>() == "8000");
  587. CHECK(result["test"].as<bool>() == true);
  588. }
  589. TEST_CASE("Option add with add_option(string, Option)", "[options]") {
  590. cxxopts::Options options("Option add with add_option", " - test Option add with add_option(string, Option)");
  591. cxxopts::Option option_1("t,test", "test option", cxxopts::value<int>()->default_value("7"), "TEST");
  592. options.add_option("", option_1);
  593. options.add_option("TEST", {"a,aggregate", "test option 2", cxxopts::value<int>(), "AGGREGATE"});
  594. Argv argv_({
  595. "test",
  596. "--test",
  597. "5",
  598. "-a",
  599. "4"
  600. });
  601. auto argc = argv_.argc();
  602. auto** argv = argv_.argv();
  603. auto result = options.parse(argc, argv);
  604. CHECK(result.arguments().size()==2);
  605. CHECK(options.groups().size() == 2);
  606. CHECK(result.count("address") == 0);
  607. CHECK(result.count("aggregate") == 1);
  608. CHECK(result.count("test") == 1);
  609. CHECK(result["aggregate"].as<int>() == 4);
  610. CHECK(result["test"].as<int>() == 5);
  611. }
  612. TEST_CASE("Const array", "[const]") {
  613. const char* const option_list[] = {"empty", "options"};
  614. cxxopts::Options options("Empty options", " - test constness");
  615. auto result = options.parse(2, option_list);
  616. }
  617. TEST_CASE("Parameter follow option", "[parameter]") {
  618. cxxopts::Options options("param_follow_opt", " - test parameter follow option without space.");
  619. options.add_options()
  620. ("j,job", "Job", cxxopts::value<std::vector<unsigned>>());
  621. Argv av({"implicit",
  622. "-j", "9",
  623. "--job", "7",
  624. "--job=10",
  625. "-j5",
  626. });
  627. auto ** argv = av.argv();
  628. auto argc = av.argc();
  629. auto result = options.parse(argc, argv);
  630. REQUIRE(result.count("job") == 4);
  631. auto job_values = result["job"].as<std::vector<unsigned>>();
  632. CHECK(job_values[0] == 9);
  633. CHECK(job_values[1] == 7);
  634. CHECK(job_values[2] == 10);
  635. CHECK(job_values[3] == 5);
  636. }