965690c37e4205872853de3909d949c64d44a03a
[platform/upstream/cmake.git] / Tests / CMakeLib / testArgumentParser.cxx
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
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
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
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
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 }