chromium/third_party/abseil-cpp/absl/flags/flag_test.cc

//
//  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 <atomic>
#include <string>
#include <thread>  // NOLINT
#include <vector>

#include "gtest/gtest.h"
#include "absl/base/attributes.h"
#include "absl/base/internal/raw_logging.h"
#include "absl/base/macros.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/parse.h"
#include "absl/flags/reflection.h"
#include "absl/flags/usage_config.h"
#include "absl/numeric/int128.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/clock.h"
#include "absl/time/time.h"
#include "absl/types/optional.h"

ABSL_DECLARE_FLAG();
ABSL_DECLARE_FLAG(std::vector<std::string>, mistyped_string_flag);

namespace {

flags;

std::string TestHelpMsg() {}
#if defined(_MSC_VER) && !defined(__clang__)
std::string TestLiteralHelpMsg() { return "literal help"; }
#endif
template <typename T>
void TestMakeDflt(void* dst) {}
void TestCallback() {}

struct UDT {};
bool AbslParseFlag(absl::string_view, UDT*, std::string*) {}
std::string AbslUnparseFlag(const UDT&) {}

class FlagTest : public testing::Test {};

struct S1 {};

struct S2 {};

TEST_F(FlagTest, Traits) {}

// --------------------------------------------------------------------

constexpr flags::FlagHelpArg help_arg{};

String;
int128;
uint128;

#define DEFINE_CONSTRUCTED_FLAG(T, dflt, dflt_kind)

DEFINE_CONSTRUCTED_FLAG();
DEFINE_CONSTRUCTED_FLAG();
DEFINE_CONSTRUCTED_FLAG();
DEFINE_CONSTRUCTED_FLAG();
DEFINE_CONSTRUCTED_FLAG();
DEFINE_CONSTRUCTED_FLAG();
DEFINE_CONSTRUCTED_FLAG();
DEFINE_CONSTRUCTED_FLAG();
DEFINE_CONSTRUCTED_FLAG();
DEFINE_CONSTRUCTED_FLAG();
DEFINE_CONSTRUCTED_FLAG();
DEFINE_CONSTRUCTED_FLAG();
DEFINE_CONSTRUCTED_FLAG();

template <typename T>
bool TestConstructionFor(const absl::Flag<T>& f1, absl::Flag<T>& f2) {}

#define TEST_CONSTRUCTED_FLAG(T)

TEST_F(FlagTest, TestConstruction) {}

// --------------------------------------------------------------------

}  // namespace

ABSL_DECLARE_FLAG(bool, test_flag_01);
ABSL_DECLARE_FLAG(int, test_flag_02);
ABSL_DECLARE_FLAG();
ABSL_DECLARE_FLAG();
ABSL_DECLARE_FLAG();
ABSL_DECLARE_FLAG();
ABSL_DECLARE_FLAG();
ABSL_DECLARE_FLAG();
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);
ABSL_DECLARE_FLAG(absl::int128, test_flag_13);
ABSL_DECLARE_FLAG(absl::uint128, test_flag_14);

namespace {

TEST_F(FlagTest, TestFlagDeclaration) {}

}  // namespace

#if ABSL_FLAGS_STRIP_NAMES
// The intent of this helper struct and an expression below is to make sure that
// in the configuration where ABSL_FLAGS_STRIP_NAMES=1 registrar construction
// (in cases of no Tail calls like OnUpdate) is constexpr and thus can and
// should be completely optimized away, thus avoiding the cost/overhead of
// static initializers.
struct VerifyConsteval {
  friend consteval flags::FlagRegistrarEmpty operator+(
      flags::FlagRegistrarEmpty, VerifyConsteval) {
    return {};
  }
};

ABSL_FLAG(int, test_registrar_const_init, 0, "") + VerifyConsteval();
#endif

// --------------------------------------------------------------------

ABSL_FLAG();
ABSL_FLAG();
ABSL_FLAG();
ABSL_FLAG();
ABSL_FLAG();
ABSL_FLAG();
ABSL_FLAG();
ABSL_FLAG();
ABSL_FLAG();
ABSL_FLAG();
ABSL_FLAG();
ABSL_FLAG();
ABSL_FLAG();
ABSL_FLAG();

