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/Checked.h>
10#include <AK/NumericLimits.h>
11
12// These tests only check whether the usual operator semantics work.
13// TODO: Add tests about the actual `Check`ing itself!
14
15TEST_CASE(address_identity)
16{
17 Checked<int> a = 4;
18 Checked<int> b = 5;
19 EXPECT_EQ(&a == &a, true);
20 EXPECT_EQ(&a == &b, false);
21 EXPECT_EQ(&a != &a, false);
22 EXPECT_EQ(&a != &b, true);
23}
24
25TEST_CASE(operator_identity)
26{
27 Checked<int> a = 4;
28 EXPECT_EQ(a == 4, true);
29 EXPECT_EQ(a == 5, false);
30 EXPECT_EQ(a != 4, false);
31 EXPECT_EQ(a != 5, true);
32}
33
34TEST_CASE(operator_incr)
35{
36 Checked<int> a = 4;
37 EXPECT_EQ(++a, 5);
38 EXPECT_EQ(++a, 6);
39 EXPECT_EQ(++a, 7);
40 EXPECT_EQ(a++, 7);
41 EXPECT_EQ(a++, 8);
42 EXPECT_EQ(a++, 9);
43 EXPECT_EQ(a, 10);
44}
45
46TEST_CASE(operator_decr)
47{
48 Checked<u32> a = 5;
49 EXPECT_EQ(--a, 4u);
50 EXPECT_EQ(--a, 3u);
51 EXPECT_EQ(a--, 3u);
52 EXPECT_EQ(a--, 2u);
53 EXPECT_EQ(a--, 1u);
54 EXPECT_EQ(a, 0u);
55 EXPECT(!a.has_overflow());
56 a--;
57 EXPECT(a.has_overflow());
58}
59
60TEST_CASE(operator_cmp)
61{
62 Checked<int> a = 4;
63 EXPECT_EQ(a > 3, true);
64 EXPECT_EQ(a < 3, false);
65 EXPECT_EQ(a >= 3, true);
66 EXPECT_EQ(a <= 3, false);
67 EXPECT_EQ(a > 4, false);
68 EXPECT_EQ(a < 4, false);
69 EXPECT_EQ(a >= 4, true);
70 EXPECT_EQ(a <= 4, true);
71 EXPECT_EQ(a > 5, false);
72 EXPECT_EQ(a < 5, true);
73 EXPECT_EQ(a >= 5, false);
74 EXPECT_EQ(a <= 5, true);
75}
76
77TEST_CASE(operator_arith)
78{
79 Checked<int> a = 12;
80 Checked<int> b = 345;
81 EXPECT_EQ(a + b, 357);
82 EXPECT_EQ(b + a, 357);
83 EXPECT_EQ(a - b, -333);
84 EXPECT_EQ(b - a, 333);
85 EXPECT_EQ(a * b, 4140);
86 EXPECT_EQ(b * a, 4140);
87 EXPECT_EQ(a / b, 0);
88 EXPECT_EQ(b / a, 28);
89}
90
91TEST_CASE(detects_signed_overflow)
92{
93 EXPECT(!(Checked<int>(0x40000000) + Checked<int>(0x3fffffff)).has_overflow());
94 EXPECT((Checked<int>(0x40000000) + Checked<int>(0x40000000)).has_overflow());
95 EXPECT(!(Checked<int>(-0x40000000) + Checked<int>(-0x40000000)).has_overflow());
96 EXPECT((Checked<int>(-0x40000001) + Checked<int>(-0x40000000)).has_overflow());
97
98 EXPECT(!(Checked<int>(0x40000000) - Checked<int>(-0x3fffffff)).has_overflow());
99 EXPECT((Checked<int>(0x40000000) - Checked<int>(-0x40000000)).has_overflow());
100 EXPECT(!(Checked<int>(-0x40000000) - Checked<int>(0x40000000)).has_overflow());
101 EXPECT((Checked<int>(-0x40000000) - Checked<int>(0x40000001)).has_overflow());
102
103 EXPECT(!(Checked<i64>(0x4000000000000000) + Checked<i64>(0x3fffffffffffffff)).has_overflow());
104 EXPECT((Checked<i64>(0x4000000000000000) + Checked<i64>(0x4000000000000000)).has_overflow());
105 EXPECT(!(Checked<i64>(-0x4000000000000000) + Checked<i64>(-0x4000000000000000)).has_overflow());
106 EXPECT((Checked<i64>(-0x4000000000000001) + Checked<i64>(-0x4000000000000000)).has_overflow());
107
108 EXPECT(!(Checked<i64>(0x4000000000000000) - Checked<i64>(-0x3fffffffffffffff)).has_overflow());
109 EXPECT((Checked<i64>(0x4000000000000000) - Checked<i64>(-0x4000000000000000)).has_overflow());
110 EXPECT(!(Checked<i64>(-0x4000000000000000) - Checked<i64>(0x4000000000000000)).has_overflow());
111 EXPECT((Checked<i64>(-0x4000000000000000) - Checked<i64>(0x4000000000000001)).has_overflow());
112
113 EXPECT((Checked<i32>(0x80000000) / Checked<i32>(-1)).has_overflow());
114 EXPECT((Checked<i64>(0x8000000000000000) / Checked<i64>(-1)).has_overflow());
115}
116
117TEST_CASE(detects_unsigned_overflow)
118{
119 EXPECT(!(Checked<u32>(0x40000000) + Checked<u32>(0x3fffffff)).has_overflow());
120 EXPECT(!(Checked<u32>(0x40000000) + Checked<u32>(0x40000000)).has_overflow());
121 EXPECT(!(Checked<u32>(0xf0000000) + Checked<u32>(0x0fffffff)).has_overflow());
122 EXPECT((Checked<u32>(0xf0000000) + Checked<u32>(0x10000000)).has_overflow());
123
124 EXPECT(!(Checked<u32>(0x40000000) - Checked<u32>(0x3fffffff)).has_overflow());
125 EXPECT(!(Checked<u32>(0x40000000) - Checked<u32>(0x40000000)).has_overflow());
126 EXPECT((Checked<u32>(0x40000000) - Checked<u32>(0x40000001)).has_overflow());
127
128 EXPECT(!(Checked<u64>(0x4000000000000000) + Checked<u64>(0x3fffffffffffffff)).has_overflow());
129 EXPECT(!(Checked<u64>(0x4000000000000000) + Checked<u64>(0x4000000000000000)).has_overflow());
130 EXPECT(!(Checked<u64>(0xf000000000000000) + Checked<u64>(0x0fffffffffffffff)).has_overflow());
131 EXPECT((Checked<u64>(0xf000000000000000) + Checked<u64>(0x1000000000000000)).has_overflow());
132
133 EXPECT(!(Checked<u64>(0x4000000000000000) - Checked<u64>(0x3fffffffffffffff)).has_overflow());
134 EXPECT(!(Checked<u64>(0x4000000000000000) - Checked<u64>(0x4000000000000000)).has_overflow());
135 EXPECT((Checked<u64>(0x4000000000000000) - Checked<u64>(0x4000000000000001)).has_overflow());
136}
137
138TEST_CASE(should_constexpr_default_construct)
139{
140 constexpr Checked<int> checked_value {};
141 static_assert(!checked_value.has_overflow());
142 static_assert(checked_value == int {});
143}
144
145TEST_CASE(should_constexpr_value_construct)
146{
147 constexpr Checked<int> checked_value { 42 };
148 static_assert(!checked_value.has_overflow());
149 static_assert(checked_value == 42);
150}
151
152TEST_CASE(should_constexpr_convert_construct)
153{
154 constexpr Checked<int> checked_value { 42u };
155 static_assert(!checked_value.has_overflow());
156 static_assert(checked_value == 42);
157}
158
159TEST_CASE(should_constexpr_copy_construct)
160{
161 constexpr auto checked_value = [] {
162 const Checked<int> old_value { 42 };
163 Checked<int> value(old_value);
164 return value;
165 }();
166 static_assert(!checked_value.has_overflow());
167 static_assert(checked_value == 42);
168}
169
170TEST_CASE(should_constexpr_move_construct)
171{
172 constexpr auto checked_value = [] {
173 Checked<int> value(Checked<int> { 42 });
174 return value;
175 }();
176 static_assert(!checked_value.has_overflow());
177 static_assert(checked_value == 42);
178}
179
180TEST_CASE(should_constexpr_copy_assign)
181{
182 constexpr auto checked_value = [] {
183 const Checked<int> old_value { 42 };
184 Checked<int> value {};
185 value = old_value;
186 return value;
187 }();
188 static_assert(!checked_value.has_overflow());
189 static_assert(checked_value == 42);
190}
191
192TEST_CASE(should_constexpr_move_assign)
193{
194 constexpr auto checked_value = [] {
195 Checked<int> value {};
196 value = Checked<int> { 42 };
197 return value;
198 }();
199 static_assert(!checked_value.has_overflow());
200 static_assert(checked_value == 42);
201}
202
203TEST_CASE(should_constexpr_convert_and_assign)
204{
205 constexpr auto checked_value = [] {
206 Checked<int> value {};
207 value = 42;
208 return value;
209 }();
210 static_assert(!checked_value.has_overflow());
211 static_assert(checked_value == 42);
212}
213
214TEST_CASE(should_constexpr_not_operator)
215{
216 constexpr Checked<int> value {};
217 static_assert(!value);
218}
219
220TEST_CASE(should_constexpr_value_accessor)
221{
222 constexpr Checked<int> value { 42 };
223 static_assert(value.value() == 42);
224}
225
226TEST_CASE(should_constexpr_add)
227{
228 constexpr auto checked_value = [] {
229 Checked<int> value { 42 };
230 value.add(3);
231 return value;
232 }();
233 static_assert(checked_value == 45);
234}
235
236TEST_CASE(should_constexpr_sub)
237{
238 constexpr auto checked_value = [] {
239 Checked<int> value { 42 };
240 value.sub(3);
241 return value;
242 }();
243 static_assert(checked_value == 39);
244}
245
246TEST_CASE(should_constexpr_mul)
247{
248 constexpr auto checked_value = [] {
249 Checked<int> value { 42 };
250 value.mul(2);
251 return value;
252 }();
253 static_assert(checked_value == 84);
254}
255
256TEST_CASE(should_constexpr_div)
257{
258 constexpr auto checked_value = [] {
259 Checked<int> value { 42 };
260 value.div(3);
261 return value;
262 }();
263 static_assert(checked_value == 14);
264}
265
266TEST_CASE(should_constexpr_assignment_by_sum)
267{
268 constexpr auto checked_value = [] {
269 Checked<int> value { 42 };
270 value += 3;
271 return value;
272 }();
273 static_assert(checked_value == 45);
274}
275
276TEST_CASE(should_constexpr_assignment_by_diff)
277{
278 constexpr auto checked_value = [] {
279 Checked<int> value { 42 };
280 value -= 3;
281 return value;
282 }();
283 static_assert(checked_value == 39);
284}
285
286TEST_CASE(should_constexpr_assignment_by_product)
287{
288 constexpr auto checked_value = [] {
289 Checked<int> value { 42 };
290 value *= 2;
291 return value;
292 }();
293 static_assert(checked_value == 84);
294}
295
296TEST_CASE(should_constexpr_assignment_by_quotient)
297{
298 constexpr auto checked_value = [] {
299 Checked<int> value { 42 };
300 value /= 3;
301 return value;
302 }();
303 static_assert(checked_value == 14);
304}
305
306TEST_CASE(should_constexpr_prefix_increment)
307{
308 constexpr auto checked_value = [] {
309 Checked<int> value { 42 };
310 ++value;
311 return value;
312 }();
313 static_assert(checked_value == 43);
314}
315
316TEST_CASE(should_constexpr_postfix_increment)
317{
318 constexpr auto checked_value = [] {
319 Checked<int> value { 42 };
320 value++;
321 return value;
322 }();
323 static_assert(checked_value == 43);
324}
325
326TEST_CASE(should_constexpr_check_for_overflow_addition)
327{
328 static_assert(Checked<int>::addition_would_overflow(NumericLimits<int>::max(), 1));
329}
330
331TEST_CASE(should_constexpr_check_for_overflow_multiplication)
332{
333 static_assert(Checked<int>::multiplication_would_overflow(NumericLimits<int>::max(), 2));
334 static_assert(Checked<int>::multiplication_would_overflow(NumericLimits<int>::max(), 1, 2));
335}
336
337TEST_CASE(should_constexpr_add_checked_values)
338{
339 constexpr Checked<int> a { 42 };
340 constexpr Checked<int> b { 17 };
341 constexpr Checked<int> expected { 59 };
342 static_assert(expected == (a + b).value());
343}
344
345TEST_CASE(should_constexpr_subtract_checked_values)
346{
347 constexpr Checked<int> a { 42 };
348 constexpr Checked<int> b { 17 };
349 constexpr Checked<int> expected { 25 };
350 static_assert(expected == (a - b).value());
351}
352
353TEST_CASE(should_constexpr_multiply_checked_values)
354{
355 constexpr Checked<int> a { 3 };
356 constexpr Checked<int> b { 5 };
357 constexpr Checked<int> expected { 15 };
358 static_assert(expected == (a * b).value());
359}
360
361TEST_CASE(should_constexpr_divide_checked_values)
362{
363 constexpr Checked<int> a { 10 };
364 constexpr Checked<int> b { 2 };
365 constexpr Checked<int> expected { 5 };
366 static_assert(expected == (a / b).value());
367}
368
369TEST_CASE(should_constexpr_compare_checked_values_lhs)
370{
371 constexpr Checked<int> a { 10 };
372
373 static_assert(a > 5);
374 static_assert(a >= 10);
375 static_assert(a >= 5);
376
377 static_assert(a < 20);
378 static_assert(a <= 30);
379 static_assert(a <= 20);
380
381 static_assert(a == 10);
382 static_assert(a != 20);
383}
384
385TEST_CASE(should_constexpr_compare_checked_values_rhs)
386{
387 constexpr Checked<int> a { 10 };
388
389 static_assert(5 < a);
390 static_assert(10 <= a);
391 static_assert(5 <= a);
392
393 static_assert(20 > a);
394 static_assert(30 >= a);
395 static_assert(30 >= a);
396
397 static_assert(10 == a);
398 static_assert(20 != a);
399}
400
401TEST_CASE(should_constexpr_make_via_factory)
402{
403 [[maybe_unused]] constexpr auto value = make_checked(42);
404}