| // |
| // Copyright 2019 The Abseil Authors. |
| // |
| // Licensed under the Apache License, Version 2.0 (the "License"); |
| // you may not use this file except in compliance with the License. |
| // You may obtain a copy of the License at |
| // |
| // https://www.apache.org/licenses/LICENSE-2.0 |
| // |
| // Unless required by applicable law or agreed to in writing, software |
| // distributed under the License is distributed on an "AS IS" BASIS, |
| // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| // See the License for the specific language governing permissions and |
| // limitations under the License. |
| |
| #include "absl/flags/flag.h" |
| |
| #include <stddef.h> |
| #include <stdint.h> |
| |
| #include <cmath> |
| #include <new> |
| #include <string> |
| #include <thread> // NOLINT |
| #include <vector> |
| |
| #include "gtest/gtest.h" |
| #include "absl/base/attributes.h" |
| #include "absl/flags/config.h" |
| #include "absl/flags/declare.h" |
| #include "absl/flags/internal/flag.h" |
| #include "absl/flags/marshalling.h" |
| #include "absl/flags/reflection.h" |
| #include "absl/flags/usage_config.h" |
| #include "absl/strings/match.h" |
| #include "absl/strings/numbers.h" |
| #include "absl/strings/str_cat.h" |
| #include "absl/strings/str_split.h" |
| #include "absl/strings/string_view.h" |
| #include "absl/time/time.h" |
| |
| ABSL_DECLARE_FLAG(int64_t, mistyped_int_flag); |
| ABSL_DECLARE_FLAG(std::vector<std::string>, mistyped_string_flag); |
| |
| namespace { |
| |
| namespace flags = absl::flags_internal; |
| |
| std::string TestHelpMsg() { return "dynamic help"; } |
| #if defined(_MSC_VER) && !defined(__clang__) |
| std::string TestLiteralHelpMsg() { return "literal help"; } |
| #endif |
| template <typename T> |
| void TestMakeDflt(void* dst) { |
| new (dst) T{}; |
| } |
| void TestCallback() {} |
| |
| struct UDT { |
| UDT() = default; |
| UDT(const UDT&) = default; |
| }; |
| bool AbslParseFlag(absl::string_view, UDT*, std::string*) { return true; } |
| std::string AbslUnparseFlag(const UDT&) { return ""; } |
| |
| class FlagTest : public testing::Test { |
| protected: |
| static void SetUpTestSuite() { |
| // Install a function to normalize filenames before this test is run. |
| absl::FlagsUsageConfig default_config; |
| default_config.normalize_filename = &FlagTest::NormalizeFileName; |
| absl::SetFlagsUsageConfig(default_config); |
| } |
| |
| private: |
| static std::string NormalizeFileName(absl::string_view fname) { |
| #ifdef _WIN32 |
| std::string normalized(fname); |
| std::replace(normalized.begin(), normalized.end(), '\\', '/'); |
| fname = normalized; |
| #endif |
| return std::string(fname); |
| } |
| absl::FlagSaver flag_saver_; |
| }; |
| |
| struct S1 { |
| S1() = default; |
| S1(const S1&) = default; |
| int32_t f1; |
| int64_t f2; |
| }; |
| |
| struct S2 { |
| S2() = default; |
| S2(const S2&) = default; |
| int64_t f1; |
| double f2; |
| }; |
| |
| TEST_F(FlagTest, Traits) { |
| EXPECT_EQ(flags::StorageKind<int>(), |
| flags::FlagValueStorageKind::kOneWordAtomic); |
| EXPECT_EQ(flags::StorageKind<bool>(), |
| flags::FlagValueStorageKind::kOneWordAtomic); |
| EXPECT_EQ(flags::StorageKind<double>(), |
| flags::FlagValueStorageKind::kOneWordAtomic); |
| EXPECT_EQ(flags::StorageKind<int64_t>(), |
| flags::FlagValueStorageKind::kOneWordAtomic); |
| |
| #if defined(ABSL_FLAGS_INTERNAL_ATOMIC_DOUBLE_WORD) |
| EXPECT_EQ(flags::StorageKind<S1>(), |
| flags::FlagValueStorageKind::kTwoWordsAtomic); |
| EXPECT_EQ(flags::StorageKind<S2>(), |
| flags::FlagValueStorageKind::kTwoWordsAtomic); |
| #else |
| EXPECT_EQ(flags::StorageKind<S1>(), |
| flags::FlagValueStorageKind::kAlignedBuffer); |
| EXPECT_EQ(flags::StorageKind<S2>(), |
| flags::FlagValueStorageKind::kAlignedBuffer); |
| #endif |
| |
| EXPECT_EQ(flags::StorageKind<std::string>(), |
| flags::FlagValueStorageKind::kAlignedBuffer); |
| EXPECT_EQ(flags::StorageKind<std::vector<std::string>>(), |
| flags::FlagValueStorageKind::kAlignedBuffer); |
| } |
| |
| // -------------------------------------------------------------------- |
| |
| constexpr flags::FlagHelpArg help_arg{flags::FlagHelpMsg("literal help"), |
| flags::FlagHelpKind::kLiteral}; |
| |
| using String = std::string; |
| |
| #if !defined(_MSC_VER) || defined(__clang__) |
| #define DEFINE_CONSTRUCTED_FLAG(T, dflt, dflt_kind) \ |
| constexpr flags::FlagDefaultArg f1default##T{ \ |
| flags::FlagDefaultSrc{dflt}, flags::FlagDefaultKind::dflt_kind}; \ |
| constexpr absl::Flag<T> f1##T{"f1", "file", help_arg, f1default##T}; \ |
| ABSL_CONST_INIT absl::Flag<T> f2##T { \ |
| "f2", "file", \ |
| {flags::FlagHelpMsg(&TestHelpMsg), flags::FlagHelpKind::kGenFunc}, \ |
| flags::FlagDefaultArg { \ |
| flags::FlagDefaultSrc(&TestMakeDflt<T>), \ |
| flags::FlagDefaultKind::kGenFunc \ |
| } \ |
| } |
| #else |
| #define DEFINE_CONSTRUCTED_FLAG(T, dflt, dflt_kind) \ |
| constexpr flags::FlagDefaultArg f1default##T{ \ |
| flags::FlagDefaultSrc{dflt}, flags::FlagDefaultKind::dflt_kind}; \ |
| constexpr absl::Flag<T> f1##T{"f1", "file", &TestLiteralHelpMsg, \ |
| &TestMakeDflt<T>}; \ |
| ABSL_CONST_INIT absl::Flag<T> f2##T { \ |
| "f2", "file", &TestHelpMsg, &TestMakeDflt<T> \ |
| } |
| #endif |
| |
| DEFINE_CONSTRUCTED_FLAG(bool, true, kOneWord); |
| DEFINE_CONSTRUCTED_FLAG(int16_t, 1, kOneWord); |
| DEFINE_CONSTRUCTED_FLAG(uint16_t, 2, kOneWord); |
| DEFINE_CONSTRUCTED_FLAG(int32_t, 3, kOneWord); |
| DEFINE_CONSTRUCTED_FLAG(uint32_t, 4, kOneWord); |
| DEFINE_CONSTRUCTED_FLAG(int64_t, 5, kOneWord); |
| DEFINE_CONSTRUCTED_FLAG(uint64_t, 6, kOneWord); |
| DEFINE_CONSTRUCTED_FLAG(float, 7.8, kOneWord); |
| DEFINE_CONSTRUCTED_FLAG(double, 9.10, kOneWord); |
| DEFINE_CONSTRUCTED_FLAG(String, &TestMakeDflt<String>, kGenFunc); |
| DEFINE_CONSTRUCTED_FLAG(UDT, &TestMakeDflt<UDT>, kGenFunc); |
| |
| template <typename T> |
| bool TestConstructionFor(const absl::Flag<T>& f1, absl::Flag<T>& f2) { |
| EXPECT_EQ(absl::GetFlagReflectionHandle(f1).Name(), "f1"); |
| EXPECT_EQ(absl::GetFlagReflectionHandle(f1).Help(), "literal help"); |
| EXPECT_EQ(absl::GetFlagReflectionHandle(f1).Filename(), "file"); |
| |
| flags::FlagRegistrar<T, false>(ABSL_FLAG_IMPL_FLAG_PTR(f2)) |
| .OnUpdate(TestCallback); |
| |
| EXPECT_EQ(absl::GetFlagReflectionHandle(f2).Name(), "f2"); |
| EXPECT_EQ(absl::GetFlagReflectionHandle(f2).Help(), "dynamic help"); |
| EXPECT_EQ(absl::GetFlagReflectionHandle(f2).Filename(), "file"); |
| |
| return true; |
| } |
| |
| #define TEST_CONSTRUCTED_FLAG(T) TestConstructionFor(f1##T, f2##T); |
| |
| TEST_F(FlagTest, TestConstruction) { |
| TEST_CONSTRUCTED_FLAG(bool); |
| TEST_CONSTRUCTED_FLAG(int16_t); |
| TEST_CONSTRUCTED_FLAG(uint16_t); |
| TEST_CONSTRUCTED_FLAG(int32_t); |
| TEST_CONSTRUCTED_FLAG(uint32_t); |
| TEST_CONSTRUCTED_FLAG(int64_t); |
| TEST_CONSTRUCTED_FLAG(uint64_t); |
| TEST_CONSTRUCTED_FLAG(float); |
| TEST_CONSTRUCTED_FLAG(double); |
| TEST_CONSTRUCTED_FLAG(String); |
| TEST_CONSTRUCTED_FLAG(UDT); |
| } |
| |
| // -------------------------------------------------------------------- |
| |
| } // namespace |
| |
| ABSL_DECLARE_FLAG(bool, test_flag_01); |
| ABSL_DECLARE_FLAG(int, test_flag_02); |
| ABSL_DECLARE_FLAG(int16_t, test_flag_03); |
| ABSL_DECLARE_FLAG(uint16_t, test_flag_04); |
| ABSL_DECLARE_FLAG(int32_t, test_flag_05); |
| ABSL_DECLARE_FLAG(uint32_t, test_flag_06); |
| ABSL_DECLARE_FLAG(int64_t, test_flag_07); |
| ABSL_DECLARE_FLAG(uint64_t, test_flag_08); |
| ABSL_DECLARE_FLAG(double, test_flag_09); |
| ABSL_DECLARE_FLAG(float, test_flag_10); |
| ABSL_DECLARE_FLAG(std::string, test_flag_11); |
| ABSL_DECLARE_FLAG(absl::Duration, test_flag_12); |
| |
| namespace { |
| |
| #if !ABSL_FLAGS_STRIP_NAMES |
| |
| TEST_F(FlagTest, TestFlagDeclaration) { |
| // test that we can access flag objects. |
| EXPECT_EQ(absl::GetFlagReflectionHandle(FLAGS_test_flag_01).Name(), |
| "test_flag_01"); |
| EXPECT_EQ(absl::GetFlagReflectionHandle(FLAGS_test_flag_02).Name(), |
| "test_flag_02"); |
| EXPECT_EQ(absl::GetFlagReflectionHandle(FLAGS_test_flag_03).Name(), |
| "test_flag_03"); |
| EXPECT_EQ(absl::GetFlagReflectionHandle(FLAGS_test_flag_04).Name(), |
| "test_flag_04"); |
| EXPECT_EQ(absl::GetFlagReflectionHandle(FLAGS_test_flag_05).Name(), |
| "test_flag_05"); |
| EXPECT_EQ(absl::GetFlagReflectionHandle(FLAGS_test_flag_06).Name(), |
| "test_flag_06"); |
| EXPECT_EQ(absl::GetFlagReflectionHandle(FLAGS_test_flag_07).Name(), |
| "test_flag_07"); |
| EXPECT_EQ(absl::GetFlagReflectionHandle(FLAGS_test_flag_08).Name(), |
| "test_flag_08"); |
| EXPECT_EQ(absl::GetFlagReflectionHandle(FLAGS_test_flag_09).Name(), |
| "test_flag_09"); |
| EXPECT_EQ(absl::GetFlagReflectionHandle(FLAGS_test_flag_10).Name(), |
| "test_flag_10"); |
| EXPECT_EQ(absl::GetFlagReflectionHandle(FLAGS_test_flag_11).Name(), |
| "test_flag_11"); |
| EXPECT_EQ(absl::GetFlagReflectionHandle(FLAGS_test_flag_12).Name(), |
| "test_flag_12"); |
| } |
| #endif // !ABSL_FLAGS_STRIP_NAMES |
| |
| // -------------------------------------------------------------------- |
| |
| } // namespace |
| |
| ABSL_FLAG(bool, test_flag_01, true, "test flag 01"); |
| ABSL_FLAG(int, test_flag_02, 1234, "test flag 02"); |
| ABSL_FLAG(int16_t, test_flag_03, -34, "test flag 03"); |
| ABSL_FLAG(uint16_t, test_flag_04, 189, "test flag 04"); |
| ABSL_FLAG(int32_t, test_flag_05, 10765, "test flag 05"); |
| ABSL_FLAG(uint32_t, test_flag_06, 40000, "test flag 06"); |
| ABSL_FLAG(int64_t, test_flag_07, -1234567, "test flag 07"); |
| ABSL_FLAG(uint64_t, test_flag_08, 9876543, "test flag 08"); |
| ABSL_FLAG(double, test_flag_09, -9.876e-50, "test flag 09"); |
| ABSL_FLAG(float, test_flag_10, 1.234e12f, "test flag 10"); |
| ABSL_FLAG(std::string, test_flag_11, "", "test flag 11"); |
| ABSL_FLAG(absl::Duration, test_flag_12, absl::Minutes(10), "test flag 12"); |
| |
| namespace { |
| |
| #if !ABSL_FLAGS_STRIP_NAMES |
| TEST_F(FlagTest, TestFlagDefinition) { |
| absl::string_view expected_file_name = "absl/flags/flag_test.cc"; |
| |
| EXPECT_EQ(absl::GetFlagReflectionHandle(FLAGS_test_flag_01).Name(), |
| "test_flag_01"); |
| EXPECT_EQ(absl::GetFlagReflectionHandle(FLAGS_test_flag_01).Help(), |
| "test flag 01"); |
| EXPECT_TRUE(absl::EndsWith( |
| absl::GetFlagReflectionHandle(FLAGS_test_flag_01).Filename(), |
| expected_file_name)) |
| << absl::GetFlagReflectionHandle(FLAGS_test_flag_01).Filename(); |
| |
| EXPECT_EQ(absl::GetFlagReflectionHandle(FLAGS_test_flag_02).Name(), |
| "test_flag_02"); |
| EXPECT_EQ(absl::GetFlagReflectionHandle(FLAGS_test_flag_02).Help(), |
| "test flag 02"); |
| EXPECT_TRUE(absl::EndsWith( |
| absl::GetFlagReflectionHandle(FLAGS_test_flag_02).Filename(), |
| expected_file_name)) |
| << absl::GetFlagReflectionHandle(FLAGS_test_flag_02).Filename(); |
| |
| EXPECT_EQ(absl::GetFlagReflectionHandle(FLAGS_test_flag_03).Name(), |
| "test_flag_03"); |
| EXPECT_EQ(absl::GetFlagReflectionHandle(FLAGS_test_flag_03).Help(), |
| "test flag 03"); |
| EXPECT_TRUE(absl::EndsWith( |
| absl::GetFlagReflectionHandle(FLAGS_test_flag_03).Filename(), |
| expected_file_name)) |
| << absl::GetFlagReflectionHandle(FLAGS_test_flag_03).Filename(); |
| |
| EXPECT_EQ(absl::GetFlagReflectionHandle(FLAGS_test_flag_04).Name(), |
| "test_flag_04"); |
| EXPECT_EQ(absl::GetFlagReflectionHandle(FLAGS_test_flag_04).Help(), |
| "test flag 04"); |
| EXPECT_TRUE(absl::EndsWith( |
| absl::GetFlagReflectionHandle(FLAGS_test_flag_04).Filename(), |
| expected_file_name)) |
| << absl::GetFlagReflectionHandle(FLAGS_test_flag_04).Filename(); |
| |
| EXPECT_EQ(absl::GetFlagReflectionHandle(FLAGS_test_flag_05).Name(), |
| "test_flag_05"); |
| EXPECT_EQ(absl::GetFlagReflectionHandle(FLAGS_test_flag_05).Help(), |
| "test flag 05"); |
| EXPECT_TRUE(absl::EndsWith( |
| absl::GetFlagReflectionHandle(FLAGS_test_flag_05).Filename(), |
| expected_file_name)) |
| << absl::GetFlagReflectionHandle(FLAGS_test_flag_05).Filename(); |
| |
| EXPECT_EQ(absl::GetFlagReflectionHandle(FLAGS_test_flag_06).Name(), |
| "test_flag_06"); |
| EXPECT_EQ(absl::GetFlagReflectionHandle(FLAGS_test_flag_06).Help(), |
| "test flag 06"); |
| EXPECT_TRUE(absl::EndsWith( |
| absl::GetFlagReflectionHandle(FLAGS_test_flag_06).Filename(), |
| expected_file_name)) |
| << absl::GetFlagReflectionHandle(FLAGS_test_flag_06).Filename(); |
| |
| EXPECT_EQ(absl::GetFlagReflectionHandle(FLAGS_test_flag_07).Name(), |
| "test_flag_07"); |
| EXPECT_EQ(absl::GetFlagReflectionHandle(FLAGS_test_flag_07).Help(), |
| "test flag 07"); |
| EXPECT_TRUE(absl::EndsWith( |
| absl::GetFlagReflectionHandle(FLAGS_test_flag_07).Filename(), |
| expected_file_name)) |
| << absl::GetFlagReflectionHandle(FLAGS_test_flag_07).Filename(); |
| |
| EXPECT_EQ(absl::GetFlagReflectionHandle(FLAGS_test_flag_08).Name(), |
| "test_flag_08"); |
| EXPECT_EQ(absl::GetFlagReflectionHandle(FLAGS_test_flag_08).Help(), |
| "test flag 08"); |
| EXPECT_TRUE(absl::EndsWith( |
| absl::GetFlagReflectionHandle(FLAGS_test_flag_08).Filename(), |
| expected_file_name)) |
| << absl::GetFlagReflectionHandle(FLAGS_test_flag_08).Filename(); |
| |
| EXPECT_EQ(absl::GetFlagReflectionHandle(FLAGS_test_flag_09).Name(), |
| "test_flag_09"); |
| EXPECT_EQ(absl::GetFlagReflectionHandle(FLAGS_test_flag_09).Help(), |
| "test flag 09"); |
| EXPECT_TRUE(absl::EndsWith( |
| absl::GetFlagReflectionHandle(FLAGS_test_flag_09).Filename(), |
| expected_file_name)) |
| << absl::GetFlagReflectionHandle(FLAGS_test_flag_09).Filename(); |
| |
| EXPECT_EQ(absl::GetFlagReflectionHandle(FLAGS_test_flag_10).Name(), |
| "test_flag_10"); |
| EXPECT_EQ(absl::GetFlagReflectionHandle(FLAGS_test_flag_10).Help(), |
| "test flag 10"); |
| EXPECT_TRUE(absl::EndsWith( |
| absl::GetFlagReflectionHandle(FLAGS_test_flag_10).Filename(), |
| expected_file_name)) |
| << absl::GetFlagReflectionHandle(FLAGS_test_flag_10).Filename(); |
| |
| EXPECT_EQ(absl::GetFlagReflectionHandle(FLAGS_test_flag_11).Name(), |
| "test_flag_11"); |
| EXPECT_EQ(absl::GetFlagReflectionHandle(FLAGS_test_flag_11).Help(), |
| "test flag 11"); |
| EXPECT_TRUE(absl::EndsWith( |
| absl::GetFlagReflectionHandle(FLAGS_test_flag_11).Filename(), |
| expected_file_name)) |
| << absl::GetFlagReflectionHandle(FLAGS_test_flag_11).Filename(); |
| |
| EXPECT_EQ(absl::GetFlagReflectionHandle(FLAGS_test_flag_12).Name(), |
| "test_flag_12"); |
| EXPECT_EQ(absl::GetFlagReflectionHandle(FLAGS_test_flag_12).Help(), |
| "test flag 12"); |
| EXPECT_TRUE(absl::EndsWith( |
| absl::GetFlagReflectionHandle(FLAGS_test_flag_12).Filename(), |
| expected_file_name)) |
| << absl::GetFlagReflectionHandle(FLAGS_test_flag_12).Filename(); |
| } |
| #endif // !ABSL_FLAGS_STRIP_NAMES |
| |
| // -------------------------------------------------------------------- |
| |
| TEST_F(FlagTest, TestDefault) { |
| EXPECT_EQ(absl::GetFlagReflectionHandle(FLAGS_test_flag_01).DefaultValue(), |
| "true"); |
| EXPECT_EQ(absl::GetFlagReflectionHandle(FLAGS_test_flag_02).DefaultValue(), |
| "1234"); |
| EXPECT_EQ(absl::GetFlagReflectionHandle(FLAGS_test_flag_03).DefaultValue(), |
| "-34"); |
| EXPECT_EQ(absl::GetFlagReflectionHandle(FLAGS_test_flag_04).DefaultValue(), |
| "189"); |
| EXPECT_EQ(absl::GetFlagReflectionHandle(FLAGS_test_flag_05).DefaultValue(), |
| "10765"); |
| EXPECT_EQ(absl::GetFlagReflectionHandle(FLAGS_test_flag_06).DefaultValue(), |
| "40000"); |
| EXPECT_EQ(absl::GetFlagReflectionHandle(FLAGS_test_flag_07).DefaultValue(), |
| "-1234567"); |
| EXPECT_EQ(absl::GetFlagReflectionHandle(FLAGS_test_flag_08).DefaultValue(), |
| "9876543"); |
| EXPECT_EQ(absl::GetFlagReflectionHandle(FLAGS_test_flag_09).DefaultValue(), |
| "-9.876e-50"); |
| EXPECT_EQ(absl::GetFlagReflectionHandle(FLAGS_test_flag_10).DefaultValue(), |
| "1.234e+12"); |
| EXPECT_EQ(absl::GetFlagReflectionHandle(FLAGS_test_flag_11).DefaultValue(), |
| ""); |
| EXPECT_EQ(absl::GetFlagReflectionHandle(FLAGS_test_flag_12).DefaultValue(), |
| "10m"); |
| |
| EXPECT_EQ(absl::GetFlagReflectionHandle(FLAGS_test_flag_01).CurrentValue(), |
| "true"); |
| EXPECT_EQ(absl::GetFlagReflectionHandle(FLAGS_test_flag_02).CurrentValue(), |
| "1234"); |
| EXPECT_EQ(absl::GetFlagReflectionHandle(FLAGS_test_flag_03).CurrentValue(), |
| "-34"); |
| EXPECT_EQ(absl::GetFlagReflectionHandle(FLAGS_test_flag_04).CurrentValue(), |
| "189"); |
| EXPECT_EQ(absl::GetFlagReflectionHandle(FLAGS_test_flag_05).CurrentValue(), |
| "10765"); |
| EXPECT_EQ(absl::GetFlagReflectionHandle(FLAGS_test_flag_06).CurrentValue(), |
| "40000"); |
| EXPECT_EQ(absl::GetFlagReflectionHandle(FLAGS_test_flag_07).CurrentValue(), |
| "-1234567"); |
| EXPECT_EQ(absl::GetFlagReflectionHandle(FLAGS_test_flag_08).CurrentValue(), |
| "9876543"); |
| EXPECT_EQ(absl::GetFlagReflectionHandle(FLAGS_test_flag_09).CurrentValue(), |
| "-9.876e-50"); |
| EXPECT_EQ(absl::GetFlagReflectionHandle(FLAGS_test_flag_10).CurrentValue(), |
| "1.234e+12"); |
| EXPECT_EQ(absl::GetFlagReflectionHandle(FLAGS_test_flag_11).CurrentValue(), |
| ""); |
| EXPECT_EQ(absl::GetFlagReflectionHandle(FLAGS_test_flag_12).CurrentValue(), |
| "10m"); |
| |
| EXPECT_EQ(absl::GetFlag(FLAGS_test_flag_01), true); |
| EXPECT_EQ(absl::GetFlag(FLAGS_test_flag_02), 1234); |
| EXPECT_EQ(absl::GetFlag(FLAGS_test_flag_03), -34); |
| EXPECT_EQ(absl::GetFlag(FLAGS_test_flag_04), 189); |
| EXPECT_EQ(absl::GetFlag(FLAGS_test_flag_05), 10765); |
| EXPECT_EQ(absl::GetFlag(FLAGS_test_flag_06), 40000); |
| EXPECT_EQ(absl::GetFlag(FLAGS_test_flag_07), -1234567); |
| EXPECT_EQ(absl::GetFlag(FLAGS_test_flag_08), 9876543); |
| EXPECT_NEAR(absl::GetFlag(FLAGS_test_flag_09), -9.876e-50, 1e-55); |
| EXPECT_NEAR(absl::GetFlag(FLAGS_test_flag_10), 1.234e12f, 1e5f); |
| EXPECT_EQ(absl::GetFlag(FLAGS_test_flag_11), ""); |
| EXPECT_EQ(absl::GetFlag(FLAGS_test_flag_12), absl::Minutes(10)); |
| } |
| |
| // -------------------------------------------------------------------- |
| |
| struct NonTriviallyCopyableAggregate { |
| NonTriviallyCopyableAggregate() = default; |
| NonTriviallyCopyableAggregate(const NonTriviallyCopyableAggregate& rhs) |
| : value(rhs.value) {} |
| NonTriviallyCopyableAggregate& operator=( |
| const NonTriviallyCopyableAggregate& rhs) { |
| value = rhs.value; |
| return *this; |
| } |
| |
| int value; |
| }; |
| bool AbslParseFlag(absl::string_view src, NonTriviallyCopyableAggregate* f, |
| std::string* e) { |
| return absl::ParseFlag(src, &f->value, e); |
| } |
| std::string AbslUnparseFlag(const NonTriviallyCopyableAggregate& ntc) { |
| return absl::StrCat(ntc.value); |
| } |
| |
| bool operator==(const NonTriviallyCopyableAggregate& ntc1, |
| const NonTriviallyCopyableAggregate& ntc2) { |
| return ntc1.value == ntc2.value; |
| } |
| |
| } // namespace |
| |
| ABSL_FLAG(bool, test_flag_eb_01, {}, ""); |
| ABSL_FLAG(int32_t, test_flag_eb_02, {}, ""); |
| ABSL_FLAG(int64_t, test_flag_eb_03, {}, ""); |
| ABSL_FLAG(double, test_flag_eb_04, {}, ""); |
| ABSL_FLAG(std::string, test_flag_eb_05, {}, ""); |
| ABSL_FLAG(NonTriviallyCopyableAggregate, test_flag_eb_06, {}, ""); |
| |
| namespace { |
| |
| TEST_F(FlagTest, TestEmptyBracesDefault) { |
| EXPECT_EQ(absl::GetFlagReflectionHandle(FLAGS_test_flag_eb_01).DefaultValue(), |
| "false"); |
| EXPECT_EQ(absl::GetFlagReflectionHandle(FLAGS_test_flag_eb_02).DefaultValue(), |
| "0"); |
| EXPECT_EQ(absl::GetFlagReflectionHandle(FLAGS_test_flag_eb_03).DefaultValue(), |
| "0"); |
| EXPECT_EQ(absl::GetFlagReflectionHandle(FLAGS_test_flag_eb_04).DefaultValue(), |
| "0"); |
| EXPECT_EQ(absl::GetFlagReflectionHandle(FLAGS_test_flag_eb_05).DefaultValue(), |
| ""); |
| EXPECT_EQ(absl::GetFlagReflectionHandle(FLAGS_test_flag_eb_06).DefaultValue(), |
| "0"); |
| |
| EXPECT_EQ(absl::GetFlag(FLAGS_test_flag_eb_01), false); |
| EXPECT_EQ(absl::GetFlag(FLAGS_test_flag_eb_02), 0); |
| EXPECT_EQ(absl::GetFlag(FLAGS_test_flag_eb_03), 0); |
| EXPECT_EQ(absl::GetFlag(FLAGS_test_flag_eb_04), 0.0); |
| EXPECT_EQ(absl::GetFlag(FLAGS_test_flag_eb_05), ""); |
| EXPECT_EQ(absl::GetFlag(FLAGS_test_flag_eb_06), |
| NonTriviallyCopyableAggregate{}); |
| } |
| |
| // -------------------------------------------------------------------- |
| |
| TEST_F(FlagTest, TestGetSet) { |
| absl::SetFlag(&FLAGS_test_flag_01, false); |
| EXPECT_EQ(absl::GetFlag(FLAGS_test_flag_01), false); |
| |
| absl::SetFlag(&FLAGS_test_flag_02, 321); |
| EXPECT_EQ(absl::GetFlag(FLAGS_test_flag_02), 321); |
| |
| absl::SetFlag(&FLAGS_test_flag_03, 67); |
| EXPECT_EQ(absl::GetFlag(FLAGS_test_flag_03), 67); |
| |
| absl::SetFlag(&FLAGS_test_flag_04, 1); |
| EXPECT_EQ(absl::GetFlag(FLAGS_test_flag_04), 1); |
| |
| absl::SetFlag(&FLAGS_test_flag_05, -908); |
| EXPECT_EQ(absl::GetFlag(FLAGS_test_flag_05), -908); |
| |
| absl::SetFlag(&FLAGS_test_flag_06, 4001); |
| EXPECT_EQ(absl::GetFlag(FLAGS_test_flag_06), 4001); |
| |
| absl::SetFlag(&FLAGS_test_flag_07, -23456); |
| EXPECT_EQ(absl::GetFlag(FLAGS_test_flag_07), -23456); |
| |
| absl::SetFlag(&FLAGS_test_flag_08, 975310); |
| EXPECT_EQ(absl::GetFlag(FLAGS_test_flag_08), 975310); |
| |
| absl::SetFlag(&FLAGS_test_flag_09, 1.00001); |
| EXPECT_NEAR(absl::GetFlag(FLAGS_test_flag_09), 1.00001, 1e-10); |
| |
| absl::SetFlag(&FLAGS_test_flag_10, -3.54f); |
| EXPECT_NEAR(absl::GetFlag(FLAGS_test_flag_10), -3.54f, 1e-6f); |
| |
| absl::SetFlag(&FLAGS_test_flag_11, "asdf"); |
| EXPECT_EQ(absl::GetFlag(FLAGS_test_flag_11), "asdf"); |
| |
| absl::SetFlag(&FLAGS_test_flag_12, absl::Seconds(110)); |
| EXPECT_EQ(absl::GetFlag(FLAGS_test_flag_12), absl::Seconds(110)); |
| } |
| |
| // -------------------------------------------------------------------- |
| |
| TEST_F(FlagTest, TestGetViaReflection) { |
| auto* handle = absl::FindCommandLineFlag("test_flag_01"); |
| EXPECT_EQ(*handle->TryGet<bool>(), true); |
| handle = absl::FindCommandLineFlag("test_flag_02"); |
| EXPECT_EQ(*handle->TryGet<int>(), 1234); |
| handle = absl::FindCommandLineFlag("test_flag_03"); |
| EXPECT_EQ(*handle->TryGet<int16_t>(), -34); |
| handle = absl::FindCommandLineFlag("test_flag_04"); |
| EXPECT_EQ(*handle->TryGet<uint16_t>(), 189); |
| handle = absl::FindCommandLineFlag("test_flag_05"); |
| EXPECT_EQ(*handle->TryGet<int32_t>(), 10765); |
| handle = absl::FindCommandLineFlag("test_flag_06"); |
| EXPECT_EQ(*handle->TryGet<uint32_t>(), 40000); |
| handle = absl::FindCommandLineFlag("test_flag_07"); |
| EXPECT_EQ(*handle->TryGet<int64_t>(), -1234567); |
| handle = absl::FindCommandLineFlag("test_flag_08"); |
| EXPECT_EQ(*handle->TryGet<uint64_t>(), 9876543); |
| handle = absl::FindCommandLineFlag("test_flag_09"); |
| EXPECT_NEAR(*handle->TryGet<double>(), -9.876e-50, 1e-55); |
| handle = absl::FindCommandLineFlag("test_flag_10"); |
| EXPECT_NEAR(*handle->TryGet<float>(), 1.234e12f, 1e5f); |
| handle = absl::FindCommandLineFlag("test_flag_11"); |
| EXPECT_EQ(*handle->TryGet<std::string>(), ""); |
| handle = absl::FindCommandLineFlag("test_flag_12"); |
| EXPECT_EQ(*handle->TryGet<absl::Duration>(), absl::Minutes(10)); |
| } |
| |
| // -------------------------------------------------------------------- |
| |
| int GetDflt1() { return 1; } |
| |
| } // namespace |
| |
| ABSL_FLAG(int, test_int_flag_with_non_const_default, GetDflt1(), |
| "test int flag non const default"); |
| ABSL_FLAG(std::string, test_string_flag_with_non_const_default, |
| absl::StrCat("AAA", "BBB"), "test string flag non const default"); |
| |
| namespace { |
| |
| TEST_F(FlagTest, TestNonConstexprDefault) { |
| EXPECT_EQ(absl::GetFlag(FLAGS_test_int_flag_with_non_const_default), 1); |
| EXPECT_EQ(absl::GetFlag(FLAGS_test_string_flag_with_non_const_default), |
| "AAABBB"); |
| } |
| |
| // -------------------------------------------------------------------- |
| |
| } // namespace |
| |
| ABSL_FLAG(bool, test_flag_with_non_const_help, true, |
| absl::StrCat("test ", "flag ", "non const help")); |
| |
| namespace { |
| |
| #if !ABSL_FLAGS_STRIP_HELP |
| TEST_F(FlagTest, TestNonConstexprHelp) { |
| EXPECT_EQ( |
| absl::GetFlagReflectionHandle(FLAGS_test_flag_with_non_const_help).Help(), |
| "test flag non const help"); |
| } |
| #endif //! ABSL_FLAGS_STRIP_HELP |
| |
| // -------------------------------------------------------------------- |
| |
| int cb_test_value = -1; |
| void TestFlagCB(); |
| |
| } // namespace |
| |
| ABSL_FLAG(int, test_flag_with_cb, 100, "").OnUpdate(TestFlagCB); |
| |
| ABSL_FLAG(int, test_flag_with_lambda_cb, 200, "").OnUpdate([]() { |
| cb_test_value = absl::GetFlag(FLAGS_test_flag_with_lambda_cb) + |
| absl::GetFlag(FLAGS_test_flag_with_cb); |
| }); |
| |
| namespace { |
| |
| void TestFlagCB() { cb_test_value = absl::GetFlag(FLAGS_test_flag_with_cb); } |
| |
| // Tests side-effects of callback invocation. |
| TEST_F(FlagTest, CallbackInvocation) { |
| EXPECT_EQ(absl::GetFlag(FLAGS_test_flag_with_cb), 100); |
| EXPECT_EQ(absl::GetFlag(FLAGS_test_flag_with_lambda_cb), 200); |
| EXPECT_EQ(cb_test_value, 300); |
| |
| absl::SetFlag(&FLAGS_test_flag_with_cb, 1); |
| EXPECT_EQ(cb_test_value, 1); |
| |
| absl::SetFlag(&FLAGS_test_flag_with_lambda_cb, 3); |
| EXPECT_EQ(cb_test_value, 4); |
| } |
| |
| // -------------------------------------------------------------------- |
| |
| struct CustomUDT { |
| CustomUDT() : a(1), b(1) {} |
| CustomUDT(int a_, int b_) : a(a_), b(b_) {} |
| |
| friend bool operator==(const CustomUDT& f1, const CustomUDT& f2) { |
| return f1.a == f2.a && f1.b == f2.b; |
| } |
| |
| int a; |
| int b; |
| }; |
| bool AbslParseFlag(absl::string_view in, CustomUDT* f, std::string*) { |
| std::vector<absl::string_view> parts = |
| absl::StrSplit(in, ':', absl::SkipWhitespace()); |
| |
| if (parts.size() != 2) return false; |
| |
| if (!absl::SimpleAtoi(parts[0], &f->a)) return false; |
| |
| if (!absl::SimpleAtoi(parts[1], &f->b)) return false; |
| |
| return true; |
| } |
| std::string AbslUnparseFlag(const CustomUDT& f) { |
| return absl::StrCat(f.a, ":", f.b); |
| } |
| |
| } // namespace |
| |
| ABSL_FLAG(CustomUDT, test_flag_custom_udt, CustomUDT(), "test flag custom UDT"); |
| |
| namespace { |
| |
| TEST_F(FlagTest, TestCustomUDT) { |
| EXPECT_EQ(absl::GetFlag(FLAGS_test_flag_custom_udt), CustomUDT(1, 1)); |
| absl::SetFlag(&FLAGS_test_flag_custom_udt, CustomUDT(2, 3)); |
| EXPECT_EQ(absl::GetFlag(FLAGS_test_flag_custom_udt), CustomUDT(2, 3)); |
| } |
| |
| // MSVC produces link error on the type mismatch. |
| // Linux does not have build errors and validations work as expected. |
| #if !defined(_WIN32) && GTEST_HAS_DEATH_TEST |
| |
| using FlagDeathTest = FlagTest; |
| |
| TEST_F(FlagDeathTest, TestTypeMismatchValidations) { |
| #if !defined(NDEBUG) |
| EXPECT_DEATH_IF_SUPPORTED( |
| static_cast<void>(absl::GetFlag(FLAGS_mistyped_int_flag)), |
| "Flag 'mistyped_int_flag' is defined as one type and declared " |
| "as another"); |
| EXPECT_DEATH_IF_SUPPORTED( |
| static_cast<void>(absl::GetFlag(FLAGS_mistyped_string_flag)), |
| "Flag 'mistyped_string_flag' is defined as one type and " |
| "declared as another"); |
| #endif |
| |
| EXPECT_DEATH_IF_SUPPORTED( |
| absl::SetFlag(&FLAGS_mistyped_int_flag, 1), |
| "Flag 'mistyped_int_flag' is defined as one type and declared " |
| "as another"); |
| EXPECT_DEATH_IF_SUPPORTED( |
| absl::SetFlag(&FLAGS_mistyped_string_flag, std::vector<std::string>{}), |
| "Flag 'mistyped_string_flag' is defined as one type and declared as " |
| "another"); |
| } |
| |
| #endif |
| |
| // -------------------------------------------------------------------- |
| |
| // A contrived type that offers implicit and explicit conversion from specific |
| // source types. |
| struct ConversionTestVal { |
| ConversionTestVal() = default; |
| explicit ConversionTestVal(int a_in) : a(a_in) {} |
| |
| enum class ViaImplicitConv { kTen = 10, kEleven }; |
| // NOLINTNEXTLINE |
| ConversionTestVal(ViaImplicitConv from) : a(static_cast<int>(from)) {} |
| |
| int a; |
| }; |
| |
| bool AbslParseFlag(absl::string_view in, ConversionTestVal* val_out, |
| std::string*) { |
| if (!absl::SimpleAtoi(in, &val_out->a)) { |
| return false; |
| } |
| return true; |
| } |
| std::string AbslUnparseFlag(const ConversionTestVal& val) { |
| return absl::StrCat(val.a); |
| } |
| |
| } // namespace |
| |
| // Flag default values can be specified with a value that converts to the flag |
| // value type implicitly. |
| ABSL_FLAG(ConversionTestVal, test_flag_implicit_conv, |
| ConversionTestVal::ViaImplicitConv::kTen, |
| "test flag init via implicit conversion"); |
| |
| namespace { |
| |
| TEST_F(FlagTest, CanSetViaImplicitConversion) { |
| EXPECT_EQ(absl::GetFlag(FLAGS_test_flag_implicit_conv).a, 10); |
| absl::SetFlag(&FLAGS_test_flag_implicit_conv, |
| ConversionTestVal::ViaImplicitConv::kEleven); |
| EXPECT_EQ(absl::GetFlag(FLAGS_test_flag_implicit_conv).a, 11); |
| } |
| |
| // -------------------------------------------------------------------- |
| |
| struct NonDfltConstructible { |
| public: |
| // This constructor tests that we can initialize the flag with int value |
| NonDfltConstructible(int i) : value(i) {} // NOLINT |
| |
| // This constructor tests that we can't initialize the flag with char value |
| // but can with explicitly constructed NonDfltConstructible. |
| explicit NonDfltConstructible(char c) : value(100 + static_cast<int>(c)) {} |
| |
| int value; |
| }; |
| |
| bool AbslParseFlag(absl::string_view in, NonDfltConstructible* ndc_out, |
| std::string*) { |
| return absl::SimpleAtoi(in, &ndc_out->value); |
| } |
| std::string AbslUnparseFlag(const NonDfltConstructible& ndc) { |
| return absl::StrCat(ndc.value); |
| } |
| |
| } // namespace |
| |
| ABSL_FLAG(NonDfltConstructible, ndc_flag1, NonDfltConstructible('1'), |
| "Flag with non default constructible type"); |
| ABSL_FLAG(NonDfltConstructible, ndc_flag2, 0, |
| "Flag with non default constructible type"); |
| |
| namespace { |
| |
| TEST_F(FlagTest, TestNonDefaultConstructibleType) { |
| EXPECT_EQ(absl::GetFlag(FLAGS_ndc_flag1).value, '1' + 100); |
| EXPECT_EQ(absl::GetFlag(FLAGS_ndc_flag2).value, 0); |
| |
| absl::SetFlag(&FLAGS_ndc_flag1, NonDfltConstructible('A')); |
| absl::SetFlag(&FLAGS_ndc_flag2, 25); |
| |
| EXPECT_EQ(absl::GetFlag(FLAGS_ndc_flag1).value, 'A' + 100); |
| EXPECT_EQ(absl::GetFlag(FLAGS_ndc_flag2).value, 25); |
| } |
| |
| } // namespace |
| |
| // -------------------------------------------------------------------- |
| |
| ABSL_RETIRED_FLAG(bool, old_bool_flag, true, "old descr"); |
| ABSL_RETIRED_FLAG(int, old_int_flag, (int)std::sqrt(10), "old descr"); |
| ABSL_RETIRED_FLAG(std::string, old_str_flag, "", absl::StrCat("old ", "descr")); |
| |
| bool initializaion_order_fiasco_test = [] { |
| // Iterate over all the flags during static initialization. |
| // This should not trigger ASan's initialization-order-fiasco. |
| auto* handle1 = absl::FindCommandLineFlag("flag_on_separate_file"); |
| auto* handle2 = absl::FindCommandLineFlag("retired_flag_on_separate_file"); |
| if (handle1 != nullptr && handle2 != nullptr) { |
| return handle1->Name() == handle2->Name(); |
| } |
| return true; |
| }(); |
| |
| namespace { |
| |
| TEST_F(FlagTest, TestRetiredFlagRegistration) { |
| auto* handle = absl::FindCommandLineFlag("old_bool_flag"); |
| EXPECT_TRUE(handle->IsOfType<bool>()); |
| EXPECT_TRUE(handle->IsRetired()); |
| handle = absl::FindCommandLineFlag("old_int_flag"); |
| EXPECT_TRUE(handle->IsOfType<int>()); |
| EXPECT_TRUE(handle->IsRetired()); |
| handle = absl::FindCommandLineFlag("old_str_flag"); |
| EXPECT_TRUE(handle->IsOfType<std::string>()); |
| EXPECT_TRUE(handle->IsRetired()); |
| } |
| |
| } // namespace |
| |
| // -------------------------------------------------------------------- |
| |
| namespace { |
| |
| // User-defined type with small alignment, but size exceeding 16. |
| struct SmallAlignUDT { |
| SmallAlignUDT() : c('A'), s(12) {} |
| char c; |
| int16_t s; |
| char bytes[14]; |
| }; |
| |
| bool AbslParseFlag(absl::string_view, SmallAlignUDT*, std::string*) { |
| return true; |
| } |
| std::string AbslUnparseFlag(const SmallAlignUDT&) { return ""; } |
| |
| // User-defined type with small size, but not trivially copyable. |
| struct NonTriviallyCopyableUDT { |
| NonTriviallyCopyableUDT() : c('A') {} |
| NonTriviallyCopyableUDT(const NonTriviallyCopyableUDT& rhs) : c(rhs.c) {} |
| NonTriviallyCopyableUDT& operator=(const NonTriviallyCopyableUDT& rhs) { |
| c = rhs.c; |
| return *this; |
| } |
| |
| char c; |
| }; |
| |
| bool AbslParseFlag(absl::string_view, NonTriviallyCopyableUDT*, std::string*) { |
| return true; |
| } |
| std::string AbslUnparseFlag(const NonTriviallyCopyableUDT&) { return ""; } |
| |
| } // namespace |
| |
| ABSL_FLAG(SmallAlignUDT, test_flag_sa_udt, {}, "help"); |
| ABSL_FLAG(NonTriviallyCopyableUDT, test_flag_ntc_udt, {}, "help"); |
| |
| namespace { |
| |
| TEST_F(FlagTest, TestSmallAlignUDT) { |
| SmallAlignUDT value = absl::GetFlag(FLAGS_test_flag_sa_udt); |
| EXPECT_EQ(value.c, 'A'); |
| EXPECT_EQ(value.s, 12); |
| |
| value.c = 'B'; |
| value.s = 45; |
| absl::SetFlag(&FLAGS_test_flag_sa_udt, value); |
| value = absl::GetFlag(FLAGS_test_flag_sa_udt); |
| EXPECT_EQ(value.c, 'B'); |
| EXPECT_EQ(value.s, 45); |
| } |
| |
| TEST_F(FlagTest, TestNonTriviallyCopyableUDT) { |
| NonTriviallyCopyableUDT value = absl::GetFlag(FLAGS_test_flag_ntc_udt); |
| EXPECT_EQ(value.c, 'A'); |
| |
| value.c = 'B'; |
| absl::SetFlag(&FLAGS_test_flag_ntc_udt, value); |
| value = absl::GetFlag(FLAGS_test_flag_ntc_udt); |
| EXPECT_EQ(value.c, 'B'); |
| } |
| |
| } // namespace |