1
0
mirror of https://github.com/CLIUtils/CLI11.git synced 2025-05-01 21:23:52 +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);
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);
};
@ -293,8 +291,6 @@ class App {
std::string simple_name = CLI::detail::split(name, ',').at(0);
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);
};
@ -325,7 +321,7 @@ class App {
};
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;
}
@ -347,7 +343,7 @@ class App {
};
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)
opt->set_default_str("[" + detail::join(variable) + "]");
return opt;
@ -454,9 +450,6 @@ class App {
std::string simple_name = CLI::detail::split(name, ',').at(0);
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);
if(!retval)
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);
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);
if(!retval)
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);
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]);
auto iter = std::find_if(std::begin(options), std::end(options), [&member](std::string val) {
return detail::to_lower(val) == member;
@ -541,9 +528,6 @@ class App {
std::string simple_name = CLI::detail::split(name, ',').at(0);
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]);
auto iter = std::find_if(std::begin(options), std::end(options), [&member](std::string val) {
return detail::to_lower(val) == member;

View File

@ -43,6 +43,7 @@ enum class ExitCodes {
InvalidError,
HorribleError,
OptionNotFound,
ArgumentMismatch,
BaseClass = 127
};
@ -146,6 +147,17 @@ class RequiredError : public ParseError {
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
class RequiresError : public ParseError {
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)
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");
else if(expected_ == 0)
throw IncorrectConstruction("Cannot make a flag take arguments!");
else if(!changeable_)
throw IncorrectConstruction("You can only change the expected arguments for vectors");
else if(last_)
throw IncorrectConstruction("You can't change expected arguments after you've set take_last!");
expected_ = value;
return this;
}
@ -447,7 +448,11 @@ class Option : public OptionBase<Option> {
results_t partial_result = {results_.back()};
local_result = !callback_(partial_result);
} 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)
@ -527,13 +532,13 @@ class Option : public OptionBase<Option> {
/// @name Custom options
///@{
/// Set a custom option, typestring, expected, and changeable
void set_custom_option(std::string typeval, int expected = 1, bool changeable = false) {
/// Set a custom option, typestring, expected; locks changeable unless expected is -1
void set_custom_option(std::string typeval, int expected = 1) {
typeval_ = typeval;
expected_ = expected;
if(expected == 0)
required_ = false;
changeable_ = changeable;
changeable_ = expected < 0;
}
/// Set the default value string representation

View File

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