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