Commit b5283241076013b325a8cf881c19829ac1cbbdb5

Authored by Jarryd Beck
1 parent cd65c459

Fix option matching

CHANGELOG.md
@@ -19,6 +19,7 @@ options. The project adheres to semantic versioning. @@ -19,6 +19,7 @@ options. The project adheres to semantic versioning.
19 * Fix a warning about possible loss of data. 19 * Fix a warning about possible loss of data.
20 * Fix version numbering in CMakeLists.txt 20 * Fix version numbering in CMakeLists.txt
21 * Remove unused declaration of the undefined `ParseResult::get_option`. 21 * Remove unused declaration of the undefined `ParseResult::get_option`.
  22 +* Throw on invalid option syntax when beginning with a `-`.
22 23
23 ## 2.1.1 24 ## 2.1.1
24 25
include/cxxopts.hpp
@@ -368,6 +368,15 @@ namespace cxxopts @@ -368,6 +368,15 @@ namespace cxxopts
368 } 368 }
369 }; 369 };
370 370
  371 + class option_syntax_exception : public OptionParseException {
  372 + public:
  373 + option_syntax_exception(const std::string& text)
  374 + : OptionParseException(u8"Argument " + LQUOTE + text + RQUOTE +
  375 + u8" starts with a - but has incorrect syntax")
  376 + {
  377 + }
  378 + };
  379 +
371 class option_not_exists_exception : public OptionParseException 380 class option_not_exists_exception : public OptionParseException
372 { 381 {
373 public: 382 public:
@@ -1701,6 +1710,11 @@ ParseResult::parse(int& argc, char**& argv) @@ -1701,6 +1710,11 @@ ParseResult::parse(int& argc, char**& argv)
1701 { 1710 {
1702 //not a flag 1711 //not a flag
1703 1712
  1713 + // but if it starts with a `-`, then it's an error
  1714 + if (argv[current][0] == '-') {
  1715 + throw option_syntax_exception(argv[current]);
  1716 + }
  1717 +
1704 //if true is returned here then it was consumed, otherwise it is 1718 //if true is returned here then it was consumed, otherwise it is
1705 //ignored 1719 //ignored
1706 if (consume_positional(argv[current])) 1720 if (consume_positional(argv[current]))
test/options.cpp
@@ -111,7 +111,7 @@ TEST_CASE("Short options", "[options]") @@ -111,7 +111,7 @@ TEST_CASE("Short options", "[options]")
111 CHECK(result.count("a") == 1); 111 CHECK(result.count("a") == 1);
112 CHECK(result["a"].as<std::string>() == "value"); 112 CHECK(result["a"].as<std::string>() == "value");
113 113
114 - REQUIRE_THROWS_AS(options.add_options()("", "nothing option"), 114 + REQUIRE_THROWS_AS(options.add_options()("", "nothing option"),
115 cxxopts::invalid_option_format_error); 115 cxxopts::invalid_option_format_error);
116 } 116 }
117 117
@@ -513,7 +513,7 @@ TEST_CASE(&quot;Unrecognised options&quot;, &quot;[options]&quot;) { @@ -513,7 +513,7 @@ TEST_CASE(&quot;Unrecognised options&quot;, &quot;[options]&quot;) {
513 "--long", 513 "--long",
514 "-su", 514 "-su",
515 "--another_unknown", 515 "--another_unknown",
516 - }); 516 + });
517 517
518 char** argv = av.argv(); 518 char** argv = av.argv();
519 auto argc = av.argc(); 519 auto argc = av.argc();
@@ -529,3 +529,19 @@ TEST_CASE(&quot;Unrecognised options&quot;, &quot;[options]&quot;) { @@ -529,3 +529,19 @@ TEST_CASE(&quot;Unrecognised options&quot;, &quot;[options]&quot;) {
529 CHECK_THAT(argv[1], Catch::Equals("--unknown")); 529 CHECK_THAT(argv[1], Catch::Equals("--unknown"));
530 } 530 }
531 } 531 }
  532 +
  533 +TEST_CASE("Invalid option syntax", "[options]") {
  534 + cxxopts::Options options("invalid_syntax", " - test invalid syntax");
  535 +
  536 + Argv av({
  537 + "invalid_syntax",
  538 + "--a",
  539 + });
  540 +
  541 + char** argv = av.argv();
  542 + auto argc = av.argc();
  543 +
  544 + SECTION("Default behaviour") {
  545 + CHECK_THROWS_AS(options.parse(argc, argv), cxxopts::option_syntax_exception);
  546 + }
  547 +}