// // options_test.cpp // program_args-test // // Created by Sam Jaffe on 2/7/21. // #include "program_args/arguments.h" #include #include "xcode_gtest_helper.h" using testing::ElementsAre; using testing::Eq; using testing::IsEmpty; template static T parse(char const * const (&argv)[N]) { return T(N, argv); } struct LongOptionTest : program::Arguments { using Arguments::Arguments; std::string endpoint = option("endpoint"); int port = option("port"); }; TEST(LongOptionTest, ArgumentsAreDefaultedNaturally) { auto const options = parse({""}); EXPECT_THAT(options.endpoint, Eq("")); EXPECT_THAT(options.port, Eq(0)); } TEST(LongOptionTest, CanProvideStringArgument) { auto const options = parse({"", "--endpoint", "/null"}); EXPECT_THAT(options.endpoint, Eq("/null")); } TEST(LongOptionTest, CanProvideNumericArgument) { auto const options = parse({"", "--port", "443"}); EXPECT_THAT(options.port, Eq(443)); } TEST(LongOptionTest, WillThrowOnInvalidNumericArgument) { EXPECT_THROW(parse({"", "--port", "one"}), program::ProgramArgumentsError); } TEST(LongOptionTest, WillThrowOnRepeatedArgument) { EXPECT_THROW(parse({"", "--port", "8080", "--port", "443"}), program::ArgumentStructureError); } TEST(LongOptionTest, WillThrowOnUnknownArgument) { EXPECT_THROW(parse({"", "--path", "/null"}), program::NotAnArgumentError); } TEST(LongOptionTest, DoesNotImplicitlyShortenArgs) { EXPECT_THROW(parse({"", "-p", "443"}), program::NotAnArgumentError); } struct LongOptionWithDefaultTest : program::Arguments { using Arguments::Arguments; std::string endpoint = option("endpoint") = "/default"; int port = option("port") = 8080; }; TEST(LongOptionWithDefaultTest, ArgumentsAreDefaultedNaturally) { auto const options = parse({""}); EXPECT_THAT(options.endpoint, Eq("/default")); EXPECT_THAT(options.port, Eq(8080)); } TEST(LongOptionWithDefaultTest, CanProvideStringArgument) { auto const options = parse({"", "--endpoint", "/null"}); EXPECT_THAT(options.endpoint, Eq("/null")); } TEST(LongOptionWithDefaultTest, CanProvideNumericArgument) { auto const options = parse({"", "--port", "443"}); EXPECT_THAT(options.port, Eq(443)); } struct LongOptionWithAbbrevTest : program::Arguments { using Arguments::Arguments; std::string endpoint = option("endpoint", 'e'); int port = option("port", 'p'); }; TEST(LongOptionWithAbbrevTest, CanProvideStringArgument) { auto const options = parse({"", "--endpoint", "/null"}); EXPECT_THAT(options.endpoint, Eq("/null")); } TEST(LongOptionWithAbbrevTest, CanProvideAbbrevStringArgument) { auto const options = parse({"", "-e", "/null"}); EXPECT_THAT(options.endpoint, Eq("/null")); } TEST(LongOptionWithAbbrevTest, CanProvideNumericArgument) { auto const options = parse({"", "--port", "443"}); EXPECT_THAT(options.port, Eq(443)); } TEST(LongOptionWithAbbrevTest, CanProvideAbbrevNumericArgument) { auto const options = parse({"", "-p", "443"}); EXPECT_THAT(options.port, Eq(443)); } TEST(LongOptionWithAbbrevTest, ShortAndLongArgsGoToSamePool) { EXPECT_THROW( parse({"", "--port", "8080", "-p", "443"}), program::ArgumentStructureError); } TEST(LongOptionWithAbbrevTest, CanPutAbbrevArgAndValueInSameToken) { EXPECT_NO_THROW(parse({"", "-p443"})); auto const options = parse({"", "-p443"}); EXPECT_THAT(options.port, Eq(443)); } struct LongOptionRepeatTest : program::Arguments { using Arguments::Arguments; std::vector port = option("port"); }; TEST(LongOptionRepeatTest, DefaultIsEmpty) { auto const options = parse({""}); EXPECT_THAT(options.port, IsEmpty()); } TEST(LongOptionRepeatTest, CanProvideArgument) { auto const options = parse({"", "--port", "443"}); EXPECT_THAT(options.port, ElementsAre(443)); } TEST(LongOptionRepeatTest, RepeatingArgumentsAppends) { auto const options = parse({"", "--port", "443", "--port", "8080"}); EXPECT_THAT(options.port, ElementsAre(443, 8080)); } struct LongOptionRepeatWithDefaultTest : program::Arguments { using Arguments::Arguments; std::vector port = option("port") = 8080; std::vector default_ports = option("default_ports") = {80, 443}; }; TEST(LongOptionRepeatWithDefaultTest, DefaultIsProvided) { auto const options = parse({""}); EXPECT_THAT(options.port, ElementsAre(8080)); EXPECT_THAT(options.default_ports, ElementsAre(80, 443)); } TEST(LongOptionRepeatWithDefaultTest, ArgumentOverwritesDefault) { auto const options = parse({"", "--port", "443"}); EXPECT_THAT(options.port, ElementsAre(443)); } namespace fs = std::filesystem; struct DeferOptionTest : program::Arguments { using Arguments::Arguments; fs::path path = option("path") = "."; fs::path log = option("log") = PROGRAM_DEFER(path / "test.log"); }; TEST(DeferOptionTest, DefaultResolves) { auto const options = parse({""}); EXPECT_THAT(options.log.string(), "./test.log"); } TEST(DeferOptionTest, CapturesUpdateToDependent) { auto const options = parse({"", "--path", "/var/log"}); EXPECT_THAT(options.log.string(), "/var/log/test.log"); } TEST(DeferOptionTest, SettingActualArgWillOverwrite) { auto const options = parse({"", "--path", "/var/log", "--log", "test.log"}); EXPECT_THAT(options.log.string(), "test.log"); } struct ShortOptionTest : program::Arguments { using Arguments::Arguments; int arg = option('n'); }; TEST(ShortOptionTest, DoesNotAllowDoubleDash) { EXPECT_THROW(parse({"", "--n", "5"}), program::NotAnArgumentError); } TEST(ShortOptionTest, CanConstructWithOnlyAbbrev) { auto const options = parse({"", "-n", "5"}); EXPECT_THAT(options.arg, 5); }