From 307ebfe3d07660afff4313aa2385598c4c850341 Mon Sep 17 00:00:00 2001 From: Krzysiek Karbowiak Date: Wed, 5 Mar 2025 18:51:47 +0100 Subject: [PATCH 1/8] Fix positional argument consuming unrecognised optional argument --- include/argparse.h | 33 +++++++++++++++++++++++++++++---- test/unittest/test_parsing.cpp | 8 ++++++++ 2 files changed, 37 insertions(+), 4 deletions(-) diff --git a/include/argparse.h b/include/argparse.h index bb78913b..d834eaa1 100644 --- a/include/argparse.h +++ b/include/argparse.h @@ -317,7 +317,7 @@ namespace argparse auto parse_args(tokens args) -> Parameters { parse_optional_arguments(args); - remove_pseudo_arguments(args); + consume_pseudo_arguments(args); parse_positional_arguments(args); ensure_no_unrecognised_arguments(args); @@ -398,9 +398,12 @@ namespace argparse } } - static auto remove_pseudo_arguments(tokens & args) -> void + static auto consume_pseudo_arguments(tokens & args) -> void { - std::erase(args, Token{"--"}); + for (auto & arg : args | std::views::filter([](auto const & arg) { return arg.m_token == "--"; })) + { + arg.m_consumed = true; + } } auto ensure_no_unrecognised_arguments(tokens const & args) const -> void @@ -681,7 +684,29 @@ namespace argparse auto parse_args(tokens & args) -> void override { - auto consumable = args | std::views::drop_while([](auto const & token) { return token.m_consumed; }); + bool past_pseudo_arg = false; + auto consumable = args + | std::views::drop_while([](auto const & token) + { + if (token.m_token == "--") + { + return false; + } + return token.m_consumed; + }) + | std::views::filter([&past_pseudo_arg](auto const & token) + { + if (past_pseudo_arg) + { + return true; + } + if (token.m_token == "--") + { + past_pseudo_arg = true; + return false; + } + return !token.m_token.starts_with("-"); + }); if (has_nargs()) { if (has_nargs_number()) diff --git a/test/unittest/test_parsing.cpp b/test/unittest/test_parsing.cpp index 429e74c1..8ae29628 100644 --- a/test/unittest/test_parsing.cpp +++ b/test/unittest/test_parsing.cpp @@ -91,3 +91,11 @@ TEST_CASE("Arguments past the -- pseudo argument are treated as positional for p CHECK(parsed.get_value("pos") == "-o"); } + +TEST_CASE("Positional argument does not consume unrecognised optional argument") +{ + auto parser = argparse::ArgumentParser().handle(argparse::Handle::none); + parser.add_argument("pos"); + + CHECK_THROWS(parser.parse_args(2, cstr_arr{"prog", "-o"})); +} From bd890670ea5ed3f51c02ad555b76b95bee19773d Mon Sep 17 00:00:00 2001 From: Krzysiek Karbowiak Date: Wed, 5 Mar 2025 18:54:04 +0100 Subject: [PATCH 2/8] Extend unit test --- test/unittest/test_parsing.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/unittest/test_parsing.cpp b/test/unittest/test_parsing.cpp index 8ae29628..bb5ffc1f 100644 --- a/test/unittest/test_parsing.cpp +++ b/test/unittest/test_parsing.cpp @@ -97,5 +97,5 @@ TEST_CASE("Positional argument does not consume unrecognised optional argument") auto parser = argparse::ArgumentParser().handle(argparse::Handle::none); parser.add_argument("pos"); - CHECK_THROWS(parser.parse_args(2, cstr_arr{"prog", "-o"})); + CHECK_THROWS_WITH_AS(parser.parse_args(2, cstr_arr{"prog", "-o"}), "unrecognised arguments: -o", argparse::parsing_error); } From 8479993b7bdcaefeae22e7a61495b37d8ec85cfb Mon Sep 17 00:00:00 2001 From: Krzysiek Karbowiak Date: Wed, 5 Mar 2025 18:55:12 +0100 Subject: [PATCH 3/8] Add unit test --- test/unittest/test_parsing.cpp | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/test/unittest/test_parsing.cpp b/test/unittest/test_parsing.cpp index bb5ffc1f..7b8bdc6b 100644 --- a/test/unittest/test_parsing.cpp +++ b/test/unittest/test_parsing.cpp @@ -99,3 +99,11 @@ TEST_CASE("Positional argument does not consume unrecognised optional argument") CHECK_THROWS_WITH_AS(parser.parse_args(2, cstr_arr{"prog", "-o"}), "unrecognised arguments: -o", argparse::parsing_error); } + +TEST_CASE("Positional argument does not consume unrecognised optional argument") +{ + auto parser = argparse::ArgumentParser().handle(argparse::Handle::none); + parser.add_argument("pos"); + + CHECK_THROWS(parser.parse_args(2, cstr_arr{"prog", "--option"})); +} From 50f7cb7cb52d82f2375f74372bcf3c63515b507b Mon Sep 17 00:00:00 2001 From: Krzysiek Karbowiak Date: Wed, 5 Mar 2025 18:56:19 +0100 Subject: [PATCH 4/8] Extend unit test --- test/unittest/test_parsing.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/unittest/test_parsing.cpp b/test/unittest/test_parsing.cpp index 7b8bdc6b..780936bd 100644 --- a/test/unittest/test_parsing.cpp +++ b/test/unittest/test_parsing.cpp @@ -105,5 +105,5 @@ TEST_CASE("Positional argument does not consume unrecognised optional argument") auto parser = argparse::ArgumentParser().handle(argparse::Handle::none); parser.add_argument("pos"); - CHECK_THROWS(parser.parse_args(2, cstr_arr{"prog", "--option"})); + CHECK_THROWS_WITH_AS(parser.parse_args(2, cstr_arr{"prog", "--option"}), "unrecognised arguments: --option", argparse::parsing_error); } From 08c975fb5e918635d8f73347f0622a901593f207 Mon Sep 17 00:00:00 2001 From: Krzysiek Karbowiak Date: Wed, 5 Mar 2025 18:59:05 +0100 Subject: [PATCH 5/8] Add unit test --- test/unittest/test_parsing.cpp | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/test/unittest/test_parsing.cpp b/test/unittest/test_parsing.cpp index 780936bd..d5cfd291 100644 --- a/test/unittest/test_parsing.cpp +++ b/test/unittest/test_parsing.cpp @@ -107,3 +107,11 @@ TEST_CASE("Positional argument does not consume unrecognised optional argument") CHECK_THROWS_WITH_AS(parser.parse_args(2, cstr_arr{"prog", "--option"}), "unrecognised arguments: --option", argparse::parsing_error); } + +TEST_CASE("Positional argument does not consume unrecognised optional argument") +{ + auto parser = argparse::ArgumentParser().handle(argparse::Handle::none); + parser.add_argument("pos").nargs(1); + + CHECK_THROWS_WITH_AS(parser.parse_args(2, cstr_arr{"prog", "-o"}), "unrecognised arguments: -o", argparse::parsing_error); +} From 57dc8e0cb3f0b380405c89066c1c773c5849648e Mon Sep 17 00:00:00 2001 From: Krzysiek Karbowiak Date: Wed, 5 Mar 2025 18:59:45 +0100 Subject: [PATCH 6/8] Add unit test --- test/unittest/test_parsing.cpp | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/test/unittest/test_parsing.cpp b/test/unittest/test_parsing.cpp index d5cfd291..2fd7f9f6 100644 --- a/test/unittest/test_parsing.cpp +++ b/test/unittest/test_parsing.cpp @@ -115,3 +115,11 @@ TEST_CASE("Positional argument does not consume unrecognised optional argument") CHECK_THROWS_WITH_AS(parser.parse_args(2, cstr_arr{"prog", "-o"}), "unrecognised arguments: -o", argparse::parsing_error); } + +TEST_CASE("Positional argument does not consume unrecognised optional argument") +{ + auto parser = argparse::ArgumentParser().handle(argparse::Handle::none); + parser.add_argument("pos").nargs(2); + + CHECK_THROWS_WITH_AS(parser.parse_args(2, cstr_arr{"prog", "-o"}), "unrecognised arguments: -o", argparse::parsing_error); +} From 06a846d332a55bb67b2d890eba8fbef6773d33f8 Mon Sep 17 00:00:00 2001 From: Krzysiek Karbowiak Date: Wed, 5 Mar 2025 19:01:43 +0100 Subject: [PATCH 7/8] Add unit test --- test/unittest/test_parsing.cpp | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/test/unittest/test_parsing.cpp b/test/unittest/test_parsing.cpp index 2fd7f9f6..216d4290 100644 --- a/test/unittest/test_parsing.cpp +++ b/test/unittest/test_parsing.cpp @@ -123,3 +123,19 @@ TEST_CASE("Positional argument does not consume unrecognised optional argument") CHECK_THROWS_WITH_AS(parser.parse_args(2, cstr_arr{"prog", "-o"}), "unrecognised arguments: -o", argparse::parsing_error); } + +TEST_CASE("Positional argument does not consume unrecognised optional argument") +{ + auto parser = argparse::ArgumentParser().handle(argparse::Handle::none); + parser.add_argument("pos").nargs(argparse::zero_or_one); + + CHECK_THROWS_WITH_AS(parser.parse_args(2, cstr_arr{"prog", "-o"}), "unrecognised arguments: -o", argparse::parsing_error); +} + +TEST_CASE("Positional argument does not consume unrecognised optional argument") +{ + auto parser = argparse::ArgumentParser().handle(argparse::Handle::none); + parser.add_argument("pos").nargs(argparse::zero_or_more); + + CHECK_THROWS_WITH_AS(parser.parse_args(2, cstr_arr{"prog", "-o"}), "unrecognised arguments: -o", argparse::parsing_error); +} From 39a0c6e0f85ef50c988f49497a209fb5f7c46d9c Mon Sep 17 00:00:00 2001 From: Krzysiek Karbowiak Date: Wed, 5 Mar 2025 19:02:14 +0100 Subject: [PATCH 8/8] Add unit test --- test/unittest/test_parsing.cpp | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/test/unittest/test_parsing.cpp b/test/unittest/test_parsing.cpp index 216d4290..27187111 100644 --- a/test/unittest/test_parsing.cpp +++ b/test/unittest/test_parsing.cpp @@ -139,3 +139,11 @@ TEST_CASE("Positional argument does not consume unrecognised optional argument") CHECK_THROWS_WITH_AS(parser.parse_args(2, cstr_arr{"prog", "-o"}), "unrecognised arguments: -o", argparse::parsing_error); } + +TEST_CASE("Positional argument does not consume unrecognised optional argument") +{ + auto parser = argparse::ArgumentParser().handle(argparse::Handle::none); + parser.add_argument("pos").nargs(argparse::one_or_more); + + CHECK_THROWS_WITH_AS(parser.parse_args(2, cstr_arr{"prog", "-o"}), "unrecognised arguments: -o", argparse::parsing_error); +}