poafloc

Parser Of Arguments For Lines Of Commands
git clone git://git.dimitrijedobrota.com/poafloc.git
Log | Files | Refs | README | LICENSE | HACKING | CONTRIBUTING | CODE_OF_CONDUCT | BUILDING

parser.cpp (21672B)


0 #define CATCH_CONFIG_RUNTIME_STATIC_REQUIRE
2 #include <string_view>
3 #include <vector>
5 #include <catch2/catch_test_macros.hpp>
7 #include "poafloc/error.hpp"
8 #include "poafloc/poafloc.hpp"
10 using namespace poafloc; // NOLINT
12 // NOLINTBEGIN(*complexity*)
13 TEST_CASE("invalid", "[poafloc/parser]")
14 {
15 struct arguments
16 {
17 bool flag;
18 int value;
19 };
21 SECTION("empty")
22 {
23 auto program = parser<arguments> {
24 group {
25 "unnamed",
26 boolean {"f", &arguments::flag, "NUM something"},
27 },
28 };
29 arguments args = {};
30 std::vector<std::string_view> cmdline = {};
31 REQUIRE_THROWS_AS(program(args, cmdline), error<error_code::empty>);
32 };
34 SECTION("short number")
35 {
36 auto construct = []()
37 {
38 return parser<arguments> {
39 group {
40 "unnamed",
41 boolean {"1", &arguments::flag, "NUM something"},
42 },
43 };
44 };
45 REQUIRE_THROWS_AS(construct(), error<error_code::invalid_option>);
46 }
48 SECTION("long upper")
49 {
50 auto construct = []()
51 {
52 return parser<arguments> {
53 group {
54 "unnamed",
55 boolean {"FLAG", &arguments::flag, "something"},
56 },
57 };
58 };
59 REQUIRE_THROWS_AS(construct(), error<error_code::invalid_option>);
60 }
62 SECTION("long number start")
63 {
64 auto construct = []()
65 {
66 return parser<arguments> {
67 group {
68 "unnamed",
69 direct {"1value", &arguments::value, "NUM something"},
70 },
71 };
72 };
73 REQUIRE_THROWS_AS(construct(), error<error_code::invalid_option>);
74 }
76 SECTION("short duplicate")
77 {
78 auto construct = []()
79 {
80 return parser<arguments> {
81 group {
82 "unnamed",
83 boolean {"f flag", &arguments::flag, "something"},
84 direct {"f follow", &arguments::value, "NUM something"},
85 },
86 };
87 };
88 REQUIRE_THROWS_AS(construct(), error<error_code::duplicate_option>);
89 }
91 SECTION("long duplicate")
92 {
93 auto construct = []()
94 {
95 return parser<arguments> {
96 group {
97 "unnamed",
98 boolean {"f flag", &arguments::flag, "something"},
99 direct {"v flag", &arguments::value, "something"},
100 },
101 };
102 };
103 REQUIRE_THROWS_AS(construct(), error<error_code::duplicate_option>);
107 TEST_CASE("boolean", "[poafloc/parser]")
109 struct arguments
111 bool flag = false;
112 } args;
114 auto program = parser<arguments> {
115 group {
116 "unnamed",
117 boolean {"f flag", &arguments::flag, "something"},
118 },
119 };
121 SECTION("short")
123 std::vector<std::string_view> cmdline = {"test", "-f"};
124 REQUIRE_NOTHROW(program(args, cmdline));
125 REQUIRE(args.flag == true);
128 SECTION("long")
130 std::vector<std::string_view> cmdline = {"test", "--flag"};
131 REQUIRE_NOTHROW(program(args, cmdline));
132 REQUIRE(args.flag == true);
135 SECTION("long partial")
137 std::vector<std::string_view> cmdline = {"test", "--fl"};
138 REQUIRE_NOTHROW(program(args, cmdline));
139 REQUIRE(args.flag == true);
142 SECTION("short unknown")
144 std::vector<std::string_view> cmdline = {"test", "-u"};
145 REQUIRE_THROWS_AS(program(args, cmdline), error<error_code::unknown_option>);
146 REQUIRE(args.flag == false);
149 SECTION("long unknown")
151 std::vector<std::string_view> cmdline = {"test", "--unknown"};
152 REQUIRE_THROWS_AS(program(args, cmdline), error<error_code::unknown_option>);
153 REQUIRE(args.flag == false);
156 SECTION("long superfluous")
158 std::vector<std::string_view> cmdline = {"test", "--fl=something"};
159 REQUIRE_THROWS_AS(program(args, cmdline), error<error_code::superfluous_argument>);
160 REQUIRE(args.flag == false);
163 SECTION("long superfluous missing")
165 std::vector<std::string_view> cmdline = {"test", "--fl="};
166 REQUIRE_THROWS_AS(program(args, cmdline), error<error_code::superfluous_argument>);
167 REQUIRE(args.flag == false);
171 TEST_CASE("direct string", "[poafloc/parser]")
173 struct arguments
175 std::string name = "default";
176 } args;
178 auto program = parser<arguments> {
179 group {
180 "unnamed",
181 direct {"n name", &arguments::name, "NAME something"},
182 },
183 };
185 SECTION("short")
187 std::vector<std::string_view> cmdline = {"test", "-n", "something"};
188 REQUIRE_NOTHROW(program(args, cmdline));
189 REQUIRE(args.name == "something");
192 SECTION("short equal")
194 std::vector<std::string_view> cmdline = {"test", "-n=something"};
195 REQUIRE_NOTHROW(program(args, cmdline));
196 REQUIRE(args.name == "something");
199 SECTION("short together")
201 std::vector<std::string_view> cmdline = {"test", "-nsomething"};
202 REQUIRE_NOTHROW(program(args, cmdline));
203 REQUIRE(args.name == "something");
206 SECTION("long")
208 std::vector<std::string_view> cmdline = {"test", "--name", "something"};
209 REQUIRE_NOTHROW(program(args, cmdline));
210 REQUIRE(args.name == "something");
213 SECTION("long partial")
215 std::vector<std::string_view> cmdline = {"test", "--na", "something"};
216 REQUIRE_NOTHROW(program(args, cmdline));
217 REQUIRE(args.name == "something");
220 SECTION("long equal")
222 std::vector<std::string_view> cmdline = {"test", "--name=something"};
223 REQUIRE_NOTHROW(program(args, cmdline));
224 REQUIRE(args.name == "something");
227 SECTION("long equal partial")
229 std::vector<std::string_view> cmdline = {"test", "--na=something"};
230 REQUIRE_NOTHROW(program(args, cmdline));
231 REQUIRE(args.name == "something");
234 SECTION("short missing")
236 std::vector<std::string_view> cmdline = {"test", "-n"};
237 REQUIRE_THROWS_AS(program(args, cmdline), error<error_code::missing_argument>);
238 REQUIRE(args.name == "default");
241 SECTION("short equal missing")
243 std::vector<std::string_view> cmdline = {"test", "-n="};
244 REQUIRE_THROWS_AS(program(args, cmdline), error<error_code::missing_argument>);
245 REQUIRE(args.name == "default");
248 SECTION("long missing")
250 std::vector<std::string_view> cmdline = {"test", "--name"};
251 REQUIRE_THROWS_AS(program(args, cmdline), error<error_code::missing_argument>);
252 REQUIRE(args.name == "default");
255 SECTION("long partial missing")
257 std::vector<std::string_view> cmdline = {"test", "--na"};
258 REQUIRE_THROWS_AS(program(args, cmdline), error<error_code::missing_argument>);
259 REQUIRE(args.name == "default");
262 SECTION("long equal missing")
264 std::vector<std::string_view> cmdline = {"test", "--name="};
265 REQUIRE_THROWS_AS(program(args, cmdline), error<error_code::missing_argument>);
266 REQUIRE(args.name == "default");
269 SECTION("long equal partial missing")
271 std::vector<std::string_view> cmdline = {"test", "--na="};
272 REQUIRE_THROWS_AS(program(args, cmdline), error<error_code::missing_argument>);
273 REQUIRE(args.name == "default");
276 SECTION("short unknown")
278 std::vector<std::string_view> cmdline = {"test", "-u", "something"};
279 REQUIRE_THROWS_AS(program(args, cmdline), error<error_code::unknown_option>);
280 REQUIRE(args.name == "default");
283 SECTION("long unknown")
285 std::vector<std::string_view> cmdline = {"test", "--unknown", "something"};
286 REQUIRE_THROWS_AS(program(args, cmdline), error<error_code::unknown_option>);
287 REQUIRE(args.name == "default");
290 SECTION("long equal unknown")
292 std::vector<std::string_view> cmdline = {"test", "--unknown=something"};
293 REQUIRE_THROWS_AS(program(args, cmdline), error<error_code::unknown_option>);
294 REQUIRE(args.name == "default");
298 TEST_CASE("direct value", "[poafloc/parser]")
300 struct arguments
302 int value = 0;
303 } args;
305 auto program = parser<arguments> {
306 group {
307 "unnamed",
308 direct {"v value", &arguments::value, "NUM something"},
309 },
310 };
312 SECTION("short")
314 std::vector<std::string_view> cmdline = {"test", "-v", "135"};
315 REQUIRE_NOTHROW(program(args, cmdline));
316 REQUIRE(args.value == 135);
319 SECTION("short equal")
321 std::vector<std::string_view> cmdline = {"test", "-v=135"};
322 REQUIRE_NOTHROW(program(args, cmdline));
323 REQUIRE(args.value == 135);
326 SECTION("short together")
328 std::vector<std::string_view> cmdline = {"test", "-v135"};
329 REQUIRE_NOTHROW(program(args, cmdline));
330 REQUIRE(args.value == 135);
333 SECTION("long")
335 std::vector<std::string_view> cmdline = {"test", "--value", "135"};
336 REQUIRE_NOTHROW(program(args, cmdline));
337 REQUIRE(args.value == 135);
340 SECTION("long partial")
342 std::vector<std::string_view> cmdline = {"test", "--val", "135"};
343 REQUIRE_NOTHROW(program(args, cmdline));
344 REQUIRE(args.value == 135);
347 SECTION("long equal")
349 std::vector<std::string_view> cmdline = {"test", "--value=135"};
350 REQUIRE_NOTHROW(program(args, cmdline));
351 REQUIRE(args.value == 135);
354 SECTION("long equal partial")
356 std::vector<std::string_view> cmdline = {"test", "--val=135"};
357 REQUIRE_NOTHROW(program(args, cmdline));
358 REQUIRE(args.value == 135);
361 SECTION("short missing")
363 std::vector<std::string_view> cmdline = {"test", "-v"};
364 REQUIRE_THROWS_AS(program(args, cmdline), error<error_code::missing_argument>);
365 REQUIRE(args.value == 0);
368 SECTION("short equal missing")
370 std::vector<std::string_view> cmdline = {"test", "-v="};
371 REQUIRE_THROWS_AS(program(args, cmdline), error<error_code::missing_argument>);
372 REQUIRE(args.value == 0);
375 SECTION("long missing")
377 std::vector<std::string_view> cmdline = {"test", "--value"};
378 REQUIRE_THROWS_AS(program(args, cmdline), error<error_code::missing_argument>);
379 REQUIRE(args.value == 0);
382 SECTION("long partial missing")
384 std::vector<std::string_view> cmdline = {"test", "--val"};
385 REQUIRE_THROWS_AS(program(args, cmdline), error<error_code::missing_argument>);
386 REQUIRE(args.value == 0);
389 SECTION("long equal missing")
391 std::vector<std::string_view> cmdline = {"test", "--value="};
392 REQUIRE_THROWS_AS(program(args, cmdline), error<error_code::missing_argument>);
393 REQUIRE(args.value == 0);
396 SECTION("long equal partial missing")
398 std::vector<std::string_view> cmdline = {"test", "--val="};
399 REQUIRE_THROWS_AS(program(args, cmdline), error<error_code::missing_argument>);
400 REQUIRE(args.value == 0);
403 SECTION("short unknown")
405 std::vector<std::string_view> cmdline = {"test", "-u", "135"};
406 REQUIRE_THROWS_AS(program(args, cmdline), error<error_code::unknown_option>);
407 REQUIRE(args.value == 0);
410 SECTION("long unknown")
412 std::vector<std::string_view> cmdline = {"test", "--unknown", "135"};
413 REQUIRE_THROWS_AS(program(args, cmdline), error<error_code::unknown_option>);
414 REQUIRE(args.value == 0);
417 SECTION("long equal unknown")
419 std::vector<std::string_view> cmdline = {"test", "--unknown=135"};
420 REQUIRE_THROWS_AS(program(args, cmdline), error<error_code::unknown_option>);
421 REQUIRE(args.value == 0);
425 TEST_CASE("list", "[poafloc/parser]")
427 struct arguments
429 void add(std::string_view value) { list.emplace_back(value); }
431 std::vector<std::string> list;
432 } args;
434 auto program = parser<arguments> {group {
435 "unnamed",
436 list {"l list", &arguments::add, "NAME something"},
437 }};
439 SECTION("short empty")
441 std::vector<std::string_view> cmdline = {"test", "-l"};
442 REQUIRE_THROWS_AS(program(args, cmdline), error<error_code::missing_argument>);
445 SECTION("short one")
447 std::vector<std::string_view> cmdline = {"test", "-l", "one"};
448 REQUIRE_NOTHROW(program(args, cmdline));
449 REQUIRE(std::size(args.list) == 1);
450 REQUIRE(args.list[0] == "one");
453 SECTION("short two")
455 std::vector<std::string_view> cmdline = {"test", "-l", "one", "two"};
456 REQUIRE_NOTHROW(program(args, cmdline));
457 REQUIRE(std::size(args.list) == 2);
458 REQUIRE(args.list[0] == "one");
459 REQUIRE(args.list[1] == "two");
462 SECTION("short three")
464 std::vector<std::string_view> cmdline = {
465 "test", "-l", "one", "two", "three"
466 };
467 REQUIRE_NOTHROW(program(args, cmdline));
468 REQUIRE(std::size(args.list) == 3);
469 REQUIRE(args.list[0] == "one");
470 REQUIRE(args.list[1] == "two");
471 REQUIRE(args.list[2] == "three");
474 SECTION("short terminal")
476 std::vector<std::string_view> cmdline = {"test", "-l", "--"};
477 REQUIRE_THROWS_AS(program(args, cmdline), error<error_code::missing_argument>);
480 SECTION("short terminal one")
482 std::vector<std::string_view> cmdline = {"test", "-l", "one", "--"};
483 REQUIRE_NOTHROW(program(args, cmdline));
484 REQUIRE(std::size(args.list) == 1);
485 REQUIRE(args.list[0] == "one");
488 SECTION("short terminal two")
490 std::vector<std::string_view> cmdline = {"test", "-l", "one", "two", "--"};
491 REQUIRE_NOTHROW(program(args, cmdline));
492 REQUIRE(std::size(args.list) == 2);
493 REQUIRE(args.list[0] == "one");
494 REQUIRE(args.list[1] == "two");
497 SECTION("short terminal three")
499 std::vector<std::string_view> cmdline = {
500 "test", "-l", "one", "two", "three", "--"
501 };
502 REQUIRE_NOTHROW(program(args, cmdline));
503 REQUIRE(std::size(args.list) == 3);
504 REQUIRE(args.list[0] == "one");
505 REQUIRE(args.list[1] == "two");
506 REQUIRE(args.list[2] == "three");
509 SECTION("long empty")
511 std::vector<std::string_view> cmdline = {"test", "--list"};
512 REQUIRE_THROWS_AS(program(args, cmdline), error<error_code::missing_argument>);
515 SECTION("long one")
517 std::vector<std::string_view> cmdline = {"test", "--list", "one"};
518 REQUIRE_NOTHROW(program(args, cmdline));
519 REQUIRE(std::size(args.list) == 1);
520 REQUIRE(args.list[0] == "one");
523 SECTION("long two")
525 std::vector<std::string_view> cmdline = {"test", "--list", "one", "two"};
526 REQUIRE_NOTHROW(program(args, cmdline));
527 REQUIRE(std::size(args.list) == 2);
528 REQUIRE(args.list[0] == "one");
529 REQUIRE(args.list[1] == "two");
532 SECTION("long three")
534 std::vector<std::string_view> cmdline = {
535 "test", "--list", "one", "two", "three"
536 };
537 REQUIRE_NOTHROW(program(args, cmdline));
538 REQUIRE(std::size(args.list) == 3);
539 REQUIRE(args.list[0] == "one");
540 REQUIRE(args.list[1] == "two");
541 REQUIRE(args.list[2] == "three");
544 SECTION("long terminal")
546 std::vector<std::string_view> cmdline = {"test", "--list", "--"};
547 REQUIRE_THROWS_AS(program(args, cmdline), error<error_code::missing_argument>);
550 SECTION("long terminal one")
552 std::vector<std::string_view> cmdline = {"test", "--list", "one", "--"};
553 REQUIRE_NOTHROW(program(args, cmdline));
554 REQUIRE(std::size(args.list) == 1);
555 REQUIRE(args.list[0] == "one");
558 SECTION("long terminal two")
560 std::vector<std::string_view> cmdline = {
561 "test", "--list", "one", "two", "--"
562 };
563 REQUIRE_NOTHROW(program(args, cmdline));
564 REQUIRE(std::size(args.list) == 2);
565 REQUIRE(args.list[0] == "one");
566 REQUIRE(args.list[1] == "two");
569 SECTION("long terminal three")
571 std::vector<std::string_view> cmdline = {
572 "test", "--list", "one", "two", "three", "--"
573 };
574 REQUIRE_NOTHROW(program(args, cmdline));
575 REQUIRE(std::size(args.list) == 3);
576 REQUIRE(args.list[0] == "one");
577 REQUIRE(args.list[1] == "two");
578 REQUIRE(args.list[2] == "three");
582 TEST_CASE("positional", "[poafloc/parser]")
584 struct arguments
586 bool flag = false;
587 int value = 0;
588 std::string one;
589 std::string two;
590 } args;
592 auto program = parser<arguments> {
593 positional {
594 argument {"one", &arguments::one},
595 argument {"two", &arguments::two},
596 },
597 group {
598 "unnamed",
599 boolean {"f flag", &arguments::flag, "something"},
600 direct {"v value", &arguments::value, "NUM something"},
602 };
604 SECTION("empty")
606 std::vector<std::string_view> cmdline = {
607 "test",
608 };
609 REQUIRE_THROWS_AS(program(args, cmdline), error<error_code::missing_positional>);
612 SECTION("one")
614 std::vector<std::string_view> cmdline = {"test", "one"};
615 REQUIRE_THROWS_AS(program(args, cmdline), error<error_code::missing_positional>);
616 REQUIRE(args.one == "one");
619 SECTION("two")
621 std::vector<std::string_view> cmdline = {"test", "one", "two"};
622 REQUIRE_NOTHROW(program(args, cmdline));
623 REQUIRE(args.one == "one");
624 REQUIRE(args.two == "two");
627 SECTION("three")
629 std::vector<std::string_view> cmdline = {"test", "one", "two", "three"};
630 REQUIRE_THROWS_AS(program(args, cmdline), error<error_code::superfluous_positional>);
631 REQUIRE(args.one == "one");
632 REQUIRE(args.two == "two");
635 SECTION("flag short")
637 std::vector<std::string_view> cmdline = {"test", "-f", "one", "two"};
638 REQUIRE_NOTHROW(program(args, cmdline));
639 REQUIRE(args.flag == true);
640 REQUIRE(args.one == "one");
641 REQUIRE(args.two == "two");
644 SECTION("flag long")
646 std::vector<std::string_view> cmdline = {"test", "--flag", "one", "two"};
647 REQUIRE_NOTHROW(program(args, cmdline));
648 REQUIRE(args.flag == true);
649 REQUIRE(args.one == "one");
650 REQUIRE(args.two == "two");
653 SECTION("value short")
655 std::vector<std::string_view> cmdline = {"test", "-v", "135", "one", "two"};
656 REQUIRE_NOTHROW(program(args, cmdline));
657 REQUIRE(args.value == 135);
658 REQUIRE(args.one == "one");
659 REQUIRE(args.two == "two");
662 SECTION("value short together")
664 std::vector<std::string_view> cmdline = {"test", "-v135", "one", "two"};
665 REQUIRE_NOTHROW(program(args, cmdline));
666 REQUIRE(args.value == 135);
667 REQUIRE(args.one == "one");
668 REQUIRE(args.two == "two");
671 SECTION("value short together")
673 std::vector<std::string_view> cmdline = {"test", "-v=135", "one", "two"};
674 REQUIRE_NOTHROW(program(args, cmdline));
675 REQUIRE(args.value == 135);
676 REQUIRE(args.one == "one");
677 REQUIRE(args.two == "two");
680 SECTION("value long")
682 std::vector<std::string_view> cmdline = {
683 "test", "--value", "135", "one", "two"
684 };
685 REQUIRE_NOTHROW(program(args, cmdline));
686 REQUIRE(args.value == 135);
687 REQUIRE(args.one == "one");
688 REQUIRE(args.two == "two");
691 SECTION("value long equal")
693 std::vector<std::string_view> cmdline = {
694 "test", "--value=135", "one", "two"
695 };
696 REQUIRE_NOTHROW(program(args, cmdline));
697 REQUIRE(args.value == 135);
698 REQUIRE(args.one == "one");
699 REQUIRE(args.two == "two");
702 SECTION("flag short terminal")
704 std::vector<std::string_view> cmdline = {"test", "--", "one", "-f", "two"};
705 REQUIRE_THROWS_AS(program(args, cmdline), error<error_code::superfluous_positional>);
706 REQUIRE(args.one == "one");
707 REQUIRE(args.two == "-f");
710 SECTION("invalid terminal")
712 std::vector<std::string_view> cmdline = {"test", "one", "--", "-f", "two"};
713 REQUIRE_THROWS_AS(program(args, cmdline), error<error_code::invalid_terminal>);
716 SECTION("flag short non-terminal")
718 std::vector<std::string_view> cmdline = {"test", "one", "-f", "two"};
719 REQUIRE_THROWS_AS(program(args, cmdline), error<error_code::invalid_positional>);
722 SECTION("flag long non-terminal")
724 std::vector<std::string_view> cmdline = {"test", "one", "--flag", "two"};
725 REQUIRE_THROWS_AS(program(args, cmdline), error<error_code::invalid_positional>);
729 TEST_CASE("multiple", "[poafloc/parser]")
731 struct arguments
733 bool flag1 = false;
734 bool flag2 = false;
735 std::string value1 = "default";
736 std::string value2 = "default";
737 } args;
739 auto program = parser<arguments> {
740 group {
741 "unnamed",
742 boolean {"f flag1", &arguments::flag1, "something"},
743 boolean {"F flag2", &arguments::flag2, "something"},
744 direct {"v value1", &arguments::value1, "NUM something"},
745 direct {"V value2", &arguments::value2, "NUM something"},
746 },
747 };
749 SECTION("valid")
751 std::vector<std::string_view> cmdline = {"test", "--flag1", "--flag2"};
752 REQUIRE_NOTHROW(program(args, cmdline));
753 REQUIRE(args.flag1 == true);
754 REQUIRE(args.flag2 == true);
755 REQUIRE(args.value1 == "default");
756 REQUIRE(args.value2 == "default");
759 SECTION("partial overlap")
761 std::vector<std::string_view> cmdline = {"test", "--fla", "--fla"};
762 REQUIRE_THROWS_AS(program(args, cmdline), error<error_code::unknown_option>);
763 REQUIRE(args.flag1 == false);
764 REQUIRE(args.flag2 == false);
765 REQUIRE(args.value1 == "default");
766 REQUIRE(args.value2 == "default");
769 SECTION("together")
771 std::vector<std::string_view> cmdline = {"test", "-fvF"};
772 REQUIRE_NOTHROW(program(args, cmdline));
773 REQUIRE(args.flag1 == true);
774 REQUIRE(args.flag2 == false);
775 REQUIRE(args.value1 == "F");
776 REQUIRE(args.value2 == "default");
779 SECTION("together equal")
781 std::vector<std::string_view> cmdline = {"test", "-fv=F"};
782 REQUIRE_NOTHROW(program(args, cmdline));
783 REQUIRE(args.flag1 == true);
784 REQUIRE(args.flag2 == false);
785 REQUIRE(args.value1 == "F");
786 REQUIRE(args.value2 == "default");
789 SECTION("together next")
791 std::vector<std::string_view> cmdline = {"test", "-fv", "F"};
792 REQUIRE_NOTHROW(program(args, cmdline));
793 REQUIRE(args.flag1 == true);
794 REQUIRE(args.flag2 == false);
795 REQUIRE(args.value1 == "F");
796 REQUIRE(args.value2 == "default");
800 // NOLINTEND(*complexity*)