flags_test.cpp 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415
  1. // Copyright (c) 2023 Google LLC.
  2. //
  3. // Licensed under the Apache License, Version 2.0 (the "License");
  4. // you may not use this file except in compliance with the License.
  5. // You may obtain a copy of the License at
  6. //
  7. // http://www.apache.org/licenses/LICENSE-2.0
  8. //
  9. // Unless required by applicable law or agreed to in writing, software
  10. // distributed under the License is distributed on an "AS IS" BASIS,
  11. // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  12. // See the License for the specific language governing permissions and
  13. // limitations under the License.
  14. #include "tools/util/flags.h"
  15. #include "gmock/gmock.h"
  16. #ifdef UTIL_FLAGS_FLAG
  17. #undef UTIL_FLAGS_FLAG
  18. #define UTIL_FLAGS_FLAG(Type, Prefix, Name, Default, Required, IsShort) \
  19. flags::Flag<Type> Name(Default); \
  20. flags::FlagRegistration Name##_registration(Name, Prefix #Name, Required, \
  21. IsShort)
  22. #else
  23. #error \
  24. "UTIL_FLAGS_FLAG is not defined. Either flags.h is not included of the flag name changed."
  25. #endif
  26. class FlagTest : public ::testing::Test {
  27. protected:
  28. void SetUp() override { flags::FlagList::reset(); }
  29. };
  30. TEST_F(FlagTest, NoFlags) {
  31. const char* argv[] = {"binary", nullptr};
  32. EXPECT_TRUE(flags::Parse(argv));
  33. EXPECT_EQ(flags::positional_arguments.size(), 0);
  34. }
  35. TEST_F(FlagTest, DashIsPositional) {
  36. const char* argv[] = {"binary", "-", nullptr};
  37. EXPECT_TRUE(flags::Parse(argv));
  38. EXPECT_EQ(flags::positional_arguments.size(), 1);
  39. EXPECT_EQ(flags::positional_arguments[0], "-");
  40. }
  41. TEST_F(FlagTest, Positional) {
  42. const char* argv[] = {"binary", "A", "BCD", nullptr};
  43. EXPECT_TRUE(flags::Parse(argv));
  44. EXPECT_EQ(flags::positional_arguments.size(), 2);
  45. EXPECT_EQ(flags::positional_arguments[0], "A");
  46. EXPECT_EQ(flags::positional_arguments[1], "BCD");
  47. }
  48. TEST_F(FlagTest, MissingRequired) {
  49. FLAG_SHORT_bool(g, false, true);
  50. const char* argv[] = {"binary", nullptr};
  51. EXPECT_FALSE(flags::Parse(argv));
  52. EXPECT_EQ(flags::positional_arguments.size(), 0);
  53. }
  54. TEST_F(FlagTest, BooleanShortValue) {
  55. FLAG_SHORT_bool(g, false, false);
  56. const char* argv[] = {"binary", "-g", nullptr};
  57. EXPECT_FALSE(g.value());
  58. EXPECT_TRUE(flags::Parse(argv));
  59. EXPECT_TRUE(g.value());
  60. EXPECT_EQ(flags::positional_arguments.size(), 0);
  61. }
  62. TEST_F(FlagTest, BooleanShortDefaultValue) {
  63. FLAG_SHORT_bool(g, true, false);
  64. const char* argv[] = {"binary", nullptr};
  65. EXPECT_TRUE(g.value());
  66. EXPECT_TRUE(flags::Parse(argv));
  67. EXPECT_TRUE(g.value());
  68. }
  69. TEST_F(FlagTest, BooleanLongValueNotParsed) {
  70. FLAG_SHORT_bool(g, false, false);
  71. const char* argv[] = {"binary", "-g", "false", nullptr};
  72. EXPECT_FALSE(g.value());
  73. EXPECT_TRUE(flags::Parse(argv));
  74. EXPECT_TRUE(g.value());
  75. EXPECT_EQ(flags::positional_arguments.size(), 1);
  76. EXPECT_EQ(flags::positional_arguments[0], "false");
  77. }
  78. TEST_F(FlagTest, BooleanLongSplitNotParsed) {
  79. FLAG_LONG_bool(foo, false, false);
  80. const char* argv[] = {"binary", "--foo", "true", nullptr};
  81. EXPECT_FALSE(foo.value());
  82. EXPECT_TRUE(flags::Parse(argv));
  83. EXPECT_TRUE(foo.value());
  84. EXPECT_EQ(flags::positional_arguments.size(), 1);
  85. EXPECT_EQ(flags::positional_arguments[0], "true");
  86. }
  87. TEST_F(FlagTest, BooleanLongExplicitTrue) {
  88. FLAG_LONG_bool(foo, false, false);
  89. const char* argv[] = {"binary", "--foo=true", nullptr};
  90. EXPECT_FALSE(foo.value());
  91. EXPECT_TRUE(flags::Parse(argv));
  92. EXPECT_TRUE(foo.value());
  93. EXPECT_EQ(flags::positional_arguments.size(), 0);
  94. }
  95. TEST_F(FlagTest, BooleanLongExplicitFalse) {
  96. FLAG_LONG_bool(foo, false, false);
  97. const char* argv[] = {"binary", "--foo=false", nullptr};
  98. EXPECT_FALSE(foo.value());
  99. EXPECT_TRUE(flags::Parse(argv));
  100. EXPECT_FALSE(foo.value());
  101. EXPECT_EQ(flags::positional_arguments.size(), 0);
  102. }
  103. TEST_F(FlagTest, BooleanLongDefaultValue) {
  104. FLAG_LONG_bool(foo, true, false);
  105. const char* argv[] = {"binary", nullptr};
  106. EXPECT_TRUE(foo.value());
  107. EXPECT_TRUE(flags::Parse(argv));
  108. EXPECT_TRUE(foo.value());
  109. EXPECT_EQ(flags::positional_arguments.size(), 0);
  110. }
  111. TEST_F(FlagTest, BooleanLongDefaultValueCancelled) {
  112. FLAG_LONG_bool(foo, true, false);
  113. const char* argv[] = {"binary", "--foo=false", nullptr};
  114. EXPECT_TRUE(foo.value());
  115. EXPECT_TRUE(flags::Parse(argv));
  116. EXPECT_FALSE(foo.value());
  117. EXPECT_EQ(flags::positional_arguments.size(), 0);
  118. }
  119. TEST_F(FlagTest, StringFlagDefaultValue) {
  120. FLAG_SHORT_string(f, "default", false);
  121. const char* argv[] = {"binary", nullptr};
  122. EXPECT_EQ(f.value(), "default");
  123. EXPECT_TRUE(flags::Parse(argv));
  124. EXPECT_EQ(f.value(), "default");
  125. EXPECT_EQ(flags::positional_arguments.size(), 0);
  126. }
  127. TEST_F(FlagTest, StringFlagShortMissingString) {
  128. FLAG_SHORT_string(f, "default", false);
  129. const char* argv[] = {"binary", "-f", nullptr};
  130. EXPECT_EQ(f.value(), "default");
  131. EXPECT_FALSE(flags::Parse(argv));
  132. }
  133. TEST_F(FlagTest, StringFlagDefault) {
  134. FLAG_SHORT_string(f, "default", false);
  135. const char* argv[] = {"binary", nullptr};
  136. EXPECT_EQ(f.value(), "default");
  137. EXPECT_TRUE(flags::Parse(argv));
  138. EXPECT_EQ(f.value(), "default");
  139. EXPECT_EQ(flags::positional_arguments.size(), 0);
  140. }
  141. TEST_F(FlagTest, StringFlagSet) {
  142. FLAG_SHORT_string(f, "default", false);
  143. const char* argv[] = {"binary", "-f", "toto", nullptr};
  144. EXPECT_EQ(f.value(), "default");
  145. EXPECT_TRUE(flags::Parse(argv));
  146. EXPECT_EQ(f.value(), "toto");
  147. EXPECT_EQ(flags::positional_arguments.size(), 0);
  148. }
  149. TEST_F(FlagTest, StringLongFlagSetSplit) {
  150. FLAG_LONG_string(foo, "default", false);
  151. const char* argv[] = {"binary", "--foo", "toto", nullptr};
  152. EXPECT_EQ(foo.value(), "default");
  153. EXPECT_TRUE(flags::Parse(argv));
  154. EXPECT_EQ(foo.value(), "toto");
  155. EXPECT_EQ(flags::positional_arguments.size(), 0);
  156. }
  157. TEST_F(FlagTest, StringLongFlagSetUnified) {
  158. FLAG_LONG_string(foo, "default", false);
  159. const char* argv[] = {"binary", "--foo=toto", nullptr};
  160. EXPECT_EQ(foo.value(), "default");
  161. EXPECT_TRUE(flags::Parse(argv));
  162. EXPECT_EQ(foo.value(), "toto");
  163. EXPECT_EQ(flags::positional_arguments.size(), 0);
  164. }
  165. TEST_F(FlagTest, StringLongFlagSetEmpty) {
  166. FLAG_LONG_string(foo, "default", false);
  167. const char* argv[] = {"binary", "--foo=", nullptr};
  168. EXPECT_EQ(foo.value(), "default");
  169. EXPECT_TRUE(flags::Parse(argv));
  170. EXPECT_EQ(foo.value(), "");
  171. EXPECT_EQ(flags::positional_arguments.size(), 0);
  172. }
  173. TEST_F(FlagTest, AllPositionalAfterDoubleDash) {
  174. FLAG_LONG_string(foo, "default", false);
  175. const char* argv[] = {"binary", "--", "--foo=toto", nullptr};
  176. EXPECT_EQ(foo.value(), "default");
  177. EXPECT_TRUE(flags::Parse(argv));
  178. EXPECT_EQ(foo.value(), "default");
  179. EXPECT_EQ(flags::positional_arguments.size(), 1);
  180. EXPECT_EQ(flags::positional_arguments[0], "--foo=toto");
  181. }
  182. TEST_F(FlagTest, NothingAfterDoubleDash) {
  183. FLAG_LONG_string(foo, "default", false);
  184. const char* argv[] = {"binary", "--", nullptr};
  185. EXPECT_EQ(foo.value(), "default");
  186. EXPECT_TRUE(flags::Parse(argv));
  187. EXPECT_EQ(foo.value(), "default");
  188. EXPECT_EQ(flags::positional_arguments.size(), 0);
  189. }
  190. TEST_F(FlagTest, FlagDoubleSetNotAllowed) {
  191. FLAG_LONG_string(foo, "default", false);
  192. const char* argv[] = {"binary", "--foo=abc", "--foo=def", nullptr};
  193. EXPECT_EQ(foo.value(), "default");
  194. EXPECT_FALSE(flags::Parse(argv));
  195. }
  196. TEST_F(FlagTest, MultipleFlags) {
  197. FLAG_LONG_string(foo, "default foo", false);
  198. FLAG_LONG_string(bar, "default_bar", false);
  199. const char* argv[] = {"binary", "--foo", "abc", "--bar=def", nullptr};
  200. EXPECT_EQ(foo.value(), "default foo");
  201. EXPECT_EQ(bar.value(), "default_bar");
  202. EXPECT_TRUE(flags::Parse(argv));
  203. EXPECT_EQ(foo.value(), "abc");
  204. EXPECT_EQ(bar.value(), "def");
  205. }
  206. TEST_F(FlagTest, MixedStringAndBool) {
  207. FLAG_LONG_string(foo, "default foo", false);
  208. FLAG_LONG_string(bar, "default_bar", false);
  209. FLAG_SHORT_bool(g, false, false);
  210. const char* argv[] = {"binary", "--foo", "abc", "-g", "--bar=def", nullptr};
  211. EXPECT_EQ(foo.value(), "default foo");
  212. EXPECT_EQ(bar.value(), "default_bar");
  213. EXPECT_FALSE(g.value());
  214. EXPECT_TRUE(flags::Parse(argv));
  215. EXPECT_EQ(foo.value(), "abc");
  216. EXPECT_EQ(bar.value(), "def");
  217. EXPECT_TRUE(g.value());
  218. }
  219. TEST_F(FlagTest, UintFlagDefaultValue) {
  220. FLAG_SHORT_uint(f, 18, false);
  221. const char* argv[] = {"binary", nullptr};
  222. EXPECT_EQ(f.value(), 18);
  223. EXPECT_TRUE(flags::Parse(argv));
  224. EXPECT_EQ(f.value(), 18);
  225. EXPECT_EQ(flags::positional_arguments.size(), 0);
  226. }
  227. TEST_F(FlagTest, UintFlagShortMissingValue) {
  228. FLAG_SHORT_uint(f, 19, false);
  229. const char* argv[] = {"binary", "-f", nullptr};
  230. EXPECT_EQ(f.value(), 19);
  231. EXPECT_FALSE(flags::Parse(argv));
  232. }
  233. TEST_F(FlagTest, UintFlagSet) {
  234. FLAG_SHORT_uint(f, 20, false);
  235. const char* argv[] = {"binary", "-f", "21", nullptr};
  236. EXPECT_EQ(f.value(), 20);
  237. EXPECT_TRUE(flags::Parse(argv));
  238. EXPECT_EQ(f.value(), 21);
  239. EXPECT_EQ(flags::positional_arguments.size(), 0);
  240. }
  241. TEST_F(FlagTest, UintLongFlagSetSplit) {
  242. FLAG_LONG_uint(foo, 22, false);
  243. const char* argv[] = {"binary", "--foo", "23", nullptr};
  244. EXPECT_EQ(foo.value(), 22);
  245. EXPECT_TRUE(flags::Parse(argv));
  246. EXPECT_EQ(foo.value(), 23);
  247. EXPECT_EQ(flags::positional_arguments.size(), 0);
  248. }
  249. TEST_F(FlagTest, UintLongFlagSetUnified) {
  250. FLAG_LONG_uint(foo, 24, false);
  251. const char* argv[] = {"binary", "--foo=25", nullptr};
  252. EXPECT_EQ(foo.value(), 24);
  253. EXPECT_TRUE(flags::Parse(argv));
  254. EXPECT_EQ(foo.value(), 25);
  255. EXPECT_EQ(flags::positional_arguments.size(), 0);
  256. }
  257. TEST_F(FlagTest, UintLongFlagSetEmptyIsWrong) {
  258. FLAG_LONG_uint(foo, 26, false);
  259. const char* argv[] = {"binary", "--foo=", nullptr};
  260. EXPECT_EQ(foo.value(), 26);
  261. EXPECT_FALSE(flags::Parse(argv));
  262. }
  263. TEST_F(FlagTest, UintLongFlagSetNegativeFails) {
  264. FLAG_LONG_uint(foo, 26, false);
  265. const char* argv[] = {"binary", "--foo=-2", nullptr};
  266. EXPECT_EQ(foo.value(), 26);
  267. EXPECT_FALSE(flags::Parse(argv));
  268. }
  269. TEST_F(FlagTest, UintLongFlagSetOverflowFails) {
  270. FLAG_LONG_uint(foo, 27, false);
  271. const char* argv[] = {
  272. "binary", "--foo=99999999999999999999999999999999999999999999999999999",
  273. nullptr};
  274. EXPECT_EQ(foo.value(), 27);
  275. EXPECT_FALSE(flags::Parse(argv));
  276. }
  277. TEST_F(FlagTest, UintLongFlagSetInvalidCharTrailing) {
  278. FLAG_LONG_uint(foo, 28, false);
  279. const char* argv[] = {"binary", "--foo=12A", nullptr};
  280. EXPECT_EQ(foo.value(), 28);
  281. EXPECT_FALSE(flags::Parse(argv));
  282. }
  283. TEST_F(FlagTest, UintLongFlagSetSpaces) {
  284. FLAG_LONG_uint(foo, 29, false);
  285. const char* argv[] = {"binary", "--foo= 12", nullptr};
  286. EXPECT_EQ(foo.value(), 29);
  287. EXPECT_TRUE(flags::Parse(argv));
  288. EXPECT_EQ(foo.value(), 12);
  289. EXPECT_EQ(flags::positional_arguments.size(), 0);
  290. }
  291. TEST_F(FlagTest, UintLongFlagSpacesOnly) {
  292. FLAG_LONG_uint(foo, 30, false);
  293. const char* argv[] = {"binary", "--foo= ", nullptr};
  294. EXPECT_EQ(foo.value(), 30);
  295. EXPECT_FALSE(flags::Parse(argv));
  296. }
  297. TEST_F(FlagTest, UintLongFlagSplitNumber) {
  298. FLAG_LONG_uint(foo, 31, false);
  299. const char* argv[] = {"binary", "--foo= 2 2", nullptr};
  300. EXPECT_EQ(foo.value(), 31);
  301. EXPECT_FALSE(flags::Parse(argv));
  302. }
  303. TEST_F(FlagTest, UintLongFlagHex) {
  304. FLAG_LONG_uint(foo, 32, false);
  305. const char* argv[] = {"binary", "--foo=0xA", nullptr};
  306. EXPECT_EQ(foo.value(), 32);
  307. EXPECT_FALSE(flags::Parse(argv));
  308. }
  309. TEST_F(FlagTest, UintLongFlagZeros) {
  310. FLAG_LONG_uint(foo, 33, false);
  311. const char* argv[] = {"binary", "--foo=0000", nullptr};
  312. EXPECT_EQ(foo.value(), 33);
  313. EXPECT_TRUE(flags::Parse(argv));
  314. EXPECT_EQ(foo.value(), 0);
  315. EXPECT_EQ(flags::positional_arguments.size(), 0);
  316. }