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