Flutter Engine
 
Loading...
Searching...
No Matches
command_line_unittest.cc
Go to the documentation of this file.
1// Copyright 2013 The Flutter Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
6
7#include <string_view>
8#include <utility>
9
10#include "flutter/fml/macros.h"
11#include "gtest/gtest.h"
12
13namespace fml {
14namespace {
15
16TEST(CommandLineTest, Basic) {
17 // Making this const verifies that the methods called are const.
18 const auto cl = CommandLineFromInitializerList(
19 {"my_program", "--flag1", "--flag2=value2", "arg1", "arg2", "arg3"});
20
21 EXPECT_TRUE(cl.has_argv0());
22 EXPECT_EQ("my_program", cl.argv0());
23
24 EXPECT_EQ(2u, cl.options().size());
25 EXPECT_EQ("flag1", cl.options()[0].name);
26 EXPECT_EQ(std::string(), cl.options()[0].value);
27 EXPECT_EQ("flag2", cl.options()[1].name);
28 EXPECT_EQ("value2", cl.options()[1].value);
29
30 EXPECT_EQ(3u, cl.positional_args().size());
31 EXPECT_EQ("arg1", cl.positional_args()[0]);
32 EXPECT_EQ("arg2", cl.positional_args()[1]);
33 EXPECT_EQ("arg3", cl.positional_args()[2]);
34
35 EXPECT_TRUE(cl.HasOption("flag1"));
36 EXPECT_TRUE(cl.HasOption("flag1", nullptr));
37 size_t index = static_cast<size_t>(-1);
38 EXPECT_TRUE(cl.HasOption("flag2", &index));
39 EXPECT_EQ(1u, index);
40 EXPECT_FALSE(cl.HasOption("flag3"));
41 EXPECT_FALSE(cl.HasOption("flag3", nullptr));
42
43 std::string value = "nonempty";
44 EXPECT_TRUE(cl.GetOptionValue("flag1", &value));
45 EXPECT_EQ(std::string(), value);
46 EXPECT_TRUE(cl.GetOptionValue("flag2", &value));
47 EXPECT_EQ("value2", value);
48 EXPECT_FALSE(cl.GetOptionValue("flag3", &value));
49
50 EXPECT_EQ(std::string(), cl.GetOptionValueWithDefault("flag1", "nope"));
51 EXPECT_EQ("value2", cl.GetOptionValueWithDefault("flag2", "nope"));
52 EXPECT_EQ("nope", cl.GetOptionValueWithDefault("flag3", "nope"));
53}
54
55TEST(CommandLineTest, DefaultConstructor) {
56 CommandLine cl;
57 EXPECT_FALSE(cl.has_argv0());
58 EXPECT_EQ(std::string(), cl.argv0());
59 EXPECT_EQ(std::vector<CommandLine::Option>(), cl.options());
60 EXPECT_EQ(std::vector<std::string>(), cl.positional_args());
61}
62
63TEST(CommandLineTest, ComponentConstructor) {
64 const std::string argv0 = "my_program";
65 const std::vector<CommandLine::Option> options = {
66 CommandLine::Option("flag", "value")};
67 const std::vector<std::string> positional_args = {"arg"};
68
69 CommandLine cl(argv0, options, positional_args);
70 EXPECT_TRUE(cl.has_argv0());
71 EXPECT_EQ(argv0, cl.argv0());
72 EXPECT_EQ(options, cl.options());
73 EXPECT_EQ(positional_args, cl.positional_args());
74 EXPECT_EQ("value", cl.GetOptionValueWithDefault("flag", "nope"));
75}
76
78 // This shows how one might process subcommands.
79 {
80 static std::vector<std::string> argv = {"my_program", "--flag1",
81 "--flag2", "subcommand",
82 "--subflag", "subarg"};
83 auto first = argv.cbegin();
84 auto last = argv.cend();
85 std::vector<std::string>::const_iterator sub_first;
86 auto cl =
88 EXPECT_TRUE(cl.has_argv0());
89 EXPECT_EQ(argv[0], cl.argv0());
90 std::vector<CommandLine::Option> expected_options = {
91 CommandLine::Option("flag1"), CommandLine::Option("flag2")};
92 EXPECT_EQ(expected_options, cl.options());
93 std::vector<std::string> expected_positional_args = {argv[3], argv[4],
94 argv[5]};
95 EXPECT_EQ(expected_positional_args, cl.positional_args());
96 EXPECT_TRUE(cl.HasOption("flag1", nullptr));
97 EXPECT_TRUE(cl.HasOption("flag2", nullptr));
98 EXPECT_FALSE(cl.HasOption("subflag", nullptr));
99
100 EXPECT_EQ(first + 3, sub_first);
101 auto sub_cl = CommandLineFromIterators(sub_first, last);
102 EXPECT_TRUE(sub_cl.has_argv0());
103 EXPECT_EQ(argv[3], sub_cl.argv0());
104 std::vector<CommandLine::Option> expected_sub_options = {
105 CommandLine::Option("subflag")};
106 EXPECT_EQ(expected_sub_options, sub_cl.options());
107 std::vector<std::string> expected_sub_positional_args = {argv[5]};
108 EXPECT_EQ(expected_sub_positional_args, sub_cl.positional_args());
109 EXPECT_FALSE(sub_cl.HasOption("flag1", nullptr));
110 EXPECT_FALSE(sub_cl.HasOption("flag2", nullptr));
111 EXPECT_TRUE(sub_cl.HasOption("subflag", nullptr));
112 }
113
114 // No positional argument.
115 {
116 static std::vector<std::string> argv = {"my_program", "--flag"};
117 std::vector<std::string>::const_iterator sub_first;
119 argv.cbegin(), argv.cend(), &sub_first);
120 EXPECT_EQ(argv.cend(), sub_first);
121 }
122
123 // Multiple positional arguments.
124 {
125 static std::vector<std::string> argv = {"my_program", "arg1", "arg2"};
126 std::vector<std::string>::const_iterator sub_first;
128 argv.cbegin(), argv.cend(), &sub_first);
129 EXPECT_EQ(argv.cbegin() + 1, sub_first);
130 }
131
132 // "--".
133 {
134 static std::vector<std::string> argv = {"my_program", "--", "--arg"};
135 std::vector<std::string>::const_iterator sub_first;
137 argv.cbegin(), argv.cend(), &sub_first);
138 EXPECT_EQ(argv.cbegin() + 2, sub_first);
139 }
140}
141
142TEST(CommandLineTest, CommmandLineFromIterators) {
143 {
144 // Note (here and below): The |const| ensures that the factory method can
145 // accept const iterators.
146 const std::vector<std::string> argv = {"my_program", "--flag=value", "arg"};
147
148 auto cl = CommandLineFromIterators(argv.begin(), argv.end());
149 EXPECT_TRUE(cl.has_argv0());
150 EXPECT_EQ(argv[0], cl.argv0());
151 std::vector<CommandLine::Option> expected_options = {
152 CommandLine::Option("flag", "value")};
153 EXPECT_EQ(expected_options, cl.options());
154 std::vector<std::string> expected_positional_args = {argv[2]};
155 EXPECT_EQ(expected_positional_args, cl.positional_args());
156 EXPECT_EQ("value", cl.GetOptionValueWithDefault("flag", "nope"));
157 }
158
159 // Can handle empty argv.
160 {
161 const std::vector<std::string> argv;
162
163 auto cl = CommandLineFromIterators(argv.begin(), argv.end());
164 EXPECT_FALSE(cl.has_argv0());
165 EXPECT_EQ(std::string(), cl.argv0());
166 EXPECT_EQ(std::vector<CommandLine::Option>(), cl.options());
167 EXPECT_EQ(std::vector<std::string>(), cl.positional_args());
168 }
169
170 // Can handle empty |argv[0]|.
171 {
172 const std::vector<std::string> argv = {""};
173
174 auto cl = CommandLineFromIterators(argv.begin(), argv.end());
175 EXPECT_TRUE(cl.has_argv0());
176 EXPECT_EQ(std::string(), cl.argv0());
177 EXPECT_EQ(std::vector<CommandLine::Option>(), cl.options());
178 EXPECT_EQ(std::vector<std::string>(), cl.positional_args());
179 }
180
181 // Can also take a vector of |const char*|s.
182 {
183 const std::vector<const char*> argv = {"my_program", "--flag=value", "arg"};
184
185 auto cl = CommandLineFromIterators(argv.begin(), argv.end());
186 EXPECT_TRUE(cl.has_argv0());
187 EXPECT_EQ(argv[0], cl.argv0());
188 std::vector<CommandLine::Option> expected_options = {
189 CommandLine::Option("flag", "value")};
190 EXPECT_EQ(expected_options, cl.options());
191 std::vector<std::string> expected_positional_args = {argv[2]};
192 EXPECT_EQ(expected_positional_args, cl.positional_args());
193 EXPECT_EQ("value", cl.GetOptionValueWithDefault("flag", "nope"));
194 }
195
196 // Or a plain old array.
197 {
198 static const char* const argv[] = {"my_program", "--flag=value", "arg"};
199
200 auto cl = CommandLineFromIterators(argv, argv + std::size(argv));
201 EXPECT_TRUE(cl.has_argv0());
202 EXPECT_EQ(argv[0], cl.argv0());
203 std::vector<CommandLine::Option> expected_options = {
204 CommandLine::Option("flag", "value")};
205 EXPECT_EQ(expected_options, cl.options());
206 std::vector<std::string> expected_positional_args = {argv[2]};
207 EXPECT_EQ(expected_positional_args, cl.positional_args());
208 EXPECT_EQ("value", cl.GetOptionValueWithDefault("flag", "nope"));
209 }
210}
211
212TEST(CommandLineTest, CommandLineFromArgcArgv) {
213 static const char* const argv[] = {"my_program", "--flag=value", "arg"};
214 const int argc = static_cast<int>(std::size(argv));
215
216 auto cl = CommandLineFromArgcArgv(argc, argv);
217 EXPECT_TRUE(cl.has_argv0());
218 EXPECT_EQ(argv[0], cl.argv0());
219 std::vector<CommandLine::Option> expected_options = {
220 CommandLine::Option("flag", "value")};
221 EXPECT_EQ(expected_options, cl.options());
222 std::vector<std::string> expected_positional_args = {argv[2]};
223 EXPECT_EQ(expected_positional_args, cl.positional_args());
224 EXPECT_EQ("value", cl.GetOptionValueWithDefault("flag", "nope"));
225}
226
227TEST(CommandLineTest, CommandLineFromInitializerList) {
228 {
229 std::initializer_list<const char*> il = {"my_program", "--flag=value",
230 "arg"};
231 auto cl = CommandLineFromInitializerList(il);
232 EXPECT_TRUE(cl.has_argv0());
233 EXPECT_EQ("my_program", cl.argv0());
234 std::vector<CommandLine::Option> expected_options = {
235 CommandLine::Option("flag", "value")};
236 EXPECT_EQ(expected_options, cl.options());
237 std::vector<std::string> expected_positional_args = {"arg"};
238 EXPECT_EQ(expected_positional_args, cl.positional_args());
239 EXPECT_EQ("value", cl.GetOptionValueWithDefault("flag", "nope"));
240 }
241
242 {
243 std::initializer_list<std::string> il = {"my_program", "--flag=value",
244 "arg"};
245 auto cl = CommandLineFromInitializerList(il);
246 EXPECT_TRUE(cl.has_argv0());
247 EXPECT_EQ("my_program", cl.argv0());
248 std::vector<CommandLine::Option> expected_options = {
249 CommandLine::Option("flag", "value")};
250 EXPECT_EQ(expected_options, cl.options());
251 std::vector<std::string> expected_positional_args = {"arg"};
252 EXPECT_EQ(expected_positional_args, cl.positional_args());
253 EXPECT_EQ("value", cl.GetOptionValueWithDefault("flag", "nope"));
254 }
255}
256
257TEST(CommandLineTest, OddArguments) {
258 {
259 // Except for "arg", these are all options.
261 {"my_program", "--=", "--=foo", "--bar=", "--==", "--===", "--==x",
262 "arg"});
263 EXPECT_TRUE(cl.has_argv0());
264 EXPECT_EQ("my_program", cl.argv0());
265 std::vector<CommandLine::Option> expected_options = {
266 CommandLine::Option("="), CommandLine::Option("=foo"),
267 CommandLine::Option("bar"), CommandLine::Option("="),
268 CommandLine::Option("=", "="), CommandLine::Option("=", "x")};
269 EXPECT_EQ(expected_options, cl.options());
270 std::vector<std::string> expected_positional_args = {"arg"};
271 EXPECT_EQ(expected_positional_args, cl.positional_args());
272 }
273
274 // "-x" is an argument, not an options.
275 {
276 auto cl = CommandLineFromInitializerList({"", "-x"});
277 EXPECT_TRUE(cl.has_argv0());
278 EXPECT_EQ(std::string(), cl.argv0());
279 EXPECT_EQ(std::vector<CommandLine::Option>(), cl.options());
280 std::vector<std::string> expected_positional_args = {"-x"};
281 EXPECT_EQ(expected_positional_args, cl.positional_args());
282 }
283
284 // Ditto for "-".
285 {
286 auto cl = CommandLineFromInitializerList({"", "-"});
287 EXPECT_TRUE(cl.has_argv0());
288 EXPECT_EQ(std::string(), cl.argv0());
289 EXPECT_EQ(std::vector<CommandLine::Option>(), cl.options());
290 std::vector<std::string> expected_positional_args = {"-"};
291 EXPECT_EQ(expected_positional_args, cl.positional_args());
292 }
293
294 // "--" terminates option processing, but isn't an argument in the first
295 // occurrence.
296 {
298 {"", "--flag=value", "--", "--not-a-flag", "arg", "--"});
299 EXPECT_TRUE(cl.has_argv0());
300 EXPECT_EQ(std::string(), cl.argv0());
301 std::vector<CommandLine::Option> expected_options = {
302 CommandLine::Option("flag", "value")};
303 std::vector<std::string> expected_positional_args = {"--not-a-flag", "arg",
304 "--"};
305 EXPECT_EQ(expected_positional_args, cl.positional_args());
306 }
307}
308
309TEST(CommandLineTest, MultipleOccurrencesOfOption) {
311 {"my_program", "--flag1=value1", "--flag2=value2", "--flag1=value3"});
312 std::vector<CommandLine::Option> expected_options = {
313 CommandLine::Option("flag1", "value1"),
314 CommandLine::Option("flag2", "value2"),
315 CommandLine::Option("flag1", "value3")};
316 EXPECT_EQ("value3", cl.GetOptionValueWithDefault("flag1", "nope"));
317 EXPECT_EQ("value2", cl.GetOptionValueWithDefault("flag2", "nope"));
318 std::vector<std::string_view> values = cl.GetOptionValues("flag1");
319 ASSERT_EQ(2u, values.size());
320 EXPECT_EQ("value1", values[0]);
321 EXPECT_EQ("value3", values[1]);
322}
323
324// |cl1| and |cl2| should be not equal.
325void ExpectNotEqual(const char* message,
326 std::initializer_list<std::string> c1,
327 std::initializer_list<std::string> c2) {
328 SCOPED_TRACE(message);
329
330 const auto cl1 = CommandLineFromInitializerList(c1);
331 const auto cl2 = CommandLineFromInitializerList(c2);
332
333 // These are tautological.
334 EXPECT_TRUE(cl1 == cl1);
335 EXPECT_FALSE(cl1 != cl1);
336 EXPECT_TRUE(cl2 == cl2);
337 EXPECT_FALSE(cl2 != cl2);
338
339 // These rely on |cl1| not being equal to |cl2|.
340 EXPECT_FALSE(cl1 == cl2);
341 EXPECT_TRUE(cl1 != cl2);
342 EXPECT_FALSE(cl2 == cl1);
343 EXPECT_TRUE(cl2 != cl1);
344}
345
346void ExpectEqual(const char* message,
347 std::initializer_list<std::string> c1,
348 std::initializer_list<std::string> c2) {
349 SCOPED_TRACE(message);
350
351 const auto cl1 = CommandLineFromInitializerList(c1);
352 const auto cl2 = CommandLineFromInitializerList(c2);
353
354 // These are tautological.
355 EXPECT_TRUE(cl1 == cl1);
356 EXPECT_FALSE(cl1 != cl1);
357 EXPECT_TRUE(cl2 == cl2);
358 EXPECT_FALSE(cl2 != cl2);
359
360 // These rely on |cl1| being equal to |cl2|.
361 EXPECT_TRUE(cl1 == cl2);
362 EXPECT_FALSE(cl1 != cl2);
363 EXPECT_TRUE(cl2 == cl1);
364 EXPECT_FALSE(cl2 != cl1);
365}
366
367TEST(CommandLineTest, ComparisonOperators) {
368 ExpectNotEqual("1", {}, {""});
369 ExpectNotEqual("2", {"abc"}, {"def"});
370 ExpectNotEqual("3", {"abc", "--flag"}, {"abc"});
371 ExpectNotEqual("4", {"abc", "--flag1"}, {"abc", "--flag2"});
372 ExpectNotEqual("5", {"abc", "--flag1", "--flag2"}, {"abc", "--flag1"});
373 ExpectNotEqual("6", {"abc", "arg"}, {"abc"});
374 ExpectNotEqual("7", {"abc", "arg1"}, {"abc", "arg2"});
375 ExpectNotEqual("8", {"abc", "arg1", "arg2"}, {"abc", "arg1"});
376 ExpectNotEqual("9", {"abc", "--flag", "arg1"}, {"abc", "--flag", "arg2"});
377
378 // However, the presence of an unnecessary "--" shouldn't affect what's
379 // constructed.
380 ExpectEqual("10", {"abc", "--flag", "arg"}, {"abc", "--flag", "--", "arg"});
381}
382
383TEST(CommandLineTest, MoveAndCopy) {
384 const auto cl = CommandLineFromInitializerList(
385 {"my_program", "--flag1=value1", "--flag2", "arg"});
386
387 // Copy constructor.
388 CommandLine cl2(cl);
389 EXPECT_EQ(cl, cl2);
390 // Check that |option_index_| gets copied too.
391 EXPECT_EQ("value1", cl2.GetOptionValueWithDefault("flag1", "nope"));
392
393 // Move constructor.
394 CommandLine cl3(std::move(cl2));
395 EXPECT_EQ(cl, cl3);
396 EXPECT_EQ("value1", cl3.GetOptionValueWithDefault("flag1", "nope"));
397
398 // Copy assignment.
399 CommandLine cl4;
400 EXPECT_NE(cl, cl4);
401 cl4 = cl;
402 EXPECT_EQ(cl, cl4);
403 EXPECT_EQ("value1", cl4.GetOptionValueWithDefault("flag1", "nope"));
404
405 // Move assignment.
406 CommandLine cl5;
407 EXPECT_NE(cl, cl5);
408 cl5 = std::move(cl4);
409 EXPECT_EQ(cl, cl5);
410 EXPECT_EQ("value1", cl5.GetOptionValueWithDefault("flag1", "nope"));
411}
412
413void ToArgvHelper(const char* message, std::initializer_list<std::string> c) {
414 SCOPED_TRACE(message);
415 std::vector<std::string> argv = c;
417 EXPECT_EQ(argv, CommandLineToArgv(cl));
418}
419
420TEST(CommandLineTest, CommandLineToArgv) {
421 ToArgvHelper("1", {});
422 ToArgvHelper("2", {""});
423 ToArgvHelper("3", {"my_program"});
424 ToArgvHelper("4", {"my_program", "--flag"});
425 ToArgvHelper("5", {"my_program", "--flag1", "--flag2=value"});
426 ToArgvHelper("6", {"my_program", "arg"});
427 ToArgvHelper("7", {"my_program", "arg1", "arg2"});
428 ToArgvHelper("8", {"my_program", "--flag1", "--flag2=value", "arg1", "arg2"});
429 ToArgvHelper("9", {"my_program", "--flag", "--", "--not-a-flag"});
430 ToArgvHelper("10", {"my_program", "--flag", "arg", "--"});
431
432 // However, |CommandLineToArgv()| will "strip" an unneeded "--".
433 {
434 auto cl = CommandLineFromInitializerList({"my_program", "--"});
435 std::vector<std::string> argv = {"my_program"};
436 EXPECT_EQ(argv, CommandLineToArgv(cl));
437 }
438 {
439 auto cl =
440 CommandLineFromInitializerList({"my_program", "--flag", "--", "arg"});
441 std::vector<std::string> argv = {"my_program", "--flag", "arg"};
442 EXPECT_EQ(argv, CommandLineToArgv(cl));
443 }
444}
445
446} // namespace
447} // namespace fml
int32_t value
G_BEGIN_DECLS GBytes * message
char ** argv
Definition library.h:9
CommandLine CommandLineFromArgcArgv(int argc, const char *const *argv)
CommandLine CommandLineFromInitializerList(std::initializer_list< StringType > argv)
std::vector< std::string > CommandLineToArgv(const CommandLine &command_line)
CommandLine CommandLineFromIterators(InputIterator first, InputIterator last)
CommandLine CommandLineFromIteratorsFindFirstPositionalArg(InputIterator first, InputIterator last, InputIterator *first_positional_arg)
TEST(MallocMapping, EmptyContructor)