Update argparse.
Otherwise .choices doesn't work properly. See https://github.com/p-ranav/argparse/issues/307
This commit is contained in:
parent
219d0c399d
commit
991b4299d6
|
@ -30,11 +30,12 @@ SOFTWARE.
|
||||||
*/
|
*/
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
|
#include <cerrno>
|
||||||
|
|
||||||
#ifndef ARGPARSE_MODULE_USE_STD_MODULE
|
#ifndef ARGPARSE_MODULE_USE_STD_MODULE
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
#include <any>
|
#include <any>
|
||||||
#include <array>
|
#include <array>
|
||||||
#include <cerrno>
|
|
||||||
#include <charconv>
|
#include <charconv>
|
||||||
#include <cstdlib>
|
#include <cstdlib>
|
||||||
#include <functional>
|
#include <functional>
|
||||||
|
@ -657,7 +658,7 @@ public:
|
||||||
}
|
}
|
||||||
|
|
||||||
template <class F, class... Args>
|
template <class F, class... Args>
|
||||||
auto action(F &&callable, Args &&...bound_args)
|
auto action(F &&callable, Args &&... bound_args)
|
||||||
-> std::enable_if_t<std::is_invocable_v<F, Args..., std::string const>,
|
-> std::enable_if_t<std::is_invocable_v<F, Args..., std::string const>,
|
||||||
Argument &> {
|
Argument &> {
|
||||||
using action_type = std::conditional_t<
|
using action_type = std::conditional_t<
|
||||||
|
@ -783,7 +784,7 @@ public:
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename T, typename... U>
|
template <typename T, typename... U>
|
||||||
Argument &choices(T &&first, U &&...rest) {
|
Argument &choices(T &&first, U &&... rest) {
|
||||||
add_choice(std::forward<T>(first));
|
add_choice(std::forward<T>(first));
|
||||||
choices(std::forward<U>(rest)...);
|
choices(std::forward<U>(rest)...);
|
||||||
return *this;
|
return *this;
|
||||||
|
@ -845,8 +846,14 @@ public:
|
||||||
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;
|
||||||
|
auto max_number_of_args = m_num_args_range.get_max();
|
||||||
for (auto it = start; it != end; ++it) {
|
for (auto it = start; it != end; ++it) {
|
||||||
|
if (i == max_number_of_args) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
find_value_in_choices_or_throw(it);
|
find_value_in_choices_or_throw(it);
|
||||||
|
i += 1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1546,7 +1553,7 @@ public:
|
||||||
// Parameter packed add_parents method
|
// Parameter packed add_parents method
|
||||||
// Accepts a variadic number of ArgumentParser objects
|
// Accepts a variadic number of ArgumentParser objects
|
||||||
template <typename... Targs>
|
template <typename... Targs>
|
||||||
ArgumentParser &add_parents(const Targs &...f_args) {
|
ArgumentParser &add_parents(const Targs &... f_args) {
|
||||||
for (const ArgumentParser &parent_parser : {std::ref(f_args)...}) {
|
for (const ArgumentParser &parent_parser : {std::ref(f_args)...}) {
|
||||||
for (const auto &argument : parent_parser.m_positional_arguments) {
|
for (const auto &argument : parent_parser.m_positional_arguments) {
|
||||||
auto it = m_positional_arguments.insert(
|
auto it = m_positional_arguments.insert(
|
||||||
|
|
|
@ -33,12 +33,13 @@ module;
|
||||||
|
|
||||||
#ifndef ARGPARSE_MODULE_USE_STD_MODULE
|
#ifndef ARGPARSE_MODULE_USE_STD_MODULE
|
||||||
#include <argparse/argparse.hpp>
|
#include <argparse/argparse.hpp>
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
export module argparse;
|
export module argparse;
|
||||||
|
|
||||||
#ifdef ARGPARSE_MODULE_USE_STD_MODULE
|
#ifdef ARGPARSE_MODULE_USE_STD_MODULE
|
||||||
import std;
|
import std;
|
||||||
|
import std.compat;
|
||||||
|
|
||||||
extern "C++" {
|
extern "C++" {
|
||||||
#include <argparse/argparse.hpp>
|
#include <argparse/argparse.hpp>
|
||||||
|
|
|
@ -23,6 +23,72 @@ TEST_CASE("Parse argument that is in the fixed number of allowed choices" *
|
||||||
program.parse_args({"test", "red"});
|
program.parse_args({"test", "red"});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
TEST_CASE("Parse argument that is in the fixed number of allowed choices, with "
|
||||||
|
"other positional argument" *
|
||||||
|
test_suite("choices")) {
|
||||||
|
argparse::ArgumentParser program("test");
|
||||||
|
program.add_argument("--input")
|
||||||
|
.default_value(std::string{"baz"})
|
||||||
|
.choices("foo", "bar", "baz");
|
||||||
|
program.add_argument("--value").scan<'i', int>().default_value(0);
|
||||||
|
|
||||||
|
REQUIRE_NOTHROW(
|
||||||
|
program.parse_args({"test", "--input", "foo", "--value", "1"}));
|
||||||
|
REQUIRE(program.get("--input") == "foo");
|
||||||
|
REQUIRE(program.get<int>("--value") == 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_CASE(
|
||||||
|
"Parse nargs argument that is in the fixed number of allowed choices, with "
|
||||||
|
"other positional argument" *
|
||||||
|
test_suite("choices")) {
|
||||||
|
argparse::ArgumentParser program("test");
|
||||||
|
program.add_argument("--input")
|
||||||
|
.default_value(std::string{"baz"})
|
||||||
|
.choices("foo", "bar", "baz")
|
||||||
|
.nargs(2);
|
||||||
|
program.add_argument("--value").scan<'i', int>().default_value(0);
|
||||||
|
|
||||||
|
REQUIRE_NOTHROW(
|
||||||
|
program.parse_args({"test", "--input", "foo", "bar", "--value", "1"}));
|
||||||
|
REQUIRE((program.get<std::vector<std::string>>("--input") ==
|
||||||
|
std::vector<std::string>{"foo", "bar"}));
|
||||||
|
REQUIRE(program.get<int>("--value") == 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_CASE("Parse argument that is in the fixed number of allowed choices, with "
|
||||||
|
"other positional argument (reversed)" *
|
||||||
|
test_suite("choices")) {
|
||||||
|
argparse::ArgumentParser program("test");
|
||||||
|
program.add_argument("--input")
|
||||||
|
.default_value(std::string{"baz"})
|
||||||
|
.choices("foo", "bar", "baz");
|
||||||
|
program.add_argument("--value").scan<'i', int>().default_value(0);
|
||||||
|
|
||||||
|
REQUIRE_NOTHROW(
|
||||||
|
program.parse_args({"test", "--value", "1", "--input", "foo"}));
|
||||||
|
REQUIRE(program.get("--input") == "foo");
|
||||||
|
REQUIRE(program.get<int>("--value") == 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_CASE(
|
||||||
|
"Parse nargs argument that is in the fixed number of allowed choices, with "
|
||||||
|
"other positional argument (reversed)" *
|
||||||
|
test_suite("choices")) {
|
||||||
|
argparse::ArgumentParser program("test");
|
||||||
|
program.add_argument("--input")
|
||||||
|
.default_value(std::string{"baz"})
|
||||||
|
.choices("foo", "bar", "baz")
|
||||||
|
.nargs(2);
|
||||||
|
program.add_argument("--value").scan<'i', int>().default_value(0);
|
||||||
|
|
||||||
|
REQUIRE_NOTHROW(
|
||||||
|
program.parse_args({"test", "--value", "1", "--input", "foo", "bar"}));
|
||||||
|
REQUIRE((program.get<std::vector<std::string>>("--input") ==
|
||||||
|
std::vector<std::string>{"foo", "bar"}));
|
||||||
|
REQUIRE(program.get<int>("--value") == 1);
|
||||||
|
}
|
||||||
|
|
||||||
TEST_CASE("Parse argument that is in the fixed number of allowed choices, with "
|
TEST_CASE("Parse argument that is in the fixed number of allowed choices, with "
|
||||||
"invalid default" *
|
"invalid default" *
|
||||||
test_suite("choices")) {
|
test_suite("choices")) {
|
||||||
|
@ -88,4 +154,4 @@ TEST_CASE("Parse multiple arguments that are not in fixed number of allowed "
|
||||||
program.parse_args({"test", "6", "7"}),
|
program.parse_args({"test", "6", "7"}),
|
||||||
"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);
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,27 +0,0 @@
|
||||||
#include <argparse/argparse.hpp>
|
|
||||||
#include <doctest.hpp>
|
|
||||||
|
|
||||||
using doctest::test_suite;
|
|
||||||
|
|
||||||
TEST_CASE("ArgumentParser is const-correct after construction and parsing" *
|
|
||||||
test_suite("value_semantics")) {
|
|
||||||
GIVEN("a parser") {
|
|
||||||
argparse::ArgumentParser parser("test");
|
|
||||||
parser.add_argument("--foo", "-f").help("I am foo");
|
|
||||||
parser.add_description("A description");
|
|
||||||
parser.add_epilog("An epilog");
|
|
||||||
|
|
||||||
WHEN("becomes const-qualified") {
|
|
||||||
parser.parse_args({"./main", "--foo", "baz"});
|
|
||||||
const auto const_parser = std::move(parser);
|
|
||||||
|
|
||||||
THEN("only const methods are accessible") {
|
|
||||||
REQUIRE(const_parser.help().str().size() > 0);
|
|
||||||
REQUIRE(const_parser.present<std::string>("--foo"));
|
|
||||||
REQUIRE(const_parser.is_used("-f"));
|
|
||||||
REQUIRE(const_parser.get("-f") == "baz");
|
|
||||||
REQUIRE(const_parser["-f"] == std::string("baz"));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,96 +0,0 @@
|
||||||
#include <argparse/argparse.hpp>
|
|
||||||
#include <doctest.hpp>
|
|
||||||
|
|
||||||
using doctest::test_suite;
|
|
||||||
|
|
||||||
TEST_CASE("ArgumentParser is MoveConstructible and MoveAssignable" *
|
|
||||||
test_suite("value_semantics")) {
|
|
||||||
GIVEN("a parser that has two arguments") {
|
|
||||||
argparse::ArgumentParser parser("test");
|
|
||||||
parser.add_argument("foo");
|
|
||||||
parser.add_argument("-f");
|
|
||||||
|
|
||||||
WHEN("move construct a new parser from it") {
|
|
||||||
auto new_parser = std::move(parser);
|
|
||||||
|
|
||||||
THEN("the old parser replaces the new parser") {
|
|
||||||
new_parser.parse_args({"test", "bar", "-f", "nul"});
|
|
||||||
|
|
||||||
REQUIRE(new_parser.get("foo") == "bar");
|
|
||||||
REQUIRE(new_parser.get("-f") == "nul");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
WHEN("move assign a parser prvalue to it") {
|
|
||||||
parser = argparse::ArgumentParser("test");
|
|
||||||
|
|
||||||
THEN("the old parser is replaced") {
|
|
||||||
REQUIRE_THROWS_AS(parser.parse_args({"test", "bar"}),
|
|
||||||
std::runtime_error);
|
|
||||||
REQUIRE_THROWS_AS(parser.parse_args({"test", "-f", "nul"}),
|
|
||||||
std::runtime_error);
|
|
||||||
REQUIRE_NOTHROW(parser.parse_args({"test"}));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
TEST_CASE("ArgumentParser is CopyConstructible and CopyAssignable" *
|
|
||||||
test_suite("value_semantics")) {
|
|
||||||
GIVEN("a parser that has two arguments") {
|
|
||||||
argparse::ArgumentParser parser("test");
|
|
||||||
parser.add_argument("foo");
|
|
||||||
parser.add_argument("-f");
|
|
||||||
|
|
||||||
WHEN("copy construct a new parser from it") {
|
|
||||||
auto new_parser = parser;
|
|
||||||
|
|
||||||
THEN("the new parser has the old parser's capability") {
|
|
||||||
new_parser.parse_args({"test", "bar", "-f", "nul"});
|
|
||||||
|
|
||||||
REQUIRE(new_parser.get("foo") == "bar");
|
|
||||||
REQUIRE(new_parser.get("-f") == "nul");
|
|
||||||
|
|
||||||
AND_THEN("but does not share states with the old parser") {
|
|
||||||
REQUIRE_THROWS_AS(parser.get("foo"), std::logic_error);
|
|
||||||
REQUIRE_THROWS_AS(parser.get("-f"), std::logic_error);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
AND_THEN("the old parser works as a distinct copy") {
|
|
||||||
new_parser.parse_args({"test", "toe", "-f", "/"});
|
|
||||||
|
|
||||||
REQUIRE(new_parser.get("foo") == "toe");
|
|
||||||
REQUIRE(new_parser.get("-f") == "/");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
WHEN("copy assign a parser lvalue to it") {
|
|
||||||
argparse::ArgumentParser optional_parser("test");
|
|
||||||
optional_parser.add_argument("-g");
|
|
||||||
parser = optional_parser;
|
|
||||||
|
|
||||||
THEN("the old parser is replaced") {
|
|
||||||
REQUIRE_THROWS_AS(parser.parse_args({"test", "bar"}),
|
|
||||||
std::runtime_error);
|
|
||||||
REQUIRE_THROWS_AS(parser.parse_args({"test", "-f", "nul"}),
|
|
||||||
std::runtime_error);
|
|
||||||
REQUIRE_NOTHROW(parser.parse_args({"test"}));
|
|
||||||
REQUIRE_NOTHROW(parser.parse_args({"test", "-g", "nul"}));
|
|
||||||
|
|
||||||
AND_THEN("but does not share states with the other parser") {
|
|
||||||
REQUIRE(parser.get("-g") == "nul");
|
|
||||||
REQUIRE_THROWS_AS(optional_parser.get("-g"), std::logic_error);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
AND_THEN("the other parser works as a distinct copy") {
|
|
||||||
REQUIRE_NOTHROW(optional_parser.parse_args({"test"}));
|
|
||||||
REQUIRE_NOTHROW(optional_parser.parse_args({"test", "-g", "nul"}));
|
|
||||||
REQUIRE_THROWS_AS(
|
|
||||||
optional_parser.parse_args({"test", "bar", "-g", "nul"}),
|
|
||||||
std::runtime_error);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
Loading…
Reference in New Issue