namespace {

TEST_F(FlagTest, TestFlagDefinition) {}

// --------------------------------------------------------------------

TEST_F(FlagTest, TestDefault) {}

// --------------------------------------------------------------------

struct NonTriviallyCopyableAggregate {};
bool AbslParseFlag(absl::string_view src, NonTriviallyCopyableAggregate* f,
                   std::string* e) {}
std::string AbslUnparseFlag(const NonTriviallyCopyableAggregate& ntc) {}

bool operator==(const NonTriviallyCopyableAggregate& ntc1,
                const NonTriviallyCopyableAggregate& ntc2) {}

}  // namespace

ABSL_FLAG();
ABSL_FLAG();
ABSL_FLAG();
ABSL_FLAG();
ABSL_FLAG();
ABSL_FLAG();

namespace {

TEST_F(FlagTest, TestEmptyBracesDefault) {}

// --------------------------------------------------------------------

TEST_F(FlagTest, TestGetSet) {}

// --------------------------------------------------------------------

TEST_F(FlagTest, TestGetViaReflection) {}

// --------------------------------------------------------------------

TEST_F(FlagTest, ConcurrentSetAndGet) {}

// --------------------------------------------------------------------

int GetDflt1() {}

}  // namespace

ABSL_FLAG();
ABSL_FLAG();

namespace {

TEST_F(FlagTest, TestNonConstexprDefault) {}

// --------------------------------------------------------------------

}  // namespace

ABSL_FLAG();

namespace {

#if !ABSL_FLAGS_STRIP_HELP
TEST_F(FlagTest, TestNonConstexprHelp) {}
#endif  //! ABSL_FLAGS_STRIP_HELP

// --------------------------------------------------------------------

int cb_test_value =;
void TestFlagCB();

}  // namespace

ABSL_FLAG();

ABSL_FLAG();

namespace {

void TestFlagCB() {}

// Tests side-effects of callback invocation.
TEST_F(FlagTest, CallbackInvocation) {}

// --------------------------------------------------------------------

struct CustomUDT {};
bool AbslParseFlag(absl::string_view in, CustomUDT* f, std::string*) {}
std::string AbslUnparseFlag(const CustomUDT& f) {}

}  // namespace

ABSL_FLAG();

namespace {

TEST_F(FlagTest, TestCustomUDT) {}

// 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
FlagDeathTest;

TEST_F(FlagDeathTest, TestTypeMismatchValidations) {}

#endif

// --------------------------------------------------------------------

// A contrived type that offers implicit and explicit conversion from specific
// source types.
struct ConversionTestVal {};

bool AbslParseFlag(absl::string_view in, ConversionTestVal* val_out,
                   std::string*) {}
std::string AbslUnparseFlag(const ConversionTestVal& val) {}

}  // namespace

// Flag default values can be specified with a value that converts to the flag
// value type implicitly.
ABSL_FLAG();

namespace {

TEST_F(FlagTest, CanSetViaImplicitConversion) {}

// --------------------------------------------------------------------

struct NonDfltConstructible {};

bool AbslParseFlag(absl::string_view in, NonDfltConstructible* ndc_out,
                   std::string*) {}
std::string AbslUnparseFlag(const NonDfltConstructible& ndc) {}

}  // namespace

ABSL_FLAG();
ABSL_FLAG();

namespace {

TEST_F(FlagTest, TestNonDefaultConstructibleType) {}

}  // namespace

// --------------------------------------------------------------------

ABSL_RETIRED_FLAG();
ABSL_RETIRED_FLAG();
ABSL_RETIRED_FLAG();

namespace {

bool initialization_order_fiasco_test ABSL_ATTRIBUTE_UNUSED =auto* handle1 =auto* handle2 =;

TEST_F(FlagTest, TestRetiredFlagRegistration) {}

}  // namespace

// --------------------------------------------------------------------

namespace {

// User-defined type with small alignment, but size exceeding 16.
struct SmallAlignUDT {};

bool AbslParseFlag(absl::string_view, SmallAlignUDT*, std::string*) {}
std::string AbslUnparseFlag(const SmallAlignUDT&) {}

}  // namespace

ABSL_FLAG();

namespace {

TEST_F(FlagTest, TestSmallAlignUDT) {}
}  // namespace

// --------------------------------------------------------------------

