• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright 2012 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/containers/enum_set.h"
6 
7 #include <stddef.h>
8 
9 #include "base/test/gtest_util.h"
10 #include "testing/gtest/include/gtest/gtest-death-test.h"
11 #include "testing/gtest/include/gtest/gtest.h"
12 
13 namespace base {
14 namespace {
15 
16 enum class TestEnum {
17   TEST_BELOW_MIN_NEGATIVE = -1,
18   TEST_BELOW_MIN = 0,
19   TEST_1 = 1,
20   TEST_MIN = TEST_1,
21   TEST_2,
22   TEST_3,
23   TEST_4,
24   TEST_5,
25   TEST_MAX = TEST_5,
26   TEST_6_OUT_OF_BOUNDS,
27   TEST_7_OUT_OF_BOUNDS
28 };
29 using TestEnumSet = EnumSet<TestEnum, TestEnum::TEST_MIN, TestEnum::TEST_MAX>;
30 
31 enum class TestEnumExtreme {
32   TEST_0 = 0,
33   TEST_MIN = TEST_0,
34   TEST_63 = 63,
35   TEST_MAX = TEST_63,
36   TEST_64_OUT_OF_BOUNDS,
37 };
38 using TestEnumExtremeSet = EnumSet<TestEnumExtreme,
39                                    TestEnumExtreme::TEST_MIN,
40                                    TestEnumExtreme::TEST_MAX>;
41 
42 class EnumSetTest : public ::testing::Test {};
43 class EnumSetDeathTest : public ::testing::Test {};
44 
TEST_F(EnumSetTest,ClassConstants)45 TEST_F(EnumSetTest, ClassConstants) {
46   EXPECT_EQ(TestEnum::TEST_MIN, TestEnumSet::kMinValue);
47   EXPECT_EQ(TestEnum::TEST_MAX, TestEnumSet::kMaxValue);
48   EXPECT_EQ(static_cast<size_t>(5), TestEnumSet::kValueCount);
49 }
50 
51 // Use static_assert to check that functions we expect to be compile time
52 // evaluatable are really that way.
TEST_F(EnumSetTest,ConstexprsAreValid)53 TEST_F(EnumSetTest, ConstexprsAreValid) {
54   static_assert(TestEnumSet::All().Has(TestEnum::TEST_2),
55                 "Expected All() to be integral constant expression");
56   static_assert(TestEnumSet::FromRange(TestEnum::TEST_2, TestEnum::TEST_4)
57                     .Has(TestEnum::TEST_2),
58                 "Expected FromRange() to be integral constant expression");
59   static_assert(TestEnumSet{TestEnum::TEST_2}.Has(TestEnum::TEST_2),
60                 "Expected TestEnumSet() to be integral constant expression");
61   static_assert(
62       TestEnumSet::FromEnumBitmask(1 << static_cast<uint64_t>(TestEnum::TEST_2))
63           .Has(TestEnum::TEST_2),
64       "Expected TestEnumSet() to be integral constant expression");
65 }
66 
TEST_F(EnumSetTest,DefaultConstructor)67 TEST_F(EnumSetTest, DefaultConstructor) {
68   const TestEnumSet enums;
69   EXPECT_TRUE(enums.Empty());
70   EXPECT_EQ(static_cast<size_t>(0), enums.Size());
71   EXPECT_FALSE(enums.Has(TestEnum::TEST_1));
72   EXPECT_FALSE(enums.Has(TestEnum::TEST_2));
73   EXPECT_FALSE(enums.Has(TestEnum::TEST_3));
74   EXPECT_FALSE(enums.Has(TestEnum::TEST_4));
75   EXPECT_FALSE(enums.Has(TestEnum::TEST_5));
76 }
77 
TEST_F(EnumSetTest,OneArgConstructor)78 TEST_F(EnumSetTest, OneArgConstructor) {
79   const TestEnumSet enums = {TestEnum::TEST_4};
80   EXPECT_FALSE(enums.Empty());
81   EXPECT_EQ(static_cast<size_t>(1), enums.Size());
82   EXPECT_FALSE(enums.Has(TestEnum::TEST_1));
83   EXPECT_FALSE(enums.Has(TestEnum::TEST_2));
84   EXPECT_FALSE(enums.Has(TestEnum::TEST_3));
85   EXPECT_TRUE(enums.Has(TestEnum::TEST_4));
86   EXPECT_FALSE(enums.Has(TestEnum::TEST_5));
87 }
88 
TEST_F(EnumSetTest,OneArgConstructorSize)89 TEST_F(EnumSetTest, OneArgConstructorSize) {
90   TestEnumExtremeSet enums = {TestEnumExtreme::TEST_0};
91   EXPECT_TRUE(enums.Has(TestEnumExtreme::TEST_0));
92 }
93 
TEST_F(EnumSetTest,TwoArgConstructor)94 TEST_F(EnumSetTest, TwoArgConstructor) {
95   const TestEnumSet enums = {TestEnum::TEST_4, TestEnum::TEST_2};
96   EXPECT_FALSE(enums.Empty());
97   EXPECT_EQ(static_cast<size_t>(2), enums.Size());
98   EXPECT_FALSE(enums.Has(TestEnum::TEST_1));
99   EXPECT_TRUE(enums.Has(TestEnum::TEST_2));
100   EXPECT_FALSE(enums.Has(TestEnum::TEST_3));
101   EXPECT_TRUE(enums.Has(TestEnum::TEST_4));
102   EXPECT_FALSE(enums.Has(TestEnum::TEST_5));
103 }
104 
TEST_F(EnumSetTest,ThreeArgConstructor)105 TEST_F(EnumSetTest, ThreeArgConstructor) {
106   const TestEnumSet enums = {TestEnum::TEST_4, TestEnum::TEST_2,
107                              TestEnum::TEST_1};
108   EXPECT_FALSE(enums.Empty());
109   EXPECT_EQ(static_cast<size_t>(3), enums.Size());
110   EXPECT_TRUE(enums.Has(TestEnum::TEST_1));
111   EXPECT_TRUE(enums.Has(TestEnum::TEST_2));
112   EXPECT_FALSE(enums.Has(TestEnum::TEST_3));
113   EXPECT_TRUE(enums.Has(TestEnum::TEST_4));
114   EXPECT_FALSE(enums.Has(TestEnum::TEST_5));
115 }
116 
TEST_F(EnumSetTest,DuplicatesInConstructor)117 TEST_F(EnumSetTest, DuplicatesInConstructor) {
118   EXPECT_EQ(
119       TestEnumSet({TestEnum::TEST_4, TestEnum::TEST_2, TestEnum::TEST_1,
120                    TestEnum::TEST_4, TestEnum::TEST_2, TestEnum::TEST_4}),
121       TestEnumSet({TestEnum::TEST_1, TestEnum::TEST_2, TestEnum::TEST_4}));
122 }
123 
TEST_F(EnumSetTest,All)124 TEST_F(EnumSetTest, All) {
125   const TestEnumSet enums(TestEnumSet::All());
126   EXPECT_FALSE(enums.Empty());
127   EXPECT_EQ(static_cast<size_t>(5), enums.Size());
128   EXPECT_TRUE(enums.Has(TestEnum::TEST_1));
129   EXPECT_TRUE(enums.Has(TestEnum::TEST_2));
130   EXPECT_TRUE(enums.Has(TestEnum::TEST_3));
131   EXPECT_TRUE(enums.Has(TestEnum::TEST_4));
132   EXPECT_TRUE(enums.Has(TestEnum::TEST_5));
133 }
134 
TEST_F(EnumSetTest,AllExtreme)135 TEST_F(EnumSetTest, AllExtreme) {
136   const TestEnumExtremeSet enums(TestEnumExtremeSet::All());
137   EXPECT_FALSE(enums.Empty());
138   EXPECT_EQ(static_cast<size_t>(64), enums.Size());
139   EXPECT_TRUE(enums.Has(TestEnumExtreme::TEST_0));
140   EXPECT_TRUE(enums.Has(TestEnumExtreme::TEST_63));
141   EXPECT_FALSE(enums.Has(TestEnumExtreme::TEST_64_OUT_OF_BOUNDS));
142 }
143 
TEST_F(EnumSetTest,FromRange)144 TEST_F(EnumSetTest, FromRange) {
145   EXPECT_EQ(TestEnumSet({TestEnum::TEST_2, TestEnum::TEST_3, TestEnum::TEST_4}),
146             TestEnumSet::FromRange(TestEnum::TEST_2, TestEnum::TEST_4));
147   EXPECT_EQ(TestEnumSet::All(),
148             TestEnumSet::FromRange(TestEnum::TEST_1, TestEnum::TEST_5));
149   EXPECT_EQ(TestEnumSet({TestEnum::TEST_2}),
150             TestEnumSet::FromRange(TestEnum::TEST_2, TestEnum::TEST_2));
151 
152   using RestrictedRangeSet =
153       EnumSet<TestEnum, TestEnum::TEST_2, TestEnum::TEST_MAX>;
154   EXPECT_EQ(RestrictedRangeSet(
155                 {TestEnum::TEST_2, TestEnum::TEST_3, TestEnum::TEST_4}),
156             RestrictedRangeSet::FromRange(TestEnum::TEST_2, TestEnum::TEST_4));
157   EXPECT_EQ(RestrictedRangeSet::All(),
158             RestrictedRangeSet::FromRange(TestEnum::TEST_2, TestEnum::TEST_5));
159 }
160 
TEST_F(EnumSetTest,Put)161 TEST_F(EnumSetTest, Put) {
162   TestEnumSet enums = {TestEnum::TEST_4};
163   enums.Put(TestEnum::TEST_3);
164   EXPECT_EQ(TestEnumSet({TestEnum::TEST_3, TestEnum::TEST_4}), enums);
165   enums.Put(TestEnum::TEST_5);
166   EXPECT_EQ(TestEnumSet({TestEnum::TEST_3, TestEnum::TEST_4, TestEnum::TEST_5}),
167             enums);
168 }
169 
TEST_F(EnumSetTest,PutAll)170 TEST_F(EnumSetTest, PutAll) {
171   TestEnumSet enums = {TestEnum::TEST_4, TestEnum::TEST_5};
172   enums.PutAll({TestEnum::TEST_3, TestEnum::TEST_4});
173   EXPECT_EQ(TestEnumSet({TestEnum::TEST_3, TestEnum::TEST_4, TestEnum::TEST_5}),
174             enums);
175 }
176 
TEST_F(EnumSetTest,PutRange)177 TEST_F(EnumSetTest, PutRange) {
178   TestEnumSet enums;
179   enums.PutRange(TestEnum::TEST_2, TestEnum::TEST_4);
180   EXPECT_EQ(TestEnumSet({TestEnum::TEST_2, TestEnum::TEST_3, TestEnum::TEST_4}),
181             enums);
182 }
183 
TEST_F(EnumSetTest,RetainAll)184 TEST_F(EnumSetTest, RetainAll) {
185   TestEnumSet enums = {TestEnum::TEST_4, TestEnum::TEST_5};
186   enums.RetainAll(TestEnumSet({TestEnum::TEST_3, TestEnum::TEST_4}));
187   EXPECT_EQ(TestEnumSet({TestEnum::TEST_4}), enums);
188 }
189 
TEST_F(EnumSetTest,Remove)190 TEST_F(EnumSetTest, Remove) {
191   TestEnumSet enums = {TestEnum::TEST_4, TestEnum::TEST_5};
192   enums.Remove(TestEnum::TEST_1);
193   enums.Remove(TestEnum::TEST_3);
194   EXPECT_EQ(TestEnumSet({TestEnum::TEST_4, TestEnum::TEST_5}), enums);
195   enums.Remove(TestEnum::TEST_4);
196   EXPECT_EQ(TestEnumSet({TestEnum::TEST_5}), enums);
197   enums.Remove(TestEnum::TEST_5);
198   enums.Remove(TestEnum::TEST_6_OUT_OF_BOUNDS);
199   EXPECT_TRUE(enums.Empty());
200 }
201 
TEST_F(EnumSetTest,RemoveAll)202 TEST_F(EnumSetTest, RemoveAll) {
203   TestEnumSet enums = {TestEnum::TEST_4, TestEnum::TEST_5};
204   enums.RemoveAll(TestEnumSet({TestEnum::TEST_3, TestEnum::TEST_4}));
205   EXPECT_EQ(TestEnumSet({TestEnum::TEST_5}), enums);
206 }
207 
TEST_F(EnumSetTest,Clear)208 TEST_F(EnumSetTest, Clear) {
209   TestEnumSet enums = {TestEnum::TEST_4, TestEnum::TEST_5};
210   enums.Clear();
211   EXPECT_TRUE(enums.Empty());
212 }
213 
TEST_F(EnumSetTest,Set)214 TEST_F(EnumSetTest, Set) {
215   TestEnumSet enums;
216   EXPECT_TRUE(enums.Empty());
217 
218   enums.PutOrRemove(TestEnum::TEST_3, false);
219   EXPECT_TRUE(enums.Empty());
220 
221   enums.PutOrRemove(TestEnum::TEST_4, true);
222   EXPECT_EQ(enums, TestEnumSet({TestEnum::TEST_4}));
223 
224   enums.PutOrRemove(TestEnum::TEST_5, true);
225   EXPECT_EQ(enums, TestEnumSet({TestEnum::TEST_4, TestEnum::TEST_5}));
226   enums.PutOrRemove(TestEnum::TEST_5, true);
227   EXPECT_EQ(enums, TestEnumSet({TestEnum::TEST_4, TestEnum::TEST_5}));
228 
229   enums.PutOrRemove(TestEnum::TEST_4, false);
230   EXPECT_EQ(enums, TestEnumSet({TestEnum::TEST_5}));
231 }
232 
TEST_F(EnumSetTest,Has)233 TEST_F(EnumSetTest, Has) {
234   const TestEnumSet enums = {TestEnum::TEST_4, TestEnum::TEST_5};
235   EXPECT_FALSE(enums.Has(TestEnum::TEST_1));
236   EXPECT_FALSE(enums.Has(TestEnum::TEST_2));
237   EXPECT_FALSE(enums.Has(TestEnum::TEST_3));
238   EXPECT_TRUE(enums.Has(TestEnum::TEST_4));
239   EXPECT_TRUE(enums.Has(TestEnum::TEST_5));
240   EXPECT_FALSE(enums.Has(TestEnum::TEST_6_OUT_OF_BOUNDS));
241 }
242 
TEST_F(EnumSetTest,HasAll)243 TEST_F(EnumSetTest, HasAll) {
244   const TestEnumSet enums1 = {TestEnum::TEST_4, TestEnum::TEST_5};
245   const TestEnumSet enums2 = {TestEnum::TEST_3, TestEnum::TEST_4};
246   const TestEnumSet enums3 = Union(enums1, enums2);
247   EXPECT_TRUE(enums1.HasAll(enums1));
248   EXPECT_FALSE(enums1.HasAll(enums2));
249   EXPECT_FALSE(enums1.HasAll(enums3));
250 
251   EXPECT_FALSE(enums2.HasAll(enums1));
252   EXPECT_TRUE(enums2.HasAll(enums2));
253   EXPECT_FALSE(enums2.HasAll(enums3));
254 
255   EXPECT_TRUE(enums3.HasAll(enums1));
256   EXPECT_TRUE(enums3.HasAll(enums2));
257   EXPECT_TRUE(enums3.HasAll(enums3));
258 }
259 
TEST_F(EnumSetTest,HasAny)260 TEST_F(EnumSetTest, HasAny) {
261   const TestEnumSet enums1 = {TestEnum::TEST_4, TestEnum::TEST_5};
262   const TestEnumSet enums2 = {TestEnum::TEST_3, TestEnum::TEST_4};
263   const TestEnumSet enums3 = {TestEnum::TEST_1, TestEnum::TEST_2};
264   EXPECT_TRUE(enums1.HasAny(enums1));
265   EXPECT_TRUE(enums1.HasAny(enums2));
266   EXPECT_FALSE(enums1.HasAny(enums3));
267 
268   EXPECT_TRUE(enums2.HasAny(enums1));
269   EXPECT_TRUE(enums2.HasAny(enums2));
270   EXPECT_FALSE(enums2.HasAny(enums3));
271 
272   EXPECT_FALSE(enums3.HasAny(enums1));
273   EXPECT_FALSE(enums3.HasAny(enums2));
274   EXPECT_TRUE(enums3.HasAny(enums3));
275 }
276 
TEST_F(EnumSetTest,Iterators)277 TEST_F(EnumSetTest, Iterators) {
278   const TestEnumSet enums1 = {TestEnum::TEST_4, TestEnum::TEST_5};
279   TestEnumSet enums2;
280   for (TestEnum e : enums1) {
281     enums2.Put(e);
282   }
283   EXPECT_EQ(enums2, enums1);
284 }
285 
TEST_F(EnumSetTest,RangeBasedForLoop)286 TEST_F(EnumSetTest, RangeBasedForLoop) {
287   const TestEnumSet enums1 = {TestEnum::TEST_2, TestEnum::TEST_5};
288   TestEnumSet enums2;
289   for (TestEnum e : enums1) {
290     enums2.Put(e);
291   }
292   EXPECT_EQ(enums2, enums1);
293 }
294 
TEST_F(EnumSetTest,IteratorComparisonOperators)295 TEST_F(EnumSetTest, IteratorComparisonOperators) {
296   const TestEnumSet enums = {TestEnum::TEST_2, TestEnum::TEST_4};
297   const auto first_it = enums.begin();
298   const auto second_it = ++enums.begin();
299 
300   // Copy for equality testing.
301   const auto first_it_copy = first_it;
302 
303   // Sanity check, as the rest of the test relies on |first_it| and
304   // |first_it_copy| pointing to the same element and |first_it| and |second_it|
305   // pointing to different elements.
306   ASSERT_EQ(*first_it, *first_it_copy);
307   ASSERT_NE(*first_it, *second_it);
308 
309   EXPECT_TRUE(first_it == first_it_copy);
310   EXPECT_FALSE(first_it != first_it_copy);
311 
312   EXPECT_TRUE(first_it != second_it);
313   EXPECT_FALSE(first_it == second_it);
314 }
315 
TEST_F(EnumSetTest,IteratorIncrementOperators)316 TEST_F(EnumSetTest, IteratorIncrementOperators) {
317   const TestEnumSet enums = {TestEnum::TEST_2, TestEnum::TEST_4};
318   const auto begin = enums.begin();
319 
320   auto post_inc_it = begin;
321   auto pre_inc_it = begin;
322 
323   auto post_inc_return_it = post_inc_it++;
324   auto pre_inc_return_it = ++pre_inc_it;
325 
326   // |pre_inc_it| and |post_inc_it| should point to the same element.
327   EXPECT_EQ(pre_inc_it, post_inc_it);
328   EXPECT_EQ(*pre_inc_it, *post_inc_it);
329 
330   // |pre_inc_it| should NOT point to the first element.
331   EXPECT_NE(begin, pre_inc_it);
332   EXPECT_NE(*begin, *pre_inc_it);
333 
334   // |post_inc_it| should NOT point to the first element.
335   EXPECT_NE(begin, post_inc_it);
336   EXPECT_NE(*begin, *post_inc_it);
337 
338   // Prefix increment should return new iterator.
339   EXPECT_EQ(pre_inc_return_it, post_inc_it);
340   EXPECT_EQ(*pre_inc_return_it, *post_inc_it);
341 
342   // Postfix increment should return original iterator.
343   EXPECT_EQ(post_inc_return_it, begin);
344   EXPECT_EQ(*post_inc_return_it, *begin);
345 }
346 
TEST_F(EnumSetTest,Union)347 TEST_F(EnumSetTest, Union) {
348   const TestEnumSet enums1 = {TestEnum::TEST_4, TestEnum::TEST_5};
349   const TestEnumSet enums2 = {TestEnum::TEST_3, TestEnum::TEST_4};
350   const TestEnumSet enums3 = Union(enums1, enums2);
351 
352   EXPECT_EQ(TestEnumSet({TestEnum::TEST_3, TestEnum::TEST_4, TestEnum::TEST_5}),
353             enums3);
354 }
355 
TEST_F(EnumSetTest,Intersection)356 TEST_F(EnumSetTest, Intersection) {
357   const TestEnumSet enums1 = {TestEnum::TEST_4, TestEnum::TEST_5};
358   const TestEnumSet enums2 = {TestEnum::TEST_3, TestEnum::TEST_4};
359   const TestEnumSet enums3 = Intersection(enums1, enums2);
360 
361   EXPECT_EQ(TestEnumSet({TestEnum::TEST_4}), enums3);
362 }
363 
TEST_F(EnumSetTest,Difference)364 TEST_F(EnumSetTest, Difference) {
365   const TestEnumSet enums1 = {TestEnum::TEST_4, TestEnum::TEST_5};
366   const TestEnumSet enums2 = {TestEnum::TEST_3, TestEnum::TEST_4};
367   const TestEnumSet enums3 = Difference(enums1, enums2);
368 
369   EXPECT_EQ(TestEnumSet({TestEnum::TEST_5}), enums3);
370 }
371 
TEST_F(EnumSetTest,ToFromEnumBitmask)372 TEST_F(EnumSetTest, ToFromEnumBitmask) {
373   const TestEnumSet empty;
374   EXPECT_EQ(empty.ToEnumBitmask(), 0ULL);
375   EXPECT_EQ(TestEnumSet::FromEnumBitmask(0), empty);
376 
377   const TestEnumSet enums1 = {TestEnum::TEST_2};
378   const uint64_t val1 = 1ULL << static_cast<uint64_t>(TestEnum::TEST_2);
379   EXPECT_EQ(enums1.ToEnumBitmask(), val1);
380   EXPECT_EQ(TestEnumSet::FromEnumBitmask(val1), enums1);
381 
382   const TestEnumSet enums2 = {TestEnum::TEST_3, TestEnum::TEST_4};
383   const uint64_t val2 = 1ULL << static_cast<uint64_t>(TestEnum::TEST_3) |
384                         1ULL << static_cast<uint64_t>(TestEnum::TEST_4);
385   EXPECT_EQ(enums2.ToEnumBitmask(), val2);
386   EXPECT_EQ(TestEnumSet::FromEnumBitmask(val2), enums2);
387 }
388 
TEST_F(EnumSetTest,ToFromEnumBitmaskExtreme)389 TEST_F(EnumSetTest, ToFromEnumBitmaskExtreme) {
390   const TestEnumExtremeSet empty;
391   EXPECT_EQ(empty.ToEnumBitmask(), 0ULL);
392   EXPECT_EQ(TestEnumExtremeSet::FromEnumBitmask(0ULL), empty);
393 
394   const TestEnumExtremeSet enums1 = {TestEnumExtreme::TEST_63};
395   const uint64_t val1 = 1ULL << static_cast<uint64_t>(TestEnumExtreme::TEST_63);
396   EXPECT_EQ(enums1.ToEnumBitmask(), val1);
397   EXPECT_EQ(TestEnumExtremeSet::FromEnumBitmask(val1), enums1);
398 }
399 
TEST_F(EnumSetTest,FromEnumBitmaskIgnoresExtraBits)400 TEST_F(EnumSetTest, FromEnumBitmaskIgnoresExtraBits) {
401   const TestEnumSet kSets[] = {
402       {},
403       {TestEnum::TEST_MIN},
404       {TestEnum::TEST_MAX},
405       {TestEnum::TEST_MIN, TestEnum::TEST_MAX},
406       {TestEnum::TEST_MIN, TestEnum::TEST_MAX},
407       {TestEnum::TEST_2, TestEnum::TEST_4},
408   };
409   size_t i = 0;
410   for (const TestEnumSet& set : kSets) {
411     SCOPED_TRACE(i++);
412     const uint64_t val = set.ToEnumBitmask();
413 
414     // Produce a bitstring for a single enum value. When `e` is in range
415     // relative to TestEnumSet, this function behaves identically to
416     // `single_val_bitstring`. When `e` is not in range, this function attempts
417     // to compute a value, while `single_val_bitstring` intentionally crashes.
418     auto single_val_bitstring = [](TestEnum e) -> uint64_t {
419       uint64_t shift_amount = static_cast<uint64_t>(e);
420       // Shifting left more than the number of bits in the lhs would be UB.
421       CHECK_LT(shift_amount, sizeof(uint64_t) * 8);
422       return 1ULL << shift_amount;
423     };
424 
425     const uint64_t kJunkVals[] = {
426         // Add junk bits above TEST_MAX.
427         val | single_val_bitstring(TestEnum::TEST_6_OUT_OF_BOUNDS),
428         val | single_val_bitstring(TestEnum::TEST_7_OUT_OF_BOUNDS),
429         val | single_val_bitstring(TestEnum::TEST_6_OUT_OF_BOUNDS) |
430             single_val_bitstring(TestEnum::TEST_7_OUT_OF_BOUNDS),
431         // Add junk bits below TEST_MIN.
432         val | single_val_bitstring(TestEnum::TEST_BELOW_MIN),
433     };
434     for (uint64_t junk_val : kJunkVals) {
435       SCOPED_TRACE(junk_val);
436       ASSERT_NE(val, junk_val);
437 
438       const TestEnumSet set_from_junk = TestEnumSet::FromEnumBitmask(junk_val);
439       EXPECT_EQ(set_from_junk, set);
440       EXPECT_EQ(set_from_junk.ToEnumBitmask(), set.ToEnumBitmask());
441 
442       // Iterating both sets should produce the same sequence.
443       auto it1 = set.begin();
444       auto it2 = set_from_junk.begin();
445       while (it1 != set.end() && it2 != set_from_junk.end()) {
446         EXPECT_EQ(*it1, *it2);
447         ++it1;
448         ++it2;
449       }
450       EXPECT_TRUE(it1 == set.end());
451       EXPECT_TRUE(it2 == set_from_junk.end());
452     }
453   }
454 }
455 
TEST_F(EnumSetTest,OneEnumValue)456 TEST_F(EnumSetTest, OneEnumValue) {
457   enum class TestEnumOne {
458     kTest1 = 1,
459     kTestMin = kTest1,
460     kTestMax = kTest1,
461   };
462   using TestEnumOneSet =
463       EnumSet<TestEnumOne, TestEnumOne::kTestMin, TestEnumOne::kTestMax>;
464   EXPECT_EQ(TestEnumOne::kTestMin, TestEnumOneSet::kMinValue);
465   EXPECT_EQ(TestEnumOne::kTestMax, TestEnumOneSet::kMaxValue);
466   EXPECT_EQ(1u, TestEnumOneSet::kValueCount);
467 }
468 
TEST_F(EnumSetTest,SparseEnum)469 TEST_F(EnumSetTest, SparseEnum) {
470   enum class TestEnumSparse {
471     TEST_1 = 1,
472     TEST_MIN = 1,
473     TEST_50 = 50,
474     TEST_100 = 100,
475     TEST_MAX = TEST_100,
476   };
477   using TestEnumSparseSet = EnumSet<TestEnumSparse, TestEnumSparse::TEST_MIN,
478                                     TestEnumSparse::TEST_MAX>;
479   TestEnumSparseSet sparse;
480   sparse.Put(TestEnumSparse::TEST_MIN);
481   sparse.Put(TestEnumSparse::TEST_MAX);
482   EXPECT_EQ(sparse.Size(), 2u);
483 
484   EXPECT_EQ(TestEnumSparseSet::All().Size(), 100u);
485 }
486 
TEST_F(EnumSetTest,SparseEnumSmall)487 TEST_F(EnumSetTest, SparseEnumSmall) {
488   enum class TestEnumSparse {
489     TEST_1 = 1,
490     TEST_MIN = 1,
491     TEST_50 = 50,
492     TEST_60 = 60,
493     TEST_MAX = TEST_60,
494   };
495   using TestEnumSparseSet = EnumSet<TestEnumSparse, TestEnumSparse::TEST_MIN,
496                                     TestEnumSparse::TEST_MAX>;
497   TestEnumSparseSet sparse;
498   sparse.Put(TestEnumSparse::TEST_MIN);
499   sparse.Put(TestEnumSparse::TEST_MAX);
500   EXPECT_EQ(sparse.Size(), 2u);
501 
502   // This may seem a little surprising! There are only 3 distinct values in
503   // TestEnumSparse, so why does TestEnumSparseSet think it has 60 of them? This
504   // is an artifact of EnumSet's design, as it has no way of knowing which
505   // values between the min and max are actually named in the enum's definition.
506   EXPECT_EQ(TestEnumSparseSet::All().Size(), 60u);
507 }
508 
TEST_F(EnumSetDeathTest,CrashesOnOutOfRange)509 TEST_F(EnumSetDeathTest, CrashesOnOutOfRange) {
510   EXPECT_CHECK_DEATH(TestEnumSet({TestEnum::TEST_BELOW_MIN}));
511   EXPECT_CHECK_DEATH(TestEnumSet({TestEnum::TEST_6_OUT_OF_BOUNDS}));
512   EXPECT_CHECK_DEATH(TestEnumSet({TestEnum::TEST_7_OUT_OF_BOUNDS}));
513 }
514 
TEST_F(EnumSetDeathTest,EnumWithNegatives)515 TEST_F(EnumSetDeathTest, EnumWithNegatives) {
516   enum class TestEnumNeg {
517     TEST_BELOW_MIN = -3,
518     TEST_A = -2,
519     TEST_MIN = TEST_A,
520     TEST_B = -1,
521     TEST_C = 0,
522     TEST_D = 1,
523     TEST_E = 2,
524     TEST_MAX = TEST_E,
525     TEST_F = 3,
526   };
527   // This EnumSet starts negative and ends positive.
528   using TestEnumWithNegSet =
529       EnumSet<TestEnumNeg, TestEnumNeg::TEST_MIN, TestEnumNeg::TEST_MAX>;
530 
531   // Should crash because TEST_BELOW_MIN is not in range.
532   EXPECT_CHECK_DEATH(TestEnumWithNegSet({TestEnumNeg::TEST_BELOW_MIN}));
533   // TEST_D is in range, but note that TEST_MIN is negative. This should work.
534   EXPECT_TRUE(
535       TestEnumWithNegSet({TestEnumNeg::TEST_D}).Has(TestEnumNeg::TEST_D));
536   // Even though TEST_A is negative, it is in range, so this should work.
537   EXPECT_TRUE(
538       TestEnumWithNegSet({TestEnumNeg::TEST_A}).Has(TestEnumNeg::TEST_A));
539 }
540 
TEST_F(EnumSetDeathTest,EnumWithOnlyNegatives)541 TEST_F(EnumSetDeathTest, EnumWithOnlyNegatives) {
542   enum class TestEnumNeg {
543     TEST_BELOW_MIN = -10,
544     TEST_A = -9,
545     TEST_MIN = TEST_A,
546     TEST_B = -8,
547     TEST_C = -7,
548     TEST_D = -6,
549     TEST_MAX = TEST_D,
550     TEST_F = -5,
551   };
552   // This EnumSet starts negative and ends negative.
553   using TestEnumWithNegSet =
554       EnumSet<TestEnumNeg, TestEnumNeg::TEST_MIN, TestEnumNeg::TEST_MAX>;
555 
556   // Should crash because TEST_BELOW_MIN is not in range.
557   EXPECT_CHECK_DEATH(TestEnumWithNegSet({TestEnumNeg::TEST_BELOW_MIN}));
558   // TEST_A, TEST_D are in range, but note that TEST_MIN and values are
559   // negative. This should work.
560   EXPECT_TRUE(
561       TestEnumWithNegSet({TestEnumNeg::TEST_A}).Has(TestEnumNeg::TEST_A));
562   EXPECT_TRUE(
563       TestEnumWithNegSet({TestEnumNeg::TEST_D}).Has(TestEnumNeg::TEST_D));
564 }
565 
TEST_F(EnumSetDeathTest,VariadicConstructorCrashesOnOutOfRange)566 TEST_F(EnumSetDeathTest, VariadicConstructorCrashesOnOutOfRange) {
567   // Constructor should crash given out-of-range values.
568   EXPECT_CHECK_DEATH(TestEnumSet({TestEnum::TEST_BELOW_MIN}).Empty());
569   EXPECT_CHECK_DEATH(TestEnumSet({TestEnum::TEST_BELOW_MIN_NEGATIVE}).Empty());
570   EXPECT_CHECK_DEATH(TestEnumSet({TestEnum::TEST_6_OUT_OF_BOUNDS}).Empty());
571 }
572 
TEST_F(EnumSetDeathTest,FromRangeCrashesOnBadInputs)573 TEST_F(EnumSetDeathTest, FromRangeCrashesOnBadInputs) {
574   // FromRange crashes when the bounds are in range, but out of order.
575   EXPECT_CHECK_DEATH(
576       TestEnumSet().FromRange(TestEnum::TEST_3, TestEnum::TEST_1));
577 
578   // FromRange crashes when the start value is out of range.
579   EXPECT_CHECK_DEATH(
580       TestEnumSet().FromRange(TestEnum::TEST_BELOW_MIN, TestEnum::TEST_1));
581   EXPECT_CHECK_DEATH(TestEnumSet().FromRange(TestEnum::TEST_BELOW_MIN_NEGATIVE,
582                                              TestEnum::TEST_1));
583   EXPECT_CHECK_DEATH(TestEnumSet().FromRange(TestEnum::TEST_6_OUT_OF_BOUNDS,
584                                              TestEnum::TEST_1));
585 
586   // FromRange crashes when the end value is out of range.
587   EXPECT_CHECK_DEATH(
588       TestEnumSet().FromRange(TestEnum::TEST_3, TestEnum::TEST_BELOW_MIN));
589   EXPECT_CHECK_DEATH(TestEnumSet().FromRange(
590       TestEnum::TEST_3, TestEnum::TEST_BELOW_MIN_NEGATIVE));
591   EXPECT_CHECK_DEATH(TestEnumSet().FromRange(TestEnum::TEST_3,
592                                              TestEnum::TEST_6_OUT_OF_BOUNDS));
593 
594   // Crashes when start and end are both out of range.
595   EXPECT_CHECK_DEATH(TestEnumSet().FromRange(TestEnum::TEST_7_OUT_OF_BOUNDS,
596                                              TestEnum::TEST_6_OUT_OF_BOUNDS));
597   EXPECT_CHECK_DEATH(TestEnumSet().FromRange(TestEnum::TEST_6_OUT_OF_BOUNDS,
598                                              TestEnum::TEST_7_OUT_OF_BOUNDS));
599 }
600 
TEST_F(EnumSetDeathTest,PutCrashesOnOutOfRange)601 TEST_F(EnumSetDeathTest, PutCrashesOnOutOfRange) {
602   EXPECT_CHECK_DEATH(TestEnumSet().Put(TestEnum::TEST_BELOW_MIN));
603   EXPECT_CHECK_DEATH(TestEnumSet().Put(TestEnum::TEST_BELOW_MIN_NEGATIVE));
604   EXPECT_CHECK_DEATH(TestEnumSet().Put(TestEnum::TEST_6_OUT_OF_BOUNDS));
605   EXPECT_CHECK_DEATH(TestEnumSet().Put(TestEnum::TEST_7_OUT_OF_BOUNDS));
606 }
607 
TEST_F(EnumSetDeathTest,PutRangeCrashesOnBadInputs)608 TEST_F(EnumSetDeathTest, PutRangeCrashesOnBadInputs) {
609   // Crashes when one input is out of range.
610   EXPECT_CHECK_DEATH(TestEnumSet().PutRange(TestEnum::TEST_BELOW_MIN_NEGATIVE,
611                                             TestEnum::TEST_BELOW_MIN));
612   EXPECT_CHECK_DEATH(
613       TestEnumSet().PutRange(TestEnum::TEST_3, TestEnum::TEST_7_OUT_OF_BOUNDS));
614 
615   // Crashes when both inputs are out of range.
616   EXPECT_CHECK_DEATH(TestEnumSet().PutRange(TestEnum::TEST_6_OUT_OF_BOUNDS,
617                                             TestEnum::TEST_7_OUT_OF_BOUNDS));
618 
619   // Crashes when inputs are out of order.
620   EXPECT_CHECK_DEATH(
621       TestEnumSet().PutRange(TestEnum::TEST_2, TestEnum::TEST_1));
622 }
623 
624 }  // namespace
625 }  // namespace base
626