about summary refs log tree commit diff
path: root/third_party/abseil_cpp/absl/flags/flag_test.cc
diff options
context:
space:
mode:
Diffstat (limited to 'third_party/abseil_cpp/absl/flags/flag_test.cc')
-rw-r--r--third_party/abseil_cpp/absl/flags/flag_test.cc783
1 files changed, 783 insertions, 0 deletions
diff --git a/third_party/abseil_cpp/absl/flags/flag_test.cc b/third_party/abseil_cpp/absl/flags/flag_test.cc
new file mode 100644
index 000000000000..416a31e5232a
--- /dev/null
+++ b/third_party/abseil_cpp/absl/flags/flag_test.cc
@@ -0,0 +1,783 @@
+//
+//  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 <stdint.h>
+
+#include <cmath>
+#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/commandlineflag.h"
+#include "absl/flags/internal/flag.h"
+#include "absl/flags/internal/registry.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"; }
+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);
+  }
+  flags::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;
+
+#define DEFINE_CONSTRUCTED_FLAG(T, dflt, dflt_kind)                      \
+  constexpr flags::FlagDefaultArg f1default##T{                          \
+      flags::FlagDefaultSrc{dflt}, flags::FlagDefaultKind::dflt_kind};   \
+  constexpr flags::Flag<T> f1##T("f1", "file", help_arg, f1default##T);  \
+  ABSL_CONST_INIT flags::Flag<T> f2##T(                                  \
+      "f2", "file",                                                      \
+      {flags::FlagHelpMsg(&TestHelpMsg), flags::FlagHelpKind::kGenFunc}, \
+      flags::FlagDefaultArg{flags::FlagDefaultSrc(&TestMakeDflt<T>),     \
+                            flags::FlagDefaultKind::kGenFunc})
+
+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 flags::Flag<T>& f1, flags::Flag<T>* f2) {
+  EXPECT_EQ(f1.Name(), "f1");
+  EXPECT_EQ(f1.Help(), "literal help");
+  EXPECT_EQ(f1.Filename(), "file");
+
+  flags::FlagRegistrar<T, false>(f2).OnUpdate(TestCallback);
+
+  EXPECT_EQ(f2->Name(), "f2");
+  EXPECT_EQ(f2->Help(), "dynamic help");
+  EXPECT_EQ(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(FLAGS_test_flag_01.Name(), "test_flag_01");
+  EXPECT_EQ(FLAGS_test_flag_02.Name(), "test_flag_02");
+  EXPECT_EQ(FLAGS_test_flag_03.Name(), "test_flag_03");
+  EXPECT_EQ(FLAGS_test_flag_04.Name(), "test_flag_04");
+  EXPECT_EQ(FLAGS_test_flag_05.Name(), "test_flag_05");
+  EXPECT_EQ(FLAGS_test_flag_06.Name(), "test_flag_06");
+  EXPECT_EQ(FLAGS_test_flag_07.Name(), "test_flag_07");
+  EXPECT_EQ(FLAGS_test_flag_08.Name(), "test_flag_08");
+  EXPECT_EQ(FLAGS_test_flag_09.Name(), "test_flag_09");
+  EXPECT_EQ(FLAGS_test_flag_10.Name(), "test_flag_10");
+  EXPECT_EQ(FLAGS_test_flag_11.Name(), "test_flag_11");
+  EXPECT_EQ(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(FLAGS_test_flag_01.Name(), "test_flag_01");
+  EXPECT_EQ(FLAGS_test_flag_01.Help(), "test flag 01");
+  EXPECT_TRUE(absl::EndsWith(FLAGS_test_flag_01.Filename(), expected_file_name))
+      << FLAGS_test_flag_01.Filename();
+
+  EXPECT_EQ(FLAGS_test_flag_02.Name(), "test_flag_02");
+  EXPECT_EQ(FLAGS_test_flag_02.Help(), "test flag 02");
+  EXPECT_TRUE(absl::EndsWith(FLAGS_test_flag_02.Filename(), expected_file_name))
+      << FLAGS_test_flag_02.Filename();
+
+  EXPECT_EQ(FLAGS_test_flag_03.Name(), "test_flag_03");
+  EXPECT_EQ(FLAGS_test_flag_03.Help(), "test flag 03");
+  EXPECT_TRUE(absl::EndsWith(FLAGS_test_flag_03.Filename(), expected_file_name))
+      << FLAGS_test_flag_03.Filename();
+
+  EXPECT_EQ(FLAGS_test_flag_04.Name(), "test_flag_04");
+  EXPECT_EQ(FLAGS_test_flag_04.Help(), "test flag 04");
+  EXPECT_TRUE(absl::EndsWith(FLAGS_test_flag_04.Filename(), expected_file_name))
+      << FLAGS_test_flag_04.Filename();
+
+  EXPECT_EQ(FLAGS_test_flag_05.Name(), "test_flag_05");
+  EXPECT_EQ(FLAGS_test_flag_05.Help(), "test flag 05");
+  EXPECT_TRUE(absl::EndsWith(FLAGS_test_flag_05.Filename(), expected_file_name))
+      << FLAGS_test_flag_05.Filename();
+
+  EXPECT_EQ(FLAGS_test_flag_06.Name(), "test_flag_06");
+  EXPECT_EQ(FLAGS_test_flag_06.Help(), "test flag 06");
+  EXPECT_TRUE(absl::EndsWith(FLAGS_test_flag_06.Filename(), expected_file_name))
+      << FLAGS_test_flag_06.Filename();
+
+  EXPECT_EQ(FLAGS_test_flag_07.Name(), "test_flag_07");
+  EXPECT_EQ(FLAGS_test_flag_07.Help(), "test flag 07");
+  EXPECT_TRUE(absl::EndsWith(FLAGS_test_flag_07.Filename(), expected_file_name))
+      << FLAGS_test_flag_07.Filename();
+
+  EXPECT_EQ(FLAGS_test_flag_08.Name(), "test_flag_08");
+  EXPECT_EQ(FLAGS_test_flag_08.Help(), "test flag 08");
+  EXPECT_TRUE(absl::EndsWith(FLAGS_test_flag_08.Filename(), expected_file_name))
+      << FLAGS_test_flag_08.Filename();
+
+  EXPECT_EQ(FLAGS_test_flag_09.Name(), "test_flag_09");
+  EXPECT_EQ(FLAGS_test_flag_09.Help(), "test flag 09");
+  EXPECT_TRUE(absl::EndsWith(FLAGS_test_flag_09.Filename(), expected_file_name))
+      << FLAGS_test_flag_09.Filename();
+
+  EXPECT_EQ(FLAGS_test_flag_10.Name(), "test_flag_10");
+  EXPECT_EQ(FLAGS_test_flag_10.Help(), "test flag 10");
+  EXPECT_TRUE(absl::EndsWith(FLAGS_test_flag_10.Filename(), expected_file_name))
+      << FLAGS_test_flag_10.Filename();
+
+  EXPECT_EQ(FLAGS_test_flag_11.Name(), "test_flag_11");
+  EXPECT_EQ(FLAGS_test_flag_11.Help(), "test flag 11");
+  EXPECT_TRUE(absl::EndsWith(FLAGS_test_flag_11.Filename(), expected_file_name))
+      << FLAGS_test_flag_11.Filename();
+
+  EXPECT_EQ(FLAGS_test_flag_12.Name(), "test_flag_12");
+  EXPECT_EQ(FLAGS_test_flag_12.Help(), "test flag 12");
+  EXPECT_TRUE(absl::EndsWith(FLAGS_test_flag_12.Filename(), expected_file_name))
+      << FLAGS_test_flag_12.Filename();
+}
+#endif  // !ABSL_FLAGS_STRIP_NAMES
+
+// --------------------------------------------------------------------
+
+TEST_F(FlagTest, TestDefault) {
+  EXPECT_EQ(FLAGS_test_flag_01.DefaultValue(), "true");
+  EXPECT_EQ(FLAGS_test_flag_02.DefaultValue(), "1234");
+  EXPECT_EQ(FLAGS_test_flag_03.DefaultValue(), "-34");
+  EXPECT_EQ(FLAGS_test_flag_04.DefaultValue(), "189");
+  EXPECT_EQ(FLAGS_test_flag_05.DefaultValue(), "10765");
+  EXPECT_EQ(FLAGS_test_flag_06.DefaultValue(), "40000");
+  EXPECT_EQ(FLAGS_test_flag_07.DefaultValue(), "-1234567");
+  EXPECT_EQ(FLAGS_test_flag_08.DefaultValue(), "9876543");
+  EXPECT_EQ(FLAGS_test_flag_09.DefaultValue(), "-9.876e-50");
+  EXPECT_EQ(FLAGS_test_flag_10.DefaultValue(), "1.234e+12");
+  EXPECT_EQ(FLAGS_test_flag_11.DefaultValue(), "");
+  EXPECT_EQ(FLAGS_test_flag_12.DefaultValue(), "10m");
+
+  EXPECT_EQ(FLAGS_test_flag_01.CurrentValue(), "true");
+  EXPECT_EQ(FLAGS_test_flag_02.CurrentValue(), "1234");
+  EXPECT_EQ(FLAGS_test_flag_03.CurrentValue(), "-34");
+  EXPECT_EQ(FLAGS_test_flag_04.CurrentValue(), "189");
+  EXPECT_EQ(FLAGS_test_flag_05.CurrentValue(), "10765");
+  EXPECT_EQ(FLAGS_test_flag_06.CurrentValue(), "40000");
+  EXPECT_EQ(FLAGS_test_flag_07.CurrentValue(), "-1234567");
+  EXPECT_EQ(FLAGS_test_flag_08.CurrentValue(), "9876543");
+  EXPECT_EQ(FLAGS_test_flag_09.CurrentValue(), "-9.876e-50");
+  EXPECT_EQ(FLAGS_test_flag_10.CurrentValue(), "1.234e+12");
+  EXPECT_EQ(FLAGS_test_flag_11.CurrentValue(), "");
+  EXPECT_EQ(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(FLAGS_test_flag_eb_01.DefaultValue(), "false");
+  EXPECT_EQ(FLAGS_test_flag_eb_02.DefaultValue(), "0");
+  EXPECT_EQ(FLAGS_test_flag_eb_03.DefaultValue(), "0");
+  EXPECT_EQ(FLAGS_test_flag_eb_04.DefaultValue(), "0");
+  EXPECT_EQ(FLAGS_test_flag_eb_05.DefaultValue(), "");
+  EXPECT_EQ(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 = flags::FindCommandLineFlag("test_flag_01");
+  EXPECT_EQ(*handle->TryGet<bool>(), true);
+  handle = flags::FindCommandLineFlag("test_flag_02");
+  EXPECT_EQ(*handle->TryGet<int>(), 1234);
+  handle = flags::FindCommandLineFlag("test_flag_03");
+  EXPECT_EQ(*handle->TryGet<int16_t>(), -34);
+  handle = flags::FindCommandLineFlag("test_flag_04");
+  EXPECT_EQ(*handle->TryGet<uint16_t>(), 189);
+  handle = flags::FindCommandLineFlag("test_flag_05");
+  EXPECT_EQ(*handle->TryGet<int32_t>(), 10765);
+  handle = flags::FindCommandLineFlag("test_flag_06");
+  EXPECT_EQ(*handle->TryGet<uint32_t>(), 40000);
+  handle = flags::FindCommandLineFlag("test_flag_07");
+  EXPECT_EQ(*handle->TryGet<int64_t>(), -1234567);
+  handle = flags::FindCommandLineFlag("test_flag_08");
+  EXPECT_EQ(*handle->TryGet<uint64_t>(), 9876543);
+  handle = flags::FindCommandLineFlag("test_flag_09");
+  EXPECT_NEAR(*handle->TryGet<double>(), -9.876e-50, 1e-55);
+  handle = flags::FindCommandLineFlag("test_flag_10");
+  EXPECT_NEAR(*handle->TryGet<float>(), 1.234e12f, 1e5f);
+  handle = flags::FindCommandLineFlag("test_flag_11");
+  EXPECT_EQ(*handle->TryGet<std::string>(), "");
+  handle = flags::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(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"));
+
+namespace {
+
+TEST_F(FlagTest, TestRetiredFlagRegistration) {
+  bool is_bool = false;
+  EXPECT_TRUE(flags::IsRetiredFlag("old_bool_flag", &is_bool));
+  EXPECT_TRUE(is_bool);
+  EXPECT_TRUE(flags::IsRetiredFlag("old_int_flag", &is_bool));
+  EXPECT_FALSE(is_bool);
+  EXPECT_TRUE(flags::IsRetiredFlag("old_str_flag", &is_bool));
+  EXPECT_FALSE(is_bool);
+  EXPECT_FALSE(flags::IsRetiredFlag("some_other_flag", &is_bool));
+}
+
+}  // 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