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.
4
5 #include "base/traits_bag.h"
6
7 #include "testing/gmock/include/gmock/gmock.h"
8 #include "third_party/abseil-cpp/absl/types/optional.h"
9
10 namespace base {
11 namespace trait_helpers {
12 namespace {
13
14 struct ExampleTrait {};
15
16 struct ExampleTrait2 {};
17
18 enum class EnumTraitA { A, B, C };
19
20 enum class EnumTraitB { ONE, TWO };
21
22 struct TestTraits {
23 // List of traits that are valid inputs for the constructor below.
24 struct ValidTrait {
25 ValidTrait(ExampleTrait);
26 ValidTrait(EnumTraitA);
27 ValidTrait(EnumTraitB);
28 };
29
30 template <class... ArgTypes>
31 requires trait_helpers::AreValidTraits<ValidTrait, ArgTypes...>
TestTraitsbase::trait_helpers::__anonb732431c0111::TestTraits32 constexpr TestTraits(ArgTypes... args)
33 : has_example_trait(trait_helpers::HasTrait<ExampleTrait, ArgTypes...>()),
34 enum_trait_a(
35 trait_helpers::GetEnum<EnumTraitA, EnumTraitA::A>(args...)),
36 enum_trait_b(
37 trait_helpers::GetEnum<EnumTraitB, EnumTraitB::ONE>(args...)) {}
38
39 const bool has_example_trait;
40 const EnumTraitA enum_trait_a;
41 const EnumTraitB enum_trait_b;
42 };
43
44 // Like TestTraits, except ExampleTrait is filtered away.
45 struct FilteredTestTraits : public TestTraits {
46 template <class... ArgTypes>
47 requires trait_helpers::AreValidTraits<ValidTrait, ArgTypes...>
FilteredTestTraitsbase::trait_helpers::__anonb732431c0111::FilteredTestTraits48 constexpr FilteredTestTraits(ArgTypes... args)
49 : TestTraits(Exclude<ExampleTrait>::Filter(args)...) {}
50 };
51
52 struct RequiredEnumTestTraits {
53 // List of traits that are required inputs for the constructor below.
54 struct ValidTrait {
55 ValidTrait(EnumTraitA);
56 };
57
58 // We require EnumTraitA to be specified.
59 template <class... ArgTypes>
60 requires trait_helpers::AreValidTraits<ValidTrait, ArgTypes...>
RequiredEnumTestTraitsbase::trait_helpers::__anonb732431c0111::RequiredEnumTestTraits61 constexpr RequiredEnumTestTraits(ArgTypes... args)
62 : enum_trait_a(trait_helpers::GetEnum<EnumTraitA>(args...)) {}
63
64 const EnumTraitA enum_trait_a;
65 };
66
67 struct OptionalEnumTestTraits {
68 // List of traits that are optional inputs for the constructor below.
69 struct ValidTrait {
70 ValidTrait(EnumTraitA);
71 };
72
73 // EnumTraitA can optionally be specified.
74 template <class... ArgTypes>
75 requires trait_helpers::AreValidTraits<ValidTrait, ArgTypes...>
OptionalEnumTestTraitsbase::trait_helpers::__anonb732431c0111::OptionalEnumTestTraits76 constexpr OptionalEnumTestTraits(ArgTypes... args)
77 : enum_trait_a(trait_helpers::GetOptionalEnum<EnumTraitA>(args...)) {}
78
79 const absl::optional<EnumTraitA> enum_trait_a;
80 };
81
82 } // namespace
83
TEST(TraitsBagTest,DefaultConstructor)84 TEST(TraitsBagTest, DefaultConstructor) {
85 constexpr TestTraits trait_test_class;
86
87 EXPECT_FALSE(trait_test_class.has_example_trait);
88 }
89
TEST(TraitsBagTest,HasTrait)90 TEST(TraitsBagTest, HasTrait) {
91 constexpr TestTraits with_trait(ExampleTrait{});
92 constexpr TestTraits without_trait;
93
94 EXPECT_TRUE(with_trait.has_example_trait);
95 EXPECT_FALSE(without_trait.has_example_trait);
96 }
97
TEST(TraitsBagTest,GetEnumWithDefault)98 TEST(TraitsBagTest, GetEnumWithDefault) {
99 constexpr TestTraits defaults;
100
101 EXPECT_EQ(defaults.enum_trait_a, EnumTraitA::A);
102 EXPECT_EQ(defaults.enum_trait_b, EnumTraitB::ONE);
103
104 constexpr TestTraits a(EnumTraitA::A);
105 constexpr TestTraits b(EnumTraitA::B);
106 constexpr TestTraits c(EnumTraitA::C);
107
108 EXPECT_EQ(a.enum_trait_a, EnumTraitA::A);
109 EXPECT_EQ(a.enum_trait_b, EnumTraitB::ONE);
110
111 EXPECT_EQ(b.enum_trait_a, EnumTraitA::B);
112 EXPECT_EQ(b.enum_trait_b, EnumTraitB::ONE);
113
114 EXPECT_EQ(c.enum_trait_a, EnumTraitA::C);
115 EXPECT_EQ(c.enum_trait_b, EnumTraitB::ONE);
116
117 constexpr TestTraits a_one(EnumTraitA::A, EnumTraitB::ONE);
118 constexpr TestTraits b_one(EnumTraitA::B, EnumTraitB::ONE);
119 constexpr TestTraits c_one(EnumTraitA::C, EnumTraitB::ONE);
120
121 EXPECT_EQ(a_one.enum_trait_a, EnumTraitA::A);
122 EXPECT_EQ(a_one.enum_trait_b, EnumTraitB::ONE);
123
124 EXPECT_EQ(b_one.enum_trait_a, EnumTraitA::B);
125 EXPECT_EQ(b_one.enum_trait_b, EnumTraitB::ONE);
126
127 EXPECT_EQ(c_one.enum_trait_a, EnumTraitA::C);
128 EXPECT_EQ(c_one.enum_trait_b, EnumTraitB::ONE);
129
130 constexpr TestTraits a_two(EnumTraitA::A, EnumTraitB::TWO);
131 constexpr TestTraits b_two(EnumTraitA::B, EnumTraitB::TWO);
132 constexpr TestTraits c_two(EnumTraitA::C, EnumTraitB::TWO);
133
134 EXPECT_EQ(a_two.enum_trait_a, EnumTraitA::A);
135 EXPECT_EQ(a_two.enum_trait_b, EnumTraitB::TWO);
136
137 EXPECT_EQ(b_two.enum_trait_a, EnumTraitA::B);
138 EXPECT_EQ(b_two.enum_trait_b, EnumTraitB::TWO);
139
140 EXPECT_EQ(c_two.enum_trait_a, EnumTraitA::C);
141 EXPECT_EQ(c_two.enum_trait_b, EnumTraitB::TWO);
142 }
143
TEST(TraitsBagTest,RequiredEnum)144 TEST(TraitsBagTest, RequiredEnum) {
145 constexpr RequiredEnumTestTraits a(EnumTraitA::A);
146 constexpr RequiredEnumTestTraits b(EnumTraitA::B);
147 constexpr RequiredEnumTestTraits c(EnumTraitA::C);
148
149 EXPECT_EQ(a.enum_trait_a, EnumTraitA::A);
150 EXPECT_EQ(b.enum_trait_a, EnumTraitA::B);
151 EXPECT_EQ(c.enum_trait_a, EnumTraitA::C);
152 }
153
TEST(TraitsBagTest,OptionalEnum)154 TEST(TraitsBagTest, OptionalEnum) {
155 constexpr OptionalEnumTestTraits not_set;
156 constexpr OptionalEnumTestTraits set(EnumTraitA::B);
157
158 EXPECT_FALSE(not_set.enum_trait_a.has_value());
159 ASSERT_TRUE(set.enum_trait_a.has_value());
160 EXPECT_EQ(*set.enum_trait_a, EnumTraitA::B);
161 }
162
TEST(TraitsBagTest,ValidTraitInheritance)163 TEST(TraitsBagTest, ValidTraitInheritance) {
164 struct ValidTraitsA {
165 ValidTraitsA(EnumTraitA);
166 };
167
168 struct ValidTraitsB {
169 ValidTraitsB(ValidTraitsA);
170 ValidTraitsB(EnumTraitB);
171 };
172
173 static_assert(AreValidTraits<ValidTraitsA, EnumTraitA>, "");
174 static_assert(AreValidTraits<ValidTraitsB, EnumTraitA, EnumTraitB>, "");
175 }
176
TEST(TraitsBagTest,Filtering)177 TEST(TraitsBagTest, Filtering) {
178 using Predicate = Exclude<ExampleTrait, EnumTraitA>;
179 static_assert(std::is_same_v<ExampleTrait2,
180 decltype(Predicate::Filter(ExampleTrait2{}))>,
181 "ExampleTrait2 should not be filtered");
182
183 static_assert(
184 std::is_same_v<EmptyTrait, decltype(Predicate::Filter(ExampleTrait{}))>,
185 "ExampleTrait should be filtered");
186
187 static_assert(
188 std::is_same_v<EmptyTrait, decltype(Predicate::Filter(EnumTraitA::A))>,
189 "EnumTraitA should be filtered");
190
191 static_assert(
192 std::is_same_v<EnumTraitB, decltype(Predicate::Filter(EnumTraitB::TWO))>,
193 "EnumTraitB should not be filtered");
194
195 static_assert(
196 std::is_same_v<EmptyTrait, decltype(Predicate::Filter(EmptyTrait{}))>,
197 "EmptyTrait should not be filtered");
198 }
199
TEST(TraitsBagTest,FilteredTestTraits)200 TEST(TraitsBagTest, FilteredTestTraits) {
201 FilteredTestTraits filtered(ExampleTrait(), EnumTraitA::C, EnumTraitB::TWO);
202
203 // ExampleTrait should have been filtered away.
204 EXPECT_FALSE(filtered.has_example_trait);
205
206 // The other traits should have been set however.
207 EXPECT_EQ(filtered.enum_trait_a, EnumTraitA::C);
208 EXPECT_EQ(filtered.enum_trait_b, EnumTraitB::TWO);
209 }
210
TEST(TraitsBagTest,EmptyTraitIsValid)211 TEST(TraitsBagTest, EmptyTraitIsValid) {
212 static_assert(IsValidTrait<TestTraits::ValidTrait, EmptyTrait>, "");
213 }
214
215 } // namespace trait_helpers
216 } // namespace base
217