argparser/tests/types.cpp
2023-05-17 10:17:56 +02:00

779 lines
29 KiB
C++

#include "argparser/argparser.h"
#include "gtest/gtest.h"
// TODO: test empty input for all types
TEST(Types, AutomaticUint8Type) {
argparser::parser p{};
argparser::type_handle_impl<uint8_t> uint8Type;
argparser::parse_result pr;
argparser::single_arg_handle<uint8_t> arg;
uint8_t val;
EXPECT_NO_THROW({
uint8Type = p.basic_type<uint8_t>("uint8");
arg = p.arg("a", uint8Type);
pr = p.parse({"250"});
val = arg->get(pr);
});
EXPECT_EQ(val, 250);
}
TEST(Types, AutomaticInt8Type) {
argparser::parser p{};
argparser::type_handle_impl<int8_t> int8Type;
argparser::parse_result pr;
argparser::single_arg_handle<int8_t> arg;
int8_t val;
EXPECT_NO_THROW({
int8Type = p.basic_type<int8_t>("int8");
arg = p.arg("a", int8Type);
pr = p.parse({"-126"});
val = arg->get(pr);
});
EXPECT_EQ(val, -126);
}
TEST(Types, AutomaticUint16Type) {
argparser::parser p{};
argparser::type_handle_impl<uint16_t> uint16Type;
argparser::parse_result pr;
argparser::single_arg_handle<uint16_t> arg;
uint16_t val;
EXPECT_NO_THROW({
uint16Type = p.basic_type<uint16_t>("uint16");
arg = p.arg("a", uint16Type);
pr = p.parse({"65530"});
val = arg->get(pr);
});
EXPECT_EQ(val, 65530);
}
TEST(Types, AutomaticInt16Type) {
argparser::parser p{};
argparser::type_handle_impl<int16_t> int16Type;
argparser::parse_result pr;
argparser::single_arg_handle<int16_t> arg;
int16_t val;
EXPECT_NO_THROW({
int16Type = p.basic_type<int16_t>("int16");
arg = p.arg("a", int16Type);
pr = p.parse({"-32760"});
val = arg->get(pr);
});
EXPECT_EQ(val, -32760);
}
TEST(Types, AutomaticUint32Type) {
argparser::parser p{};
argparser::type_handle_impl<uint32_t> uint32Type;
argparser::parse_result pr;
argparser::single_arg_handle<uint32_t> arg;
uint32_t val;
EXPECT_NO_THROW({
uint32Type = p.basic_type<uint32_t>("uint32");
arg = p.arg("a", uint32Type);
pr = p.parse({"4294967290"});
val = arg->get(pr);
});
EXPECT_EQ(val, 4294967290);
}
TEST(Types, AutomaticInt32Type) {
argparser::parser p{};
argparser::type_handle_impl<int32_t> int32Type;
argparser::parse_result pr;
argparser::single_arg_handle<int32_t> arg;
int32_t val;
EXPECT_NO_THROW({
int32Type = p.basic_type<int32_t>("int32");
arg = p.arg("a", int32Type);
pr = p.parse({"-2147483645"});
val = arg->get(pr);
});
EXPECT_EQ(val, -2147483645);
}
TEST(Types, AutomaticUint64Type) {
argparser::parser p{};
argparser::type_handle_impl<uint64_t> uint64Type;
argparser::parse_result pr;
argparser::single_arg_handle<uint64_t> arg;
uint64_t val;
EXPECT_NO_THROW({
uint64Type = p.basic_type<uint64_t>("uint64");
arg = p.arg("a", uint64Type);
pr = p.parse({"18446744073709551612"});
val = arg->get(pr);
});
EXPECT_EQ(val, 18446744073709551612ull);
}
TEST(Types, AutomaticInt64Type) {
argparser::parser p{};
argparser::type_handle_impl<int64_t> int64Type;
argparser::parse_result pr;
argparser::single_arg_handle<int64_t> arg;
int64_t val;
EXPECT_NO_THROW({
int64Type = p.basic_type<int64_t>("int64");
arg = p.arg("a", int64Type);
pr = p.parse({"-9223372036854775803"});
val = arg->get(pr);
});
EXPECT_EQ(val, -9223372036854775803);
}
TEST(Types, AutomaticFloatType) {
argparser::parser p{};
argparser::type_handle_impl<float> floatType;
argparser::parse_result pr;
argparser::single_arg_handle<float> arg;
float val;
EXPECT_NO_THROW({
floatType = p.basic_type<float>("float");
arg = p.arg("a", floatType);
pr = p.parse({"23.45"});
val = arg->get(pr);
});
EXPECT_EQ(val, 23.45f);
}
TEST(Types, AutomaticDoubleType) {
argparser::parser p{};
argparser::type_handle_impl<double> doubleType;
argparser::parse_result pr;
argparser::single_arg_handle<double> arg;
double val;
EXPECT_NO_THROW({
doubleType = p.basic_type<double>("double");
arg = p.arg("a", doubleType);
pr = p.parse({"23.45"});
val = arg->get(pr);
});
EXPECT_EQ(val, 23.45);
}
TEST(Types, AutomaticStringType) {
argparser::parser p{};
auto stringType = p.basic_type<std::string>("string");
auto arg = p.arg("a", stringType);
argparser::parse_result pr;
EXPECT_NO_THROW(pr = p.parse({"foo bar"}));
EXPECT_EQ(arg->get(pr), "foo bar");
EXPECT_NO_THROW(pr = p.parse({"'foo bar'"}));
EXPECT_EQ(arg->get(pr), "foo bar");
EXPECT_NO_THROW(pr = p.parse({"\"foo bar\""}));
EXPECT_EQ(arg->get(pr), "foo bar");
}
TEST(Types, AutomaticStringTypeBareEmptyString) {
argparser::parser p{};
auto stringType = p.basic_type<std::string, argparser::internal::parse_opt::BareString>("string");
auto arg = p.arg("a", stringType);
argparser::parse_result pr;
EXPECT_NO_THROW(pr = p.parse({""}));
EXPECT_EQ(arg->get(pr), "");
}
TEST(Types, AutomaticStringTypeSingleQuotedEmptyString) {
argparser::parser p{};
auto stringType = p.basic_type<std::string, argparser::internal::parse_opt::SingleQuotedString>("string");
auto arg = p.arg("a", stringType);
argparser::parse_result pr;
EXPECT_NO_THROW(pr = p.parse({"''"}));
EXPECT_EQ(arg->get(pr), "");
EXPECT_THROW(pr = p.parse({""}), argparser::errors::type_parsing_error);
}
TEST(Types, AutomaticStringTypeDoubleQuotedEmptyString) {
argparser::parser p{};
auto stringType = p.basic_type<std::string, argparser::internal::parse_opt::DoubleQuotedString>("string");
auto arg = p.arg("a", stringType);
argparser::parse_result pr;
EXPECT_NO_THROW(pr = p.parse({"\"\""}));
EXPECT_EQ(arg->get(pr), "");
EXPECT_THROW(pr = p.parse({""}), argparser::errors::type_parsing_error);
}
TEST(Types, AutomaticStringTypeBrokenQuote) {
argparser::parser p{};
auto stringType = p.basic_type<std::string>("string");
auto arg = p.arg("a", stringType);
argparser::parse_result pr;
EXPECT_THROW(pr = p.parse({"'foobar"}), argparser::errors::type_parsing_error);
EXPECT_THROW(pr = p.parse({"\"foobar"}), argparser::errors::type_parsing_error);
EXPECT_THROW(pr = p.parse({"foo'bar"}), argparser::errors::type_parsing_error);
EXPECT_THROW(pr = p.parse({"foo\"bar"}), argparser::errors::type_parsing_error);
EXPECT_THROW(pr = p.parse({"foobar'"}), argparser::errors::type_parsing_error);
EXPECT_THROW(pr = p.parse({"foobar\""}), argparser::errors::type_parsing_error);
}
TEST(Types, AutomaticStringTypeBareComma) {
argparser::parser p{};
auto stringType = p.basic_type<std::string>("string");
auto arg = p.arg("a", stringType);
argparser::parse_result pr;
EXPECT_NO_THROW(pr = p.parse({"foo,bar"}));
EXPECT_EQ(arg->get(pr), "foo,bar");
}
TEST(Types, AutomaticStringTypeNoBareCommaInTuple) {
argparser::parser p{};
auto stringType = p.basic_type<std::string>("string");
auto uintType = p.basic_type<uint32_t>("uint");
auto tupleType = p.tuple_type("tuple", stringType, uintType);
auto arg = p.arg("a", tupleType);
argparser::parse_result pr;
EXPECT_THROW(pr = p.parse({"tuple(foo,bar, 2)"}), argparser::errors::type_parsing_error);
}
TEST(Types, AutomaticStringTypeBareWithWhitespaceInTuple) {
argparser::parser p{};
auto stringType = p.basic_type<std::string>("string");
auto uintType = p.basic_type<uint32_t>("uint");
auto tupleType = p.tuple_type("tuple", stringType, uintType);
auto arg = p.arg("a", tupleType);
argparser::parse_result pr;
EXPECT_NO_THROW(pr = p.parse({"tuple( foo bar , 2)"}));
EXPECT_EQ(arg->get(pr), std::make_tuple(" foo bar ", 2));
}
TEST(Types, AutomaticStringTypeExplicitAny) {
argparser::parser p{};
auto stringType = p.basic_type<std::string, argparser::internal::parse_opt::AnyString>("string");
auto arg = p.arg("a", stringType);
argparser::parse_result pr;
EXPECT_NO_THROW(pr = p.parse({"foo bar"}));
EXPECT_EQ(arg->get(pr), "foo bar");
EXPECT_NO_THROW(pr = p.parse({"'foo bar'"}));
EXPECT_EQ(arg->get(pr), "foo bar");
EXPECT_NO_THROW(pr = p.parse({"\"foo bar\""}));
EXPECT_EQ(arg->get(pr), "foo bar");
}
TEST(Types, AutomaticStringOnlyBare) {
argparser::parser p{};
auto stringType = p.basic_type<std::string, argparser::internal::parse_opt::BareString>("string");
auto arg = p.arg("a", stringType);
argparser::parse_result pr;
EXPECT_NO_THROW(pr = p.parse({"foo bar"}));
EXPECT_EQ(arg->get(pr), "foo bar");
EXPECT_THROW(pr = p.parse({"'foo bar'"}), argparser::errors::type_parsing_error);
EXPECT_THROW(pr = p.parse({"\"foo bar\""}), argparser::errors::type_parsing_error);
}
TEST(Types, AutomaticStringOnlySingleQuoted) {
argparser::parser p{};
auto stringType = p.basic_type<std::string, argparser::internal::parse_opt::SingleQuotedString>("string");
auto arg = p.arg("a", stringType);
argparser::parse_result pr;
EXPECT_NO_THROW(pr = p.parse({"'foo bar'"}));
EXPECT_EQ(arg->get(pr), "foo bar");
EXPECT_THROW(pr = p.parse({"foo bar"}), argparser::errors::type_parsing_error);
EXPECT_THROW(pr = p.parse({"\"foo bar\""}), argparser::errors::type_parsing_error);
}
TEST(Types, AutomaticStringOnlyDoubleQuoted) {
argparser::parser p{};
auto stringType = p.basic_type<std::string, argparser::internal::parse_opt::DoubleQuotedString>("string");
auto arg = p.arg("a", stringType);
argparser::parse_result pr;
EXPECT_NO_THROW(pr = p.parse({"\"foo bar\""}));
EXPECT_EQ(arg->get(pr), "foo bar");
EXPECT_THROW(pr = p.parse({"foo bar"}), argparser::errors::type_parsing_error);
EXPECT_THROW(pr = p.parse({"'foo bar'"}), argparser::errors::type_parsing_error);
}
TEST(Types, AutomaticStringOnlyQuoted) {
argparser::parser p{};
auto stringType = p.basic_type<std::string, argparser::internal::parse_opt::SingleQuotedString | argparser::internal::parse_opt::DoubleQuotedString>("string");
auto arg = p.arg("a", stringType);
argparser::parse_result pr;
EXPECT_NO_THROW(pr = p.parse({"\"foo bar\""}));
EXPECT_EQ(arg->get(pr), "foo bar");
EXPECT_NO_THROW(pr = p.parse({"'foo bar'"}));
EXPECT_EQ(arg->get(pr), "foo bar");
EXPECT_THROW(pr = p.parse({"foo bar"}), argparser::errors::type_parsing_error);
}
TEST(Types, AutomaticStringOnlyBareOrSingleQuoted) {
argparser::parser p{};
auto stringType = p.basic_type<std::string, argparser::internal::parse_opt::SingleQuotedString | argparser::internal::parse_opt::BareString>("string");
auto arg = p.arg("a", stringType);
argparser::parse_result pr;
EXPECT_NO_THROW(pr = p.parse({"'foo bar'"}));
EXPECT_EQ(arg->get(pr), "foo bar");
EXPECT_NO_THROW(pr = p.parse({"foo bar"}));
EXPECT_EQ(arg->get(pr), "foo bar");
EXPECT_THROW(pr = p.parse({"\"foo bar\""}), argparser::errors::type_parsing_error);
}
TEST(Types, AutomaticStringOnlyBareOrDoubleQuoted) {
argparser::parser p{};
auto stringType = p.basic_type<std::string, argparser::internal::parse_opt::DoubleQuotedString | argparser::internal::parse_opt::BareString>("string");
auto arg = p.arg("a", stringType);
argparser::parse_result pr;
EXPECT_NO_THROW(pr = p.parse({"\"foo bar\""}));
EXPECT_EQ(arg->get(pr), "foo bar");
EXPECT_NO_THROW(pr = p.parse({"foo bar"}));
EXPECT_EQ(arg->get(pr), "foo bar");
EXPECT_THROW(pr = p.parse({"'foo bar'"}), argparser::errors::type_parsing_error);
}
TEST(Types, AutomaticStringTypeUnquotedInTuple) {
argparser::parser p{};
auto stringType = p.basic_type<std::string>("string");
auto tupleType = p.tuple_type("tuple", stringType, stringType);
auto arg = p.arg("a", tupleType);
auto pr = p.parse({"(foo bar, asdf)"});
auto val = arg->get(pr);
EXPECT_EQ(val, std::make_tuple("foo bar", " asdf"));
}
TEST(Types, AutomaticStringTypeTrim) {
argparser::parser p{};
auto stringType = p.basic_type<std::string, argparser::internal::parse_opt::TrimString>("string");
auto arg = p.arg("a", stringType);
auto pr = p.parse({" foo "});
EXPECT_EQ(arg->get(pr), "foo");
pr = p.parse({"' foo '"});
EXPECT_EQ(arg->get(pr), "foo");
pr = p.parse({"\" foo \""});
EXPECT_EQ(arg->get(pr), "foo");
}
TEST(Types, AutomaticStringTypeTrimOnlyWhitespace) {
argparser::parser p{};
auto stringType = p.basic_type<std::string, argparser::internal::parse_opt::TrimString>("string");
auto arg = p.arg("a", stringType);
auto pr = p.parse({" "});
EXPECT_EQ(arg->get(pr), "");
pr = p.parse({"' '"});
EXPECT_EQ(arg->get(pr), "");
pr = p.parse({"\" \""});
EXPECT_EQ(arg->get(pr), "");
}
TEST(Types, AutomaticStringTypeTrimUnquoted) {
argparser::parser p{};
auto stringType = p.basic_type<std::string, argparser::internal::parse_opt::TrimBareString>("string");
auto arg = p.arg("a", stringType);
auto pr = p.parse({" foo "});
EXPECT_EQ(arg->get(pr), "foo");
pr = p.parse({"' foo '"});
EXPECT_EQ(arg->get(pr), " foo ");
pr = p.parse({"\" foo \""});
EXPECT_EQ(arg->get(pr), " foo ");
}
TEST(Types, EnumType) {
argparser::parser p;
auto boolType = p.enum_type<bool>("bool", {{"true", true},
{"yes", true},
{"false", false},
{"no", false}});
auto fooOption = p.option("--foo", boolType);
auto parsed = p.parse({"--foo", "true"});
EXPECT_EQ(fooOption->get(parsed), true);
parsed = p.parse({"--foo", "false"});
EXPECT_EQ(fooOption->get(parsed), false);
parsed = p.parse({"--foo", "yes"});
EXPECT_EQ(fooOption->get(parsed), true);
parsed = p.parse({"--foo", "no"});
EXPECT_EQ(fooOption->get(parsed), false);
}
TEST(Types, EnumTypeEmptyError) {
argparser::parser p;
EXPECT_THROW(p.enum_type("enum1", {}), argparser::errors::empty_enum_map_error);
EXPECT_THROW(p.enum_type<bool>("enum1", {}), argparser::errors::empty_enum_map_error);
}
TEST(Types, EnumTypeLongestMatching) {
argparser::parser p;
auto enumType = p.enum_type<int>("enum", {
{"a", 1},
{"ab", 2},
});
auto fooOption = p.option("--foo", enumType);
auto parsed = p.parse({"--foo", "a"});
EXPECT_EQ(fooOption->get(parsed), 1);
parsed = p.parse({"--foo", "ab"});
EXPECT_EQ(fooOption->get(parsed), 2);
}
TEST(Types, EnumTypeLongestMatchingReverseOrder) {
argparser::parser p;
auto enumType = p.enum_type<int>("enum", {
{"ab", 2},
{"a", 1},
});
auto fooOption = p.option("--foo", enumType);
auto parsed = p.parse({"--foo", "a"});
EXPECT_EQ(fooOption->get(parsed), 1);
parsed = p.parse({"--foo", "ab"});
EXPECT_EQ(fooOption->get(parsed), 2);
}
TEST(Types, EnumTypeInvalidValue) {
argparser::parser p;
auto enumType = p.enum_type<int>("enum", {{"a", 1}, {"b", 2}, {"c", 3}});
auto _1 = p.option("--foo", enumType);
EXPECT_THROW(auto _ = p.parse({"--foo", "x"}), argparser::errors::type_parsing_error);
EXPECT_THROW(auto _ = p.parse({"--foo", "aa"}), argparser::errors::type_parsing_error);
}
TEST(Types, StringEnumType) {
argparser::parser p;
auto enumType = p.enum_type("enum", {"foo", "bar"});
auto fooOption = p.option("--foo", enumType);
auto parsed = p.parse({"--foo", "foo"});
EXPECT_EQ(fooOption->get(parsed), "foo");
parsed = p.parse({"--foo", "bar"});
EXPECT_EQ(fooOption->get(parsed), "bar");
}
TEST(Types, UnionType) {
argparser::parser p;
auto enumType1 = p.enum_type("enum", {"foo", "bar"});
auto enumType2 = p.enum_type<bool>("bool", {{"true", true}, {"false", false}});
auto unionType = p.union_type("enum-or-bool", enumType1, enumType2);
auto fooOption = p.option("--foo", unionType);
auto parsed = p.parse({"--foo", "bar"});
auto val = fooOption->get(parsed);
EXPECT_EQ(std::holds_alternative<std::string>(val), true);
EXPECT_EQ(std::get<std::string>(val), "bar");
parsed = p.parse({"--foo", "true"});
val = fooOption->get(parsed);
EXPECT_EQ(std::holds_alternative<bool>(val), true);
EXPECT_EQ(std::get<bool>(val), true);
}
TEST(Types, UnionTypeWithSameUnderlyingBaseType) {
argparser::parser p;
auto enumType1 = p.enum_type("enum", {"foo", "bar"});
auto enumType2 = p.enum_type("enum", {"hello", "world"});
auto unionType = p.union_type("enum-or-bool", enumType1, enumType2);
auto fooOption = p.option("--foo", unionType);
auto parsed = p.parse({"--foo", "bar"});
auto val = fooOption->get(parsed);
EXPECT_EQ(val, "bar");
parsed = p.parse({"--foo", "hello"});
val = fooOption->get(parsed);
EXPECT_EQ(val, "hello");
}
TEST(Types, UnionTypeError) {
argparser::parser p;
auto enumType1 = p.enum_type("enum", {"foo", "bar"});
auto enumType2 = p.enum_type<bool>("bool", {{"true", true}, {"false", false}});
auto unionType = p.union_type("union", enumType1, enumType2);
auto fooOption = p.option("--foo", unionType);
EXPECT_THROW(auto _ = p.parse({"--foo", "123"}), argparser::errors::type_parsing_error);
}
TEST(Types, UnionTypeErrorOnAmbiguity) {
argparser::parser p;
auto enumType1 = p.enum_type<int>("enum1", {{"foo", 1}, {"bar", 2}});
auto enumType2 = p.enum_type<bool>("enum2", {{"bar", true}, {"hello-world", false}});
auto unionType = p.union_type("union", enumType1, enumType2);
auto fooOption = p.option("--foo", unionType);
EXPECT_THROW(auto _1 = p.parse({"--foo", "bar"});, argparser::errors::ambiguous_parse_error);
auto enumType3 = p.enum_type<int>("enum3", {{"bar", 1}, {"hello-world", 2}});
auto unionType2 = p.union_type("union", enumType1, enumType3);
auto barOption = p.option("--bar", unionType2);
EXPECT_THROW(auto _1 = p.parse({"--bar", "bar"});, argparser::errors::ambiguous_parse_error);
}
TEST(Types, UnionTypeNoAmbiguityErrorIfPossibleValuesIdentical) {
argparser::parser p;
auto enumType1 = p.enum_type<int>("enum1", {{"foo", 1}, {"bar", 2}});
auto enumType2 = p.enum_type<int>("enum2", {{"foo", 1}, {"foobar", 3}});
auto unionType = p.union_type("union", enumType1, enumType2);
auto fooOption = p.option("--foo", unionType);
argparser::parse_result parsed;
EXPECT_NO_THROW(parsed = p.parse({"--foo", "foo"}));
ASSERT_EQ(fooOption->get(parsed), 1);
}
TEST(Types, ListType) {
argparser::parser p;
auto uintType = p.basic_type<uint32_t>("uint");
auto listType = p.list_type("uint[]", uintType);
auto fooOption = p.option("--foo", listType);
auto parsed = p.parse({"--foo", "[1,2,3,4]"});
auto val = fooOption->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);
}
TEST(Types, ListTypeWithoutBracketsAtRoot) {
argparser::parser p;
auto uintType = p.basic_type<uint32_t>("uint");
auto listType = p.list_type("uint[]", uintType);
auto fooOption = p.option("--foo", listType);
auto parsed = p.parse({"--foo", "1,2,3,4"});
auto val = fooOption->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);
}
TEST(Types, ListTypeTrailingComma) {
argparser::parser p;
auto uintType = p.basic_type<uint32_t>("uint");
auto listType = p.list_type("uint[]", uintType);
auto fooOption = p.option("--foo", listType);
auto parsed = p.parse({"--foo", "[1,2,3,]"});
auto val = fooOption->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,2,3,"});
val = fooOption->get(parsed);
EXPECT_EQ(val.size(), 3);
EXPECT_EQ(val[0], 1);
EXPECT_EQ(val[1], 2);
EXPECT_EQ(val[2], 3);
}
TEST(Types, ListTypeOnlyOneTrailingComma) {
argparser::parser p;
auto uintType = p.basic_type<uint32_t>("uint");
auto listType = p.list_type("uint[]", uintType);
auto fooOption = p.option("--foo", listType);
EXPECT_THROW(auto _1 = p.parse({"--foo", "[1,2,3,,]"});, argparser::errors::type_parsing_error);
EXPECT_THROW(auto _2 = p.parse({"--foo", "1,2,3,,"});, argparser::errors::type_parsing_error);
}
TEST(Types, ListTypeNoPrecedingComma) {
argparser::parser p;
auto uintType = p.basic_type<uint32_t>("uint");
auto listType = p.list_type("uint[]", uintType);
auto fooOption = p.option("--foo", listType);
EXPECT_THROW(auto _1 = p.parse({"--foo", "[,1,2,3]"});, argparser::errors::type_parsing_error);
EXPECT_THROW(auto _2 = p.parse({"--foo", ",1,2,3"});, argparser::errors::type_parsing_error);
}
TEST(Types, ListTypeNoDoubleComma) {
argparser::parser p;
auto uintType = p.basic_type<uint32_t>("uint");
auto listType = p.list_type("uint[]", uintType);
auto fooOption = p.option("--foo", listType);
EXPECT_THROW(auto _1 = p.parse({"--foo", "[1,,2,3]"});, argparser::errors::type_parsing_error);
EXPECT_THROW(auto _2 = p.parse({"--foo", "[1, ,2,3]"});, argparser::errors::type_parsing_error);
}
TEST(Types, ListTypeInvalidBrackets) {
argparser::parser p;
auto uintType = p.basic_type<uint32_t>("uint");
auto listType = p.list_type("uint[]", uintType);
auto fooOption = p.option("--foo", listType);
EXPECT_THROW(auto _1 = p.parse({"--foo", "[1,2,3"});, argparser::errors::type_parsing_error);
EXPECT_THROW(auto _2 = p.parse({"--foo", "1,2,3]"});, argparser::errors::type_parsing_error);
EXPECT_THROW(auto _2 = p.parse({"--foo", "1[,2,3"});, argparser::errors::type_parsing_error);
EXPECT_THROW(auto _2 = p.parse({"--foo", "1,[2,3"});, argparser::errors::type_parsing_error);
EXPECT_THROW(auto _2 = p.parse({"--foo", "1,2],3"});, argparser::errors::type_parsing_error);
EXPECT_THROW(auto _2 = p.parse({"--foo", "1,2,]3"});, argparser::errors::type_parsing_error);
EXPECT_THROW(auto _2 = p.parse({"--foo", "[1,2],3"});, argparser::errors::type_parsing_error);
EXPECT_THROW(auto _2 = p.parse({"--foo", "[1,2,]3"});, argparser::errors::type_parsing_error);
}
TEST(Types, TupleType) {
argparser::parser p;
auto uintType = p.basic_type<uint32_t>("uint");
auto boolType = p.enum_type<bool>("bool", {{"true", true}, {"false", false}});
auto tupleType = p.tuple_type("tuple", uintType, uintType, boolType);
auto fooOption = p.option("--foo", tupleType);
auto parsed = p.parse({"--foo", "(1,2,true)"});
auto val = fooOption->get(parsed);
EXPECT_EQ(std::get<0>(val), 1);
EXPECT_EQ(std::get<1>(val), 2);
EXPECT_EQ(std::get<2>(val), true);
}
TEST(Types, TupleTypeWithoutParenthesesAtRoot) {
argparser::parser p;
auto uintType = p.basic_type<uint32_t>("uint");
auto tupleType = p.tuple_type("tuple", uintType, uintType, uintType);
auto fooOption = p.option("--foo", tupleType);
auto parsed = p.parse({"--foo", "1,2,3"});
auto val = fooOption->get(parsed);
EXPECT_EQ(std::get<0>(val), 1);
EXPECT_EQ(std::get<1>(val), 2);
EXPECT_EQ(std::get<2>(val), 3);
}
TEST(Types, TupleTypeInvalidParentheses) {
argparser::parser p;
auto uintType = p.basic_type<uint32_t>("uint");
auto tupleType = p.tuple_type("tuple", uintType, uintType, uintType);
auto fooOption = p.option("--foo", tupleType);
EXPECT_THROW(auto _1 = p.parse({"--foo", "(1,2,3"});, argparser::errors::type_parsing_error);
EXPECT_THROW(auto _2 = p.parse({"--foo", "1,2,3)"});, argparser::errors::type_parsing_error);
EXPECT_THROW(auto _2 = p.parse({"--foo", "1(,2,3"});, argparser::errors::type_parsing_error);
EXPECT_THROW(auto _2 = p.parse({"--foo", "1,(2,3"});, argparser::errors::type_parsing_error);
EXPECT_THROW(auto _2 = p.parse({"--foo", "1,2),3"});, argparser::errors::type_parsing_error);
EXPECT_THROW(auto _2 = p.parse({"--foo", "1,2,)3"});, argparser::errors::type_parsing_error);
EXPECT_THROW(auto _2 = p.parse({"--foo", "(1,2),3"});, argparser::errors::type_parsing_error);
EXPECT_THROW(auto _2 = p.parse({"--foo", "(1,2,)3"});, argparser::errors::type_parsing_error);
}
TEST(Types, TupleTypeNoInvalidComma) {
argparser::parser p;
auto uintType = p.basic_type<uint32_t>("uint");
auto tupleType = p.tuple_type("tuple", uintType, uintType, uintType);
auto fooOption = p.option("--foo", tupleType);
EXPECT_THROW(auto _2 = p.parse({"--foo", "(1,2,3,)"});, argparser::errors::type_parsing_error);
EXPECT_THROW(auto _2 = p.parse({"--foo", "(,1,2,3)"});, argparser::errors::type_parsing_error);
EXPECT_THROW(auto _2 = p.parse({"--foo", "(1,,2,3)"});, argparser::errors::type_parsing_error);
EXPECT_THROW(auto _2 = p.parse({"--foo", "(1, ,2,3)"});, argparser::errors::type_parsing_error);
EXPECT_THROW(auto _2 = p.parse({"--foo", "1,2,3,"});, argparser::errors::type_parsing_error);
}
struct SomeStruct {
uint32_t foo;
uint32_t bar;
bool foobar;
};
TEST(Types, TupleTypeWithCustomType) {
argparser::parser p;
auto uintType = p.basic_type<uint32_t>("uint");
auto boolType = p.enum_type<bool>("bool", {{"true", true}, {"false", false}});
auto tupleType = p.tuple_type<SomeStruct>("tuple", uintType, uintType, boolType);
auto fooOption = p.option("--foo", tupleType);
auto parsed = p.parse({"--foo", "(1,2,true)"});
auto val = fooOption->get(parsed);
EXPECT_EQ(val.foo, 1);
EXPECT_EQ(val.bar, 2);
EXPECT_EQ(val.foobar, true);
}
TEST(Types, TupleWithCustomTypeAndCustomConstructor) {
argparser::parser p;
auto uintType = p.basic_type<uint32_t>("uint");
auto boolType = p.enum_type<bool>("bool", {{"true", true}, {"false", false}});
auto tupleType = p.tuple_type<SomeStruct>(
"tuple",
std::make_tuple(uintType, uintType, boolType),
[](uint32_t a, uint32_t b, bool c) {
return SomeStruct{a * 2, b * 3, !c};
});
auto fooOption = p.option("--foo", tupleType);
auto parsed = p.parse({"--foo", "(1,2,true)"});
auto val = fooOption->get(parsed);
EXPECT_EQ(val.foo, 2);
EXPECT_EQ(val.bar, 6);
EXPECT_EQ(val.foobar, false);
}
TEST(Types, TupleWithSharedPointerAndConstructor) {
argparser::parser p;
auto uintType = p.basic_type<uint32_t>("uint");
auto boolType = p.enum_type<bool>("bool", {{"true", true}, {"false", false}});
auto tupleType = p.tuple_type<std::shared_ptr<SomeStruct>>(
"tuple",
std::make_tuple(uintType, uintType, boolType),
[](uint32_t a, uint32_t b, bool c) {
return std::make_shared<SomeStruct>(a, b, c);
});
auto fooOption = p.option("--foo", tupleType);
auto parsed = p.parse({"--foo", "(1,2,true)"});
auto val = fooOption->get(parsed);
EXPECT_EQ(val->foo, 1);
EXPECT_EQ(val->bar, 2);
EXPECT_EQ(val->foobar, true);
}
class SomeVirtualClass {
public:
virtual int foo() = 0;
};
class SomeClass : public SomeVirtualClass {
public:
SomeClass(int a, int b) : a(a), b(b) {}
int a{};
int b{};
int foo() override {
return a + b;
}
};
TEST(Types, TupleWithSharedPointerToVirtualClass) {
argparser::parser p;
auto uintType = p.basic_type<uint32_t>("uint");
auto tupleType = p.tuple_type<std::shared_ptr<SomeVirtualClass>>(
"tuple",
std::make_tuple(uintType, uintType),
[](uint32_t a, uint32_t b) {
return std::make_shared<SomeClass>(a, b);
});
auto fooOption = p.option("--foo", tupleType);
auto parsed = p.parse({"--foo", "(1,2)"});
auto val = fooOption->get(parsed);
EXPECT_EQ(val->foo(), 3);
}
TEST(Types, TuplesCanBeNamePrefixed) {
argparser::parser p;
auto uintType = p.basic_type<uint32_t>("uint");
auto boolType = p.enum_type<bool>("bool", {{"true", true}, {"false", false}});
auto tupleType = p.tuple_type("tuple", uintType, uintType, boolType);
auto fooOption = p.option("--foo", tupleType);
auto parsed = p.parse({"--foo", "tuple(1,2,true)"});
auto val = fooOption->get(parsed);
EXPECT_EQ(std::get<0>(val), 1);
EXPECT_EQ(std::get<1>(val), 2);
EXPECT_EQ(std::get<2>(val), true);
}
TEST(Types, TupleNamePrefixMustBeCorrect) {
argparser::parser p;
auto uintType = p.basic_type<uint32_t>("uint");
auto boolType = p.enum_type<bool>("bool", {{"true", true}, {"false", false}});
auto tupleType = p.tuple_type("tuple", uintType, uintType, boolType);
auto fooOption = p.option("--foo", tupleType);
EXPECT_THROW(auto _1 = p.parse({"--foo", "foobar(1,2,true)"});, argparser::errors::type_parsing_error);
}
TEST(Types, ComplexNestedTypes) {
argparser::parser p;
auto uintType = p.basic_type<uint32_t>("uint");
auto tupleType = p.tuple_type("uint-tuple", uintType, uintType, uintType);
auto enumType = p.enum_type("enum", {"foo", "bar", "hello", "world"});
auto unionType = p.union_type("union", tupleType, enumType);
auto listType = p.list_type("uint-tuple-list", unionType);
auto fooOption = p.option("--foo", listType);
auto parsed = p.parse({"--foo", "[foo,(1,2,3),hello,world,(2,3,4),(4,5,6)]"});
auto val = fooOption->get(parsed);
using tuplet = std::tuple<uint32_t, uint32_t, uint32_t>;
EXPECT_EQ(val.size(), 6);
EXPECT_TRUE(std::holds_alternative<std::string>(val[0]));
EXPECT_EQ(std::get<std::string>(val[0]), "foo");
EXPECT_TRUE(std::holds_alternative<tuplet>(val[1]));
EXPECT_EQ(std::get<0>(std::get<tuplet>(val[1])), 1);
EXPECT_EQ(std::get<1>(std::get<tuplet>(val[1])), 2);
EXPECT_EQ(std::get<2>(std::get<tuplet>(val[1])), 3);
EXPECT_TRUE(std::holds_alternative<std::string>(val[2]));
EXPECT_EQ(std::get<std::string>(val[2]), "hello");
EXPECT_TRUE(std::holds_alternative<std::string>(val[3]));
EXPECT_EQ(std::get<std::string>(val[3]), "world");
EXPECT_TRUE(std::holds_alternative<tuplet>(val[4]));
EXPECT_EQ(std::get<0>(std::get<tuplet>(val[4])), 2);
EXPECT_EQ(std::get<1>(std::get<tuplet>(val[4])), 3);
EXPECT_EQ(std::get<2>(std::get<tuplet>(val[4])), 4);
EXPECT_TRUE(std::holds_alternative<tuplet>(val[5]));
EXPECT_EQ(std::get<0>(std::get<tuplet>(val[5])), 4);
EXPECT_EQ(std::get<1>(std::get<tuplet>(val[5])), 5);
EXPECT_EQ(std::get<2>(std::get<tuplet>(val[5])), 6);
}