1 // Copyright (C) 2016-2020 Jonathan Müller <jonathanmueller.dev@gmail.com>
2 // This file is subject to the license terms in the LICENSE file
3 // found in the top-level directory of this distribution.
4
5 #include <type_safe/flag_set.hpp>
6
7 #include <catch.hpp>
8
9 // no using namespace to test operator namespace
10
11 enum class test_flags
12 {
13 a,
14 b,
15 c
16 };
17
18 namespace type_safe
19 {
20 template <>
21 struct flag_set_traits<test_flags> : std::true_type
22 {
sizetype_safe::flag_set_traits23 static constexpr std::size_t size()
24 {
25 return 3;
26 }
27 };
28 } // namespace type_safe
29
check_set(const type_safe::flag_set<test_flags> & set,bool a,bool b,bool c)30 void check_set(const type_safe::flag_set<test_flags>& set, bool a, bool b, bool c)
31 {
32 REQUIRE(set.is_set(test_flags::a) == a);
33 REQUIRE(set.as_flag(test_flags::a) == a);
34 if (a)
35 REQUIRE((set & test_flags::a));
36
37 REQUIRE(set.is_set(test_flags::b) == b);
38 REQUIRE(set.as_flag(test_flags::b) == b);
39 if (b)
40 REQUIRE((set & test_flags::b));
41
42 REQUIRE(set.is_set(test_flags::c) == c);
43 REQUIRE(set.as_flag(test_flags::c) == c);
44 if (c)
45 REQUIRE((set & test_flags::c));
46
47 if (a || b || c)
48 {
49 REQUIRE(set.any());
50 REQUIRE_FALSE(set.none());
51 REQUIRE(set != type_safe::noflag);
52 REQUIRE(type_safe::noflag != set);
53 }
54 else
55 {
56 REQUIRE_FALSE(set.any());
57 REQUIRE(set.none());
58 REQUIRE(set == type_safe::noflag);
59 REQUIRE(type_safe::noflag == set);
60 }
61
62 auto number = (a ? 4 : 0) + (b ? 2 : 0) + (c ? 1 : 0);
63 switch (number)
64 {
65 case 0:
66 REQUIRE(set == type_safe::flag_set<test_flags>());
67 break;
68 case 1:
69 REQUIRE(set == test_flags::c);
70 REQUIRE(set == type_safe::combo(~test_flags::a & ~test_flags::b));
71 REQUIRE((set & test_flags::c));
72 break;
73 case 2:
74 REQUIRE(set == test_flags::b);
75 REQUIRE(set == type_safe::combo(~test_flags::a & ~test_flags::c));
76 REQUIRE((set & test_flags::b));
77 break;
78 case 3:
79 REQUIRE(set == (test_flags::b | test_flags::c));
80 REQUIRE(set == type_safe::combo(~test_flags::a));
81 REQUIRE((set & (test_flags::b | test_flags::c)));
82 break;
83 case 4:
84 REQUIRE(set == test_flags::a);
85 REQUIRE(set == type_safe::combo(~test_flags::b & ~test_flags::c));
86 REQUIRE((set & test_flags::a));
87 break;
88 case 5:
89 REQUIRE(set == (test_flags::a | test_flags::c));
90 REQUIRE(set == type_safe::combo(~test_flags::b));
91 REQUIRE((set & (test_flags::a | test_flags::c)));
92 break;
93 case 6:
94 REQUIRE(set == (test_flags::a | test_flags::b));
95 REQUIRE(set == type_safe::combo(~test_flags::c));
96 REQUIRE((set & (test_flags::a | test_flags::b)));
97 break;
98 case 7:
99 REQUIRE(set.all());
100 REQUIRE(set == (test_flags::a | test_flags::b | test_flags::c));
101 REQUIRE((set & (test_flags::a | test_flags::b | test_flags::c)));
102 break;
103
104 default:
105 REQUIRE(false);
106 break;
107 }
108 }
109
110 TEST_CASE("flag_set_traits")
111 {
112 using namespace type_safe;
113
114 enum class a
115 {
116 e1,
117 e2,
118 e3
119 };
120 static_assert(!flag_set_traits<a>::value, "a is not a flag set enum");
121
122 enum class b
123 {
124 e1,
125 e2,
126 e3,
127 _flag_set_size,
128 };
129 static_assert(flag_set_traits<b>::value, "b is a flag set enum");
130 static_assert(flag_set_traits<b>::size() == 3u, "size of b is 3");
131 }
132
133 TEST_CASE("flag_set")
134 {
135 using namespace type_safe;
136
137 using set = flag_set<test_flags>;
138
139 set s;
140 check_set(s, false, false, false);
141
142 SECTION("constructor/assignment")
143 {
144 set a;
145 check_set(a, false, false, false);
146
147 set b(test_flags::a);
148 check_set(b, true, false, false);
149
150 a = test_flags::b;
151 check_set(a, false, true, false);
152
153 b = test_flags::c;
154 check_set(b, false, false, true);
155 }
156 SECTION("set")
157 {
158 s.set(test_flags::a);
159 check_set(s, true, false, false);
160
161 s.set(test_flags::b, true);
162 check_set(s, true, true, false);
163
164 s.set(test_flags::a, false);
165 check_set(s, false, true, false);
166
167 s.set(test_flags::a, flag(true));
168 check_set(s, true, true, false);
169 }
170 SECTION("reset")
171 {
172 s.set(test_flags::a);
173 check_set(s, true, false, false);
174
175 s.reset(test_flags::b);
176 check_set(s, true, false, false);
177
178 s.reset(test_flags::a);
179 check_set(s, false, false, false);
180 }
181 SECTION("toggle")
182 {
183 s.toggle(test_flags::a);
184 check_set(s, true, false, false);
185
186 s.toggle(test_flags::b);
187 check_set(s, true, true, false);
188
189 s.toggle(test_flags::a);
190 check_set(s, false, true, false);
191 }
192 SECTION("set_all/reset_all/toggle_all")
193 {
194 s.set_all();
195 check_set(s, true, true, true);
196
197 s.reset_all();
198 check_set(s, false, false, false);
199
200 s.set(test_flags::c);
201 check_set(s, false, false, true);
202
203 s.toggle_all();
204 check_set(s, true, true, false);
205 }
206 SECTION("binary op")
207 {
208 s |= test_flags::a;
209 check_set(s, true, false, false);
210
211 s |= test_flags::b | test_flags::c;
212 check_set(s, true, true, true);
213
214 s &= ~test_flags::c;
215 check_set(s, true, true, false);
216
217 s = ~s;
218 check_set(s, false, false, true);
219
220 s ^= test_flags::a | test_flags::c;
221 check_set(s, true, false, false);
222 }
223 }
224