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