1
0
mirror of https://github.com/CLIUtils/CLI11.git synced 2025-05-02 05:33:53 +00:00

Adding ArgumentMismatch, changable improvement

This commit is contained in:
Henry Fredrick Schreiner 2017-11-26 07:54:29 -05:00 committed by Henry Schreiner
parent afd4e32809
commit 4d5bff2393
4 changed files with 32 additions and 35 deletions

View File

@ -274,8 +274,6 @@ class App {
std::string simple_name = CLI::detail::split(name, ',').at(0); std::string simple_name = CLI::detail::split(name, ',').at(0);
CLI::callback_t fun = [&variable, simple_name](CLI::results_t res) { CLI::callback_t fun = [&variable, simple_name](CLI::results_t res) {
if(res.size() != 1)
throw ConversionError("Only one " + simple_name + " allowed");
return detail::lexical_cast(res[0], variable); return detail::lexical_cast(res[0], variable);
}; };
@ -293,8 +291,6 @@ class App {
std::string simple_name = CLI::detail::split(name, ',').at(0); std::string simple_name = CLI::detail::split(name, ',').at(0);
CLI::callback_t fun = [&variable, simple_name](CLI::results_t res) { CLI::callback_t fun = [&variable, simple_name](CLI::results_t res) {
if(res.size() != 1)
throw ConversionError("Only one " + simple_name + " allowed");
return detail::lexical_cast(res[0], variable); return detail::lexical_cast(res[0], variable);
}; };
@ -325,7 +321,7 @@ class App {
}; };
Option *opt = add_option(name, fun, description, false); Option *opt = add_option(name, fun, description, false);
opt->set_custom_option(detail::type_name<T>(), -1, true); opt->set_custom_option(detail::type_name<T>(), -1);
return opt; return opt;
} }
@ -347,7 +343,7 @@ class App {
}; };
Option *opt = add_option(name, fun, description, defaulted); Option *opt = add_option(name, fun, description, defaulted);
opt->set_custom_option(detail::type_name<T>(), -1, true); opt->set_custom_option(detail::type_name<T>(), -1);
if(defaulted) if(defaulted)
opt->set_default_str("[" + detail::join(variable) + "]"); opt->set_default_str("[" + detail::join(variable) + "]");
return opt; return opt;
@ -454,9 +450,6 @@ class App {
std::string simple_name = CLI::detail::split(name, ',').at(0); std::string simple_name = CLI::detail::split(name, ',').at(0);
CLI::callback_t fun = [&member, options, simple_name](CLI::results_t res) { CLI::callback_t fun = [&member, options, simple_name](CLI::results_t res) {
if(res.size() != 1) {
throw ConversionError("Only one " + simple_name + " allowed");
}
bool retval = detail::lexical_cast(res[0], member); bool retval = detail::lexical_cast(res[0], member);
if(!retval) if(!retval)
throw ConversionError("The value " + res[0] + "is not an allowed value for " + simple_name); throw ConversionError("The value " + res[0] + "is not an allowed value for " + simple_name);
@ -480,9 +473,6 @@ class App {
std::string simple_name = CLI::detail::split(name, ',').at(0); std::string simple_name = CLI::detail::split(name, ',').at(0);
CLI::callback_t fun = [&member, options, simple_name](CLI::results_t res) { CLI::callback_t fun = [&member, options, simple_name](CLI::results_t res) {
if(res.size() != 1) {
throw ConversionError("Only one " + simple_name + " allowed");
}
bool retval = detail::lexical_cast(res[0], member); bool retval = detail::lexical_cast(res[0], member);
if(!retval) if(!retval)
throw ConversionError("The value " + res[0] + "is not an allowed value for " + simple_name); throw ConversionError("The value " + res[0] + "is not an allowed value for " + simple_name);
@ -509,9 +499,6 @@ class App {
std::string simple_name = CLI::detail::split(name, ',').at(0); std::string simple_name = CLI::detail::split(name, ',').at(0);
CLI::callback_t fun = [&member, options, simple_name](CLI::results_t res) { CLI::callback_t fun = [&member, options, simple_name](CLI::results_t res) {
if(res.size() != 1) {
throw ConversionError("Only one " + simple_name + " allowed");
}
member = detail::to_lower(res[0]); member = detail::to_lower(res[0]);
auto iter = std::find_if(std::begin(options), std::end(options), [&member](std::string val) { auto iter = std::find_if(std::begin(options), std::end(options), [&member](std::string val) {
return detail::to_lower(val) == member; return detail::to_lower(val) == member;
@ -541,9 +528,6 @@ class App {
std::string simple_name = CLI::detail::split(name, ',').at(0); std::string simple_name = CLI::detail::split(name, ',').at(0);
CLI::callback_t fun = [&member, options, simple_name](CLI::results_t res) { CLI::callback_t fun = [&member, options, simple_name](CLI::results_t res) {
if(res.size() != 1) {
throw ConversionError("Only one " + simple_name + " allowed");
}
member = detail::to_lower(res[0]); member = detail::to_lower(res[0]);
auto iter = std::find_if(std::begin(options), std::end(options), [&member](std::string val) { auto iter = std::find_if(std::begin(options), std::end(options), [&member](std::string val) {
return detail::to_lower(val) == member; return detail::to_lower(val) == member;

View File

@ -43,6 +43,7 @@ enum class ExitCodes {
InvalidError, InvalidError,
HorribleError, HorribleError,
OptionNotFound, OptionNotFound,
ArgumentMismatch,
BaseClass = 127 BaseClass = 127
}; };
@ -146,6 +147,17 @@ class RequiredError : public ParseError {
CLI11_ERROR_SIMPLE(RequiredError) CLI11_ERROR_SIMPLE(RequiredError)
}; };
/// Thrown when the wrong number of arguments has been recieved
class ArgumentMismatch : ParseError {
CLI11_ERROR_DEF(ParseError, ArgumentMismatch)
ArgumentMismatch(std::string name, int expected, size_t recieved)
: ArgumentMismatch(expected > 0 ? ("Expected exactly " + std::to_string(expected) + " arguments to " + name +
", got " + std::to_string(recieved))
: ("Expected at least " + std::to_string(-expected) + " arguments to " + name +
", got " + std::to_string(recieved)),
ExitCodes::ArgumentMismatch) {}
};
/// Thrown when a requires option is missing /// Thrown when a requires option is missing
class RequiresError : public ParseError { class RequiresError : public ParseError {
CLI11_ERROR_DEF(ParseError, RequiresError) CLI11_ERROR_DEF(ParseError, RequiresError)

View File

@ -207,14 +207,15 @@ class Option : public OptionBase<Option> {
/// Set the number of expected arguments (Flags bypass this) /// Set the number of expected arguments (Flags bypass this)
Option *expected(int value) { Option *expected(int value) {
if(value == 0) if(expected_ == value)
return this;
else if(value == 0)
throw IncorrectConstruction("Cannot set 0 expected, use a flag instead"); throw IncorrectConstruction("Cannot set 0 expected, use a flag instead");
else if(expected_ == 0)
throw IncorrectConstruction("Cannot make a flag take arguments!");
else if(!changeable_) else if(!changeable_)
throw IncorrectConstruction("You can only change the expected arguments for vectors"); throw IncorrectConstruction("You can only change the expected arguments for vectors");
else if(last_) else if(last_)
throw IncorrectConstruction("You can't change expected arguments after you've set take_last!"); throw IncorrectConstruction("You can't change expected arguments after you've set take_last!");
expected_ = value; expected_ = value;
return this; return this;
} }
@ -447,7 +448,11 @@ class Option : public OptionBase<Option> {
results_t partial_result = {results_.back()}; results_t partial_result = {results_.back()};
local_result = !callback_(partial_result); local_result = !callback_(partial_result);
} else { } else {
local_result = !callback_(results_); if((expected_ > 0 && results_.size() != static_cast<size_t>(expected_)) ||
(expected_ < 0 && results_.size() < static_cast<size_t>(-expected_)))
throw ArgumentMismatch(single_name(), expected_, results_.size());
else
local_result = !callback_(results_);
} }
if(local_result) if(local_result)
@ -527,13 +532,13 @@ class Option : public OptionBase<Option> {
/// @name Custom options /// @name Custom options
///@{ ///@{
/// Set a custom option, typestring, expected, and changeable /// Set a custom option, typestring, expected; locks changeable unless expected is -1
void set_custom_option(std::string typeval, int expected = 1, bool changeable = false) { void set_custom_option(std::string typeval, int expected = 1) {
typeval_ = typeval; typeval_ = typeval;
expected_ = expected; expected_ = expected;
if(expected == 0) if(expected == 0)
required_ = false; required_ = false;
changeable_ = changeable; changeable_ = expected < 0;
} }
/// Set the default value string representation /// Set the default value string representation

View File

@ -119,7 +119,7 @@ TEST_F(TApp, DualOptions) {
EXPECT_EQ(ans, vstr); EXPECT_EQ(ans, vstr);
args = {"--string=one", "--string=two"}; args = {"--string=one", "--string=two"};
EXPECT_THROW(run(), CLI::ConversionError); EXPECT_THROW(run(), CLI::ArgumentMismatch);
} }
TEST_F(TApp, LotsOfFlags) { TEST_F(TApp, LotsOfFlags) {
@ -737,7 +737,7 @@ TEST_F(TApp, FailSet) {
app.add_set("-q,--quick", choice, {1, 2, 3}); app.add_set("-q,--quick", choice, {1, 2, 3});
args = {"--quick", "3", "--quick=2"}; args = {"--quick", "3", "--quick=2"};
EXPECT_THROW(run(), CLI::ConversionError); EXPECT_THROW(run(), CLI::ArgumentMismatch);
app.reset(); app.reset();
@ -770,7 +770,7 @@ TEST_F(TApp, InSetIgnoreCase) {
app.reset(); app.reset();
args = {"--quick=one", "--quick=two"}; args = {"--quick=one", "--quick=two"};
EXPECT_THROW(run(), CLI::ConversionError); EXPECT_THROW(run(), CLI::ArgumentMismatch);
} }
TEST_F(TApp, VectorFixedString) { TEST_F(TApp, VectorFixedString) {
@ -1145,27 +1145,24 @@ TEST_F(TApp, CheckSubcomFail) {
EXPECT_THROW(CLI::detail::AppFriend::parse_subcommand(&app, args), CLI::HorribleError); EXPECT_THROW(CLI::detail::AppFriend::parse_subcommand(&app, args), CLI::HorribleError);
} }
// Added to test defaults on dual method
TEST_F(TApp, OptionWithDefaults) { TEST_F(TApp, OptionWithDefaults) {
int someint = 2; int someint = 2;
app.add_option("-a", someint, "", true); app.add_option("-a", someint, "", true);
args = {"-a1", "-a2"}; args = {"-a1", "-a2"};
EXPECT_THROW(run(), CLI::ConversionError); EXPECT_THROW(run(), CLI::ArgumentMismatch);
} }
// Added to test defaults on dual method
TEST_F(TApp, SetWithDefaults) { TEST_F(TApp, SetWithDefaults) {
int someint = 2; int someint = 2;
app.add_set("-a", someint, {1, 2, 3, 4}, "", true); app.add_set("-a", someint, {1, 2, 3, 4}, "", true);
args = {"-a1", "-a2"}; args = {"-a1", "-a2"};
EXPECT_THROW(run(), CLI::ConversionError); EXPECT_THROW(run(), CLI::ArgumentMismatch);
} }
// Added to test defaults on dual method
TEST_F(TApp, SetWithDefaultsConversion) { TEST_F(TApp, SetWithDefaultsConversion) {
int someint = 2; int someint = 2;
app.add_set("-a", someint, {1, 2, 3, 4}, "", true); app.add_set("-a", someint, {1, 2, 3, 4}, "", true);
@ -1175,14 +1172,13 @@ TEST_F(TApp, SetWithDefaultsConversion) {
EXPECT_THROW(run(), CLI::ConversionError); EXPECT_THROW(run(), CLI::ConversionError);
} }
// Added to test defaults on dual method
TEST_F(TApp, SetWithDefaultsIC) { TEST_F(TApp, SetWithDefaultsIC) {
std::string someint = "ho"; std::string someint = "ho";
app.add_set_ignore_case("-a", someint, {"Hi", "Ho"}, "", true); app.add_set_ignore_case("-a", someint, {"Hi", "Ho"}, "", true);
args = {"-aHi", "-aHo"}; args = {"-aHi", "-aHo"};
EXPECT_THROW(run(), CLI::ConversionError); EXPECT_THROW(run(), CLI::ArgumentMismatch);
} }
// Added to test ->transform // Added to test ->transform