1 // Copyright 2018 The Chromium Authors
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 #include "base/traits_bag.h"
7 #include "testing/gmock/include/gmock/gmock.h"
8 #include "third_party/abseil-cpp/absl/types/optional.h"
11 namespace trait_helpers {
14 struct ExampleTrait {};
16 struct ExampleTrait2 {};
18 enum class EnumTraitA { A, B, C };
20 enum class EnumTraitB { ONE, TWO };
23 // List of traits that are valid inputs for the constructor below.
25 ValidTrait(ExampleTrait);
26 ValidTrait(EnumTraitA);
27 ValidTrait(EnumTraitB);
30 template <class... ArgTypes,
31 class CheckArgumentsAreValid = std::enable_if_t<
32 trait_helpers::AreValidTraits<ValidTrait, ArgTypes...>::value>>
33 constexpr TestTraits(ArgTypes... args)
34 : has_example_trait(trait_helpers::HasTrait<ExampleTrait, ArgTypes...>()),
36 trait_helpers::GetEnum<EnumTraitA, EnumTraitA::A>(args...)),
38 trait_helpers::GetEnum<EnumTraitB, EnumTraitB::ONE>(args...)) {}
40 const bool has_example_trait;
41 const EnumTraitA enum_trait_a;
42 const EnumTraitB enum_trait_b;
45 // Like TestTraits, except ExampleTrait is filtered away.
46 struct FilteredTestTraits : public TestTraits {
47 template <class... ArgTypes,
48 class CheckArgumentsAreValid = std::enable_if_t<
49 trait_helpers::AreValidTraits<ValidTrait, ArgTypes...>::value>>
50 constexpr FilteredTestTraits(ArgTypes... args)
51 : TestTraits(Exclude<ExampleTrait>::Filter(args)...) {}
54 struct RequiredEnumTestTraits {
55 // List of traits that are required inputs for the constructor below.
57 ValidTrait(EnumTraitA);
60 // We require EnumTraitA to be specified.
61 template <class... ArgTypes,
62 class CheckArgumentsAreValid = std::enable_if_t<
63 trait_helpers::AreValidTraits<ValidTrait, ArgTypes...>::value>>
64 constexpr RequiredEnumTestTraits(ArgTypes... args)
65 : enum_trait_a(trait_helpers::GetEnum<EnumTraitA>(args...)) {}
67 const EnumTraitA enum_trait_a;
70 struct OptionalEnumTestTraits {
71 // List of traits that are optional inputs for the constructor below.
73 ValidTrait(EnumTraitA);
76 // EnumTraitA can optionally be specified.
77 template <class... ArgTypes,
78 class CheckArgumentsAreValid = std::enable_if_t<
79 trait_helpers::AreValidTraits<ValidTrait, ArgTypes...>::value>>
80 constexpr OptionalEnumTestTraits(ArgTypes... args)
81 : enum_trait_a(trait_helpers::GetOptionalEnum<EnumTraitA>(args...)) {}
83 const absl::optional<EnumTraitA> enum_trait_a;
88 TEST(TraitsBagTest, DefaultConstructor) {
89 constexpr TestTraits trait_test_class;
91 EXPECT_FALSE(trait_test_class.has_example_trait);
94 TEST(TraitsBagTest, HasTrait) {
95 constexpr TestTraits with_trait(ExampleTrait{});
96 constexpr TestTraits without_trait;
98 EXPECT_TRUE(with_trait.has_example_trait);
99 EXPECT_FALSE(without_trait.has_example_trait);
102 TEST(TraitsBagTest, GetEnumWithDefault) {
103 constexpr TestTraits defaults;
105 EXPECT_EQ(defaults.enum_trait_a, EnumTraitA::A);
106 EXPECT_EQ(defaults.enum_trait_b, EnumTraitB::ONE);
108 constexpr TestTraits a(EnumTraitA::A);
109 constexpr TestTraits b(EnumTraitA::B);
110 constexpr TestTraits c(EnumTraitA::C);
112 EXPECT_EQ(a.enum_trait_a, EnumTraitA::A);
113 EXPECT_EQ(a.enum_trait_b, EnumTraitB::ONE);
115 EXPECT_EQ(b.enum_trait_a, EnumTraitA::B);
116 EXPECT_EQ(b.enum_trait_b, EnumTraitB::ONE);
118 EXPECT_EQ(c.enum_trait_a, EnumTraitA::C);
119 EXPECT_EQ(c.enum_trait_b, EnumTraitB::ONE);
121 constexpr TestTraits a_one(EnumTraitA::A, EnumTraitB::ONE);
122 constexpr TestTraits b_one(EnumTraitA::B, EnumTraitB::ONE);
123 constexpr TestTraits c_one(EnumTraitA::C, EnumTraitB::ONE);
125 EXPECT_EQ(a_one.enum_trait_a, EnumTraitA::A);
126 EXPECT_EQ(a_one.enum_trait_b, EnumTraitB::ONE);
128 EXPECT_EQ(b_one.enum_trait_a, EnumTraitA::B);
129 EXPECT_EQ(b_one.enum_trait_b, EnumTraitB::ONE);
131 EXPECT_EQ(c_one.enum_trait_a, EnumTraitA::C);
132 EXPECT_EQ(c_one.enum_trait_b, EnumTraitB::ONE);
134 constexpr TestTraits a_two(EnumTraitA::A, EnumTraitB::TWO);
135 constexpr TestTraits b_two(EnumTraitA::B, EnumTraitB::TWO);
136 constexpr TestTraits c_two(EnumTraitA::C, EnumTraitB::TWO);
138 EXPECT_EQ(a_two.enum_trait_a, EnumTraitA::A);
139 EXPECT_EQ(a_two.enum_trait_b, EnumTraitB::TWO);
141 EXPECT_EQ(b_two.enum_trait_a, EnumTraitA::B);
142 EXPECT_EQ(b_two.enum_trait_b, EnumTraitB::TWO);
144 EXPECT_EQ(c_two.enum_trait_a, EnumTraitA::C);
145 EXPECT_EQ(c_two.enum_trait_b, EnumTraitB::TWO);
148 TEST(TraitsBagTest, RequiredEnum) {
149 constexpr RequiredEnumTestTraits a(EnumTraitA::A);
150 constexpr RequiredEnumTestTraits b(EnumTraitA::B);
151 constexpr RequiredEnumTestTraits c(EnumTraitA::C);
153 EXPECT_EQ(a.enum_trait_a, EnumTraitA::A);
154 EXPECT_EQ(b.enum_trait_a, EnumTraitA::B);
155 EXPECT_EQ(c.enum_trait_a, EnumTraitA::C);
158 TEST(TraitsBagTest, OptionalEnum) {
159 constexpr OptionalEnumTestTraits not_set;
160 constexpr OptionalEnumTestTraits set(EnumTraitA::B);
162 EXPECT_FALSE(not_set.enum_trait_a.has_value());
163 ASSERT_TRUE(set.enum_trait_a.has_value());
164 EXPECT_EQ(*set.enum_trait_a, EnumTraitA::B);
167 TEST(TraitsBagTest, ValidTraitInheritance) {
168 struct ValidTraitsA {
169 ValidTraitsA(EnumTraitA);
172 struct ValidTraitsB {
173 ValidTraitsB(ValidTraitsA);
174 ValidTraitsB(EnumTraitB);
177 static_assert(AreValidTraits<ValidTraitsA, EnumTraitA>(), "");
178 static_assert(AreValidTraits<ValidTraitsB, EnumTraitA, EnumTraitB>(), "");
181 TEST(TraitsBagTest, Filtering) {
182 using Predicate = Exclude<ExampleTrait, EnumTraitA>;
183 static_assert(std::is_same_v<ExampleTrait2,
184 decltype(Predicate::Filter(ExampleTrait2{}))>,
185 "ExampleTrait2 should not be filtered");
188 std::is_same_v<EmptyTrait, decltype(Predicate::Filter(ExampleTrait{}))>,
189 "ExampleTrait should be filtered");
192 std::is_same_v<EmptyTrait, decltype(Predicate::Filter(EnumTraitA::A))>,
193 "EnumTraitA should be filtered");
196 std::is_same_v<EnumTraitB, decltype(Predicate::Filter(EnumTraitB::TWO))>,
197 "EnumTraitB should not be filtered");
200 std::is_same_v<EmptyTrait, decltype(Predicate::Filter(EmptyTrait{}))>,
201 "EmptyTrait should not be filtered");
204 TEST(TraitsBagTest, FilteredTestTraits) {
205 FilteredTestTraits filtered(ExampleTrait(), EnumTraitA::C, EnumTraitB::TWO);
207 // ExampleTrait should have been filtered away.
208 EXPECT_FALSE(filtered.has_example_trait);
210 // The other traits should have been set however.
211 EXPECT_EQ(filtered.enum_trait_a, EnumTraitA::C);
212 EXPECT_EQ(filtered.enum_trait_b, EnumTraitB::TWO);
215 TEST(TraitsBagTest, EmptyTraitIsValid) {
216 static_assert(IsValidTrait<TestTraits::ValidTrait, EmptyTrait>(), "");
219 } // namespace trait_helpers