1 /* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
2 file Copyright.txt or https://cmake.org/licensing for details. */
3
4 #include <initializer_list>
5 #include <iostream>
6 #include <string>
7 #include <vector>
8
9 #include <cm/string_view>
10 #include <cmext/string_view>
11
12 #include "cmArgumentParser.h"
13
14 namespace {
15
16 struct Result
17 {
18 bool Option1 = false;
19 bool Option2 = false;
20
21 std::string String1;
22 std::string String2;
23
24 std::vector<std::string> List1;
25 std::vector<std::string> List2;
26 std::vector<std::string> List3;
27
28 std::vector<std::vector<std::string>> Multi1;
29 std::vector<std::vector<std::string>> Multi2;
30 std::vector<std::vector<std::string>> Multi3;
31 };
32
33 std::initializer_list<cm::string_view> const args = {
34 /* clang-format off */
35 "OPTION_1", // option
36 "STRING_1", // string arg missing value
37 "STRING_2", "foo", "bar", // string arg + unparsed value
38 "LIST_1", // list arg missing values
39 "LIST_2", "foo", "bar", // list arg with 2 elems
40 "LIST_3", "bar", // list arg ...
41 "LIST_3", "foo", // ... with continuation
42 "MULTI_2", // multi list with 0 lists
43 "MULTI_3", "foo", "bar", // multi list with first list with two elems
44 "MULTI_3", "bar", "foo", // multi list with second list with two elems
45 /* clang-format on */
46 };
47
verifyResult(Result const & result,std::vector<std::string> const & unparsedArguments,std::vector<std::string> const & keywordsMissingValue)48 bool verifyResult(Result const& result,
49 std::vector<std::string> const& unparsedArguments,
50 std::vector<std::string> const& keywordsMissingValue)
51 {
52 static std::vector<std::string> const foobar = { "foo", "bar" };
53 static std::vector<std::string> const barfoo = { "bar", "foo" };
54 static std::vector<std::string> const missing = { "STRING_1", "LIST_1" };
55
56 #define ASSERT_TRUE(x) \
57 do { \
58 if (!(x)) { \
59 std::cout << "ASSERT_TRUE(" #x ") failed on line " << __LINE__ << "\n"; \
60 return false; \
61 } \
62 } while (false)
63
64 ASSERT_TRUE(result.Option1);
65 ASSERT_TRUE(!result.Option2);
66
67 ASSERT_TRUE(result.String1.empty());
68 ASSERT_TRUE(result.String2 == "foo");
69
70 ASSERT_TRUE(result.List1.empty());
71 ASSERT_TRUE(result.List2 == foobar);
72 ASSERT_TRUE(result.List3 == barfoo);
73
74 ASSERT_TRUE(result.Multi1.empty());
75 ASSERT_TRUE(result.Multi2.size() == 1);
76 ASSERT_TRUE(result.Multi2[0].empty());
77 ASSERT_TRUE(result.Multi3.size() == 2);
78 ASSERT_TRUE(result.Multi3[0] == foobar);
79 ASSERT_TRUE(result.Multi3[1] == barfoo);
80
81 ASSERT_TRUE(unparsedArguments.size() == 1);
82 ASSERT_TRUE(unparsedArguments[0] == "bar");
83 ASSERT_TRUE(keywordsMissingValue == missing);
84
85 return true;
86 }
87
testArgumentParserDynamic()88 bool testArgumentParserDynamic()
89 {
90 Result result;
91 std::vector<std::string> unparsedArguments;
92 std::vector<std::string> keywordsMissingValue;
93
94 cmArgumentParser<void>{}
95 .Bind("OPTION_1"_s, result.Option1)
96 .Bind("OPTION_2"_s, result.Option2)
97 .Bind("STRING_1"_s, result.String1)
98 .Bind("STRING_2"_s, result.String2)
99 .Bind("LIST_1"_s, result.List1)
100 .Bind("LIST_2"_s, result.List2)
101 .Bind("LIST_3"_s, result.List3)
102 .Bind("MULTI_1"_s, result.Multi1)
103 .Bind("MULTI_2"_s, result.Multi2)
104 .Bind("MULTI_3"_s, result.Multi3)
105 .Parse(args, &unparsedArguments, &keywordsMissingValue);
106
107 return verifyResult(result, unparsedArguments, keywordsMissingValue);
108 }
109
testArgumentParserStatic()110 bool testArgumentParserStatic()
111 {
112 static auto const parser = //
113 cmArgumentParser<Result>{}
114 .Bind("OPTION_1"_s, &Result::Option1)
115 .Bind("OPTION_2"_s, &Result::Option2)
116 .Bind("STRING_1"_s, &Result::String1)
117 .Bind("STRING_2"_s, &Result::String2)
118 .Bind("LIST_1"_s, &Result::List1)
119 .Bind("LIST_2"_s, &Result::List2)
120 .Bind("LIST_3"_s, &Result::List3)
121 .Bind("MULTI_1"_s, &Result::Multi1)
122 .Bind("MULTI_2"_s, &Result::Multi2)
123 .Bind("MULTI_3"_s, &Result::Multi3);
124
125 std::vector<std::string> unparsedArguments;
126 std::vector<std::string> keywordsMissingValue;
127 Result const result =
128 parser.Parse(args, &unparsedArguments, &keywordsMissingValue);
129
130 return verifyResult(result, unparsedArguments, keywordsMissingValue);
131 }
132
133 } // namespace
134
testArgumentParser(int,char * [])135 int testArgumentParser(int /*unused*/, char* /*unused*/ [])
136 {
137 if (!testArgumentParserDynamic()) {
138 std::cout << "While executing testArgumentParserDynamic().\n";
139 return -1;
140 }
141
142 if (!testArgumentParserStatic()) {
143 std::cout << "While executing testArgumentParserStatic().\n";
144 return -1;
145 }
146
147 return 0;
148 }
149