#include "argparser/argparser.h" #include "gtest/gtest.h" // TODO: test whitespace in tuples and arrays // TODO: test empty values for everything // TODO: test option->has(result), flag->has(result) and arg->has(result) // TODO: test enum types and commas // TODO: fuzz testing (blocked on clang 16 being available on arch) class Parser : public ::testing::Test { protected: argparser::parser p{}; argparser::type_handle_impl uintType; Parser() = default; ~Parser() override = default; void SetUp() override { uintType = p.basic_type("uint"); } void TearDown() override { } }; TEST_F(Parser, SingleOption) { auto fooOption = p.option("--foo", uintType); auto parsed = p.parse({"--foo", "123"}); auto foo = fooOption->get(parsed); EXPECT_EQ(foo, 123); } TEST_F(Parser, OptionWithEqualsSign) { auto fooOption = p.option("--foo", uintType); auto parsed = p.parse({"--foo=123"}); auto foo = fooOption->get(parsed); EXPECT_EQ(foo, 123); } TEST_F(Parser, MultipleOptions) { auto fooOption = p.option("--foo", uintType); auto barOption = p.option("--bar", uintType); auto parsed = p.parse({"--foo", "234", "--bar", "345"}); auto foo = fooOption->get(parsed); auto bar = barOption->get(parsed); EXPECT_EQ(foo, 234); EXPECT_EQ(bar, 345); } TEST_F(Parser, MultipleOptionsDifferentOrder) { auto fooOption = p.option("--foo", uintType); auto barOption = p.option("--bar", uintType); auto parsed = p.parse({"--bar", "345", "--foo", "234"}); auto foo = fooOption->get(parsed); auto bar = barOption->get(parsed); EXPECT_EQ(foo, 234); EXPECT_EQ(bar, 345); } TEST_F(Parser, OptionsAreNotRequiredByDefault) { auto fooOption = p.option("--foo", uintType); auto barOption = p.option("--bar", uintType); auto parsed = p.parse({"--foo", "234"}); auto foo = fooOption->get(parsed); auto has_bar = barOption->has(parsed); EXPECT_EQ(foo, 234); EXPECT_EQ(has_bar, false); } TEST_F(Parser, RequiredOption) { auto _1 = p.option("--foo", uintType); [[maybe_unused]] auto _2 = p.option("--bar", uintType)->required(); EXPECT_THROW(auto _3 = p.parse({"--foo", "234"});, argparser::errors::missing_option_error); } TEST_F(Parser, MissingValue) { auto _1 = p.option("--foo", uintType); EXPECT_THROW(auto _2 = p.parse({"--foo"});, argparser::errors::missing_option_value_error); } TEST_F(Parser, MissingValueWithNextOption) { auto _1 = p.option("--foo", uintType); auto _2 = p.option("--bar", uintType); EXPECT_THROW(auto _3 = p.parse({"--foo", "--bar", "123"});, argparser::errors::missing_option_value_error); } TEST_F(Parser, InvalidValue) { auto _1 = p.option("--foo", uintType); EXPECT_THROW(auto _2 = p.parse({"--foo", "-12"});, argparser::errors::type_parsing_error); } TEST_F(Parser, InvalidEmptyValue) { auto _1 = p.option("--foo", uintType); EXPECT_THROW(auto _2 = p.parse({"--foo", ""});, argparser::errors::type_parsing_error); } TEST_F(Parser, OptionPassedMultipleTimesReturnsLastValue) { auto fooOption = p.option("--foo", uintType); auto parsed = p.parse({"--foo", "23", "--foo", "45"}); EXPECT_EQ(fooOption->get(parsed), 45); } TEST_F(Parser, OptionNameMustStartWithTwoDashes) { EXPECT_THROW(auto _1 = p.option("foo", uintType);, argparser::errors::invalid_option_name_error); } TEST_F(Parser, DefaultValue) { auto fooOption = p.option("--foo", uintType)->default_value(123); auto parsed = p.parse({}); EXPECT_EQ(fooOption->get(parsed), 123); EXPECT_EQ(fooOption->has(parsed), false); } TEST_F(Parser, RepeatableOption) { auto fooOption = p.repeatable_option("--foo", uintType); auto parsed = p.parse({"--foo", "123", "--foo", "234"}); auto foo = fooOption->get(parsed); EXPECT_EQ(foo.size(), 2); EXPECT_EQ(foo[0], 123); EXPECT_EQ(foo[1], 234); } TEST_F(Parser, RepeatableOptionDefaultValue) { auto fooOption = p.repeatable_option("--foo", uintType)->default_value({1, 2, 3}); auto parsed = p.parse({}); auto foo = fooOption->get(parsed); EXPECT_EQ(foo.size(), 3); EXPECT_EQ(foo[0], 1); EXPECT_EQ(foo[1], 2); EXPECT_EQ(foo[2], 3); } TEST_F(Parser, RepeatableOptionLimits) { auto fooFlag = p.repeatable_option("--foo", uintType)->min(2)->max(4); auto parsed = p.parse({"--foo", "1", "--foo", "2"}); auto val = fooFlag->get(parsed); EXPECT_EQ(val.size(), 2); EXPECT_EQ(val[0], 1); EXPECT_EQ(val[1], 2); parsed = p.parse({"--foo", "1", "--foo", "2", "--foo", "3"}); val = fooFlag->get(parsed); EXPECT_EQ(val.size(), 3); EXPECT_EQ(val[0], 1); EXPECT_EQ(val[1], 2); EXPECT_EQ(val[2], 3); parsed = p.parse({"--foo", "1", "--foo", "2", "--foo", "3", "--foo", "4"}); val = fooFlag->get(parsed); EXPECT_EQ(val.size(), 4); EXPECT_EQ(val[0], 1); EXPECT_EQ(val[1], 2); EXPECT_EQ(val[2], 3); EXPECT_EQ(val[3], 4); EXPECT_THROW(auto _1 = p.parse({});, argparser::errors::wrong_option_count_error); EXPECT_THROW(auto _2 = p.parse({"--foo", "1"});, argparser::errors::wrong_option_count_error); EXPECT_THROW(auto _3 = p.parse({"--foo", "1", "--foo", "2", "--foo", "3", "--foo", "4", "--foo", "5"});, argparser::errors::wrong_option_count_error); EXPECT_THROW(auto _4 = p.parse({"--foo", "1", "--foo", "2", "--foo", "3", "--foo", "4", "--foo", "5", "--foo", "6"});, argparser::errors::wrong_option_count_error); } TEST_F(Parser, Flag) { auto fooFlag = p.flag("--foo"); auto parsed = p.parse({"--foo"}); EXPECT_EQ(fooFlag->get(parsed), true); parsed = p.parse({}); EXPECT_EQ(fooFlag->get(parsed), false); } TEST_F(Parser, FlagInverted) { auto fooFlag = p.flag("--foo")->invert(); auto parsed = p.parse({"--foo"}); EXPECT_EQ(fooFlag->get(parsed), false); parsed = p.parse({}); EXPECT_EQ(fooFlag->get(parsed), true); } TEST_F(Parser, RepeatableFLag) { auto fooFlag = p.repeatable_flag("--foo"); auto parsed = p.parse({}); EXPECT_EQ(fooFlag->get(parsed), 0); parsed = p.parse({"--foo"}); EXPECT_EQ(fooFlag->get(parsed), 1); parsed = p.parse({"--foo", "--foo", "--foo", "--foo", "--foo"}); EXPECT_EQ(fooFlag->get(parsed), 5); } TEST_F(Parser, RepeatableFlagLimits) { auto fooFlag = p.repeatable_flag("--foo")->min(2)->max(4); auto parsed = p.parse({"--foo", "--foo"}); EXPECT_EQ(fooFlag->get(parsed), 2); parsed = p.parse({"--foo", "--foo", "--foo"}); EXPECT_EQ(fooFlag->get(parsed), 3); parsed = p.parse({"--foo", "--foo", "--foo", "--foo"}); EXPECT_EQ(fooFlag->get(parsed), 4); EXPECT_THROW(auto _1 = p.parse({});, argparser::errors::wrong_option_count_error); EXPECT_THROW(auto _2 = p.parse({"--foo"});, argparser::errors::wrong_option_count_error); EXPECT_THROW(auto _3 = p.parse({"--foo", "--foo", "--foo", "--foo", "--foo"});, argparser::errors::wrong_option_count_error); EXPECT_THROW(auto _4 = p.parse({"--foo", "--foo", "--foo", "--foo", "--foo", "--foo"});, argparser::errors::wrong_option_count_error); } TEST_F(Parser, OptionAndFlagNamesMustBeUnique) { EXPECT_THROW({ auto _1 = p.option("--optopt", uintType); auto _2 = p.option("--optopt", uintType); }, argparser::errors::duplicate_option_name); EXPECT_THROW({ auto _1 = p.flag("--flagflag"); auto _2 = p.flag("--flagflag"); }, argparser::errors::duplicate_option_name); EXPECT_THROW({ auto _1 = p.option("--optflag", uintType); auto _2 = p.flag("--optflag"); }, argparser::errors::duplicate_option_name); EXPECT_THROW({ auto _1 = p.option("--optrepflag", uintType); auto _2 = p.repeatable_flag("--optrepflag"); }, argparser::errors::duplicate_option_name); EXPECT_THROW({ auto _1 = p.flag("--flagopt"); auto _2 = p.option("--flagopt", uintType); }, argparser::errors::duplicate_option_name); } TEST_F(Parser, OptionWithOnlyShortName) { auto fooOpt = p.option("-f", uintType); argparser::parse_result pr; uint32_t fooVal; EXPECT_NO_THROW(pr = p.parse({"-f", "123"})); EXPECT_NO_THROW(fooVal = fooOpt->get(pr)); EXPECT_EQ(fooVal, 123); } TEST_F(Parser, RepeatableOptionWithOnlyShortName) { auto fooOpt = p.repeatable_option("-f", uintType); argparser::parse_result pr; std::vector fooVal; EXPECT_NO_THROW(pr = p.parse({"-f", "123"})); EXPECT_NO_THROW(fooVal = fooOpt->get(pr)); EXPECT_EQ(fooVal, (decltype(fooVal){123})); } TEST_F(Parser, FlagWithOnlyShortName) { auto fooFlag = p.flag("-f"); argparser::parse_result pr; bool fooVal; EXPECT_NO_THROW(pr = p.parse({"-f"})); EXPECT_NO_THROW(fooVal = fooFlag->get(pr)); EXPECT_EQ(fooVal, true); } TEST_F(Parser, RepeatableFlagWithOnlyShortName) { auto fooFlag = p.flag("-f"); argparser::parse_result pr; unsigned int fooVal; EXPECT_NO_THROW(pr = p.parse({"-f"})); EXPECT_NO_THROW(fooVal = fooFlag->get(pr)); EXPECT_EQ(fooVal, 1); } TEST_F(Parser, OptionWithLongAndShortName) { auto fooOpt = p.option("--foo", "-f", uintType); argparser::parse_result pr; uint32_t fooVal; EXPECT_NO_THROW(pr = p.parse({"-f", "123"})); EXPECT_NO_THROW(fooVal = fooOpt->get(pr)); EXPECT_EQ(fooVal, 123); EXPECT_NO_THROW(pr = p.parse({"--foo", "123"})); EXPECT_NO_THROW(fooVal = fooOpt->get(pr)); EXPECT_EQ(fooVal, 123); } TEST_F(Parser, OptionWithShortAndLongName) { auto fooOpt = p.option("-f", "--foo", uintType); argparser::parse_result pr; uint32_t fooVal; EXPECT_NO_THROW(pr = p.parse({"-f", "123"})); EXPECT_NO_THROW(fooVal = fooOpt->get(pr)); EXPECT_EQ(fooVal, 123); EXPECT_NO_THROW(pr = p.parse({"--foo", "123"})); EXPECT_NO_THROW(fooVal = fooOpt->get(pr)); EXPECT_EQ(fooVal, 123); } TEST_F(Parser, RepeatableOptionWithLongAndShortName) { auto fooOpt = p.repeatable_option("--foo", "-f", uintType); argparser::parse_result pr; std::vector fooVal; EXPECT_NO_THROW(pr = p.parse({"-f", "123"})); EXPECT_NO_THROW(fooVal = fooOpt->get(pr)); EXPECT_EQ(fooVal, (decltype(fooVal){123})); EXPECT_NO_THROW(pr = p.parse({"--foo", "123"})); EXPECT_NO_THROW(fooVal = fooOpt->get(pr)); EXPECT_EQ(fooVal, (decltype(fooVal){123})); EXPECT_NO_THROW(pr = p.parse({"--foo", "123", "-f", "234"})); EXPECT_NO_THROW(fooVal = fooOpt->get(pr)); EXPECT_EQ(fooVal, (decltype(fooVal){123, 234})); EXPECT_NO_THROW(pr = p.parse({"-f", "123", "--foo", "234"})); EXPECT_NO_THROW(fooVal = fooOpt->get(pr)); EXPECT_EQ(fooVal, (decltype(fooVal){123, 234})); } TEST_F(Parser, RepeatableOptionWithShortAndLongName) { auto fooOpt = p.repeatable_option("-f", "--foo", uintType); argparser::parse_result pr; std::vector fooVal; EXPECT_NO_THROW(pr = p.parse({"-f", "123"})); EXPECT_NO_THROW(fooVal = fooOpt->get(pr)); EXPECT_EQ(fooVal, (decltype(fooVal){123})); EXPECT_NO_THROW(pr = p.parse({"--foo", "123"})); EXPECT_NO_THROW(fooVal = fooOpt->get(pr)); EXPECT_EQ(fooVal, (decltype(fooVal){123})); EXPECT_NO_THROW(pr = p.parse({"--foo", "123", "-f", "234"})); EXPECT_NO_THROW(fooVal = fooOpt->get(pr)); EXPECT_EQ(fooVal, (decltype(fooVal){123, 234})); EXPECT_NO_THROW(pr = p.parse({"-f", "123", "--foo", "234"})); EXPECT_NO_THROW(fooVal = fooOpt->get(pr)); EXPECT_EQ(fooVal, (decltype(fooVal){123, 234})); } TEST_F(Parser, FlagWithLongAndSHortName) { auto fooFlag = p.flag("--foo", "-f"); argparser::parse_result pr; bool fooVal; EXPECT_NO_THROW(pr = p.parse({"-f"})); EXPECT_NO_THROW(fooVal = fooFlag->get(pr)); EXPECT_EQ(fooVal, true); EXPECT_NO_THROW(pr = p.parse({"--foo"})); EXPECT_NO_THROW(fooVal = fooFlag->get(pr)); EXPECT_EQ(fooVal, true); } TEST_F(Parser, FlagWithShortAndLongName) { auto fooFlag = p.flag("-f", "--foo"); argparser::parse_result pr; bool fooVal; EXPECT_NO_THROW(pr = p.parse({"-f"})); EXPECT_NO_THROW(fooVal = fooFlag->get(pr)); EXPECT_EQ(fooVal, true); EXPECT_NO_THROW(pr = p.parse({"--foo"})); EXPECT_NO_THROW(fooVal = fooFlag->get(pr)); EXPECT_EQ(fooVal, true); } TEST_F(Parser, RepeatableFlagWithLongAndShortName) { auto fooFlag = p.repeatable_flag("--foo", "-f"); argparser::parse_result pr; unsigned int fooVal; EXPECT_NO_THROW(pr = p.parse({"-f"})); EXPECT_NO_THROW(fooVal = fooFlag->get(pr)); EXPECT_EQ(fooVal, 1); EXPECT_NO_THROW(pr = p.parse({"--foo"})); EXPECT_NO_THROW(fooVal = fooFlag->get(pr)); EXPECT_EQ(fooVal, 1); EXPECT_NO_THROW(pr = p.parse({"-f", "--foo"})); EXPECT_NO_THROW(fooVal = fooFlag->get(pr)); EXPECT_EQ(fooVal, 2); EXPECT_NO_THROW(pr = p.parse({"--foo", "-f"})); EXPECT_NO_THROW(fooVal = fooFlag->get(pr)); EXPECT_EQ(fooVal, 2); } TEST_F(Parser, RepeatableFlagWithShortAndLongName) { auto fooFlag = p.repeatable_flag("-f", "--foo"); argparser::parse_result pr; unsigned int fooVal; EXPECT_NO_THROW(pr = p.parse({"-f"})); EXPECT_NO_THROW(fooVal = fooFlag->get(pr)); EXPECT_EQ(fooVal, 1); EXPECT_NO_THROW(pr = p.parse({"--foo"})); EXPECT_NO_THROW(fooVal = fooFlag->get(pr)); EXPECT_EQ(fooVal, 1); EXPECT_NO_THROW(pr = p.parse({"-f", "--foo"})); EXPECT_NO_THROW(fooVal = fooFlag->get(pr)); EXPECT_EQ(fooVal, 2); EXPECT_NO_THROW(pr = p.parse({"--foo", "-f"})); EXPECT_NO_THROW(fooVal = fooFlag->get(pr)); EXPECT_EQ(fooVal, 2); } TEST_F(Parser, ShortOptionCombinedWithValue) { auto fooOpt = p.option("-f", uintType); argparser::parse_result pr; uint32_t fooVal; EXPECT_NO_THROW(pr = p.parse({"-f123"})); EXPECT_NO_THROW(fooVal = fooOpt->get(pr)); EXPECT_EQ(fooVal, 123); } TEST_F(Parser, MultipleShortFlags) { auto flagA = p.flag("-a"); auto flagB = p.flag("-b"); auto flagC = p.flag("-c"); argparser::parse_result pr; EXPECT_NO_THROW(pr = p.parse({"-cab"})); EXPECT_EQ(flagA->get(pr), true); EXPECT_EQ(flagB->get(pr), true); EXPECT_EQ(flagC->get(pr), true); } TEST_F(Parser, MultipleShortFlagsCombinedWithShortOptionWithValue) { auto flagA = p.flag("-a"); auto flagB = p.flag("-b"); auto flagC = p.flag("-c"); auto fooOpt = p.option("-f", uintType); argparser::parse_result pr; EXPECT_NO_THROW(pr = p.parse({"-cabf123"})); EXPECT_EQ(flagA->get(pr), true); EXPECT_EQ(flagB->get(pr), true); EXPECT_EQ(flagC->get(pr), true); EXPECT_EQ(fooOpt->get(pr), 123); } TEST_F(Parser, SingleArgument) { auto fooArg = p.arg("foo", uintType); auto parsed = p.parse({"123"}); EXPECT_EQ(fooArg->get(parsed), 123); } TEST_F(Parser, MissingArgumentThrows) { auto fooArg = p.arg("foo", uintType); EXPECT_THROW(auto _ = p.parse({});, argparser::errors::missing_argument_error); } TEST_F(Parser, MultipleArguments) { auto fooArg = p.arg("foo", uintType); auto barArg = p.arg("bar", uintType); auto parsed = p.parse({"123", "234"}); EXPECT_EQ(fooArg->get(parsed), 123); EXPECT_EQ(barArg->get(parsed), 234); } TEST_F(Parser, MixedArgumentsAndOptionsAndFlags) { auto fooArg = p.arg("foo", uintType); auto barArg = p.arg("bar", uintType); auto asdfOpt = p.option("--asdf", uintType); auto qwertyFlag = p.flag("--qwerty"); auto parsed = p.parse({"123", "--asdf", "1", "234", "--qwerty"}); EXPECT_EQ(fooArg->get(parsed), 123); EXPECT_EQ(barArg->get(parsed), 234); EXPECT_EQ(asdfOpt->get(parsed), 1); EXPECT_EQ(qwertyFlag->get(parsed), true); parsed = p.parse({"--asdf", "123", "234", "345"}); EXPECT_EQ(fooArg->get(parsed), 234); EXPECT_EQ(barArg->get(parsed), 345); EXPECT_EQ(asdfOpt->get(parsed), 123); EXPECT_EQ(qwertyFlag->get(parsed), false); } TEST_F(Parser, OptionalArgument) { auto fooArg = p.optional_arg("foo", uintType); auto parsed = p.parse({"123"}); EXPECT_EQ(fooArg->get(parsed).has_value(), true); EXPECT_EQ(fooArg->get(parsed).value(), 123); EXPECT_EQ(fooArg->has(parsed), true); parsed = p.parse({}); EXPECT_EQ(fooArg->get(parsed).has_value(), false); EXPECT_EQ(fooArg->has(parsed), false); } TEST_F(Parser, OptionalArgumentDefaultValue) { auto fooArg = p.optional_arg("foo", uintType)->default_value(99); auto parsed = p.parse({"123"}); EXPECT_EQ(fooArg->get(parsed), 123); EXPECT_EQ(fooArg->has(parsed), true); parsed = p.parse({}); EXPECT_EQ(fooArg->get(parsed), 99); EXPECT_EQ(fooArg->has(parsed), false); } TEST_F(Parser, RepeatedArgument) { auto fooArg = p.repeatable_arg("foo", uintType); auto parsed = p.parse({"123", "234", "345", "456"}); auto val = fooArg->get(parsed); EXPECT_EQ(val.size(), 4); EXPECT_EQ(val[0], 123); EXPECT_EQ(val[1], 234); EXPECT_EQ(val[2], 345); EXPECT_EQ(val[3], 456); } TEST_F(Parser, RepeatedArgumentLimits) { auto fooArg = p.repeatable_arg("foo", uintType)->min(2)->max(4); argparser::parse_result parsed; EXPECT_NO_THROW(parsed = p.parse({"1", "2"});); EXPECT_EQ(fooArg->get(parsed), (std::vector{1, 2})); EXPECT_NO_THROW(parsed = p.parse({"1", "2", "3"});); EXPECT_EQ(fooArg->get(parsed), (std::vector{1, 2, 3})); EXPECT_NO_THROW(parsed = p.parse({"1", "2", "3", "4"});); EXPECT_EQ(fooArg->get(parsed), (std::vector{1, 2, 3, 4})); EXPECT_THROW(parsed = p.parse({}), argparser::errors::missing_argument_error); EXPECT_THROW(parsed = p.parse({"1"}), argparser::errors::missing_argument_error); EXPECT_THROW(parsed = p.parse({"1", "2", "3", "4", "5"}), argparser::errors::too_many_arguments_error); EXPECT_THROW(parsed = p.parse({"1", "2", "3", "4", "5", "6"}), argparser::errors::too_many_arguments_error); EXPECT_THROW(parsed = p.parse({"1", "2", "3", "4", "5", "6", "7"}), argparser::errors::too_many_arguments_error); } TEST_F(Parser, MixedArguments) { auto boolType = p.enum_type("bool", {{"true", true}, {"false", false}}); auto tupleType = p.tuple_type("tuple", uintType, uintType); auto argA = p.repeatable_arg("a", uintType); auto argB = p.optional_arg("b", boolType); auto argC = p.arg("c", tupleType); auto argD = p.repeatable_arg("d", uintType); auto parsed = p.parse({"1", "2", "3", "true", "1,2", "4", "5"}); auto valA = argA->get(parsed); auto valB = argB->get(parsed); auto valC = argC->get(parsed); auto valD = argD->get(parsed); EXPECT_EQ(valA.size(), 3); EXPECT_EQ(valA[0], 1); EXPECT_EQ(valA[1], 2); EXPECT_EQ(valA[2], 3); EXPECT_TRUE(valB.has_value()); EXPECT_EQ(valB.value(), true); EXPECT_EQ(valC, (std::make_tuple(1, 2))); EXPECT_EQ(valD, (decltype(valD){4, 5})); } TEST_F(Parser, ArgumentWrongType) { auto boolType = p.enum_type("bool", {{"true", true}, {"false", false}}); auto fooArg = p.arg("foo", boolType); EXPECT_THROW(auto _ = p.parse({"123", "true"});, argparser::errors::type_parsing_error); } TEST_F(Parser, RemainingArguments) { auto fooArg = p.arg("foo", uintType); p.enable_remaining_args(); argparser::parse_result pr; EXPECT_NO_THROW(pr = p.parse({"123", "234", "456"})); EXPECT_EQ(fooArg->get(pr), 123); EXPECT_EQ(pr.remaining(), (std::vector{"234", "456"})); } TEST_F(Parser, OptionsAndFlagsAsRemainingArguments) { auto fooOpt = p.option("--foo", uintType); auto barFlag = p.flag("--bar"); p.enable_remaining_args(); argparser::parse_result pr; EXPECT_NO_THROW(pr = p.parse({"123", "--foo", "456", "--bar"})); EXPECT_EQ(pr.remaining(), (std::vector{"123", "--foo", "456", "--bar"})); EXPECT_FALSE(fooOpt->has(pr)); EXPECT_FALSE(barFlag->has(pr)); } TEST_F(Parser, RemainingArgumentsWithDoubleDash) { auto fooOpt = p.option("--foo", uintType); auto barFlag = p.flag("--bar"); auto arg = p.arg("arg", uintType); p.enable_remaining_args(); argparser::parse_result pr; EXPECT_NO_THROW(pr = p.parse({"123", "--", "--foo", "456", "--bar"})); EXPECT_EQ(pr.remaining(), (std::vector{"--foo", "456", "--bar"})); EXPECT_FALSE(fooOpt->has(pr)); EXPECT_FALSE(barFlag->has(pr)); EXPECT_EQ(arg->get(pr), 123); }