blob: 970421117d46c3637074dbc97f028435dd06c198 [file] [log] [blame]
Avi Drissmane4622aa2022-09-08 20:36:061// Copyright 2018 The Chromium Authors
Alex Clarke3cf9cd8e2019-01-08 08:40:002// 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
Arthur Sonzognie5fff99c2024-02-21 15:58:247#include <optional>
8
Alex Clarke3cf9cd8e2019-01-08 08:40:009#include "testing/gmock/include/gmock/gmock.h"
10
Peter Kasting811504a72025-01-09 03:18:5011namespace base::trait_helpers {
Alex Clarke3cf9cd8e2019-01-08 08:40:0012namespace {
13
14struct ExampleTrait {};
15
Alex Clarkef0527a9b2019-01-23 10:43:2516struct ExampleTrait2 {};
17
Alex Clarke3cf9cd8e2019-01-08 08:40:0018enum class EnumTraitA { A, B, C };
19
20enum class EnumTraitB { ONE, TWO };
21
22struct TestTraits {
23 // List of traits that are valid inputs for the constructor below.
24 struct ValidTrait {
Peter Kasting6218bbad2025-01-10 11:26:4025 explicit ValidTrait(ExampleTrait);
26 explicit ValidTrait(EnumTraitA);
27 explicit ValidTrait(EnumTraitB);
Alex Clarke3cf9cd8e2019-01-08 08:40:0028 };
29
Jeremy Roman0b7de492023-11-15 04:52:1030 template <class... ArgTypes>
31 requires trait_helpers::AreValidTraits<ValidTrait, ArgTypes...>
Peter Kasting811504a72025-01-09 03:18:5032 constexpr explicit TestTraits(ArgTypes... args)
Gabriel Charettef929cf02019-08-20 19:59:0233 : has_example_trait(trait_helpers::HasTrait<ExampleTrait, ArgTypes...>()),
Alex Clarke3cf9cd8e2019-01-08 08:40:0034 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
Alex Clarkef0527a9b2019-01-23 10:43:2544// Like TestTraits, except ExampleTrait is filtered away.
45struct FilteredTestTraits : public TestTraits {
Jeremy Roman0b7de492023-11-15 04:52:1046 template <class... ArgTypes>
47 requires trait_helpers::AreValidTraits<ValidTrait, ArgTypes...>
Peter Kasting811504a72025-01-09 03:18:5048 constexpr explicit FilteredTestTraits(ArgTypes... args)
Alex Clarkef0527a9b2019-01-23 10:43:2549 : TestTraits(Exclude<ExampleTrait>::Filter(args)...) {}
50};
51
Alex Clarke3cf9cd8e2019-01-08 08:40:0052struct RequiredEnumTestTraits {
Alex Clarke198beef2019-01-11 15:38:0053 // List of traits that are required inputs for the constructor below.
Alex Clarke3cf9cd8e2019-01-08 08:40:0054 struct ValidTrait {
Peter Kasting6218bbad2025-01-10 11:26:4055 explicit ValidTrait(EnumTraitA);
Alex Clarke3cf9cd8e2019-01-08 08:40:0056 };
57
58 // We require EnumTraitA to be specified.
Jeremy Roman0b7de492023-11-15 04:52:1059 template <class... ArgTypes>
60 requires trait_helpers::AreValidTraits<ValidTrait, ArgTypes...>
Peter Kasting811504a72025-01-09 03:18:5061 constexpr explicit RequiredEnumTestTraits(ArgTypes... args)
Alex Clarke3cf9cd8e2019-01-08 08:40:0062 : enum_trait_a(trait_helpers::GetEnum<EnumTraitA>(args...)) {}
63
64 const EnumTraitA enum_trait_a;
65};
Alex Clarke198beef2019-01-11 15:38:0066
Alex Clarkef0527a9b2019-01-23 10:43:2567struct OptionalEnumTestTraits {
68 // List of traits that are optional inputs for the constructor below.
69 struct ValidTrait {
Peter Kasting6218bbad2025-01-10 11:26:4070 explicit ValidTrait(EnumTraitA);
Alex Clarkef0527a9b2019-01-23 10:43:2571 };
72
73 // EnumTraitA can optionally be specified.
Jeremy Roman0b7de492023-11-15 04:52:1074 template <class... ArgTypes>
75 requires trait_helpers::AreValidTraits<ValidTrait, ArgTypes...>
Peter Kasting811504a72025-01-09 03:18:5076 constexpr explicit OptionalEnumTestTraits(ArgTypes... args)
Alex Clarkef0527a9b2019-01-23 10:43:2577 : enum_trait_a(trait_helpers::GetOptionalEnum<EnumTraitA>(args...)) {}
78
Arthur Sonzognie5fff99c2024-02-21 15:58:2479 const std::optional<EnumTraitA> enum_trait_a;
Alex Clarkef0527a9b2019-01-23 10:43:2580};
81
Alex Clarke3cf9cd8e2019-01-08 08:40:0082} // namespace
83
84TEST(TraitsBagTest, DefaultConstructor) {
Alex Clarke198beef2019-01-11 15:38:0085 constexpr TestTraits trait_test_class;
Alex Clarke3cf9cd8e2019-01-08 08:40:0086
87 EXPECT_FALSE(trait_test_class.has_example_trait);
88}
89
90TEST(TraitsBagTest, HasTrait) {
Alex Clarke198beef2019-01-11 15:38:0091 constexpr TestTraits with_trait(ExampleTrait{});
92 constexpr TestTraits without_trait;
Alex Clarke3cf9cd8e2019-01-08 08:40:0093
94 EXPECT_TRUE(with_trait.has_example_trait);
95 EXPECT_FALSE(without_trait.has_example_trait);
96}
97
98TEST(TraitsBagTest, GetEnumWithDefault) {
Alex Clarke198beef2019-01-11 15:38:0099 constexpr TestTraits defaults;
Alex Clarke3cf9cd8e2019-01-08 08:40:00100
101 EXPECT_EQ(defaults.enum_trait_a, EnumTraitA::A);
102 EXPECT_EQ(defaults.enum_trait_b, EnumTraitB::ONE);
103
Alex Clarke198beef2019-01-11 15:38:00104 constexpr TestTraits a(EnumTraitA::A);
105 constexpr TestTraits b(EnumTraitA::B);
106 constexpr TestTraits c(EnumTraitA::C);
Alex Clarke3cf9cd8e2019-01-08 08:40:00107
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
Alex Clarke198beef2019-01-11 15:38:00117 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);
Alex Clarke3cf9cd8e2019-01-08 08:40:00120
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
Alex Clarke198beef2019-01-11 15:38:00130 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);
Alex Clarke3cf9cd8e2019-01-08 08:40:00133
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
144TEST(TraitsBagTest, RequiredEnum) {
Alex Clarke198beef2019-01-11 15:38:00145 constexpr RequiredEnumTestTraits a(EnumTraitA::A);
146 constexpr RequiredEnumTestTraits b(EnumTraitA::B);
147 constexpr RequiredEnumTestTraits c(EnumTraitA::C);
Alex Clarke3cf9cd8e2019-01-08 08:40:00148
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
Alex Clarkef0527a9b2019-01-23 10:43:25154TEST(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
Alex Clarkef1415b52019-01-08 15:02:31163TEST(TraitsBagTest, ValidTraitInheritance) {
164 struct ValidTraitsA {
Peter Kasting6218bbad2025-01-10 11:26:40165 // For inheritance to work transparently, all constructors but the last in
166 // the chain must be implicit.
167 ValidTraitsA(EnumTraitA); // NOLINT(google-explicit-constructor)
Alex Clarkef1415b52019-01-08 15:02:31168 };
169
170 struct ValidTraitsB {
Peter Kasting6218bbad2025-01-10 11:26:40171 explicit ValidTraitsB(ValidTraitsA);
172 explicit ValidTraitsB(EnumTraitB);
Alex Clarkef1415b52019-01-08 15:02:31173 };
174
Jeremy Roman0b7de492023-11-15 04:52:10175 static_assert(AreValidTraits<ValidTraitsA, EnumTraitA>, "");
176 static_assert(AreValidTraits<ValidTraitsB, EnumTraitA, EnumTraitB>, "");
Alex Clarkef1415b52019-01-08 15:02:31177}
178
Alex Clarkef0527a9b2019-01-23 10:43:25179TEST(TraitsBagTest, Filtering) {
180 using Predicate = Exclude<ExampleTrait, EnumTraitA>;
Andrew Rayskiy6f021362023-10-19 19:55:06181 static_assert(std::is_same_v<ExampleTrait2,
182 decltype(Predicate::Filter(ExampleTrait2{}))>,
183 "ExampleTrait2 should not be filtered");
Alex Clarkef0527a9b2019-01-23 10:43:25184
185 static_assert(
Andrew Rayskiy6f021362023-10-19 19:55:06186 std::is_same_v<EmptyTrait, decltype(Predicate::Filter(ExampleTrait{}))>,
Alex Clarkef0527a9b2019-01-23 10:43:25187 "ExampleTrait should be filtered");
188
Andrew Rayskiy6f021362023-10-19 19:55:06189 static_assert(
190 std::is_same_v<EmptyTrait, decltype(Predicate::Filter(EnumTraitA::A))>,
191 "EnumTraitA should be filtered");
Alex Clarkef0527a9b2019-01-23 10:43:25192
193 static_assert(
Andrew Rayskiy6f021362023-10-19 19:55:06194 std::is_same_v<EnumTraitB, decltype(Predicate::Filter(EnumTraitB::TWO))>,
Alex Clarkef0527a9b2019-01-23 10:43:25195 "EnumTraitB should not be filtered");
196
Andrew Rayskiy6f021362023-10-19 19:55:06197 static_assert(
198 std::is_same_v<EmptyTrait, decltype(Predicate::Filter(EmptyTrait{}))>,
199 "EmptyTrait should not be filtered");
Alex Clarkef0527a9b2019-01-23 10:43:25200}
201
202TEST(TraitsBagTest, FilteredTestTraits) {
203 FilteredTestTraits filtered(ExampleTrait(), EnumTraitA::C, EnumTraitB::TWO);
204
205 // ExampleTrait should have been filtered away.
206 EXPECT_FALSE(filtered.has_example_trait);
207
208 // The other traits should have been set however.
209 EXPECT_EQ(filtered.enum_trait_a, EnumTraitA::C);
210 EXPECT_EQ(filtered.enum_trait_b, EnumTraitB::TWO);
211}
212
213TEST(TraitsBagTest, EmptyTraitIsValid) {
Jeremy Roman0b7de492023-11-15 04:52:10214 static_assert(IsValidTrait<TestTraits::ValidTrait, EmptyTrait>, "");
Alex Clarkef0527a9b2019-01-23 10:43:25215}
216
Peter Kasting811504a72025-01-09 03:18:50217} // namespace base::trait_helpers