TestLibCoreArgsParser.cpp 22 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591
  1. /*
  2. * Copyright (c) 2021, the SerenityOS developers.
  3. *
  4. * SPDX-License-Identifier: BSD-2-Clause
  5. */
  6. #include <AK/Function.h>
  7. #include <AK/String.h>
  8. #include <AK/Vector.h>
  9. #include <LibCore/ArgsParser.h>
  10. #include <LibTest/TestCase.h>
  11. class ParserResult {
  12. public:
  13. ParserResult(Vector<StringView> arguments)
  14. : arguments(move(arguments))
  15. {
  16. }
  17. ParserResult(ParserResult&& other)
  18. {
  19. arguments = move(other.arguments);
  20. result = other.result;
  21. }
  22. ParserResult& operator=(ParserResult&& other)
  23. {
  24. if (this != &other) {
  25. arguments = move(other.arguments);
  26. result = other.result;
  27. }
  28. return *this;
  29. }
  30. Vector<StringView> arguments;
  31. bool result { false };
  32. };
  33. static ParserResult run_parser(Vector<StringView> arguments, Function<void(Core::ArgsParser&)> parser_initialization = {})
  34. {
  35. Core::ArgsParser parser;
  36. if (parser_initialization)
  37. parser_initialization(parser);
  38. auto parse_result = ParserResult { move(arguments) };
  39. parse_result.result = parser.parse(parse_result.arguments, Core::ArgsParser::FailureBehavior::Ignore);
  40. return parse_result;
  41. }
  42. TEST_CASE(no_arguments)
  43. {
  44. auto parser_result = run_parser({ "app"sv });
  45. EXPECT_EQ(parser_result.result, true);
  46. }
  47. TEST_CASE(bool_option)
  48. {
  49. // Short option
  50. bool force = false;
  51. auto parser_result = run_parser({ "app"sv, "-f"sv }, [&](auto& parser) {
  52. parser.add_option(force, "force", nullptr, 'f');
  53. });
  54. EXPECT_EQ(parser_result.result, true);
  55. EXPECT_EQ(force, true);
  56. // Short option, not given
  57. force = false;
  58. parser_result = run_parser({ "app"sv }, [&](auto& parser) {
  59. parser.add_option(force, "force", nullptr, 'f');
  60. });
  61. EXPECT_EQ(parser_result.result, true);
  62. EXPECT_EQ(force, false);
  63. // Long option
  64. force = false;
  65. parser_result = run_parser({ "app"sv, "--force"sv }, [&](auto& parser) {
  66. parser.add_option(force, "force", "force", '\0');
  67. });
  68. EXPECT_EQ(parser_result.result, true);
  69. EXPECT_EQ(force, true);
  70. // Long option, not given
  71. force = false;
  72. parser_result = run_parser({ "app"sv }, [&](auto& parser) {
  73. parser.add_option(force, "force", "force", '\0');
  74. });
  75. EXPECT_EQ(parser_result.result, true);
  76. EXPECT_EQ(force, false);
  77. // Allow both short and long option, provide short
  78. force = false;
  79. parser_result = run_parser({ "app"sv, "-f"sv }, [&](auto& parser) {
  80. parser.add_option(force, "force", "force", 'f');
  81. });
  82. EXPECT_EQ(parser_result.result, true);
  83. EXPECT_EQ(force, true);
  84. // Allow both short and long option, provide long
  85. force = false;
  86. parser_result = run_parser({ "app"sv, "--force"sv }, [&](auto& parser) {
  87. parser.add_option(force, "force", "force", 'f');
  88. });
  89. EXPECT_EQ(parser_result.result, true);
  90. EXPECT_EQ(force, true);
  91. // Allow both short and long option, provide both
  92. force = false;
  93. parser_result = run_parser({ "app"sv, "--force"sv, "-f"sv }, [&](auto& parser) {
  94. parser.add_option(force, "force", "force", 'f');
  95. });
  96. EXPECT_EQ(parser_result.result, true);
  97. EXPECT_EQ(force, true);
  98. }
  99. TEST_CASE(string_option)
  100. {
  101. ByteString string_option;
  102. // short option
  103. auto parser_result = run_parser({ "app"sv, "-d"sv, "foo"sv }, [&](auto& parser) {
  104. parser.add_option(string_option, "dummy", nullptr, 'd', "DUMMY");
  105. });
  106. EXPECT_EQ(parser_result.result, true);
  107. EXPECT_EQ(string_option, "foo");
  108. // short option, not given
  109. string_option = "";
  110. parser_result = run_parser({ "app"sv, "-d"sv }, [&](auto& parser) {
  111. parser.add_option(string_option, "dummy", nullptr, 'd', "DUMMY");
  112. });
  113. EXPECT_EQ(parser_result.result, false);
  114. // long option
  115. string_option = "";
  116. parser_result = run_parser({ "app"sv, "--dummy"sv, "foo"sv }, [&](auto& parser) {
  117. parser.add_option(string_option, "dummy", "dummy", {}, "DUMMY");
  118. });
  119. EXPECT_EQ(parser_result.result, true);
  120. EXPECT_EQ(string_option, "foo");
  121. // long option, not given
  122. string_option = "";
  123. parser_result = run_parser({ "app"sv, "--dummy"sv }, [&](auto& parser) {
  124. parser.add_option(string_option, "dummy", "dummy", {}, "DUMMY");
  125. });
  126. EXPECT_EQ(parser_result.result, false);
  127. }
  128. TEST_CASE(positional_string_argument)
  129. {
  130. // Single required string argument
  131. ByteString name = "";
  132. auto parser_result = run_parser({ "app"sv, "buggie"sv }, [&](auto& parser) {
  133. parser.add_positional_argument(name, "name", "name", Core::ArgsParser::Required::Yes);
  134. });
  135. EXPECT_EQ(parser_result.result, true);
  136. EXPECT_EQ(name, "buggie");
  137. // Single required string argument, not given
  138. name = "";
  139. parser_result = run_parser({ "app"sv }, [&](auto& parser) {
  140. parser.add_positional_argument(name, "name", "name", Core::ArgsParser::Required::Yes);
  141. });
  142. EXPECT_EQ(parser_result.result, false);
  143. EXPECT_EQ(name, "");
  144. // Single optional string argument
  145. name = "";
  146. parser_result = run_parser({ "app"sv, "buggie"sv }, [&](auto& parser) {
  147. parser.add_positional_argument(name, "name", "name", Core::ArgsParser::Required::No);
  148. });
  149. EXPECT_EQ(parser_result.result, true);
  150. EXPECT_EQ(name, "buggie");
  151. // Single optional string argument, not given
  152. name = "";
  153. parser_result = run_parser({ "app"sv }, [&](auto& parser) {
  154. parser.add_positional_argument(name, "name", "name", Core::ArgsParser::Required::No);
  155. });
  156. EXPECT_EQ(parser_result.result, true);
  157. EXPECT_EQ(name, "");
  158. }
  159. TEST_CASE(positional_vector_string_argument)
  160. {
  161. Vector<StringView> values;
  162. // Zero or more positional arguments, zero given
  163. auto parser_result = run_parser({ "app"sv }, [&](auto& parser) {
  164. parser.add_positional_argument(values, "values", "values", Core::ArgsParser::Required::No);
  165. });
  166. EXPECT_EQ(parser_result.result, true);
  167. EXPECT_EQ(values.size(), 0u);
  168. // Zero or more positional arguments, one given
  169. values = {};
  170. parser_result = run_parser({ "app"sv, "one"sv }, [&](auto& parser) {
  171. parser.add_positional_argument(values, "values", "values", Core::ArgsParser::Required::No);
  172. });
  173. EXPECT_EQ(parser_result.result, true);
  174. EXPECT_EQ(values.size(), 1u);
  175. if (values.size() == 1u)
  176. EXPECT_EQ(values[0], "one");
  177. // Zero or more positional arguments, two given
  178. values = {};
  179. parser_result = run_parser({ "app"sv, "one"sv, "two"sv }, [&](auto& parser) {
  180. parser.add_positional_argument(values, "values", "values", Core::ArgsParser::Required::No);
  181. });
  182. EXPECT_EQ(parser_result.result, true);
  183. EXPECT_EQ(values.size(), 2u);
  184. if (values.size() == 2u) {
  185. EXPECT_EQ(values[0], "one");
  186. EXPECT_EQ(values[1], "two");
  187. }
  188. // One or more positional arguments, zero given
  189. values = {};
  190. parser_result = run_parser({ "app"sv }, [&](auto& parser) {
  191. parser.add_positional_argument(values, "values", "values", Core::ArgsParser::Required::Yes);
  192. });
  193. EXPECT_EQ(parser_result.result, false);
  194. EXPECT_EQ(values.size(), 0u);
  195. // One or more positional arguments, one given
  196. values = {};
  197. parser_result = run_parser({ "app"sv, "one"sv }, [&](auto& parser) {
  198. parser.add_positional_argument(values, "values", "values", Core::ArgsParser::Required::Yes);
  199. });
  200. EXPECT_EQ(parser_result.result, true);
  201. EXPECT_EQ(values.size(), 1u);
  202. if (values.size() == 1u)
  203. EXPECT_EQ(values[0], "one");
  204. // One or more positional arguments, two given
  205. values = {};
  206. parser_result = run_parser({ "app"sv, "one"sv, "two"sv }, [&](auto& parser) {
  207. parser.add_positional_argument(values, "values", "values", Core::ArgsParser::Required::Yes);
  208. });
  209. EXPECT_EQ(parser_result.result, true);
  210. EXPECT_EQ(values.size(), 2u);
  211. if (values.size() == 2u) {
  212. EXPECT_EQ(values[0], "one");
  213. EXPECT_EQ(values[1], "two");
  214. }
  215. }
  216. TEST_CASE(combination_of_bool_options_with_positional_vector_string)
  217. {
  218. Vector<StringView> positionals;
  219. // Bool options (given) and positional arguments (given)
  220. // Expected: all arguments fill as given
  221. bool bool_opt1 = false;
  222. bool bool_opt2 = false;
  223. auto parser_result = run_parser({ "app"sv, "-b"sv, "-c"sv, "one"sv, "two"sv }, [&](auto& parser) {
  224. parser.add_option(bool_opt1, "bool_opt1", nullptr, 'b');
  225. parser.add_option(bool_opt2, "bool_opt2", nullptr, 'c');
  226. parser.add_positional_argument(positionals, "pos", "pos", Core::ArgsParser::Required::No);
  227. });
  228. EXPECT_EQ(parser_result.result, true);
  229. EXPECT_EQ(bool_opt1, true);
  230. EXPECT_EQ(bool_opt2, true);
  231. EXPECT_EQ(positionals.size(), 2u);
  232. if (positionals.size() == 2u) {
  233. EXPECT_EQ(positionals[0], "one");
  234. EXPECT_EQ(positionals[1], "two");
  235. }
  236. // Bool options (missing) and positional arguments (given)
  237. // Expected: only the positional arguments are filled
  238. bool_opt1 = false;
  239. bool_opt2 = false;
  240. positionals = {};
  241. parser_result = run_parser({ "app"sv, "one"sv, "two"sv }, [&](auto& parser) {
  242. parser.add_option(bool_opt1, "bool_opt1", nullptr, 'b');
  243. parser.add_option(bool_opt2, "bool_opt2", nullptr, 'c');
  244. parser.add_positional_argument(positionals, "pos", "pos", Core::ArgsParser::Required::No);
  245. });
  246. EXPECT_EQ(parser_result.result, true);
  247. EXPECT_EQ(bool_opt1, false);
  248. EXPECT_EQ(bool_opt2, false);
  249. EXPECT_EQ(positionals.size(), 2u);
  250. if (positionals.size() == 2u) {
  251. EXPECT_EQ(positionals[0], "one");
  252. EXPECT_EQ(positionals[1], "two");
  253. }
  254. // Bool options (given) and positional arguments (missing)
  255. // Expected: only the bool options are filled
  256. bool_opt1 = false;
  257. bool_opt2 = false;
  258. positionals = {};
  259. parser_result = run_parser({ "app"sv, "-b"sv, "-c"sv }, [&](auto& parser) {
  260. parser.add_option(bool_opt1, "bool_opt1", nullptr, 'b');
  261. parser.add_option(bool_opt2, "bool_opt2", nullptr, 'c');
  262. parser.add_positional_argument(positionals, "pos", "pos", Core::ArgsParser::Required::No);
  263. });
  264. EXPECT_EQ(parser_result.result, true);
  265. EXPECT_EQ(bool_opt1, true);
  266. EXPECT_EQ(bool_opt2, true);
  267. EXPECT_EQ(positionals.size(), 0u);
  268. // Bool options (missing) and positional arguments (given) using double dash
  269. // Expected: the bool options are interpreted as positional arguments
  270. bool_opt1 = false;
  271. bool_opt2 = false;
  272. positionals = {};
  273. parser_result = run_parser({ "app"sv, "--"sv, "-b"sv, "-c"sv }, [&](auto& parser) {
  274. parser.add_option(bool_opt1, "bool_opt1", nullptr, 'b');
  275. parser.add_option(bool_opt2, "bool_opt2", nullptr, 'c');
  276. parser.add_positional_argument(positionals, "pos", "pos", Core::ArgsParser::Required::No);
  277. });
  278. EXPECT_EQ(parser_result.result, true);
  279. EXPECT_EQ(bool_opt1, false);
  280. EXPECT_EQ(bool_opt2, false);
  281. EXPECT_EQ(positionals.size(), 2u);
  282. if (positionals.size() == 2u) {
  283. EXPECT_EQ(positionals[0], "-b");
  284. EXPECT_EQ(positionals[1], "-c");
  285. }
  286. // Bool options (one given) and positional arguments (one given) using double dash
  287. // Expected: bool_opt1 is set, one positional is added
  288. bool_opt1 = false;
  289. bool_opt2 = false;
  290. positionals = {};
  291. parser_result = run_parser({ "app"sv, "-b"sv, "--"sv, "-c"sv }, [&](auto& parser) {
  292. parser.add_option(bool_opt1, "bool_opt1", nullptr, 'b');
  293. parser.add_option(bool_opt2, "bool_opt2", nullptr, 'c');
  294. parser.add_positional_argument(positionals, "pos", "pos", Core::ArgsParser::Required::No);
  295. });
  296. EXPECT_EQ(parser_result.result, true);
  297. EXPECT_EQ(bool_opt1, true);
  298. EXPECT_EQ(bool_opt2, false);
  299. EXPECT_EQ(positionals.size(), 1u);
  300. if (positionals.size() == 1u) {
  301. EXPECT_EQ(positionals[0], "-c");
  302. }
  303. // Bool options (three given, one incorrect) and positional arguments (missing)
  304. // Expected: parser fails
  305. bool_opt1 = false;
  306. bool_opt2 = false;
  307. positionals = {};
  308. parser_result = run_parser({ "app"sv, "-b"sv, "-d"sv, "-c"sv }, [&](auto& parser) {
  309. parser.add_option(bool_opt1, "bool_opt1", nullptr, 'b');
  310. parser.add_option(bool_opt2, "bool_opt2", nullptr, 'c');
  311. parser.add_positional_argument(positionals, "pos", "pos", Core::ArgsParser::Required::No);
  312. });
  313. EXPECT_EQ(parser_result.result, false);
  314. }
  315. TEST_CASE(combination_of_bool_and_string_short_options_with_positional_vector_string)
  316. {
  317. // #22759: Positional arguments were sometimes incorrectly not shifted, leading to an incorrect parse.
  318. // Bool options (given), string options (given) and one positional argument (given)
  319. // Expected: all arguments fill as given
  320. bool bool_opt1 = false;
  321. bool bool_opt2 = false;
  322. ByteString string_opt1;
  323. ByteString string_opt2;
  324. Vector<StringView> positionals;
  325. auto parser_result = run_parser({ "app"sv, "-b"sv, "-c"sv, "-d"sv, "foo"sv, "-e"sv, "bar"sv, "one"sv }, [&](auto& parser) {
  326. parser.add_option(bool_opt1, "bool_opt1", nullptr, 'b');
  327. parser.add_option(bool_opt2, "bool_opt2", nullptr, 'c');
  328. parser.add_option(string_opt1, "string_opt1", nullptr, 'd', "D");
  329. parser.add_option(string_opt2, "string_opt2", nullptr, 'e', "E");
  330. parser.add_positional_argument(positionals, "pos", "pos", Core::ArgsParser::Required::No);
  331. });
  332. EXPECT_EQ(parser_result.result, true);
  333. EXPECT_EQ(bool_opt1, true);
  334. EXPECT_EQ(bool_opt2, true);
  335. EXPECT_EQ(string_opt1, "foo");
  336. EXPECT_EQ(string_opt2, "bar");
  337. EXPECT_EQ(positionals.size(), 1u);
  338. if (positionals.size() == 1u) {
  339. EXPECT_EQ(positionals[0], "one");
  340. }
  341. // Bool options (given), string options (given) and one positional argument (given)
  342. // one bool option after positional
  343. // Expected: all arguments fill as given
  344. bool_opt1 = false;
  345. bool_opt2 = false;
  346. string_opt1 = "";
  347. string_opt2 = "";
  348. positionals = {};
  349. parser_result = run_parser({ "app"sv, "-c"sv, "-d"sv, "foo"sv, "-e"sv, "bar"sv, "one"sv, "-b"sv }, [&](auto& parser) {
  350. parser.add_option(bool_opt1, "bool_opt1", nullptr, 'b');
  351. parser.add_option(bool_opt2, "bool_opt2", nullptr, 'c');
  352. parser.add_option(string_opt1, "string_opt1", nullptr, 'd', "D");
  353. parser.add_option(string_opt2, "string_opt2", nullptr, 'e', "E");
  354. parser.add_positional_argument(positionals, "pos", "pos", Core::ArgsParser::Required::No);
  355. });
  356. EXPECT_EQ(parser_result.result, true);
  357. EXPECT_EQ(bool_opt1, true);
  358. EXPECT_EQ(bool_opt2, true);
  359. EXPECT_EQ(string_opt1, "foo");
  360. EXPECT_EQ(string_opt2, "bar");
  361. EXPECT_EQ(positionals.size(), 1u);
  362. if (positionals.size() == 1u) {
  363. EXPECT_EQ(positionals[0], "one");
  364. }
  365. // Bool options (given), string options (given) and one positional argument (given)
  366. // one string and one bool option after positional
  367. // Expected: all arguments fill as given
  368. bool_opt1 = false;
  369. bool_opt2 = false;
  370. string_opt1 = "";
  371. string_opt2 = "";
  372. positionals = {};
  373. parser_result = run_parser({ "app"sv, "-c"sv, "-e"sv, "bar"sv, "one"sv, "-d"sv, "foo"sv, "-b"sv }, [&](auto& parser) {
  374. parser.add_option(bool_opt1, "bool_opt1", nullptr, 'b');
  375. parser.add_option(bool_opt2, "bool_opt2", nullptr, 'c');
  376. parser.add_option(string_opt1, "string_opt1", nullptr, 'd', "D");
  377. parser.add_option(string_opt2, "string_opt2", nullptr, 'e', "E");
  378. parser.add_positional_argument(positionals, "pos", "pos", Core::ArgsParser::Required::No);
  379. });
  380. EXPECT_EQ(parser_result.result, true);
  381. EXPECT_EQ(bool_opt1, true);
  382. EXPECT_EQ(bool_opt2, true);
  383. EXPECT_EQ(string_opt1, "foo");
  384. EXPECT_EQ(string_opt2, "bar");
  385. EXPECT_EQ(positionals.size(), 1u);
  386. if (positionals.size() == 1u) {
  387. EXPECT_EQ(positionals[0], "one");
  388. }
  389. // Bool options (given), string options (given) and two positional arguments (given)
  390. // positional arguments are separated by options
  391. // Expected: all arguments fill as given
  392. bool_opt1 = false;
  393. bool_opt2 = false;
  394. string_opt1 = "";
  395. string_opt2 = "";
  396. positionals = {};
  397. parser_result = run_parser({ "app"sv, "-b"sv, "-d"sv, "foo"sv, "one"sv, "-c"sv, "-e"sv, "bar"sv, "two"sv }, [&](auto& parser) {
  398. parser.add_option(bool_opt1, "bool_opt1", nullptr, 'b');
  399. parser.add_option(bool_opt2, "bool_opt2", nullptr, 'c');
  400. parser.add_option(string_opt1, "string_opt1", nullptr, 'd', "D");
  401. parser.add_option(string_opt2, "string_opt2", nullptr, 'e', "E");
  402. parser.add_positional_argument(positionals, "pos", "pos", Core::ArgsParser::Required::No);
  403. });
  404. EXPECT_EQ(parser_result.result, true);
  405. EXPECT_EQ(bool_opt1, true);
  406. EXPECT_EQ(bool_opt2, true);
  407. EXPECT_EQ(string_opt1, "foo");
  408. EXPECT_EQ(string_opt2, "bar");
  409. EXPECT_EQ(positionals.size(), 2u);
  410. if (positionals.size() == 2u) {
  411. EXPECT_EQ(positionals[0], "one");
  412. EXPECT_EQ(positionals[1], "two");
  413. }
  414. // Bool options (given), string options (given) and two positional arguments (given)
  415. // positional arguments are separated and followed by options
  416. // Expected: all arguments fill as given
  417. bool_opt1 = false;
  418. bool_opt2 = false;
  419. string_opt1 = "";
  420. string_opt2 = "";
  421. positionals = {};
  422. parser_result = run_parser({ "app"sv, "one"sv, "-b"sv, "-d"sv, "foo"sv, "two"sv, "-c"sv, "-e"sv, "bar"sv }, [&](auto& parser) {
  423. parser.add_option(bool_opt1, "bool_opt1", nullptr, 'b');
  424. parser.add_option(bool_opt2, "bool_opt2", nullptr, 'c');
  425. parser.add_option(string_opt1, "string_opt1", nullptr, 'd', "D");
  426. parser.add_option(string_opt2, "string_opt2", nullptr, 'e', "E");
  427. parser.add_positional_argument(positionals, "pos", "pos", Core::ArgsParser::Required::No);
  428. });
  429. EXPECT_EQ(parser_result.result, true);
  430. EXPECT_EQ(bool_opt1, true);
  431. EXPECT_EQ(bool_opt2, true);
  432. EXPECT_EQ(string_opt1, "foo");
  433. EXPECT_EQ(string_opt2, "bar");
  434. EXPECT_EQ(positionals.size(), 2u);
  435. if (positionals.size() == 2u) {
  436. EXPECT_EQ(positionals[0], "one");
  437. EXPECT_EQ(positionals[1], "two");
  438. }
  439. // Bool options (given), string options (given) and two positional arguments (given)
  440. // positional arguments are separated and followed by options, variation on options order
  441. // Expected: all arguments fill as given
  442. bool_opt1 = false;
  443. bool_opt2 = false;
  444. string_opt1 = "";
  445. string_opt2 = "";
  446. positionals = {};
  447. parser_result = run_parser({ "app"sv, "one"sv, "-d"sv, "foo"sv, "-b"sv, "two"sv, "-e"sv, "bar"sv, "-c"sv }, [&](auto& parser) {
  448. parser.add_option(bool_opt1, "bool_opt1", nullptr, 'b');
  449. parser.add_option(bool_opt2, "bool_opt2", nullptr, 'c');
  450. parser.add_option(string_opt1, "string_opt1", nullptr, 'd', "D");
  451. parser.add_option(string_opt2, "string_opt2", nullptr, 'e', "E");
  452. parser.add_positional_argument(positionals, "pos", "pos", Core::ArgsParser::Required::No);
  453. });
  454. EXPECT_EQ(parser_result.result, true);
  455. EXPECT_EQ(bool_opt1, true);
  456. EXPECT_EQ(bool_opt2, true);
  457. EXPECT_EQ(string_opt1, "foo");
  458. EXPECT_EQ(string_opt2, "bar");
  459. EXPECT_EQ(positionals.size(), 2u);
  460. if (positionals.size() == 2u) {
  461. EXPECT_EQ(positionals[0], "one");
  462. EXPECT_EQ(positionals[1], "two");
  463. }
  464. }
  465. TEST_CASE(stop_on_first_non_option)
  466. {
  467. // Do not stop on first non-option; arguments in correct order
  468. // Expected: bool options are set and one positional argument is filled
  469. bool bool_opt1 = false;
  470. bool bool_opt2 = false;
  471. Vector<StringView> positionals;
  472. auto parser_result = run_parser({ "app"sv, "-b"sv, "-c"sv, "one"sv }, [&](auto& parser) {
  473. parser.set_stop_on_first_non_option(false);
  474. parser.add_option(bool_opt1, "bool_opt1", nullptr, 'b');
  475. parser.add_option(bool_opt2, "bool_opt2", nullptr, 'c');
  476. parser.add_positional_argument(positionals, "pos", "pos", Core::ArgsParser::Required::Yes);
  477. });
  478. EXPECT_EQ(parser_result.result, true);
  479. EXPECT_EQ(bool_opt1, true);
  480. EXPECT_EQ(bool_opt2, true);
  481. EXPECT_EQ(positionals.size(), 1u);
  482. if (positionals.size() == 1u)
  483. EXPECT_EQ(positionals[0], "one");
  484. // Do not stop on first non-option; arguments in wrong order
  485. // Expected: bool options are set and one positional argument is filled
  486. bool_opt1 = false;
  487. bool_opt2 = false;
  488. positionals = {};
  489. parser_result = run_parser({ "app"sv, "-b"sv, "one"sv, "-c"sv }, [&](auto& parser) {
  490. parser.set_stop_on_first_non_option(false);
  491. parser.add_option(bool_opt1, "bool_opt1", nullptr, 'b');
  492. parser.add_option(bool_opt2, "bool_opt2", nullptr, 'c');
  493. parser.add_positional_argument(positionals, "pos", "pos", Core::ArgsParser::Required::Yes);
  494. });
  495. EXPECT_EQ(parser_result.result, true);
  496. EXPECT_EQ(bool_opt1, true);
  497. EXPECT_EQ(bool_opt2, true);
  498. EXPECT_EQ(positionals.size(), 1u);
  499. if (positionals.size() == 1u)
  500. EXPECT_EQ(positionals[0], "one");
  501. // Stop on first non-option; arguments in correct order
  502. // Expected: bool options are set and one positional argument is filled
  503. bool_opt1 = false;
  504. bool_opt2 = false;
  505. positionals = {};
  506. parser_result = run_parser({ "app"sv, "-b"sv, "-c"sv, "one"sv }, [&](auto& parser) {
  507. parser.set_stop_on_first_non_option(true);
  508. parser.add_option(bool_opt1, "bool_opt1", nullptr, 'b');
  509. parser.add_option(bool_opt2, "bool_opt2", nullptr, 'c');
  510. parser.add_positional_argument(positionals, "pos", "pos", Core::ArgsParser::Required::Yes);
  511. });
  512. EXPECT_EQ(parser_result.result, true);
  513. EXPECT_EQ(bool_opt1, true);
  514. EXPECT_EQ(bool_opt2, true);
  515. EXPECT_EQ(positionals.size(), 1u);
  516. if (positionals.size() == 1u)
  517. EXPECT_EQ(positionals[0], "one");
  518. // Stop on first non-option; arguments in wrong order
  519. // Expected: bool_opt1 is set, other arguments are filled as positional arguments
  520. bool_opt1 = false;
  521. bool_opt2 = false;
  522. positionals = {};
  523. parser_result = run_parser({ "app"sv, "-b"sv, "one"sv, "-c"sv }, [&](auto& parser) {
  524. parser.set_stop_on_first_non_option(true);
  525. parser.add_option(bool_opt1, "bool_opt1", nullptr, 'b');
  526. parser.add_option(bool_opt2, "bool_opt2", nullptr, 'c');
  527. parser.add_positional_argument(positionals, "pos", "pos", Core::ArgsParser::Required::Yes);
  528. });
  529. EXPECT_EQ(parser_result.result, true);
  530. EXPECT_EQ(bool_opt1, true);
  531. EXPECT_EQ(bool_opt2, false);
  532. EXPECT_EQ(positionals.size(), 2u);
  533. if (positionals.size() == 2u) {
  534. EXPECT_EQ(positionals[0], "one");
  535. EXPECT_EQ(positionals[1], "-c");
  536. }
  537. }