Serenity Operating System
1/*
2 * Copyright (c) 2020, Ben Wiederhake <BenWiederhake.GitHub@gmx.de>
3 *
4 * SPDX-License-Identifier: BSD-2-Clause
5 */
6
7#include <LibTest/TestCase.h>
8
9#include <AK/DistinctNumeric.h>
10
11template<typename T>
12class ForType {
13public:
14 static void check_size()
15 {
16 AK_TYPEDEF_DISTINCT_NUMERIC_GENERAL(T, TheNumeric);
17 EXPECT_EQ(sizeof(T), sizeof(TheNumeric));
18 }
19};
20
21TEST_CASE(check_size)
22{
23#define CHECK_SIZE_FOR_SIGNABLE(T) \
24 do { \
25 ForType<signed T>::check_size(); \
26 ForType<unsigned T>::check_size(); \
27 } while (false)
28 CHECK_SIZE_FOR_SIGNABLE(char);
29 CHECK_SIZE_FOR_SIGNABLE(short);
30 CHECK_SIZE_FOR_SIGNABLE(int);
31 CHECK_SIZE_FOR_SIGNABLE(long);
32 CHECK_SIZE_FOR_SIGNABLE(long long);
33 ForType<float>::check_size();
34 ForType<double>::check_size();
35}
36
37AK_TYPEDEF_DISTINCT_NUMERIC_GENERAL(int, BareNumeric);
38AK_TYPEDEF_DISTINCT_NUMERIC_GENERAL(int, IncrNumeric, Increment);
39AK_TYPEDEF_DISTINCT_NUMERIC_GENERAL(int, CmpNumeric, Comparison);
40AK_TYPEDEF_DISTINCT_NUMERIC_GENERAL(int, BoolNumeric, CastToBool);
41AK_TYPEDEF_DISTINCT_NUMERIC_GENERAL(int, FlagsNumeric, Flags);
42AK_TYPEDEF_DISTINCT_NUMERIC_GENERAL(int, ShiftNumeric, Shift);
43AK_TYPEDEF_DISTINCT_NUMERIC_GENERAL(int, ArithNumeric, Arithmetic);
44AK_TYPEDEF_DISTINCT_NUMERIC_GENERAL(int, UnderlyingNumeric, CastToUnderlying);
45AK_TYPEDEF_DISTINCT_NUMERIC_GENERAL(int, GeneralNumeric, Arithmetic, CastToBool, CastToUnderlying, Comparison, Flags, Increment, Shift);
46
47TEST_CASE(address_identity)
48{
49 BareNumeric a = 4;
50 BareNumeric b = 5;
51 EXPECT_EQ(&a == &a, true);
52 EXPECT_EQ(&a == &b, false);
53 EXPECT_EQ(&a != &a, false);
54 EXPECT_EQ(&a != &b, true);
55}
56
57TEST_CASE(operator_identity)
58{
59 BareNumeric a = 4;
60 BareNumeric b = 5;
61 EXPECT_EQ(a == a, true);
62 EXPECT_EQ(a == b, false);
63 EXPECT_EQ(a != a, false);
64 EXPECT_EQ(a != b, true);
65}
66
67TEST_CASE(operator_incr)
68{
69 IncrNumeric a = 4;
70 IncrNumeric b = 5;
71 IncrNumeric c = 6;
72 EXPECT_EQ(++a, b);
73 EXPECT_EQ(a++, b);
74 EXPECT_EQ(a, c);
75 EXPECT_EQ(--a, b);
76 EXPECT_EQ(a--, b);
77 EXPECT(a != b);
78}
79
80TEST_CASE(operator_cmp)
81{
82 CmpNumeric a = 4;
83 CmpNumeric b = 5;
84 CmpNumeric c = 5;
85 EXPECT_EQ(a > b, false);
86 EXPECT_EQ(a < b, true);
87 EXPECT_EQ(a >= b, false);
88 EXPECT_EQ(a <= b, true);
89 EXPECT_EQ(b > a, true);
90 EXPECT_EQ(b < a, false);
91 EXPECT_EQ(b >= a, true);
92 EXPECT_EQ(b <= a, false);
93 EXPECT_EQ(b > c, false);
94 EXPECT_EQ(b < c, false);
95 EXPECT_EQ(b >= c, true);
96 EXPECT_EQ(b <= c, true);
97}
98
99TEST_CASE(operator_bool)
100{
101 BoolNumeric a = 0;
102 BoolNumeric b = 42;
103 BoolNumeric c = 1337;
104 EXPECT_EQ(!a, true);
105 EXPECT_EQ(!b, false);
106 EXPECT_EQ(!c, false);
107}
108
109TEST_CASE(operator_underlying)
110{
111 UnderlyingNumeric a = 0;
112 UnderlyingNumeric b = 42;
113 EXPECT_EQ(static_cast<int>(a), 0);
114 EXPECT_EQ(static_cast<int>(b), 42);
115}
116
117TEST_CASE(operator_flags)
118{
119 FlagsNumeric a = 0;
120 FlagsNumeric b = 0xA60;
121 FlagsNumeric c = 0x03B;
122 EXPECT_EQ(~a, FlagsNumeric(~0x0));
123 EXPECT_EQ(~b, FlagsNumeric(~0xA60));
124 EXPECT_EQ(~c, FlagsNumeric(~0x03B));
125
126 EXPECT_EQ(a & b, b & a);
127 EXPECT_EQ(a & c, c & a);
128 EXPECT_EQ(b & c, c & b);
129 EXPECT_EQ(a | b, b | a);
130 EXPECT_EQ(a | c, c | a);
131 EXPECT_EQ(b | c, c | b);
132 EXPECT_EQ(a ^ b, b ^ a);
133 EXPECT_EQ(a ^ c, c ^ a);
134 EXPECT_EQ(b ^ c, c ^ b);
135
136 EXPECT_EQ(a & b, FlagsNumeric(0x000));
137 EXPECT_EQ(a & c, FlagsNumeric(0x000));
138 EXPECT_EQ(b & c, FlagsNumeric(0x020));
139 EXPECT_EQ(a | b, FlagsNumeric(0xA60));
140 EXPECT_EQ(a | c, FlagsNumeric(0x03B));
141 EXPECT_EQ(b | c, FlagsNumeric(0xA7B));
142 EXPECT_EQ(a ^ b, FlagsNumeric(0xA60));
143 EXPECT_EQ(a ^ c, FlagsNumeric(0x03B));
144 EXPECT_EQ(b ^ c, FlagsNumeric(0xA5B));
145
146 EXPECT_EQ(a &= b, FlagsNumeric(0x000));
147 EXPECT_EQ(a, FlagsNumeric(0x000));
148 EXPECT_EQ(a |= b, FlagsNumeric(0xA60));
149 EXPECT_EQ(a, FlagsNumeric(0xA60));
150 EXPECT_EQ(a &= c, FlagsNumeric(0x020));
151 EXPECT_EQ(a, FlagsNumeric(0x020));
152 EXPECT_EQ(a ^= b, FlagsNumeric(0xA40));
153 EXPECT_EQ(a, FlagsNumeric(0xA40));
154
155 EXPECT_EQ(b, FlagsNumeric(0xA60));
156 EXPECT_EQ(c, FlagsNumeric(0x03B));
157}
158
159TEST_CASE(operator_shift)
160{
161 ShiftNumeric a = 0x040;
162 EXPECT_EQ(a << ShiftNumeric(0), ShiftNumeric(0x040));
163 EXPECT_EQ(a << ShiftNumeric(1), ShiftNumeric(0x080));
164 EXPECT_EQ(a << ShiftNumeric(2), ShiftNumeric(0x100));
165 EXPECT_EQ(a >> ShiftNumeric(0), ShiftNumeric(0x040));
166 EXPECT_EQ(a >> ShiftNumeric(1), ShiftNumeric(0x020));
167 EXPECT_EQ(a >> ShiftNumeric(2), ShiftNumeric(0x010));
168
169 EXPECT_EQ(a <<= ShiftNumeric(5), ShiftNumeric(0x800));
170 EXPECT_EQ(a, ShiftNumeric(0x800));
171 EXPECT_EQ(a >>= ShiftNumeric(8), ShiftNumeric(0x008));
172 EXPECT_EQ(a, ShiftNumeric(0x008));
173}
174
175TEST_CASE(operator_arith)
176{
177 ArithNumeric a = 12;
178 ArithNumeric b = 345;
179 EXPECT_EQ(a + b, ArithNumeric(357));
180 EXPECT_EQ(b + a, ArithNumeric(357));
181 EXPECT_EQ(a - b, ArithNumeric(-333));
182 EXPECT_EQ(b - a, ArithNumeric(333));
183 EXPECT_EQ(+a, ArithNumeric(12));
184 EXPECT_EQ(-a, ArithNumeric(-12));
185 EXPECT_EQ(a * b, ArithNumeric(4140));
186 EXPECT_EQ(b * a, ArithNumeric(4140));
187 EXPECT_EQ(a / b, ArithNumeric(0));
188 EXPECT_EQ(b / a, ArithNumeric(28));
189 EXPECT_EQ(a % b, ArithNumeric(12));
190 EXPECT_EQ(b % a, ArithNumeric(9));
191
192 EXPECT_EQ(a += a, ArithNumeric(24));
193 EXPECT_EQ(a, ArithNumeric(24));
194 EXPECT_EQ(a *= a, ArithNumeric(576));
195 EXPECT_EQ(a, ArithNumeric(576));
196 EXPECT_EQ(a /= a, ArithNumeric(1));
197 EXPECT_EQ(a, ArithNumeric(1));
198 EXPECT_EQ(a %= a, ArithNumeric(0));
199 EXPECT_EQ(a, ArithNumeric(0));
200
201 a = ArithNumeric(12);
202 EXPECT_EQ(a -= a, ArithNumeric(0));
203 EXPECT_EQ(a, ArithNumeric(0));
204}
205
206TEST_CASE(composability)
207{
208 GeneralNumeric a = 0;
209 GeneralNumeric b = 1;
210 // Ident
211 EXPECT_EQ(a == a, true);
212 EXPECT_EQ(a == b, false);
213 // Incr
214 EXPECT_EQ(++a, b);
215 EXPECT_EQ(a--, b);
216 EXPECT_EQ(a == b, false);
217 // Cmp
218 EXPECT_EQ(a < b, true);
219 EXPECT_EQ(a >= b, false);
220 // Bool
221 EXPECT_EQ(!a, true);
222 // Flags
223 EXPECT_EQ(a & b, GeneralNumeric(0));
224 EXPECT_EQ(a | b, GeneralNumeric(1));
225 // Shift
226 EXPECT_EQ(b << GeneralNumeric(4), GeneralNumeric(0x10));
227 EXPECT_EQ(b >> b, GeneralNumeric(0));
228 // Arith
229 EXPECT_EQ(-b, GeneralNumeric(-1));
230 EXPECT_EQ(a + b, b);
231 EXPECT_EQ(b * GeneralNumeric(42), GeneralNumeric(42));
232 // Underlying
233 EXPECT_EQ(static_cast<int>(a), 0);
234 EXPECT_EQ(static_cast<int>(b), 1);
235}
236
237/*
238 * FIXME: These `negative_*` tests should cause precisely one compilation error
239 * each, and always for the specified reason. Currently we do not have a harness
240 * for that, so in order to run the test you need to set the #define to 1, compile
241 * it, and check the error messages manually.
242 */
243#define COMPILE_NEGATIVE_TESTS 0
244#if COMPILE_NEGATIVE_TESTS
245TEST_CASE(negative_incr)
246{
247 BareNumeric a = 12;
248 a++;
249 // error: static assertion failed: 'a++' is only available for DistinctNumeric types with 'Increment'.
250}
251
252TEST_CASE(negative_cmp)
253{
254 BareNumeric a = 12;
255 [[maybe_unused]] auto res = (a < a);
256 // error: static assertion failed: 'a<b' is only available for DistinctNumeric types with 'Comparison'.
257}
258
259TEST_CASE(negative_bool)
260{
261 BareNumeric a = 12;
262 [[maybe_unused]] auto res = !a;
263 // error: static assertion failed: '!a', 'a&&b', 'a||b' and similar operators are only available for DistinctNumeric types with 'CastToBool'.
264}
265
266TEST_CASE(negative_flags)
267{
268 BareNumeric a = 12;
269 [[maybe_unused]] auto res = (a & a);
270 // error: static assertion failed: 'a&b' is only available for DistinctNumeric types with 'Flags'.
271}
272
273TEST_CASE(negative_shift)
274{
275 BareNumeric a = 12;
276 [[maybe_unused]] auto res = (a << a);
277 // error: static assertion failed: 'a<<b' is only available for DistinctNumeric types with 'Shift'.
278}
279
280TEST_CASE(negative_arith)
281{
282 BareNumeric a = 12;
283 [[maybe_unused]] auto res = (a + a);
284 // error: static assertion failed: 'a+b' is only available for DistinctNumeric types with 'Arithmetic'.
285}
286
287TEST_CASE(negative_underlying)
288{
289 BareNumeric a = 12;
290 [[maybe_unused]] int res = static_cast<int>(a);
291 // error: static assertion failed: Cast to underlying type is only available for DistinctNumeric types with 'CastToUnderlying'.
292}
293
294TEST_CASE(negative_incompatible)
295{
296 GeneralNumeric a = 12;
297 ArithNumeric b = 345;
298 // And this is the entire point of `DistinctNumeric`:
299 // Theoretically, the operation *could* be supported, but we declared those int types incompatible.
300 [[maybe_unused]] auto res = (a + b);
301 // error: no match for ‘operator+’ (operand types are ‘GeneralNumeric’ {aka ‘AK::DistinctNumeric<int, true, true, true, true, true, true, 64, 64>’} and ‘ArithNumeric’ {aka ‘AK::DistinctNumeric<int, false, false, false, false, false, true, 64, 63>’})
302 // 313 | [[maybe_unused]] auto res = (a + b);
303 // | ~ ^ ~
304 // | | |
305 // | | DistinctNumeric<[...],false,false,false,false,false,[...],[...],63>
306 // | DistinctNumeric<[...],true,true,true,true,true,[...],[...],64>
307}
308#endif /* COMPILE_NEGATIVE_TESTS */