Project
Loading...
Searching...
No Matches
testEnumFlags.cxx
Go to the documentation of this file.
1// Copyright 2019-2020 CERN and copyright holders of ALICE O2.
2// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders.
3// All rights not expressly granted are reserved.
4//
5// This software is distributed under the terms of the GNU General Public
6// License v3 (GPL Version 3), copied verbatim in the file "COPYING".
7//
8// In applying this license CERN does not waive the privileges and immunities
9// granted to it by virtue of its status as an Intergovernmental Organization
10// or submit itself to any jurisdiction.
11
12#define BOOST_TEST_MODULE Test Flags
13#define BOOST_TEST_MAIN
14#define BOOST_TEST_DYN_LINK
15
16#include <boost/test/unit_test.hpp>
17#include <boost/preprocessor/arithmetic/inc.hpp>
18#include <boost/preprocessor/repetition/repeat.hpp>
19
20#include <stdexcept>
21#include <string>
22
24
25// Example enum to use with EnumFlags
26enum class TestEnum : uint8_t {
27 Bit1 = 0,
28 Bit2,
29 Bit3,
30 Bit4,
32};
33
34// Very long enum
35// to test that it works beyond 32 bits upto 64 bits
36#define ENUM_BIT_NAME(n) Bit##n
37#define ENUM_BIT_NAME_EXPAND(n) ENUM_BIT_NAME(n)
38#define ENUM_BIT(z, n, _) ENUM_BIT_NAME_EXPAND(BOOST_PP_INC(n)) = (n),
39enum class TestEnumLong : uint64_t {
40 BOOST_PP_REPEAT(64, ENUM_BIT, _)
41};
42#undef ENUM_BIT
43#undef ENUM_BIT_NAME
44#undef ENUM_BIT_NAME_EXPAND
45
47{
48 using EFlags = o2::utils::EnumFlags<TestEnum>;
49
50 // Test default initialization
51 EFlags flags;
52 BOOST_TEST(flags.None == 0);
53 BOOST_TEST(flags.All == 31);
54 BOOST_TEST(flags.value() == 0);
55 BOOST_TEST(!flags.any());
56
57 // Test initialization with a single flag
58 EFlags flag1(TestEnum::Bit1);
59 BOOST_TEST(flag1.test(TestEnum::Bit1));
60 BOOST_TEST(!flag1.test(TestEnum::Bit2));
61 BOOST_TEST(flag1.value() == (1 << static_cast<unsigned int>(TestEnum::Bit1)));
62
63 // Test initialization with initializer list
64 EFlags multipleFlags({TestEnum::Bit1, TestEnum::Bit3});
65 BOOST_TEST(multipleFlags.test(TestEnum::Bit1));
66 BOOST_TEST(multipleFlags.test(TestEnum::Bit3));
67 BOOST_TEST(!multipleFlags.test(TestEnum::Bit2));
68 BOOST_TEST(multipleFlags.any());
69
70 // Test reset
71 multipleFlags.reset(TestEnum::Bit1);
72 BOOST_TEST(!multipleFlags.test(TestEnum::Bit1));
73 BOOST_TEST(multipleFlags.test(TestEnum::Bit3));
74 multipleFlags.reset();
75 BOOST_TEST(!multipleFlags.any());
76
77 // Test operator|
78 EFlags combinedFlags = flag1 | EFlags(TestEnum::Bit2);
79 BOOST_TEST(combinedFlags.test(TestEnum::Bit1));
80 BOOST_TEST(combinedFlags.test(TestEnum::Bit2));
81 BOOST_TEST(!combinedFlags.test(TestEnum::Bit3));
82
83 // Test operator[]
84 BOOST_TEST(combinedFlags[TestEnum::Bit1]);
85 BOOST_TEST(combinedFlags[TestEnum::Bit2]);
86 BOOST_TEST(!combinedFlags[TestEnum::Bit3]);
87
88 // Test operator|=
89 combinedFlags |= TestEnum::Bit3;
90 BOOST_TEST(combinedFlags.test(TestEnum::Bit3));
91
92 // Test operator&
93 EFlags intersection = combinedFlags & TestEnum::Bit1;
94 BOOST_TEST(intersection.test(TestEnum::Bit1));
95 BOOST_TEST(!intersection.test(TestEnum::Bit2));
96 BOOST_TEST(intersection.value() == (1 << static_cast<unsigned int>(TestEnum::Bit1)));
97
98 // Test operator&=
99 combinedFlags &= TestEnum::Bit1;
100 BOOST_TEST(combinedFlags.test(TestEnum::Bit1));
101 BOOST_TEST(!combinedFlags.test(TestEnum::Bit2));
102 BOOST_TEST(!combinedFlags.test(TestEnum::Bit3));
103
104 // Test operator~ (complement)
105 EFlags complement = ~EFlags(TestEnum::Bit1);
106 BOOST_TEST(!complement.test(TestEnum::Bit1));
107 BOOST_TEST(complement.test(TestEnum::Bit2));
108 BOOST_TEST(complement.test(TestEnum::Bit3));
109
110 // Test string() method
111 {
112 std::string flagString = flag1.string();
113 BOOST_TEST(flagString.back() == '1'); // Ensure the least significant bit is set for flag1
114 }
115
116 // Test set with binary string
117 {
118 std::string binaryStr = "101";
119 flags.set(binaryStr, 2);
123 }
124
125 // Test invalid binary string in set
126 BOOST_CHECK_THROW(flags.set(std::string("invalid"), 2), std::invalid_argument);
127
128 // Test range validation in set
129 BOOST_CHECK_THROW(flags.set(std::string("100000000"), 2), std::out_of_range);
130
131 { // Test that return lists are sensible
132 const auto n = flags.getNames();
133 const auto v = flags.getValues();
134 BOOST_CHECK(n.size() == v.size());
135 }
136
137 { // print test
138 std::cout << flags;
139 }
140
141 // Test flag tokenization and parsing
142 {
143 { // only one scoped flag
144 std::string str = "TestEnum::Bit2";
145 flags.set(str);
148 }
149
150 { // test with ws-triming and scope mixing
151 std::string str = "Bit4|TestEnum::Bit2 | Bit1 ";
152 flags.set(str);
157 }
158
159 { // test with , delimiter
160 std::string str = "Bit4,TestEnum::Bit2 , Bit1 ";
161 flags.set(str);
166 }
167
168 { // test with ; delimiter
169 std::string str = "Bit4;TestEnum::Bit2 ; Bit1 ";
170 flags.set(str);
175 }
176
177 { // throw test with mixed delimiter
178 std::string str = "Bit4|TestEnum::Bit2 , Bit1 ";
179 BOOST_CHECK_THROW(flags.set(str), std::invalid_argument);
180 }
181
182 { // test throw
183 std::string str = "Invalid";
184 BOOST_CHECK_THROW(flags.set(str), std::invalid_argument);
185 }
186 }
187
188 // Test all_of and none_of
189 {
190 EFlags allFlags({TestEnum::Bit1, TestEnum::Bit2, TestEnum::Bit3});
191 BOOST_TEST(allFlags.all_of(TestEnum::Bit1, TestEnum::Bit2));
192 BOOST_TEST(!allFlags.all_of(TestEnum::Bit4));
193 BOOST_TEST(allFlags.none_of(TestEnum::Bit4));
194 }
195
196 // Test toggle
197 {
198 EFlags toggleFlags;
199 toggleFlags.toggle(TestEnum::Bit4);
200 BOOST_TEST(toggleFlags.test(TestEnum::Bit4));
201 toggleFlags.toggle(TestEnum::Bit4);
202 BOOST_TEST(!toggleFlags.test(TestEnum::Bit4));
203 }
204
205 // Create a flag set and serialize it
206 {
207 EFlags serializedFlags{TestEnum::Bit1, TestEnum::Bit3};
208 std::string serialized = serializedFlags.serialize();
209 BOOST_CHECK_EQUAL(serialized, "5"); // 5 in binary is 0101, meaning Bit1 and Bit3 are set.
210
211 // Deserialize back into a flag set
212 EFlags deserializedFlags;
213 deserializedFlags.deserialize(serialized);
214 BOOST_CHECK(deserializedFlags == serializedFlags); // Ensure the deserialized flags match the original
215 }
216
217 // Test with an empty flag set
218 {
219 EFlags emptyFlags;
220 std::string serialized = emptyFlags.serialize();
221 BOOST_CHECK_EQUAL(serialized, "0");
222
223 EFlags deserialized;
224 deserialized.deserialize(serialized);
225 BOOST_CHECK(deserialized == emptyFlags);
226
227 // Test with all flags set
228 EFlags allFlags(EFlags::All);
229 serialized = allFlags.serialize();
230 BOOST_CHECK_EQUAL(serialized, std::to_string(EFlags::All));
231
232 deserialized.deserialize(serialized);
233 BOOST_CHECK(deserialized == allFlags);
234 }
235
236 // check throw deserializng out of range
237 {
238 EFlags flag;
239 std::string str = "999999";
240 BOOST_CHECK_THROW(flag.deserialize(str), std::out_of_range);
241 }
242
243 // Create two flag sets
244 {
245 EFlags flags1{TestEnum::Bit1, TestEnum::Bit2};
246 EFlags flags2{TestEnum::Bit3, TestEnum::Bit4};
247
248 // Perform a union operation
249 EFlags unionFlags = flags1.union_with(flags2);
250 BOOST_CHECK(unionFlags.test(TestEnum::Bit1));
251 BOOST_CHECK(unionFlags.test(TestEnum::Bit2));
252 BOOST_CHECK(unionFlags.test(TestEnum::Bit3));
253 BOOST_CHECK(unionFlags.test(TestEnum::Bit4));
254 BOOST_CHECK_EQUAL(unionFlags.value(), 15); // 1111 in binary
255 }
256
257 // Create two overlapping flag sets
258 {
261
262 // test xor
263 auto flagsXOR = flags3 ^ flags4;
265
266 // test and
267 auto flagsAND = flags3 & flags4;
269
270 // Perform an intersection operation
271 EFlags intersectionFlags = flags3.intersection_with(flags4);
272 BOOST_CHECK(intersectionFlags.test(TestEnum::Bit2));
273 BOOST_CHECK(intersectionFlags.test(TestEnum::Bit3));
274 BOOST_CHECK(!intersectionFlags.test(TestEnum::Bit1));
275 BOOST_CHECK(!intersectionFlags.test(TestEnum::Bit4));
276 BOOST_CHECK_EQUAL(intersectionFlags.value(), 6); // 0110 in binary
277 }
278
279 {
280 // Check special flag names.
281 EFlags flag("all");
282 BOOST_CHECK(flag.all());
283 flag.set("none");
284 BOOST_CHECK(!flag.any());
285 }
286
287 {
288 // Create two flag sets
290 EFlags flags2{TestEnum::Bit2, TestEnum::Bit3};
291
292 // Check containment
293 BOOST_CHECK(flags1.contains(flags2)); // flags1 contains all flags in flags2
294 BOOST_CHECK(!flags2.contains(flags1)); // flags2 does not contain all flags in flags1
295
296 // Test with disjoint sets
297 EFlags flags3{TestEnum::Bit4};
298 BOOST_CHECK(!flags1.contains(flags3)); // flags1 does not contain flags3
299 }
300
301 {
302 // Test compilation using an enum with more than 32 bits
303 // Also tests space delimiter and construction from string.
305 BOOST_CHECK(test.test(TestEnumLong::Bit32, TestEnumLong::Bit34));
306 BOOST_CHECK(!test.test(TestEnumLong::Bit1, TestEnumLong::Bit23));
307 }
308}
Classs to aggregate and manage enum-based on-off flags.
Definition EnumFlags.h:357
GLdouble n
Definition glcorearb.h:1982
const GLdouble * v
Definition glcorearb.h:832
GLbitfield flags
Definition glcorearb.h:1570
std::string to_string(gsl::span< T, Size > span)
Definition common.h:52
FIXME: do not use data model tables.
#define ENUM_BIT(z, n, _)
TestEnum
@ Bit5VeryLongName
TestEnumLong
BOOST_AUTO_TEST_CASE(Flags_test)
BOOST_CHECK(tree)
BOOST_TEST(digits==digitsD, boost::test_tools::per_element())
BOOST_CHECK_EQUAL(triggersD.size(), triggers.size())
const std::string str