// Copyright 2018 The Chromium Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. #include "base/traits_bag.h" #include "testing/gmock/include/gmock/gmock.h" #include "third_party/abseil-cpp/absl/types/optional.h" namespace base { namespace trait_helpers { namespace { struct ExampleTrait {}; struct ExampleTrait2 {}; enum class EnumTraitA { A, B, C }; enum class EnumTraitB { ONE, TWO }; struct TestTraits { // List of traits that are valid inputs for the constructor below. struct ValidTrait { ValidTrait(ExampleTrait); ValidTrait(EnumTraitA); ValidTrait(EnumTraitB); }; template ::value>> constexpr TestTraits(ArgTypes... args) : has_example_trait(trait_helpers::HasTrait()), enum_trait_a( trait_helpers::GetEnum(args...)), enum_trait_b( trait_helpers::GetEnum(args...)) {} const bool has_example_trait; const EnumTraitA enum_trait_a; const EnumTraitB enum_trait_b; }; // Like TestTraits, except ExampleTrait is filtered away. struct FilteredTestTraits : public TestTraits { template ::value>> constexpr FilteredTestTraits(ArgTypes... args) : TestTraits(Exclude::Filter(args)...) {} }; struct RequiredEnumTestTraits { // List of traits that are required inputs for the constructor below. struct ValidTrait { ValidTrait(EnumTraitA); }; // We require EnumTraitA to be specified. template ::value>> constexpr RequiredEnumTestTraits(ArgTypes... args) : enum_trait_a(trait_helpers::GetEnum(args...)) {} const EnumTraitA enum_trait_a; }; struct OptionalEnumTestTraits { // List of traits that are optional inputs for the constructor below. struct ValidTrait { ValidTrait(EnumTraitA); }; // EnumTraitA can optionally be specified. template ::value>> constexpr OptionalEnumTestTraits(ArgTypes... args) : enum_trait_a(trait_helpers::GetOptionalEnum(args...)) {} const absl::optional enum_trait_a; }; } // namespace TEST(TraitsBagTest, DefaultConstructor) { constexpr TestTraits trait_test_class; EXPECT_FALSE(trait_test_class.has_example_trait); } TEST(TraitsBagTest, HasTrait) { constexpr TestTraits with_trait(ExampleTrait{}); constexpr TestTraits without_trait; EXPECT_TRUE(with_trait.has_example_trait); EXPECT_FALSE(without_trait.has_example_trait); } TEST(TraitsBagTest, GetEnumWithDefault) { constexpr TestTraits defaults; EXPECT_EQ(defaults.enum_trait_a, EnumTraitA::A); EXPECT_EQ(defaults.enum_trait_b, EnumTraitB::ONE); constexpr TestTraits a(EnumTraitA::A); constexpr TestTraits b(EnumTraitA::B); constexpr TestTraits c(EnumTraitA::C); EXPECT_EQ(a.enum_trait_a, EnumTraitA::A); EXPECT_EQ(a.enum_trait_b, EnumTraitB::ONE); EXPECT_EQ(b.enum_trait_a, EnumTraitA::B); EXPECT_EQ(b.enum_trait_b, EnumTraitB::ONE); EXPECT_EQ(c.enum_trait_a, EnumTraitA::C); EXPECT_EQ(c.enum_trait_b, EnumTraitB::ONE); constexpr TestTraits a_one(EnumTraitA::A, EnumTraitB::ONE); constexpr TestTraits b_one(EnumTraitA::B, EnumTraitB::ONE); constexpr TestTraits c_one(EnumTraitA::C, EnumTraitB::ONE); EXPECT_EQ(a_one.enum_trait_a, EnumTraitA::A); EXPECT_EQ(a_one.enum_trait_b, EnumTraitB::ONE); EXPECT_EQ(b_one.enum_trait_a, EnumTraitA::B); EXPECT_EQ(b_one.enum_trait_b, EnumTraitB::ONE); EXPECT_EQ(c_one.enum_trait_a, EnumTraitA::C); EXPECT_EQ(c_one.enum_trait_b, EnumTraitB::ONE); constexpr TestTraits a_two(EnumTraitA::A, EnumTraitB::TWO); constexpr TestTraits b_two(EnumTraitA::B, EnumTraitB::TWO); constexpr TestTraits c_two(EnumTraitA::C, EnumTraitB::TWO); EXPECT_EQ(a_two.enum_trait_a, EnumTraitA::A); EXPECT_EQ(a_two.enum_trait_b, EnumTraitB::TWO); EXPECT_EQ(b_two.enum_trait_a, EnumTraitA::B); EXPECT_EQ(b_two.enum_trait_b, EnumTraitB::TWO); EXPECT_EQ(c_two.enum_trait_a, EnumTraitA::C); EXPECT_EQ(c_two.enum_trait_b, EnumTraitB::TWO); } TEST(TraitsBagTest, RequiredEnum) { constexpr RequiredEnumTestTraits a(EnumTraitA::A); constexpr RequiredEnumTestTraits b(EnumTraitA::B); constexpr RequiredEnumTestTraits c(EnumTraitA::C); EXPECT_EQ(a.enum_trait_a, EnumTraitA::A); EXPECT_EQ(b.enum_trait_a, EnumTraitA::B); EXPECT_EQ(c.enum_trait_a, EnumTraitA::C); } TEST(TraitsBagTest, OptionalEnum) { constexpr OptionalEnumTestTraits not_set; constexpr OptionalEnumTestTraits set(EnumTraitA::B); EXPECT_FALSE(not_set.enum_trait_a.has_value()); ASSERT_TRUE(set.enum_trait_a.has_value()); EXPECT_EQ(*set.enum_trait_a, EnumTraitA::B); } TEST(TraitsBagTest, ValidTraitInheritance) { struct ValidTraitsA { ValidTraitsA(EnumTraitA); }; struct ValidTraitsB { ValidTraitsB(ValidTraitsA); ValidTraitsB(EnumTraitB); }; static_assert(AreValidTraits(), ""); static_assert(AreValidTraits(), ""); } TEST(TraitsBagTest, Filtering) { using Predicate = Exclude; static_assert( std::is_same::value, "ExampleTrait2 should not be filtered"); static_assert( std::is_same::value, "ExampleTrait should be filtered"); static_assert(std::is_same::value, "EnumTraitA should be filtered"); static_assert( std::is_same::value, "EnumTraitB should not be filtered"); static_assert(std::is_same::value, "EmptyTrait should not be filtered"); } TEST(TraitsBagTest, FilteredTestTraits) { FilteredTestTraits filtered(ExampleTrait(), EnumTraitA::C, EnumTraitB::TWO); // ExampleTrait should have been filtered away. EXPECT_FALSE(filtered.has_example_trait); // The other traits should have been set however. EXPECT_EQ(filtered.enum_trait_a, EnumTraitA::C); EXPECT_EQ(filtered.enum_trait_b, EnumTraitB::TWO); } TEST(TraitsBagTest, EmptyTraitIsValid) { static_assert(IsValidTrait(), ""); } } // namespace trait_helpers } // namespace base