Commit f6c9ce610966f9a71e314dc85a6a43360a3d722e
Committed by
Henry Schreiner
1 parent
4d5bff23
Moving code to Error, better ArgumentMismatch throwing
Showing
6 changed files
with
52 additions
and
23 deletions
include/CLI/App.hpp
| ... | ... | @@ -452,7 +452,7 @@ class App { |
| 452 | 452 | CLI::callback_t fun = [&member, options, simple_name](CLI::results_t res) { |
| 453 | 453 | bool retval = detail::lexical_cast(res[0], member); |
| 454 | 454 | if(!retval) |
| 455 | - throw ConversionError("The value " + res[0] + "is not an allowed value for " + simple_name); | |
| 455 | + throw ConversionError(res[0], simple_name); | |
| 456 | 456 | return std::find(std::begin(options), std::end(options), member) != std::end(options); |
| 457 | 457 | }; |
| 458 | 458 | |
| ... | ... | @@ -475,7 +475,7 @@ class App { |
| 475 | 475 | CLI::callback_t fun = [&member, options, simple_name](CLI::results_t res) { |
| 476 | 476 | bool retval = detail::lexical_cast(res[0], member); |
| 477 | 477 | if(!retval) |
| 478 | - throw ConversionError("The value " + res[0] + "is not an allowed value for " + simple_name); | |
| 478 | + throw ConversionError(res[0], simple_name); | |
| 479 | 479 | return std::find(std::begin(options), std::end(options), member) != std::end(options); |
| 480 | 480 | }; |
| 481 | 481 | |
| ... | ... | @@ -504,7 +504,7 @@ class App { |
| 504 | 504 | return detail::to_lower(val) == member; |
| 505 | 505 | }); |
| 506 | 506 | if(iter == std::end(options)) |
| 507 | - throw ConversionError("The value " + member + "is not an allowed value for " + simple_name); | |
| 507 | + throw ConversionError(member, simple_name); | |
| 508 | 508 | else { |
| 509 | 509 | member = *iter; |
| 510 | 510 | return true; |
| ... | ... | @@ -533,7 +533,7 @@ class App { |
| 533 | 533 | return detail::to_lower(val) == member; |
| 534 | 534 | }); |
| 535 | 535 | if(iter == std::end(options)) |
| 536 | - throw ConversionError("The value " + member + "is not an allowed value for " + simple_name); | |
| 536 | + throw ConversionError(member, simple_name); | |
| 537 | 537 | else { |
| 538 | 538 | member = *iter; |
| 539 | 539 | return true; |
| ... | ... | @@ -1149,12 +1149,7 @@ class App { |
| 1149 | 1149 | |
| 1150 | 1150 | // Required but empty |
| 1151 | 1151 | if(opt->get_required() && opt->count() == 0) |
| 1152 | - throw RequiredError(opt->help_name() + " is required"); | |
| 1153 | - | |
| 1154 | - // Partially filled | |
| 1155 | - if(opt->get_expected() > 0 && static_cast<int>(opt->count()) < opt->get_expected()) | |
| 1156 | - throw RequiredError(opt->help_name() + " requires " + std::to_string(opt->get_expected()) + | |
| 1157 | - " arguments"); | |
| 1152 | + throw RequiredError(opt->single_name() + " is required"); | |
| 1158 | 1153 | } |
| 1159 | 1154 | // Requires |
| 1160 | 1155 | for(const Option *opt_req : opt->requires_) |
| ... | ... | @@ -1409,8 +1404,8 @@ class App { |
| 1409 | 1404 | } |
| 1410 | 1405 | |
| 1411 | 1406 | if(num > 0) { |
| 1412 | - throw RequiredError(op->single_name() + ": " + std::to_string(num) + " required " + | |
| 1413 | - op->get_type_name() + " missing"); | |
| 1407 | + throw ArgumentMismatch(op->single_name() + ": " + std::to_string(num) + " required " + | |
| 1408 | + op->get_type_name() + " missing"); | |
| 1414 | 1409 | } |
| 1415 | 1410 | } |
| 1416 | 1411 | |
| ... | ... | @@ -1490,8 +1485,8 @@ class App { |
| 1490 | 1485 | args.pop_back(); |
| 1491 | 1486 | } |
| 1492 | 1487 | if(num > 0) { |
| 1493 | - throw RequiredError(op->single_name() + ": " + std::to_string(num) + " required " + | |
| 1494 | - op->get_type_name() + " missing"); | |
| 1488 | + throw ArgumentMismatch(op->single_name() + ": " + std::to_string(num) + " required " + | |
| 1489 | + op->get_type_name() + " missing"); | |
| 1495 | 1490 | } |
| 1496 | 1491 | } |
| 1497 | 1492 | return; | ... | ... |
include/CLI/Error.hpp
| ... | ... | @@ -126,19 +126,22 @@ class RuntimeError : public ParseError { |
| 126 | 126 | /// Thrown when parsing an INI file and it is missing |
| 127 | 127 | class FileError : public ParseError { |
| 128 | 128 | CLI11_ERROR_DEF(ParseError, FileError) |
| 129 | - FileError(std::string msg) : FileError(msg, ExitCodes::File) {} | |
| 129 | + FileError(std::string name) : FileError(name + " was not readable (missing?)", ExitCodes::File) {} | |
| 130 | 130 | }; |
| 131 | 131 | |
| 132 | 132 | /// Thrown when conversion call back fails, such as when an int fails to coerce to a string |
| 133 | 133 | class ConversionError : public ParseError { |
| 134 | 134 | CLI11_ERROR_DEF(ParseError, ConversionError) |
| 135 | 135 | CLI11_ERROR_SIMPLE(ConversionError) |
| 136 | + ConversionError(std::string member, std::string name) | |
| 137 | + : ConversionError("The value " + member + "is not an allowed value for " + name) {} | |
| 136 | 138 | }; |
| 137 | 139 | |
| 138 | 140 | /// Thrown when validation of results fails |
| 139 | 141 | class ValidationError : public ParseError { |
| 140 | 142 | CLI11_ERROR_DEF(ParseError, ValidationError) |
| 141 | 143 | CLI11_ERROR_SIMPLE(ValidationError) |
| 144 | + ValidationError(std::string name, std::string msg) : ValidationError(name + ": " + msg) {} | |
| 142 | 145 | }; |
| 143 | 146 | |
| 144 | 147 | /// Thrown when a required option is missing |
| ... | ... | @@ -150,6 +153,7 @@ class RequiredError : public ParseError { |
| 150 | 153 | /// Thrown when the wrong number of arguments has been recieved |
| 151 | 154 | class ArgumentMismatch : ParseError { |
| 152 | 155 | CLI11_ERROR_DEF(ParseError, ArgumentMismatch) |
| 156 | + CLI11_ERROR_SIMPLE(ArgumentMismatch) | |
| 153 | 157 | ArgumentMismatch(std::string name, int expected, size_t recieved) |
| 154 | 158 | : ArgumentMismatch(expected > 0 ? ("Expected exactly " + std::to_string(expected) + " arguments to " + name + |
| 155 | 159 | ", got " + std::to_string(recieved)) | ... | ... |
include/CLI/Ini.hpp
| ... | ... | @@ -106,7 +106,7 @@ inline std::vector<ini_ret_t> parse_ini(const std::string &name) { |
| 106 | 106 | |
| 107 | 107 | std::ifstream input{name}; |
| 108 | 108 | if(!input.good()) |
| 109 | - throw FileError(name + " was not readable (missing?)"); | |
| 109 | + throw FileError(name); | |
| 110 | 110 | |
| 111 | 111 | return parse_ini(input); |
| 112 | 112 | } | ... | ... |
include/CLI/Option.hpp
| ... | ... | @@ -438,7 +438,7 @@ class Option : public OptionBase<Option> { |
| 438 | 438 | for(const std::function<std::string(std::string &)> &vali : validators_) { |
| 439 | 439 | std::string err_msg = vali(result); |
| 440 | 440 | if(!err_msg.empty()) |
| 441 | - throw ValidationError(single_name() + ": " + err_msg); | |
| 441 | + throw ValidationError(single_name(), err_msg); | |
| 442 | 442 | } |
| 443 | 443 | } |
| 444 | 444 | ... | ... |
tests/AppTest.cpp
| ... | ... | @@ -243,6 +243,26 @@ TEST_F(TApp, MissingValueNonRequiredOpt) { |
| 243 | 243 | EXPECT_ANY_THROW(run()); |
| 244 | 244 | } |
| 245 | 245 | |
| 246 | +TEST_F(TApp, NotRequiredOptsSingle) { | |
| 247 | + | |
| 248 | + std::string str; | |
| 249 | + app.add_option("--str", str); | |
| 250 | + | |
| 251 | + args = {"--str"}; | |
| 252 | + | |
| 253 | + EXPECT_THROW(run(), CLI::ArgumentMismatch); | |
| 254 | +} | |
| 255 | + | |
| 256 | +TEST_F(TApp, NotRequiredOptsSingleShort) { | |
| 257 | + | |
| 258 | + std::string str; | |
| 259 | + app.add_option("-s", str); | |
| 260 | + | |
| 261 | + args = {"-s"}; | |
| 262 | + | |
| 263 | + EXPECT_THROW(run(), CLI::ArgumentMismatch); | |
| 264 | +} | |
| 265 | + | |
| 246 | 266 | TEST_F(TApp, RequiredOptsSingle) { |
| 247 | 267 | |
| 248 | 268 | std::string str; |
| ... | ... | @@ -250,7 +270,7 @@ TEST_F(TApp, RequiredOptsSingle) { |
| 250 | 270 | |
| 251 | 271 | args = {"--str"}; |
| 252 | 272 | |
| 253 | - EXPECT_THROW(run(), CLI::RequiredError); | |
| 273 | + EXPECT_THROW(run(), CLI::ArgumentMismatch); | |
| 254 | 274 | } |
| 255 | 275 | |
| 256 | 276 | TEST_F(TApp, RequiredOptsSingleShort) { |
| ... | ... | @@ -260,7 +280,7 @@ TEST_F(TApp, RequiredOptsSingleShort) { |
| 260 | 280 | |
| 261 | 281 | args = {"-s"}; |
| 262 | 282 | |
| 263 | - EXPECT_THROW(run(), CLI::RequiredError); | |
| 283 | + EXPECT_THROW(run(), CLI::ArgumentMismatch); | |
| 264 | 284 | } |
| 265 | 285 | |
| 266 | 286 | TEST_F(TApp, RequiredOptsDouble) { |
| ... | ... | @@ -270,7 +290,7 @@ TEST_F(TApp, RequiredOptsDouble) { |
| 270 | 290 | |
| 271 | 291 | args = {"--str", "one"}; |
| 272 | 292 | |
| 273 | - EXPECT_THROW(run(), CLI::RequiredError); | |
| 293 | + EXPECT_THROW(run(), CLI::ArgumentMismatch); | |
| 274 | 294 | |
| 275 | 295 | app.reset(); |
| 276 | 296 | args = {"--str", "one", "two"}; |
| ... | ... | @@ -287,7 +307,7 @@ TEST_F(TApp, RequiredOptsDoubleShort) { |
| 287 | 307 | |
| 288 | 308 | args = {"-s", "one"}; |
| 289 | 309 | |
| 290 | - EXPECT_THROW(run(), CLI::RequiredError); | |
| 310 | + EXPECT_THROW(run(), CLI::ArgumentMismatch); | |
| 291 | 311 | |
| 292 | 312 | app.reset(); |
| 293 | 313 | args = {"-s", "one", "two"}; |
| ... | ... | @@ -414,7 +434,17 @@ TEST_F(TApp, NotRequiedExpectedDouble) { |
| 414 | 434 | |
| 415 | 435 | args = {"--str", "one"}; |
| 416 | 436 | |
| 417 | - EXPECT_THROW(run(), CLI::RequiredError); | |
| 437 | + EXPECT_THROW(run(), CLI::ArgumentMismatch); | |
| 438 | +} | |
| 439 | + | |
| 440 | +TEST_F(TApp, NotRequiedExpectedDoubleShort) { | |
| 441 | + | |
| 442 | + std::vector<std::string> strs; | |
| 443 | + app.add_option("-s", strs)->expected(2); | |
| 444 | + | |
| 445 | + args = {"-s", "one"}; | |
| 446 | + | |
| 447 | + EXPECT_THROW(run(), CLI::ArgumentMismatch); | |
| 418 | 448 | } |
| 419 | 449 | |
| 420 | 450 | TEST_F(TApp, EnumTest) { | ... | ... |