Commit 815553211b644b2a64b5dc671c602233c49c065f

Authored by Philip Top
Committed by GitHub
1 parent 728ac3a8

fix and test some reported issues (#661)

include/CLI/App.hpp
... ... @@ -2825,10 +2825,13 @@ class App {
2825 2825 parse_order_.push_back(op.get());
2826 2826 }
2827 2827 }
2828   -
2829   - // if we only partially completed a type then add an empty string for later processing
2830   - if(min_num > 0 && op->get_type_size_max() != min_num && (collected % op->get_type_size_max()) != 0) {
2831   - op->add_result(std::string{});
  2828 + // if we only partially completed a type then add an empty string if allowed for later processing
  2829 + if(min_num > 0 && (collected % op->get_type_size_max()) != 0) {
  2830 + if(op->get_type_size_max() != op->get_type_size_min()) {
  2831 + op->add_result(std::string{});
  2832 + } else {
  2833 + throw ArgumentMismatch::PartialType(op->get_name(), op->get_type_size_min(), op->get_type_name());
  2834 + }
2832 2835 }
2833 2836 if(op->get_trigger_on_parse()) {
2834 2837 op->run_callback();
... ...
include/CLI/Error.hpp
... ... @@ -277,6 +277,10 @@ class ArgumentMismatch : public ParseError {
277 277 static ArgumentMismatch FlagOverride(std::string name) {
278 278 return ArgumentMismatch(name + " was given a disallowed flag override");
279 279 }
  280 + static ArgumentMismatch PartialType(std::string name, int num, std::string type) {
  281 + return ArgumentMismatch(name + ": " + type + " only partially specified: " + std::to_string(num) +
  282 + " required for each element");
  283 + }
280 284 };
281 285  
282 286 /// Thrown when a requires option is missing
... ...
tests/ConfigFileTest.cpp
... ... @@ -2103,6 +2103,19 @@ TEST_CASE_METHOD(TApp, "TomlOutputVector", "[config]") {
2103 2103 CHECK(str == "vector=[1, 2, 3]\n");
2104 2104 }
2105 2105  
  2106 +TEST_CASE_METHOD(TApp, "TomlOutputTuple", "[config]") {
  2107 +
  2108 + std::tuple<double, double, double, double> t;
  2109 + app.add_option("--tuple", t);
  2110 + app.config_formatter(std::make_shared<CLI::ConfigTOML>());
  2111 + args = {"--tuple", "1", "2", "3", "4"};
  2112 +
  2113 + run();
  2114 +
  2115 + std::string str = app.config_to_str();
  2116 + CHECK(str == "tuple=[1, 2, 3, 4]\n");
  2117 +}
  2118 +
2106 2119 TEST_CASE_METHOD(TApp, "ConfigOutputVectorCustom", "[config]") {
2107 2120  
2108 2121 std::vector<int> v;
... ...
tests/OptionTypeTest.cpp
... ... @@ -554,6 +554,27 @@ TEST_CASE_METHOD(TApp, &quot;vectorPairFail&quot;, &quot;[optiontype]&quot;) {
554 554 CHECK_THROWS_AS(run(), CLI::ConversionError);
555 555 }
556 556  
  557 +TEST_CASE_METHOD(TApp, "vectorPairFail2", "[optiontype]") {
  558 +
  559 + std::vector<std::pair<int, int>> custom_opt;
  560 +
  561 + auto opt = app.add_option("--pairs", custom_opt);
  562 +
  563 + args = {"--pairs", "1", "2", "3", "4"};
  564 +
  565 + run();
  566 + CHECK(custom_opt.size() == 2U);
  567 +
  568 + args = {"--pairs", "1", "2", "3"};
  569 +
  570 + CHECK_THROWS_AS(run(), CLI::ArgumentMismatch);
  571 + // now change the type size to explicitly allow 1 or 2
  572 + opt->type_size(1, 2);
  573 +
  574 + run();
  575 + CHECK(custom_opt.size() == 2U);
  576 +}
  577 +
557 578 TEST_CASE_METHOD(TApp, "vectorPairTypeRange", "[optiontype]") {
558 579  
559 580 std::vector<std::pair<int, std::string>> custom_opt;
... ...