mirror of
https://github.com/KeqingMoe/argparse.git
synced 2025-07-03 22:54:39 +00:00
Fix range of choices bug
- Support range of choices. - Add testcases for range of choices scenario. fix #370
This commit is contained in:
parent
8a7fa18998
commit
43072b8e8c
@ -927,24 +927,26 @@ public:
|
|||||||
}
|
}
|
||||||
|
|
||||||
template <typename Iterator>
|
template <typename Iterator>
|
||||||
void find_value_in_choices_or_throw(Iterator it) const {
|
bool is_value_in_choices(Iterator option_it) const {
|
||||||
|
|
||||||
const auto &choices = m_choices.value();
|
const auto &choices = m_choices.value();
|
||||||
|
|
||||||
if (std::find(choices.begin(), choices.end(), *it) == choices.end()) {
|
return (std::find(choices.begin(), choices.end(), *option_it) !=
|
||||||
// provided arg not in list of allowed choices
|
choices.end());
|
||||||
// report error
|
}
|
||||||
|
|
||||||
std::string choices_as_csv =
|
template <typename Iterator>
|
||||||
std::accumulate(choices.begin(), choices.end(), std::string(),
|
void throw_invalid_arguments_error(Iterator option_it) const {
|
||||||
[](const std::string &a, const std::string &b) {
|
const auto &choices = m_choices.value();
|
||||||
return a + (a.empty() ? "" : ", ") + b;
|
const std::string choices_as_csv = std::accumulate(
|
||||||
});
|
choices.begin(), choices.end(), std::string(),
|
||||||
|
[](const std::string &option_a, const std::string &option_b) {
|
||||||
|
return option_a + (option_a.empty() ? "" : ", ") + option_b;
|
||||||
|
});
|
||||||
|
|
||||||
throw std::runtime_error(std::string{"Invalid argument "} +
|
throw std::runtime_error(std::string{"Invalid argument "} +
|
||||||
details::repr(*it) + " - allowed options: {" +
|
details::repr(*option_it) +
|
||||||
choices_as_csv + "}");
|
" - allowed options: {" + choices_as_csv + "}");
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* The dry_run parameter can be set to true to avoid running the actions,
|
/* The dry_run parameter can be set to true to avoid running the actions,
|
||||||
@ -960,21 +962,30 @@ public:
|
|||||||
}
|
}
|
||||||
m_used_name = used_name;
|
m_used_name = used_name;
|
||||||
|
|
||||||
|
std::size_t passed_options = 0;
|
||||||
|
|
||||||
if (m_choices.has_value()) {
|
if (m_choices.has_value()) {
|
||||||
// Check each value in (start, end) and make sure
|
// Check each value in (start, end) and make sure
|
||||||
// it is in the list of allowed choices/options
|
// it is in the list of allowed choices/options
|
||||||
std::size_t i = 0;
|
const auto max_number_of_args = m_num_args_range.get_max();
|
||||||
auto max_number_of_args = m_num_args_range.get_max();
|
const auto min_number_of_args = m_num_args_range.get_min();
|
||||||
for (auto it = start; it != end; ++it) {
|
for (auto it = start; it != end; ++it) {
|
||||||
if (i == max_number_of_args) {
|
if (is_value_in_choices(it)) {
|
||||||
|
passed_options += 1;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((passed_options >= min_number_of_args) &&
|
||||||
|
(passed_options <= max_number_of_args)) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
find_value_in_choices_or_throw(it);
|
|
||||||
i += 1;
|
throw_invalid_arguments_error(it);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const auto num_args_max = m_num_args_range.get_max();
|
const auto num_args_max =
|
||||||
|
(m_choices.has_value()) ? passed_options : m_num_args_range.get_max();
|
||||||
const auto num_args_min = m_num_args_range.get_min();
|
const auto num_args_min = m_num_args_range.get_min();
|
||||||
std::size_t dist = 0;
|
std::size_t dist = 0;
|
||||||
if (num_args_max == 0) {
|
if (num_args_max == 0) {
|
||||||
@ -1001,7 +1012,6 @@ public:
|
|||||||
std::string(m_used_name) + "'.");
|
std::string(m_used_name) + "'.");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
struct ActionApply {
|
struct ActionApply {
|
||||||
void operator()(valued_action &f) {
|
void operator()(valued_action &f) {
|
||||||
std::transform(first, last, std::back_inserter(self.m_values), f);
|
std::transform(first, last, std::back_inserter(self.m_values), f);
|
||||||
|
@ -155,3 +155,51 @@ TEST_CASE("Parse multiple arguments that are not in fixed number of allowed "
|
|||||||
"Invalid argument \"6\" - allowed options: {1, 2, 3, 4, 5}",
|
"Invalid argument \"6\" - allowed options: {1, 2, 3, 4, 5}",
|
||||||
std::runtime_error);
|
std::runtime_error);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
TEST_CASE("Parse multiple arguments that are in range of allowed "
|
||||||
|
"INTEGER choices (Min Range case)" *
|
||||||
|
test_suite("choices")) {
|
||||||
|
argparse::ArgumentParser program("test");
|
||||||
|
program.add_argument("indices").nargs(1, 3).choices(1, 2, 3, 4, 5);
|
||||||
|
|
||||||
|
REQUIRE_NOTHROW(program.parse_args({"test", "1"}));
|
||||||
|
REQUIRE(program.get<std::vector<std::string>>("indices") ==
|
||||||
|
std::vector<std::string>{"1"});
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_CASE("Parse multiple arguments that are in range of allowed choices (In "
|
||||||
|
"Range case)" *
|
||||||
|
test_suite("choices")) {
|
||||||
|
argparse::ArgumentParser program("test");
|
||||||
|
program.add_argument("--foo");
|
||||||
|
program.add_argument("--bar").nargs(1, 3).choices("a", "b", "c");
|
||||||
|
|
||||||
|
REQUIRE_NOTHROW(
|
||||||
|
program.parse_args({"test", "--bar", "a", "b", "--foo", "x"}));
|
||||||
|
REQUIRE(program.get<std::vector<std::string>>("--bar") ==
|
||||||
|
std::vector<std::string>{"a", "b"});
|
||||||
|
REQUIRE(program.get<std::string>("--foo") == "x");
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_CASE("Parse multiple arguments that are in range of allowed "
|
||||||
|
"INTEGER choices (Max Range case)" *
|
||||||
|
test_suite("choices")) {
|
||||||
|
argparse::ArgumentParser program("test");
|
||||||
|
program.add_argument("indices").nargs(2, 3).choices(1, 2, 3, 4, 5);
|
||||||
|
|
||||||
|
REQUIRE_NOTHROW(program.parse_args({"test", "3", "4", "5"}));
|
||||||
|
REQUIRE(program.get<std::vector<std::string>>("indices") ==
|
||||||
|
std::vector<std::string>{"3", "4", "5"});
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_CASE("Parse multiple arguments that are not in range of allowed choices" *
|
||||||
|
test_suite("choices")) {
|
||||||
|
argparse::ArgumentParser program("test");
|
||||||
|
program.add_argument("--foo");
|
||||||
|
program.add_argument("--bar").nargs(1, 3).choices("a", "b", "c");
|
||||||
|
|
||||||
|
REQUIRE_THROWS_WITH_AS(
|
||||||
|
program.parse_args({"test", "--bar", "d", "--foo", "x"}),
|
||||||
|
"Invalid argument \"d\" - allowed options: {a, b, c}",
|
||||||
|
std::runtime_error);
|
||||||
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user