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 class CheckArgumentsAreValid = std::enable_if_t<
32 trait_helpers::AreValidTraits<ValidTrait, ArgTypes...>::value>>
TestTraitsbase::trait_helpers::__anond461dc6d0111::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 class CheckArgumentsAreValid = std::enable_if_t<
49 trait_helpers::AreValidTraits<ValidTrait, ArgTypes...>::value>>
FilteredTestTraitsbase::trait_helpers::__anond461dc6d0111::FilteredTestTraits50 constexpr FilteredTestTraits(ArgTypes... args)
51 : TestTraits(Exclude<ExampleTrait>::Filter(args)...) {}
52 };
53
54 struct RequiredEnumTestTraits {
55 // List of traits that are required inputs for the constructor below.
56 struct ValidTrait {
57 ValidTrait(EnumTraitA);
58 };
59
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>>
RequiredEnumTestTraitsbase::trait_helpers::__anond461dc6d0111::RequiredEnumTestTraits64 constexpr RequiredEnumTestTraits(ArgTypes... args)
65 : enum_trait_a(trait_helpers::GetEnum<EnumTraitA>(args...)) {}
66
67 const EnumTraitA enum_trait_a;
68 };
69
70 struct OptionalEnumTestTraits {
71 // List of traits that are optional inputs for the constructor below.
72 struct ValidTrait {
73 ValidTrait(EnumTraitA);
74 };
75
76 // EnumTraitA can optionally be specified.
77 template <class... ArgTypes,
78 class CheckArgumentsAreValid = std::enable_if_t<
79 trait_helpers::AreValidTraits<ValidTrait, ArgTypes...>::value>>
OptionalEnumTestTraitsbase::trait_helpers::__anond461dc6d0111::OptionalEnumTestTraits80 constexpr OptionalEnumTestTraits(ArgTypes... args)
81 : enum_trait_a(trait_helpers::GetOptionalEnum<EnumTraitA>(args...)) {}
82
83 const absl::optional<EnumTraitA> enum_trait_a;
84 };
85
86 } // namespace
87
TEST(TraitsBagTest,DefaultConstructor)88 TEST(TraitsBagTest, DefaultConstructor) {
89 constexpr TestTraits trait_test_class;
90
91 EXPECT_FALSE(trait_test_class.has_example_trait);
92 }
93
TEST(TraitsBagTest,HasTrait)94 TEST(TraitsBagTest, HasTrait) {
95 constexpr TestTraits with_trait(ExampleTrait{});
96 constexpr TestTraits without_trait;
97
98 EXPECT_TRUE(with_trait.has_example_trait);
99 EXPECT_FALSE(without_trait.has_example_trait);
100 }
101
TEST(TraitsBagTest,GetEnumWithDefault)102 TEST(TraitsBagTest, GetEnumWithDefault) {
103 constexpr TestTraits defaults;
104
105 EXPECT_EQ(defaults.enum_trait_a, EnumTraitA::A);
106 EXPECT_EQ(defaults.enum_trait_b, EnumTraitB::ONE);
107
108 constexpr TestTraits a(EnumTraitA::A);
109 constexpr TestTraits b(EnumTraitA::B);
110 constexpr TestTraits c(EnumTraitA::C);
111
112 EXPECT_EQ(a.enum_trait_a, EnumTraitA::A);
113 EXPECT_EQ(a.enum_trait_b, EnumTraitB::ONE);
114
115 EXPECT_EQ(b.enum_trait_a, EnumTraitA::B);
116 EXPECT_EQ(b.enum_trait_b, EnumTraitB::ONE);
117
118 EXPECT_EQ(c.enum_trait_a, EnumTraitA::C);
119 EXPECT_EQ(c.enum_trait_b, EnumTraitB::ONE);
120
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);
124
125 EXPECT_EQ(a_one.enum_trait_a, EnumTraitA::A);
126 EXPECT_EQ(a_one.enum_trait_b, EnumTraitB::ONE);
127
128 EXPECT_EQ(b_one.enum_trait_a, EnumTraitA::B);
129 EXPECT_EQ(b_one.enum_trait_b, EnumTraitB::ONE);
130
131 EXPECT_EQ(c_one.enum_trait_a, EnumTraitA::C);
132 EXPECT_EQ(c_one.enum_trait_b, EnumTraitB::ONE);
133
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);
137
138 EXPECT_EQ(a_two.enum_trait_a, EnumTraitA::A);
139 EXPECT_EQ(a_two.enum_trait_b, EnumTraitB::TWO);
140
141 EXPECT_EQ(b_two.enum_trait_a, EnumTraitA::B);
142 EXPECT_EQ(b_two.enum_trait_b, EnumTraitB::TWO);
143
144 EXPECT_EQ(c_two.enum_trait_a, EnumTraitA::C);
145 EXPECT_EQ(c_two.enum_trait_b, EnumTraitB::TWO);
146 }
147
TEST(TraitsBagTest,RequiredEnum)148 TEST(TraitsBagTest, RequiredEnum) {
149 constexpr RequiredEnumTestTraits a(EnumTraitA::A);
150 constexpr RequiredEnumTestTraits b(EnumTraitA::B);
151 constexpr RequiredEnumTestTraits c(EnumTraitA::C);
152
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);
156 }
157
TEST(TraitsBagTest,OptionalEnum)158 TEST(TraitsBagTest, OptionalEnum) {
159 constexpr OptionalEnumTestTraits not_set;
160 constexpr OptionalEnumTestTraits set(EnumTraitA::B);
161
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);
165 }
166
TEST(TraitsBagTest,ValidTraitInheritance)167 TEST(TraitsBagTest, ValidTraitInheritance) {
168 struct ValidTraitsA {
169 ValidTraitsA(EnumTraitA);
170 };
171
172 struct ValidTraitsB {
173 ValidTraitsB(ValidTraitsA);
174 ValidTraitsB(EnumTraitB);
175 };
176
177 static_assert(AreValidTraits<ValidTraitsA, EnumTraitA>(), "");
178 static_assert(AreValidTraits<ValidTraitsB, EnumTraitA, EnumTraitB>(), "");
179 }
180
TEST(TraitsBagTest,Filtering)181 TEST(TraitsBagTest, Filtering) {
182 using Predicate = Exclude<ExampleTrait, EnumTraitA>;
183 static_assert(
184 std::is_same<ExampleTrait2,
185 decltype(Predicate::Filter(ExampleTrait2{}))>::value,
186 "ExampleTrait2 should not be filtered");
187
188 static_assert(
189 std::is_same<EmptyTrait,
190 decltype(Predicate::Filter(ExampleTrait{}))>::value,
191 "ExampleTrait should be filtered");
192
193 static_assert(std::is_same<EmptyTrait,
194 decltype(Predicate::Filter(EnumTraitA::A))>::value,
195 "EnumTraitA should be filtered");
196
197 static_assert(
198 std::is_same<EnumTraitB,
199 decltype(Predicate::Filter(EnumTraitB::TWO))>::value,
200 "EnumTraitB should not be filtered");
201
202 static_assert(std::is_same<EmptyTrait,
203 decltype(Predicate::Filter(EmptyTrait{}))>::value,
204 "EmptyTrait should not be filtered");
205 }
206
TEST(TraitsBagTest,FilteredTestTraits)207 TEST(TraitsBagTest, FilteredTestTraits) {
208 FilteredTestTraits filtered(ExampleTrait(), EnumTraitA::C, EnumTraitB::TWO);
209
210 // ExampleTrait should have been filtered away.
211 EXPECT_FALSE(filtered.has_example_trait);
212
213 // The other traits should have been set however.
214 EXPECT_EQ(filtered.enum_trait_a, EnumTraitA::C);
215 EXPECT_EQ(filtered.enum_trait_b, EnumTraitB::TWO);
216 }
217
TEST(TraitsBagTest,EmptyTraitIsValid)218 TEST(TraitsBagTest, EmptyTraitIsValid) {
219 static_assert(IsValidTrait<TestTraits::ValidTrait, EmptyTrait>(), "");
220 }
221
222 } // namespace trait_helpers
223 } // namespace base
224