1// Copyright 2014 The Chromium OS 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
5#include <cstdint>
6#include <cstdio>
7#include <sysexits.h>
8
9#include <base/command_line.h>
10#include <base/macros.h>
11#include <brillo/flag_helper.h>
12
13#include <gtest/gtest.h>
14
15namespace brillo {
16
17class FlagHelperTest : public ::testing::Test {
18 public:
19  FlagHelperTest() {}
20  ~FlagHelperTest() override { brillo::FlagHelper::ResetForTesting(); }
21  static void SetUpTestCase() { base::CommandLine::Init(0, nullptr); }
22};
23
24// Test that the DEFINE_xxxx macros can create the respective variables
25// correctly with the default value.
26TEST_F(FlagHelperTest, Defaults) {
27  DEFINE_bool(bool1, true, "Test bool flag");
28  DEFINE_bool(bool2, false, "Test bool flag");
29  DEFINE_int32(int32_1, INT32_MIN, "Test int32 flag");
30  DEFINE_int32(int32_2, 0, "Test int32 flag");
31  DEFINE_int32(int32_3, INT32_MAX, "Test int32 flag");
32  DEFINE_int64(int64_1, INT64_MIN, "Test int64 flag");
33  DEFINE_int64(int64_2, 0, "Test int64 flag");
34  DEFINE_int64(int64_3, INT64_MAX, "Test int64 flag");
35  DEFINE_uint64(uint64_1, 0, "Test uint64 flag");
36  DEFINE_uint64(uint64_2, UINT_LEAST64_MAX, "Test uint64 flag");
37  DEFINE_double(double_1, -100.5, "Test double flag");
38  DEFINE_double(double_2, 0, "Test double flag");
39  DEFINE_double(double_3, 100.5, "Test double flag");
40  DEFINE_string(string_1, "", "Test string flag");
41  DEFINE_string(string_2, "value", "Test string flag");
42
43  const char* argv[] = {"test_program"};
44  base::CommandLine command_line(arraysize(argv), argv);
45
46  brillo::FlagHelper::GetInstance()->set_command_line_for_testing(
47      &command_line);
48  brillo::FlagHelper::Init(arraysize(argv), argv, "TestDefaultTrue");
49
50  EXPECT_TRUE(FLAGS_bool1);
51  EXPECT_FALSE(FLAGS_bool2);
52  EXPECT_EQ(FLAGS_int32_1, INT32_MIN);
53  EXPECT_EQ(FLAGS_int32_2, 0);
54  EXPECT_EQ(FLAGS_int32_3, INT32_MAX);
55  EXPECT_EQ(FLAGS_int64_1, INT64_MIN);
56  EXPECT_EQ(FLAGS_int64_2, 0);
57  EXPECT_EQ(FLAGS_int64_3, INT64_MAX);
58  EXPECT_EQ(FLAGS_uint64_1, 0);
59  EXPECT_EQ(FLAGS_uint64_2, UINT_LEAST64_MAX);
60  EXPECT_DOUBLE_EQ(FLAGS_double_1, -100.5);
61  EXPECT_DOUBLE_EQ(FLAGS_double_2, 0);
62  EXPECT_DOUBLE_EQ(FLAGS_double_3, 100.5);
63  EXPECT_STREQ(FLAGS_string_1.c_str(), "");
64  EXPECT_STREQ(FLAGS_string_2.c_str(), "value");
65}
66
67// Test that command line flag values are parsed and update the flag
68// variable values correctly when using double '--' flags
69TEST_F(FlagHelperTest, SetValueDoubleDash) {
70  DEFINE_bool(bool1, false, "Test bool flag");
71  DEFINE_bool(bool2, true, "Test bool flag");
72  DEFINE_bool(bool3, false, "Test bool flag");
73  DEFINE_bool(bool4, true, "Test bool flag");
74  DEFINE_int32(int32_1, 1, "Test int32 flag");
75  DEFINE_int32(int32_2, 1, "Test int32 flag");
76  DEFINE_int32(int32_3, 1, "Test int32 flag");
77  DEFINE_int64(int64_1, 1, "Test int64 flag");
78  DEFINE_int64(int64_2, 1, "Test int64 flag");
79  DEFINE_int64(int64_3, 1, "Test int64 flag");
80  DEFINE_uint64(uint64_1, 1, "Test uint64 flag");
81  DEFINE_uint64(uint64_2, 1, "Test uint64 flag");
82  DEFINE_double(double_1, 1, "Test double flag");
83  DEFINE_double(double_2, 1, "Test double flag");
84  DEFINE_double(double_3, 1, "Test double flag");
85  DEFINE_string(string_1, "default", "Test string flag");
86  DEFINE_string(string_2, "default", "Test string flag");
87
88  const char* argv[] = {"test_program",
89                        "--bool1",
90                        "--nobool2",
91                        "--bool3=true",
92                        "--bool4=false",
93                        "--int32_1=-2147483648",
94                        "--int32_2=0",
95                        "--int32_3=2147483647",
96                        "--int64_1=-9223372036854775808",
97                        "--int64_2=0",
98                        "--int64_3=9223372036854775807",
99                        "--uint64_1=0",
100                        "--uint64_2=18446744073709551615",
101                        "--double_1=-100.5",
102                        "--double_2=0",
103                        "--double_3=100.5",
104                        "--string_1=",
105                        "--string_2=value"};
106  base::CommandLine command_line(arraysize(argv), argv);
107
108  brillo::FlagHelper::GetInstance()->set_command_line_for_testing(
109      &command_line);
110  brillo::FlagHelper::Init(arraysize(argv), argv, "TestDefaultTrue");
111
112  EXPECT_TRUE(FLAGS_bool1);
113  EXPECT_FALSE(FLAGS_bool2);
114  EXPECT_TRUE(FLAGS_bool3);
115  EXPECT_FALSE(FLAGS_bool4);
116  EXPECT_EQ(FLAGS_int32_1, INT32_MIN);
117  EXPECT_EQ(FLAGS_int32_2, 0);
118  EXPECT_EQ(FLAGS_int32_3, INT32_MAX);
119  EXPECT_EQ(FLAGS_int64_1, INT64_MIN);
120  EXPECT_EQ(FLAGS_int64_2, 0);
121  EXPECT_EQ(FLAGS_int64_3, INT64_MAX);
122  EXPECT_EQ(FLAGS_uint64_1, 0);
123  EXPECT_EQ(FLAGS_uint64_2, UINT_LEAST64_MAX);
124  EXPECT_DOUBLE_EQ(FLAGS_double_1, -100.5);
125  EXPECT_DOUBLE_EQ(FLAGS_double_2, 0);
126  EXPECT_DOUBLE_EQ(FLAGS_double_3, 100.5);
127  EXPECT_STREQ(FLAGS_string_1.c_str(), "");
128  EXPECT_STREQ(FLAGS_string_2.c_str(), "value");
129}
130
131// Test that command line flag values are parsed and update the flag
132// variable values correctly when using single '-' flags
133TEST_F(FlagHelperTest, SetValueSingleDash) {
134  DEFINE_bool(bool1, false, "Test bool flag");
135  DEFINE_bool(bool2, true, "Test bool flag");
136  DEFINE_int32(int32_1, 1, "Test int32 flag");
137  DEFINE_int32(int32_2, 1, "Test int32 flag");
138  DEFINE_int32(int32_3, 1, "Test int32 flag");
139  DEFINE_int64(int64_1, 1, "Test int64 flag");
140  DEFINE_int64(int64_2, 1, "Test int64 flag");
141  DEFINE_int64(int64_3, 1, "Test int64 flag");
142  DEFINE_uint64(uint64_1, 1, "Test uint64 flag");
143  DEFINE_uint64(uint64_2, 1, "Test uint64 flag");
144  DEFINE_double(double_1, 1, "Test double flag");
145  DEFINE_double(double_2, 1, "Test double flag");
146  DEFINE_double(double_3, 1, "Test double flag");
147  DEFINE_string(string_1, "default", "Test string flag");
148  DEFINE_string(string_2, "default", "Test string flag");
149
150  const char* argv[] = {"test_program",
151                        "-bool1",
152                        "-nobool2",
153                        "-int32_1=-2147483648",
154                        "-int32_2=0",
155                        "-int32_3=2147483647",
156                        "-int64_1=-9223372036854775808",
157                        "-int64_2=0",
158                        "-int64_3=9223372036854775807",
159                        "-uint64_1=0",
160                        "-uint64_2=18446744073709551615",
161                        "-double_1=-100.5",
162                        "-double_2=0",
163                        "-double_3=100.5",
164                        "-string_1=",
165                        "-string_2=value"};
166  base::CommandLine command_line(arraysize(argv), argv);
167
168  brillo::FlagHelper::GetInstance()->set_command_line_for_testing(
169      &command_line);
170  brillo::FlagHelper::Init(arraysize(argv), argv, "TestDefaultTrue");
171
172  EXPECT_TRUE(FLAGS_bool1);
173  EXPECT_FALSE(FLAGS_bool2);
174  EXPECT_EQ(FLAGS_int32_1, INT32_MIN);
175  EXPECT_EQ(FLAGS_int32_2, 0);
176  EXPECT_EQ(FLAGS_int32_3, INT32_MAX);
177  EXPECT_EQ(FLAGS_int64_1, INT64_MIN);
178  EXPECT_EQ(FLAGS_int64_2, 0);
179  EXPECT_EQ(FLAGS_int64_3, INT64_MAX);
180  EXPECT_EQ(FLAGS_uint64_1, 0);
181  EXPECT_EQ(FLAGS_uint64_2, UINT_LEAST64_MAX);
182  EXPECT_DOUBLE_EQ(FLAGS_double_1, -100.5);
183  EXPECT_DOUBLE_EQ(FLAGS_double_2, 0);
184  EXPECT_DOUBLE_EQ(FLAGS_double_3, 100.5);
185  EXPECT_STREQ(FLAGS_string_1.c_str(), "");
186  EXPECT_STREQ(FLAGS_string_2.c_str(), "value");
187}
188
189// Test that a duplicated flag on the command line picks up the last
190// value set.
191TEST_F(FlagHelperTest, DuplicateSetValue) {
192  DEFINE_int32(int32_1, 0, "Test in32 flag");
193
194  const char* argv[] = {"test_program", "--int32_1=5", "--int32_1=10"};
195  base::CommandLine command_line(arraysize(argv), argv);
196
197  brillo::FlagHelper::GetInstance()->set_command_line_for_testing(
198      &command_line);
199  brillo::FlagHelper::Init(arraysize(argv), argv, "TestDuplicateSetvalue");
200
201  EXPECT_EQ(FLAGS_int32_1, 10);
202}
203
204// Test that flags set after the -- marker are not parsed as command line flags
205TEST_F(FlagHelperTest, FlagTerminator) {
206  DEFINE_int32(int32_1, 0, "Test int32 flag");
207
208  const char* argv[] = {"test_program", "--int32_1=5", "--", "--int32_1=10"};
209  base::CommandLine command_line(arraysize(argv), argv);
210
211  brillo::FlagHelper::GetInstance()->set_command_line_for_testing(
212      &command_line);
213  brillo::FlagHelper::Init(arraysize(argv), argv, "TestFlagTerminator");
214
215  EXPECT_EQ(FLAGS_int32_1, 5);
216}
217
218// Test that help messages are generated correctly when the --help flag
219// is passed to the program.
220TEST_F(FlagHelperTest, HelpMessage) {
221  DEFINE_bool(bool_1, true, "Test bool flag");
222  DEFINE_int32(int_1, 0, "Test int flag");
223  DEFINE_int64(int64_1, 0, "Test int64 flag");
224  DEFINE_uint64(uint64_1, 0, "Test uint64 flag");
225  DEFINE_double(double_1, 0, "Test double flag");
226  DEFINE_string(string_1, "", "Test string flag");
227
228  const char* argv[] = {"test_program", "--int_1=value", "--help"};
229  base::CommandLine command_line(arraysize(argv), argv);
230
231  brillo::FlagHelper::GetInstance()->set_command_line_for_testing(
232      &command_line);
233
234  FILE* orig = stdout;
235  stdout = stderr;
236
237  ASSERT_EXIT(
238      brillo::FlagHelper::Init(arraysize(argv), argv, "TestHelpMessage"),
239      ::testing::ExitedWithCode(EX_OK),
240      "TestHelpMessage\n\n"
241      "  --bool_1  \\(Test bool flag\\)  type: bool  default: true\n"
242      "  --double_1  \\(Test double flag\\)  type: double  default: 0\n"
243      "  --help  \\(Show this help message\\)  type: bool  default: false\n"
244      "  --int64_1  \\(Test int64 flag\\)  type: int64  default: 0\n"
245      "  --int_1  \\(Test int flag\\)  type: int  default: 0\n"
246      "  --string_1  \\(Test string flag\\)  type: string  default: \"\"\n"
247      "  --uint64_1  \\(Test uint64 flag\\)  type: uint64  default: 0\n");
248
249  stdout = orig;
250}
251
252// Test that passing in unknown command line flags causes the program
253// to exit with EX_USAGE error code and corresponding error message.
254TEST_F(FlagHelperTest, UnknownFlag) {
255  const char* argv[] = {"test_program", "--flag=value"};
256  base::CommandLine command_line(arraysize(argv), argv);
257
258  brillo::FlagHelper::GetInstance()->set_command_line_for_testing(
259      &command_line);
260
261  FILE* orig = stdout;
262  stdout = stderr;
263
264  ASSERT_EXIT(brillo::FlagHelper::Init(arraysize(argv), argv, "TestIntExit"),
265              ::testing::ExitedWithCode(EX_USAGE),
266              "ERROR: unknown command line flag 'flag'");
267
268  stdout = orig;
269}
270
271// Test that when passing an incorrect/unparsable type to a command line flag,
272// the program exits with code EX_DATAERR and outputs a corresponding message.
273TEST_F(FlagHelperTest, BoolParseError) {
274  DEFINE_bool(bool_1, 0, "Test bool flag");
275
276  const char* argv[] = {"test_program", "--bool_1=value"};
277  base::CommandLine command_line(arraysize(argv), argv);
278
279  brillo::FlagHelper::GetInstance()->set_command_line_for_testing(
280      &command_line);
281
282  FILE* orig = stdout;
283  stdout = stderr;
284
285  ASSERT_EXIT(
286      brillo::FlagHelper::Init(arraysize(argv), argv, "TestBoolParseError"),
287      ::testing::ExitedWithCode(EX_DATAERR),
288      "ERROR: illegal value 'value' specified for bool flag 'bool_1'");
289
290  stdout = orig;
291}
292
293// Test that when passing an incorrect/unparsable type to a command line flag,
294// the program exits with code EX_DATAERR and outputs a corresponding message.
295TEST_F(FlagHelperTest, Int32ParseError) {
296  DEFINE_int32(int_1, 0, "Test int flag");
297
298  const char* argv[] = {"test_program", "--int_1=value"};
299  base::CommandLine command_line(arraysize(argv), argv);
300
301  brillo::FlagHelper::GetInstance()->set_command_line_for_testing(
302      &command_line);
303
304  FILE* orig = stdout;
305  stdout = stderr;
306
307  ASSERT_EXIT(brillo::FlagHelper::Init(arraysize(argv),
308                                       argv,
309                                       "TestInt32ParseError"),
310              ::testing::ExitedWithCode(EX_DATAERR),
311              "ERROR: illegal value 'value' specified for int flag 'int_1'");
312
313  stdout = orig;
314}
315
316// Test that when passing an incorrect/unparsable type to a command line flag,
317// the program exits with code EX_DATAERR and outputs a corresponding message.
318TEST_F(FlagHelperTest, Int64ParseError) {
319  DEFINE_int64(int64_1, 0, "Test int64 flag");
320
321  const char* argv[] = {"test_program", "--int64_1=value"};
322  base::CommandLine command_line(arraysize(argv), argv);
323
324  brillo::FlagHelper::GetInstance()->set_command_line_for_testing(
325      &command_line);
326
327  FILE* orig = stdout;
328  stdout = stderr;
329
330  ASSERT_EXIT(
331      brillo::FlagHelper::Init(arraysize(argv), argv, "TestInt64ParseError"),
332      ::testing::ExitedWithCode(EX_DATAERR),
333      "ERROR: illegal value 'value' specified for int64 flag "
334      "'int64_1'");
335
336  stdout = orig;
337}
338
339// Test that when passing an incorrect/unparsable type to a command line flag,
340// the program exits with code EX_DATAERR and outputs a corresponding message.
341TEST_F(FlagHelperTest, UInt64ParseError) {
342  DEFINE_uint64(uint64_1, 0, "Test uint64 flag");
343
344  const char* argv[] = {"test_program", "--uint64_1=value"};
345  base::CommandLine command_line(arraysize(argv), argv);
346
347  brillo::FlagHelper::GetInstance()->set_command_line_for_testing(
348      &command_line);
349
350  FILE* orig = stdout;
351  stdout = stderr;
352
353  ASSERT_EXIT(
354      brillo::FlagHelper::Init(arraysize(argv), argv, "TestUInt64ParseError"),
355      ::testing::ExitedWithCode(EX_DATAERR),
356      "ERROR: illegal value 'value' specified for uint64 flag "
357      "'uint64_1'");
358
359  stdout = orig;
360}
361
362}  // namespace brillo
363