namespace {

// User-defined not trivially copyable type.
template <int id>
struct NonTriviallyCopyableUDT {};

template <int id>
uint64_t NonTriviallyCopyableUDT<id>::s_num_instance =;

template <int id>
bool AbslParseFlag(absl::string_view txt, NonTriviallyCopyableUDT<id>* f,
                   std::string*) {}
template <int id>
std::string AbslUnparseFlag(const NonTriviallyCopyableUDT<id>&) {}

template <int id, typename F>
void TestExpectedLeaks(
    F&& f, uint64_t num_leaks,
    absl::optional<uint64_t> num_new_instances = absl::nullopt) {}
}  // namespace

ABSL_FLAG();
ABSL_FLAG();
ABSL_FLAG();
ABSL_FLAG();
ABSL_FLAG();

namespace {

TEST_F(FlagTest, TestNonTriviallyCopyableGetSetSet) {}

TEST_F(FlagTest, TestNonTriviallyCopyableParseSet) {}

TEST_F(FlagTest, TestNonTriviallyCopyableSet) {}

// One new instance created during initialization and stored in the flag.
auto premain_utd4_get =;

TEST_F(FlagTest, TestNonTriviallyCopyableGetBeforeMainParseGet) {}

// One new instance created during initialization, which is reused since it was
// never read.
auto premain_utd5_set =<5> value;
                               value.c =;

TEST_F(FlagTest, TestNonTriviallyCopyableSetParseGet) {}

}  // namespace

// --------------------------------------------------------------------

namespace {

enum TestE {};

struct EnumWrapper {};

bool AbslParseFlag(absl::string_view, EnumWrapper*, std::string*) {}
std::string AbslUnparseFlag(const EnumWrapper&) {}

}  // namespace

ABSL_FLAG();

TEST_F(FlagTest, TesTypeWrappingEnum) {}

// This is a compile test to ensure macros are expanded within ABSL_FLAG and
// ABSL_DECLARE_FLAG.
#define FLAG_NAME_MACRO(name)
ABSL_DECLARE_FLAG(int, FLAG_NAME_MACRO(test_macro_named_flag));
ABSL_FLAG();

TEST_F(FlagTest, MacroWithinAbslFlag) {}

// --------------------------------------------------------------------

ABSL_FLAG();
ABSL_FLAG();
ABSL_FLAG();
ABSL_FLAG();
ABSL_FLAG();
ABSL_FLAG();
#if defined(ABSL_HAVE_STD_OPTIONAL) && !defined(ABSL_USES_STD_OPTIONAL)
ABSL_FLAG(std::optional<int64_t>, std_optional_int64, std::nullopt, "help");
#endif

namespace {

TEST_F(FlagTest, TestOptionalBool) {}

// --------------------------------------------------------------------

TEST_F(FlagTest, TestOptionalInt) {}

// --------------------------------------------------------------------

TEST_F(FlagTest, TestOptionalDouble) {}

// --------------------------------------------------------------------

TEST_F(FlagTest, TestOptionalString) {}

// --------------------------------------------------------------------

TEST_F(FlagTest, TestOptionalDuration) {}

// --------------------------------------------------------------------

TEST_F(FlagTest, TestOptionalOptional) {}

// --------------------------------------------------------------------

#if defined(ABSL_HAVE_STD_OPTIONAL) && !defined(ABSL_USES_STD_OPTIONAL)

TEST_F(FlagTest, TestStdOptional) {
  EXPECT_FALSE(absl::GetFlag(FLAGS_std_optional_int64).has_value());
  EXPECT_EQ(absl::GetFlag(FLAGS_std_optional_int64), std::nullopt);

  absl::SetFlag(&FLAGS_std_optional_int64, 0);
  EXPECT_TRUE(absl::GetFlag(FLAGS_std_optional_int64).has_value());
  EXPECT_EQ(absl::GetFlag(FLAGS_std_optional_int64), 0);

  absl::SetFlag(&FLAGS_std_optional_int64, 0xFFFFFFFFFF16);
  EXPECT_TRUE(absl::GetFlag(FLAGS_std_optional_int64).has_value());
  EXPECT_EQ(absl::GetFlag(FLAGS_std_optional_int64), 0xFFFFFFFFFF16);

  absl::SetFlag(&FLAGS_std_optional_int64, std::nullopt);
  EXPECT_FALSE(absl::GetFlag(FLAGS_std_optional_int64).has_value());
  EXPECT_EQ(absl::GetFlag(FLAGS_std_optional_int64), std::nullopt);
}

// --------------------------------------------------------------------

#endif

}  // namespace