• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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