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