options_test.cpp 6.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204
  1. //
  2. // options_test.cpp
  3. // program_args-test
  4. //
  5. // Created by Sam Jaffe on 2/7/21.
  6. //
  7. #include "program_args/arguments.h"
  8. #include <filesystem>
  9. #include "xcode_gtest_helper.h"
  10. using testing::ElementsAre;
  11. using testing::Eq;
  12. using testing::IsEmpty;
  13. template <typename T, size_t N> static T parse(char const * const (&argv)[N]) {
  14. return T(N, argv);
  15. }
  16. struct LongOptionTest : program::Arguments<LongOptionTest> {
  17. using program::Arguments<LongOptionTest>::Arguments;
  18. std::string endpoint = option("endpoint");
  19. int port = option("port");
  20. };
  21. TEST(LongOptionTest, ArgumentsAreDefaultedNaturally) {
  22. auto const options = parse<LongOptionTest>({""});
  23. EXPECT_THAT(options.endpoint, Eq(""));
  24. EXPECT_THAT(options.port, Eq(0));
  25. }
  26. TEST(LongOptionTest, CanProvideStringArgument) {
  27. auto const options = parse<LongOptionTest>({"", "--endpoint", "/null"});
  28. EXPECT_THAT(options.endpoint, Eq("/null"));
  29. }
  30. TEST(LongOptionTest, CanProvideNumericArgument) {
  31. auto const options = parse<LongOptionTest>({"", "--port", "443"});
  32. EXPECT_THAT(options.port, Eq(443));
  33. }
  34. TEST(LongOptionTest, WillThrowOnInvalidNumericArgument) {
  35. EXPECT_THROW(parse<LongOptionTest>({"", "--port", "one"}),
  36. program::ProgramArgumentsError);
  37. }
  38. TEST(LongOptionTest, WillThrowOnRepeatedArgument) {
  39. EXPECT_THROW(parse<LongOptionTest>({"", "--port", "8080", "--port", "443"}),
  40. program::ArgumentStructureError);
  41. }
  42. TEST(LongOptionTest, WillThrowOnUnknownArgument) {
  43. EXPECT_THROW(parse<LongOptionTest>({"", "--path", "/null"}),
  44. program::NotAnArgumentError);
  45. }
  46. TEST(LongOptionTest, DoesNotImplicitlyShortenArgs) {
  47. EXPECT_THROW(parse<LongOptionTest>({"", "-p", "443"}),
  48. program::NotAnArgumentError);
  49. }
  50. struct LongOptionWithDefaultTest
  51. : program::Arguments<LongOptionWithDefaultTest> {
  52. using program::Arguments<LongOptionWithDefaultTest>::Arguments;
  53. std::string endpoint = option("endpoint") = "/default";
  54. int port = option("port") = 8080;
  55. };
  56. TEST(LongOptionWithDefaultTest, ArgumentsAreDefaultedNaturally) {
  57. auto const options = parse<LongOptionWithDefaultTest>({""});
  58. EXPECT_THAT(options.endpoint, Eq("/default"));
  59. EXPECT_THAT(options.port, Eq(8080));
  60. }
  61. TEST(LongOptionWithDefaultTest, CanProvideStringArgument) {
  62. auto const options =
  63. parse<LongOptionWithDefaultTest>({"", "--endpoint", "/null"});
  64. EXPECT_THAT(options.endpoint, Eq("/null"));
  65. }
  66. TEST(LongOptionWithDefaultTest, CanProvideNumericArgument) {
  67. auto const options = parse<LongOptionWithDefaultTest>({"", "--port", "443"});
  68. EXPECT_THAT(options.port, Eq(443));
  69. }
  70. struct LongOptionWithAbbrevTest : program::Arguments<LongOptionWithAbbrevTest> {
  71. using program::Arguments<LongOptionWithAbbrevTest>::Arguments;
  72. std::string endpoint = option("endpoint", 'e');
  73. int port = option("port", 'p');
  74. };
  75. TEST(LongOptionWithAbbrevTest, CanProvideStringArgument) {
  76. auto const options =
  77. parse<LongOptionWithAbbrevTest>({"", "--endpoint", "/null"});
  78. EXPECT_THAT(options.endpoint, Eq("/null"));
  79. }
  80. TEST(LongOptionWithAbbrevTest, CanProvideAbbrevStringArgument) {
  81. auto const options = parse<LongOptionWithAbbrevTest>({"", "-e", "/null"});
  82. EXPECT_THAT(options.endpoint, Eq("/null"));
  83. }
  84. TEST(LongOptionWithAbbrevTest, CanProvideNumericArgument) {
  85. auto const options = parse<LongOptionWithAbbrevTest>({"", "--port", "443"});
  86. EXPECT_THAT(options.port, Eq(443));
  87. }
  88. TEST(LongOptionWithAbbrevTest, CanProvideAbbrevNumericArgument) {
  89. auto const options = parse<LongOptionWithAbbrevTest>({"", "-p", "443"});
  90. EXPECT_THAT(options.port, Eq(443));
  91. }
  92. TEST(LongOptionWithAbbrevTest, ShortAndLongArgsGoToSamePool) {
  93. EXPECT_THROW(
  94. parse<LongOptionWithAbbrevTest>({"", "--port", "8080", "-p", "443"}),
  95. program::ArgumentStructureError);
  96. }
  97. TEST(LongOptionWithAbbrevTest, CanPutAbbrevArgAndValueInSameToken) {
  98. EXPECT_NO_THROW(parse<LongOptionWithAbbrevTest>({"", "-p443"}));
  99. auto const options = parse<LongOptionWithAbbrevTest>({"", "-p443"});
  100. EXPECT_THAT(options.port, Eq(443));
  101. }
  102. struct LongOptionRepeatTest : program::Arguments<LongOptionRepeatTest> {
  103. using program::Arguments<LongOptionRepeatTest>::Arguments;
  104. std::vector<int> port = option("port");
  105. };
  106. TEST(LongOptionRepeatTest, DefaultIsEmpty) {
  107. auto const options = parse<LongOptionRepeatTest>({""});
  108. EXPECT_THAT(options.port, IsEmpty());
  109. }
  110. TEST(LongOptionRepeatTest, CanProvideArgument) {
  111. auto const options = parse<LongOptionRepeatTest>({"", "--port", "443"});
  112. EXPECT_THAT(options.port, ElementsAre(443));
  113. }
  114. TEST(LongOptionRepeatTest, RepeatingArgumentsAppends) {
  115. auto const options =
  116. parse<LongOptionRepeatTest>({"", "--port", "443", "--port", "8080"});
  117. EXPECT_THAT(options.port, ElementsAre(443, 8080));
  118. }
  119. struct LongOptionRepeatWithDefaultTest
  120. : program::Arguments<LongOptionRepeatWithDefaultTest> {
  121. using program::Arguments<LongOptionRepeatWithDefaultTest>::Arguments;
  122. std::vector<int> port = option("port") = std::vector{8080};
  123. };
  124. TEST(LongOptionRepeatWithDefaultTest, DefaultIsProvided) {
  125. auto const options = parse<LongOptionRepeatWithDefaultTest>({""});
  126. EXPECT_THAT(options.port, ElementsAre(8080));
  127. }
  128. TEST(LongOptionRepeatWithDefaultTest, ArgumentOverwritesDefault) {
  129. auto const options =
  130. parse<LongOptionRepeatWithDefaultTest>({"", "--port", "443"});
  131. EXPECT_THAT(options.port, ElementsAre(443));
  132. }
  133. namespace fs = std::filesystem;
  134. struct DeferOptionTest : program::Arguments<DeferOptionTest> {
  135. using Arguments::Arguments;
  136. fs::path path = option("path") = ".";
  137. fs::path log = option("log") = PROGRAM_DEFER(path / "test.log");
  138. };
  139. TEST(DeferOptionTest, DefaultResolves) {
  140. auto const options = parse<DeferOptionTest>({""});
  141. EXPECT_THAT(options.log.string(), "./test.log");
  142. }
  143. TEST(DeferOptionTest, CapturesUpdateToDependent) {
  144. auto const options = parse<DeferOptionTest>({"", "--path", "/var/log"});
  145. EXPECT_THAT(options.log.string(), "/var/log/test.log");
  146. }
  147. TEST(DeferOptionTest, SettingActualArgWillOverwrite) {
  148. auto const options = parse<DeferOptionTest>({"", "--path", "/var/log", "--log", "test.log"});
  149. EXPECT_THAT(options.log.string(), "test.log");
  150. }
  151. struct ShortOptionTest : program::Arguments<ShortOptionTest> {
  152. using Arguments::Arguments;
  153. int arg = option('n');
  154. };
  155. TEST(ShortOptionTest, DoesNotAllowDoubleDash) {
  156. EXPECT_THROW(parse<ShortOptionTest>({"", "--n", "5"}), program::NotAnArgumentError);
  157. }
  158. TEST(ShortOptionTest, CanConstructWithOnlyAbbrev) {
  159. auto const options = parse<ShortOptionTest>({"", "-n", "5"});
  160. EXPECT_THAT(options.arg, 5);
  161. }