blob: a652042c8aae457029d7ff7171435d7e9c4bff9a [file] [log] [blame]
Austin Schuh36244a12019-09-21 17:52:38 -07001//
2// Copyright 2019 The Abseil Authors.
3//
4// Licensed under the Apache License, Version 2.0 (the "License");
5// you may not use this file except in compliance with the License.
6// You may obtain a copy of the License at
7//
8// https://www.apache.org/licenses/LICENSE-2.0
9//
10// Unless required by applicable law or agreed to in writing, software
11// distributed under the License is distributed on an "AS IS" BASIS,
12// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13// See the License for the specific language governing permissions and
14// limitations under the License.
15
16#include "absl/flags/flag.h"
17
18#include <algorithm>
19#include <string>
20
21#include "gtest/gtest.h"
22#include "absl/flags/usage_config.h"
23#include "absl/strings/match.h"
24#include "absl/strings/numbers.h"
25#include "absl/strings/str_cat.h"
26#include "absl/strings/str_split.h"
27
28ABSL_DECLARE_FLAG(int64_t, mistyped_int_flag);
29ABSL_DECLARE_FLAG(std::vector<std::string>, mistyped_string_flag);
30
31namespace {
32
33namespace flags = absl::flags_internal;
34
35std::string TestHelpMsg() { return "help"; }
36template <typename T>
37void* TestMakeDflt() {
38 return new T{};
39}
40void TestCallback() {}
41
42template <typename T>
43bool TestConstructionFor() {
44 constexpr flags::Flag<T> f1("f1", &TestHelpMsg, "file",
45 &absl::flags_internal::FlagMarshallingOps<T>,
46 &TestMakeDflt<T>);
47 EXPECT_EQ(f1.Name(), "f1");
48 EXPECT_EQ(f1.Help(), "help");
49 EXPECT_EQ(f1.Filename(), "file");
50
51 ABSL_CONST_INIT static flags::Flag<T> f2(
52 "f2", &TestHelpMsg, "file", &absl::flags_internal::FlagMarshallingOps<T>,
53 &TestMakeDflt<T>);
54 flags::FlagRegistrar<T, false>(&f2).OnUpdate(TestCallback);
55
56 EXPECT_EQ(f2.Name(), "f2");
57 EXPECT_EQ(f2.Help(), "help");
58 EXPECT_EQ(f2.Filename(), "file");
59
60 return true;
61}
62
63struct UDT {
64 UDT() = default;
65 UDT(const UDT&) = default;
66};
67bool AbslParseFlag(absl::string_view, UDT*, std::string*) { return true; }
68std::string AbslUnparseFlag(const UDT&) { return ""; }
69
70class FlagTest : public testing::Test {
71 protected:
72 static void SetUpTestSuite() {
73 // Install a function to normalize filenames before this test is run.
74 absl::FlagsUsageConfig default_config;
75 default_config.normalize_filename = &FlagTest::NormalizeFileName;
76 absl::SetFlagsUsageConfig(default_config);
77 }
78
79 private:
80 static std::string NormalizeFileName(absl::string_view fname) {
81#ifdef _WIN32
82 std::string normalized(fname);
83 std::replace(normalized.begin(), normalized.end(), '\\', '/');
84 fname = normalized;
85#endif
86 return std::string(fname);
87 }
88};
89
90TEST_F(FlagTest, TestConstruction) {
91 TestConstructionFor<bool>();
92 TestConstructionFor<int16_t>();
93 TestConstructionFor<uint16_t>();
94 TestConstructionFor<int32_t>();
95 TestConstructionFor<uint32_t>();
96 TestConstructionFor<int64_t>();
97 TestConstructionFor<uint64_t>();
98 TestConstructionFor<double>();
99 TestConstructionFor<float>();
100 TestConstructionFor<std::string>();
101
102 TestConstructionFor<UDT>();
103}
104
105// --------------------------------------------------------------------
106
107} // namespace
108
109ABSL_DECLARE_FLAG(bool, test_flag_01);
110ABSL_DECLARE_FLAG(int, test_flag_02);
111ABSL_DECLARE_FLAG(int16_t, test_flag_03);
112ABSL_DECLARE_FLAG(uint16_t, test_flag_04);
113ABSL_DECLARE_FLAG(int32_t, test_flag_05);
114ABSL_DECLARE_FLAG(uint32_t, test_flag_06);
115ABSL_DECLARE_FLAG(int64_t, test_flag_07);
116ABSL_DECLARE_FLAG(uint64_t, test_flag_08);
117ABSL_DECLARE_FLAG(double, test_flag_09);
118ABSL_DECLARE_FLAG(float, test_flag_10);
119ABSL_DECLARE_FLAG(std::string, test_flag_11);
120
121namespace {
122
123#if !ABSL_FLAGS_STRIP_NAMES
124
125TEST_F(FlagTest, TestFlagDeclaration) {
126 // test that we can access flag objects.
127 EXPECT_EQ(FLAGS_test_flag_01.Name(), "test_flag_01");
128 EXPECT_EQ(FLAGS_test_flag_02.Name(), "test_flag_02");
129 EXPECT_EQ(FLAGS_test_flag_03.Name(), "test_flag_03");
130 EXPECT_EQ(FLAGS_test_flag_04.Name(), "test_flag_04");
131 EXPECT_EQ(FLAGS_test_flag_05.Name(), "test_flag_05");
132 EXPECT_EQ(FLAGS_test_flag_06.Name(), "test_flag_06");
133 EXPECT_EQ(FLAGS_test_flag_07.Name(), "test_flag_07");
134 EXPECT_EQ(FLAGS_test_flag_08.Name(), "test_flag_08");
135 EXPECT_EQ(FLAGS_test_flag_09.Name(), "test_flag_09");
136 EXPECT_EQ(FLAGS_test_flag_10.Name(), "test_flag_10");
137 EXPECT_EQ(FLAGS_test_flag_11.Name(), "test_flag_11");
138}
139#endif // !ABSL_FLAGS_STRIP_NAMES
140
141// --------------------------------------------------------------------
142
143} // namespace
144
145ABSL_FLAG(bool, test_flag_01, true, "test flag 01");
146ABSL_FLAG(int, test_flag_02, 1234, "test flag 02");
147ABSL_FLAG(int16_t, test_flag_03, -34, "test flag 03");
148ABSL_FLAG(uint16_t, test_flag_04, 189, "test flag 04");
149ABSL_FLAG(int32_t, test_flag_05, 10765, "test flag 05");
150ABSL_FLAG(uint32_t, test_flag_06, 40000, "test flag 06");
151ABSL_FLAG(int64_t, test_flag_07, -1234567, "test flag 07");
152ABSL_FLAG(uint64_t, test_flag_08, 9876543, "test flag 08");
153ABSL_FLAG(double, test_flag_09, -9.876e-50, "test flag 09");
154ABSL_FLAG(float, test_flag_10, 1.234e12f, "test flag 10");
155ABSL_FLAG(std::string, test_flag_11, "", "test flag 11");
156
157namespace {
158
159#if !ABSL_FLAGS_STRIP_NAMES
160TEST_F(FlagTest, TestFlagDefinition) {
161 absl::string_view expected_file_name = "absl/flags/flag_test.cc";
162
163 EXPECT_EQ(FLAGS_test_flag_01.Name(), "test_flag_01");
164 EXPECT_EQ(FLAGS_test_flag_01.Help(), "test flag 01");
165 EXPECT_TRUE(absl::EndsWith(FLAGS_test_flag_01.Filename(), expected_file_name))
166 << FLAGS_test_flag_01.Filename();
167
168 EXPECT_EQ(FLAGS_test_flag_02.Name(), "test_flag_02");
169 EXPECT_EQ(FLAGS_test_flag_02.Help(), "test flag 02");
170 EXPECT_TRUE(absl::EndsWith(FLAGS_test_flag_02.Filename(), expected_file_name))
171 << FLAGS_test_flag_02.Filename();
172
173 EXPECT_EQ(FLAGS_test_flag_03.Name(), "test_flag_03");
174 EXPECT_EQ(FLAGS_test_flag_03.Help(), "test flag 03");
175 EXPECT_TRUE(absl::EndsWith(FLAGS_test_flag_03.Filename(), expected_file_name))
176 << FLAGS_test_flag_03.Filename();
177
178 EXPECT_EQ(FLAGS_test_flag_04.Name(), "test_flag_04");
179 EXPECT_EQ(FLAGS_test_flag_04.Help(), "test flag 04");
180 EXPECT_TRUE(absl::EndsWith(FLAGS_test_flag_04.Filename(), expected_file_name))
181 << FLAGS_test_flag_04.Filename();
182
183 EXPECT_EQ(FLAGS_test_flag_05.Name(), "test_flag_05");
184 EXPECT_EQ(FLAGS_test_flag_05.Help(), "test flag 05");
185 EXPECT_TRUE(absl::EndsWith(FLAGS_test_flag_05.Filename(), expected_file_name))
186 << FLAGS_test_flag_05.Filename();
187
188 EXPECT_EQ(FLAGS_test_flag_06.Name(), "test_flag_06");
189 EXPECT_EQ(FLAGS_test_flag_06.Help(), "test flag 06");
190 EXPECT_TRUE(absl::EndsWith(FLAGS_test_flag_06.Filename(), expected_file_name))
191 << FLAGS_test_flag_06.Filename();
192
193 EXPECT_EQ(FLAGS_test_flag_07.Name(), "test_flag_07");
194 EXPECT_EQ(FLAGS_test_flag_07.Help(), "test flag 07");
195 EXPECT_TRUE(absl::EndsWith(FLAGS_test_flag_07.Filename(), expected_file_name))
196 << FLAGS_test_flag_07.Filename();
197
198 EXPECT_EQ(FLAGS_test_flag_08.Name(), "test_flag_08");
199 EXPECT_EQ(FLAGS_test_flag_08.Help(), "test flag 08");
200 EXPECT_TRUE(absl::EndsWith(FLAGS_test_flag_08.Filename(), expected_file_name))
201 << FLAGS_test_flag_08.Filename();
202
203 EXPECT_EQ(FLAGS_test_flag_09.Name(), "test_flag_09");
204 EXPECT_EQ(FLAGS_test_flag_09.Help(), "test flag 09");
205 EXPECT_TRUE(absl::EndsWith(FLAGS_test_flag_09.Filename(), expected_file_name))
206 << FLAGS_test_flag_09.Filename();
207
208 EXPECT_EQ(FLAGS_test_flag_10.Name(), "test_flag_10");
209 EXPECT_EQ(FLAGS_test_flag_10.Help(), "test flag 10");
210 EXPECT_TRUE(absl::EndsWith(FLAGS_test_flag_10.Filename(), expected_file_name))
211 << FLAGS_test_flag_10.Filename();
212
213 EXPECT_EQ(FLAGS_test_flag_11.Name(), "test_flag_11");
214 EXPECT_EQ(FLAGS_test_flag_11.Help(), "test flag 11");
215 EXPECT_TRUE(absl::EndsWith(FLAGS_test_flag_11.Filename(), expected_file_name))
216 << FLAGS_test_flag_11.Filename();
217}
218#endif // !ABSL_FLAGS_STRIP_NAMES
219
220// --------------------------------------------------------------------
221
222TEST_F(FlagTest, TestDefault) {
223 EXPECT_EQ(absl::GetFlag(FLAGS_test_flag_01), true);
224 EXPECT_EQ(absl::GetFlag(FLAGS_test_flag_02), 1234);
225 EXPECT_EQ(absl::GetFlag(FLAGS_test_flag_03), -34);
226 EXPECT_EQ(absl::GetFlag(FLAGS_test_flag_04), 189);
227 EXPECT_EQ(absl::GetFlag(FLAGS_test_flag_05), 10765);
228 EXPECT_EQ(absl::GetFlag(FLAGS_test_flag_06), 40000);
229 EXPECT_EQ(absl::GetFlag(FLAGS_test_flag_07), -1234567);
230 EXPECT_EQ(absl::GetFlag(FLAGS_test_flag_08), 9876543);
231 EXPECT_NEAR(absl::GetFlag(FLAGS_test_flag_09), -9.876e-50, 1e-55);
232 EXPECT_NEAR(absl::GetFlag(FLAGS_test_flag_10), 1.234e12f, 1e5f);
233 EXPECT_EQ(absl::GetFlag(FLAGS_test_flag_11), "");
234}
235
236// --------------------------------------------------------------------
237
238TEST_F(FlagTest, TestGetSet) {
239 absl::SetFlag(&FLAGS_test_flag_01, false);
240 EXPECT_EQ(absl::GetFlag(FLAGS_test_flag_01), false);
241
242 absl::SetFlag(&FLAGS_test_flag_02, 321);
243 EXPECT_EQ(absl::GetFlag(FLAGS_test_flag_02), 321);
244
245 absl::SetFlag(&FLAGS_test_flag_03, 67);
246 EXPECT_EQ(absl::GetFlag(FLAGS_test_flag_03), 67);
247
248 absl::SetFlag(&FLAGS_test_flag_04, 1);
249 EXPECT_EQ(absl::GetFlag(FLAGS_test_flag_04), 1);
250
251 absl::SetFlag(&FLAGS_test_flag_05, -908);
252 EXPECT_EQ(absl::GetFlag(FLAGS_test_flag_05), -908);
253
254 absl::SetFlag(&FLAGS_test_flag_06, 4001);
255 EXPECT_EQ(absl::GetFlag(FLAGS_test_flag_06), 4001);
256
257 absl::SetFlag(&FLAGS_test_flag_07, -23456);
258 EXPECT_EQ(absl::GetFlag(FLAGS_test_flag_07), -23456);
259
260 absl::SetFlag(&FLAGS_test_flag_08, 975310);
261 EXPECT_EQ(absl::GetFlag(FLAGS_test_flag_08), 975310);
262
263 absl::SetFlag(&FLAGS_test_flag_09, 1.00001);
264 EXPECT_NEAR(absl::GetFlag(FLAGS_test_flag_09), 1.00001, 1e-10);
265
266 absl::SetFlag(&FLAGS_test_flag_10, -3.54f);
267 EXPECT_NEAR(absl::GetFlag(FLAGS_test_flag_10), -3.54f, 1e-6f);
268
269 absl::SetFlag(&FLAGS_test_flag_11, "asdf");
270 EXPECT_EQ(absl::GetFlag(FLAGS_test_flag_11), "asdf");
271}
272
273// --------------------------------------------------------------------
274
275int GetDflt1() { return 1; }
276
277} // namespace
278
279ABSL_FLAG(int, test_flag_12, GetDflt1(), "test flag 12");
280ABSL_FLAG(std::string, test_flag_13, absl::StrCat("AAA", "BBB"),
281 "test flag 13");
282
283namespace {
284
285TEST_F(FlagTest, TestNonConstexprDefault) {
286 EXPECT_EQ(absl::GetFlag(FLAGS_test_flag_12), 1);
287 EXPECT_EQ(absl::GetFlag(FLAGS_test_flag_13), "AAABBB");
288}
289
290// --------------------------------------------------------------------
291
292} // namespace
293
294ABSL_FLAG(bool, test_flag_14, true, absl::StrCat("test ", "flag ", "14"));
295
296namespace {
297
298#if !ABSL_FLAGS_STRIP_HELP
299TEST_F(FlagTest, TestNonConstexprHelp) {
300 EXPECT_EQ(FLAGS_test_flag_14.Help(), "test flag 14");
301}
302#endif //! ABSL_FLAGS_STRIP_HELP
303
304// --------------------------------------------------------------------
305
306int cb_test_value = -1;
307void TestFlagCB();
308
309} // namespace
310
311ABSL_FLAG(int, test_flag_with_cb, 100, "").OnUpdate(TestFlagCB);
312
313ABSL_FLAG(int, test_flag_with_lambda_cb, 200, "").OnUpdate([]() {
314 cb_test_value = absl::GetFlag(FLAGS_test_flag_with_lambda_cb) +
315 absl::GetFlag(FLAGS_test_flag_with_cb);
316});
317
318namespace {
319
320void TestFlagCB() { cb_test_value = absl::GetFlag(FLAGS_test_flag_with_cb); }
321
322// Tests side-effects of callback invocation.
323TEST_F(FlagTest, CallbackInvocation) {
324 EXPECT_EQ(absl::GetFlag(FLAGS_test_flag_with_cb), 100);
325 EXPECT_EQ(absl::GetFlag(FLAGS_test_flag_with_lambda_cb), 200);
326 EXPECT_EQ(cb_test_value, 300);
327
328 absl::SetFlag(&FLAGS_test_flag_with_cb, 1);
329 EXPECT_EQ(cb_test_value, 1);
330
331 absl::SetFlag(&FLAGS_test_flag_with_lambda_cb, 3);
332 EXPECT_EQ(cb_test_value, 4);
333}
334
335// --------------------------------------------------------------------
336
337struct CustomUDT {
338 CustomUDT() : a(1), b(1) {}
339 CustomUDT(int a_, int b_) : a(a_), b(b_) {}
340
341 friend bool operator==(const CustomUDT& f1, const CustomUDT& f2) {
342 return f1.a == f2.a && f1.b == f2.b;
343 }
344
345 int a;
346 int b;
347};
348bool AbslParseFlag(absl::string_view in, CustomUDT* f, std::string*) {
349 std::vector<absl::string_view> parts =
350 absl::StrSplit(in, ':', absl::SkipWhitespace());
351
352 if (parts.size() != 2) return false;
353
354 if (!absl::SimpleAtoi(parts[0], &f->a)) return false;
355
356 if (!absl::SimpleAtoi(parts[1], &f->b)) return false;
357
358 return true;
359}
360std::string AbslUnparseFlag(const CustomUDT& f) {
361 return absl::StrCat(f.a, ":", f.b);
362}
363
364} // namespace
365
366ABSL_FLAG(CustomUDT, test_flag_15, CustomUDT(), "test flag 15");
367
368namespace {
369
370TEST_F(FlagTest, TestCustomUDT) {
371 EXPECT_EQ(absl::GetFlag(FLAGS_test_flag_15), CustomUDT(1, 1));
372 absl::SetFlag(&FLAGS_test_flag_15, CustomUDT(2, 3));
373 EXPECT_EQ(absl::GetFlag(FLAGS_test_flag_15), CustomUDT(2, 3));
374}
375
376// MSVC produces link error on the type mismatch.
377// Linux does not have build errors and validations work as expected.
378#if 0 // !defined(_WIN32) && GTEST_HAS_DEATH_TEST
379
380TEST(Flagtest, TestTypeMismatchValidations) {
381 // For builtin types, GetFlag() only does validation in debug mode.
382 EXPECT_DEBUG_DEATH(
383 absl::GetFlag(FLAGS_mistyped_int_flag),
384 "Flag 'mistyped_int_flag' is defined as one type and declared "
385 "as another");
386 EXPECT_DEATH(absl::SetFlag(&FLAGS_mistyped_int_flag, 0),
387 "Flag 'mistyped_int_flag' is defined as one type and declared "
388 "as another");
389
390 EXPECT_DEATH(absl::GetFlag(FLAGS_mistyped_string_flag),
391 "Flag 'mistyped_string_flag' is defined as one type and "
392 "declared as another");
393 EXPECT_DEATH(
394 absl::SetFlag(&FLAGS_mistyped_string_flag, std::vector<std::string>{}),
395 "Flag 'mistyped_string_flag' is defined as one type and declared as "
396 "another");
397}
398
399#endif
400
401// --------------------------------------------------------------------
402
403// A contrived type that offers implicit and explicit conversion from specific
404// source types.
405struct ConversionTestVal {
406 ConversionTestVal() = default;
407 explicit ConversionTestVal(int a_in) : a(a_in) {}
408
409 enum class ViaImplicitConv { kTen = 10, kEleven };
410 // NOLINTNEXTLINE
411 ConversionTestVal(ViaImplicitConv from) : a(static_cast<int>(from)) {}
412
413 int a;
414};
415
416bool AbslParseFlag(absl::string_view in, ConversionTestVal* val_out,
417 std::string*) {
418 if (!absl::SimpleAtoi(in, &val_out->a)) {
419 return false;
420 }
421 return true;
422}
423std::string AbslUnparseFlag(const ConversionTestVal& val) {
424 return absl::StrCat(val.a);
425}
426
427} // namespace
428
429// Flag default values can be specified with a value that converts to the flag
430// value type implicitly.
431ABSL_FLAG(ConversionTestVal, test_flag_16,
432 ConversionTestVal::ViaImplicitConv::kTen, "test flag 16");
433
434namespace {
435
436TEST_F(FlagTest, CanSetViaImplicitConversion) {
437 EXPECT_EQ(absl::GetFlag(FLAGS_test_flag_16).a, 10);
438 absl::SetFlag(&FLAGS_test_flag_16,
439 ConversionTestVal::ViaImplicitConv::kEleven);
440 EXPECT_EQ(absl::GetFlag(FLAGS_test_flag_16).a, 11);
441}
442
443// --------------------------------------------------------------------
444
445struct NonDfltConstructible {
446 public:
447 // This constructor tests that we can initialize the flag with int value
448 NonDfltConstructible(int i) : value(i) {} // NOLINT
449
450 // This constructor tests that we can't initialize the flag with char value
451 // but can with explicitly constructed NonDfltConstructible.
452 explicit NonDfltConstructible(char c) : value(100 + static_cast<int>(c)) {}
453
454 int value;
455};
456
457bool AbslParseFlag(absl::string_view in, NonDfltConstructible* ndc_out,
458 std::string*) {
459 return absl::SimpleAtoi(in, &ndc_out->value);
460}
461std::string AbslUnparseFlag(const NonDfltConstructible& ndc) {
462 return absl::StrCat(ndc.value);
463}
464
465} // namespace
466
467ABSL_FLAG(NonDfltConstructible, ndc_flag1, NonDfltConstructible('1'),
468 "Flag with non default constructible type");
469ABSL_FLAG(NonDfltConstructible, ndc_flag2, 0,
470 "Flag with non default constructible type");
471
472namespace {
473
474TEST_F(FlagTest, TestNonDefaultConstructibleType) {
475 EXPECT_EQ(absl::GetFlag(FLAGS_ndc_flag1).value, '1' + 100);
476 EXPECT_EQ(absl::GetFlag(FLAGS_ndc_flag2).value, 0);
477
478 absl::SetFlag(&FLAGS_ndc_flag1, NonDfltConstructible('A'));
479 absl::SetFlag(&FLAGS_ndc_flag2, 25);
480
481 EXPECT_EQ(absl::GetFlag(FLAGS_ndc_flag1).value, 'A' + 100);
482 EXPECT_EQ(absl::GetFlag(FLAGS_ndc_flag2).value, 25);
483}
484
485// --------------------------------------------------------------------
486
487} // namespace
488
489ABSL_RETIRED_FLAG(bool, old_bool_flag, true, "old descr");
490ABSL_RETIRED_FLAG(int, old_int_flag, (int)std::sqrt(10), "old descr");
491ABSL_RETIRED_FLAG(std::string, old_str_flag, "", absl::StrCat("old ", "descr"));
492
493namespace {
494
495TEST_F(FlagTest, TestRetiredFlagRegistration) {
496 bool is_bool = false;
497 EXPECT_TRUE(flags::IsRetiredFlag("old_bool_flag", &is_bool));
498 EXPECT_TRUE(is_bool);
499 EXPECT_TRUE(flags::IsRetiredFlag("old_int_flag", &is_bool));
500 EXPECT_FALSE(is_bool);
501 EXPECT_TRUE(flags::IsRetiredFlag("old_str_flag", &is_bool));
502 EXPECT_FALSE(is_bool);
503 EXPECT_FALSE(flags::IsRetiredFlag("some_other_flag", &is_bool));
504}
505
506} // namespace