1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /* vim: set ts=8 sts=2 et sw=2 tw=80: */
3 /* This Source Code Form is subject to the terms of the Mozilla Public
4 * License, v. 2.0. If a copy of the MPL was not distributed with this file,
5 * You can obtain one at http://mozilla.org/MPL/2.0/. */
7 #include "mozilla/CheckedInt.h"
11 #include <type_traits>
13 using namespace mozilla
;
15 int gIntegerTypesTested
= 0;
19 void verifyImplFunction(bool aX
, bool aExpected
, const char* aFile
, int aLine
,
20 int aSize
, bool aIsTSigned
) {
21 if (aX
== aExpected
) {
25 std::cerr
<< "Test failed at " << aFile
<< ":" << aLine
;
26 std::cerr
<< " with T a ";
28 std::cerr
<< "signed";
30 std::cerr
<< "unsigned";
32 std::cerr
<< " " << CHAR_BIT
* aSize
<< "-bit integer type" << std::endl
;
36 #define VERIFY_IMPL(x, expected) \
37 verifyImplFunction((x), (expected), __FILE__, __LINE__, sizeof(T), \
40 #define VERIFY(x) VERIFY_IMPL(x, true)
41 #define VERIFY_IS_FALSE(x) VERIFY_IMPL(x, false)
42 #define VERIFY_IS_VALID(x) VERIFY_IMPL((x).isValid(), true)
43 #define VERIFY_IS_INVALID(x) VERIFY_IMPL((x).isValid(), false)
44 #define VERIFY_IS_VALID_IF(x, condition) VERIFY_IMPL((x).isValid(), (condition))
46 template <typename T
, size_t Size
= sizeof(T
)>
47 struct testTwiceBiggerType
{
50 detail::IsSupported
<typename
detail::TwiceBiggerType
<T
>::Type
>::value
);
51 VERIFY(sizeof(typename
detail::TwiceBiggerType
<T
>::Type
) == 2 * sizeof(T
));
52 VERIFY(bool(std::is_signed_v
<typename
detail::TwiceBiggerType
<T
>::Type
>) ==
53 bool(std::is_signed_v
<T
>));
58 struct testTwiceBiggerType
<T
, 8> {
61 detail::IsSupported
<typename
detail::TwiceBiggerType
<T
>::Type
>::value
);
67 static bool alreadyRun
= false;
68 // Integer types from different families may just be typedefs for types from
69 // other families. E.g. int32_t might be just a typedef for int. No point
70 // re-running the same tests then.
76 VERIFY(detail::IsSupported
<T
>::value
);
77 const bool isTSigned
= std::is_signed_v
<T
>;
78 VERIFY(bool(isTSigned
) == !bool(T(-1) > T(0)));
80 testTwiceBiggerType
<T
>::run();
82 using unsignedT
= std::make_unsigned_t
<T
>;
84 VERIFY(sizeof(unsignedT
) == sizeof(T
));
85 VERIFY(std::is_signed_v
<unsignedT
> == false);
87 const CheckedInt
<T
> max(std::numeric_limits
<T
>::max());
88 const CheckedInt
<T
> min(std::numeric_limits
<T
>::min());
90 // Check MinValue and MaxValue, since they are custom implementations and a
91 // mistake there could potentially NOT be caught by any other tests... while
92 // making everything wrong!
95 unsignedT
unsignedMinValue(min
.value());
96 unsignedT
unsignedMaxValue(max
.value());
97 for (size_t i
= 0; i
< sizeof(T
) * CHAR_BIT
- 1; i
++) {
98 VERIFY((unsignedMinValue
& bit
) == 0);
101 VERIFY((unsignedMinValue
& bit
) == (isTSigned
? bit
: unsignedT(0)));
102 VERIFY(unsignedMaxValue
== unsignedT(~unsignedMinValue
));
104 const CheckedInt
<T
> zero(0);
105 const CheckedInt
<T
> one(1);
106 const CheckedInt
<T
> two(2);
107 const CheckedInt
<T
> three(3);
108 const CheckedInt
<T
> four(4);
110 /* Addition / subtraction checks */
112 VERIFY_IS_VALID(zero
+ zero
);
113 VERIFY(zero
+ zero
== zero
);
114 VERIFY_IS_FALSE(zero
+ zero
== one
); // Check == doesn't always return true
115 VERIFY_IS_VALID(zero
+ one
);
116 VERIFY(zero
+ one
== one
);
117 VERIFY_IS_VALID(one
+ one
);
118 VERIFY(one
+ one
== two
);
120 const CheckedInt
<T
> maxMinusOne
= max
- one
;
121 const CheckedInt
<T
> maxMinusTwo
= max
- two
;
122 VERIFY_IS_VALID(maxMinusOne
);
123 VERIFY_IS_VALID(maxMinusTwo
);
124 VERIFY_IS_VALID(maxMinusOne
+ one
);
125 VERIFY_IS_VALID(maxMinusTwo
+ one
);
126 VERIFY_IS_VALID(maxMinusTwo
+ two
);
127 VERIFY(maxMinusOne
+ one
== max
);
128 VERIFY(maxMinusTwo
+ one
== maxMinusOne
);
129 VERIFY(maxMinusTwo
+ two
== max
);
131 VERIFY_IS_VALID(max
+ zero
);
132 VERIFY_IS_VALID(max
- zero
);
133 VERIFY_IS_INVALID(max
+ one
);
134 VERIFY_IS_INVALID(max
+ two
);
135 VERIFY_IS_INVALID(max
+ maxMinusOne
);
136 VERIFY_IS_INVALID(max
+ max
);
138 const CheckedInt
<T
> minPlusOne
= min
+ one
;
139 const CheckedInt
<T
> minPlusTwo
= min
+ two
;
140 VERIFY_IS_VALID(minPlusOne
);
141 VERIFY_IS_VALID(minPlusTwo
);
142 VERIFY_IS_VALID(minPlusOne
- one
);
143 VERIFY_IS_VALID(minPlusTwo
- one
);
144 VERIFY_IS_VALID(minPlusTwo
- two
);
145 VERIFY(minPlusOne
- one
== min
);
146 VERIFY(minPlusTwo
- one
== minPlusOne
);
147 VERIFY(minPlusTwo
- two
== min
);
149 const CheckedInt
<T
> minMinusOne
= min
- one
;
150 VERIFY_IS_VALID(min
+ zero
);
151 VERIFY_IS_VALID(min
- zero
);
152 VERIFY_IS_INVALID(min
- one
);
153 VERIFY_IS_INVALID(min
- two
);
154 VERIFY_IS_INVALID(min
- minMinusOne
);
155 VERIFY_IS_VALID(min
- min
);
157 const CheckedInt
<T
> maxOverTwo
= max
/ two
;
158 VERIFY_IS_VALID(maxOverTwo
+ maxOverTwo
);
159 VERIFY_IS_VALID(maxOverTwo
+ one
);
160 VERIFY((maxOverTwo
+ one
) - one
== maxOverTwo
);
161 VERIFY_IS_VALID(maxOverTwo
- maxOverTwo
);
162 VERIFY(maxOverTwo
- maxOverTwo
== zero
);
164 const CheckedInt
<T
> minOverTwo
= min
/ two
;
165 VERIFY_IS_VALID(minOverTwo
+ minOverTwo
);
166 VERIFY_IS_VALID(minOverTwo
+ one
);
167 VERIFY((minOverTwo
+ one
) - one
== minOverTwo
);
168 VERIFY_IS_VALID(minOverTwo
- minOverTwo
);
169 VERIFY(minOverTwo
- minOverTwo
== zero
);
171 VERIFY_IS_INVALID(min
- one
);
172 VERIFY_IS_INVALID(min
- two
);
175 VERIFY_IS_INVALID(min
+ min
);
176 VERIFY_IS_INVALID(minOverTwo
+ minOverTwo
+ minOverTwo
);
177 VERIFY_IS_INVALID(zero
- min
+ min
);
178 VERIFY_IS_INVALID(one
- min
+ min
);
182 VERIFY_IS_INVALID(zero
% zero
);
183 VERIFY_IS_INVALID(one
% zero
);
184 VERIFY_IS_VALID(zero
% one
);
185 VERIFY_IS_VALID(zero
% max
);
186 VERIFY_IS_VALID(one
% max
);
187 VERIFY_IS_VALID(max
% one
);
188 VERIFY_IS_VALID(max
% max
);
190 const CheckedInt
<T
> minusOne
= zero
- one
;
191 VERIFY_IS_INVALID(minusOne
% minusOne
);
192 VERIFY_IS_INVALID(zero
% minusOne
);
193 VERIFY_IS_INVALID(one
% minusOne
);
194 VERIFY_IS_INVALID(minusOne
% one
);
196 VERIFY_IS_INVALID(min
% min
);
197 VERIFY_IS_INVALID(zero
% min
);
198 VERIFY_IS_INVALID(min
% one
);
201 /* Unary operator- checks */
203 const CheckedInt
<T
> negOne
= -one
;
204 const CheckedInt
<T
> negTwo
= -two
;
207 VERIFY_IS_VALID(-max
);
208 VERIFY_IS_INVALID(-min
);
209 VERIFY(-max
- min
== one
);
210 VERIFY_IS_VALID(-max
- one
);
211 VERIFY_IS_VALID(negOne
);
212 VERIFY_IS_VALID(-max
+ negOne
);
213 VERIFY_IS_VALID(negOne
+ one
);
214 VERIFY(negOne
+ one
== zero
);
215 VERIFY_IS_VALID(negTwo
);
216 VERIFY_IS_VALID(negOne
+ negOne
);
217 VERIFY(negOne
+ negOne
== negTwo
);
219 VERIFY_IS_INVALID(-max
);
220 VERIFY_IS_VALID(-min
);
222 VERIFY_IS_INVALID(negOne
);
225 /* multiplication checks */
227 VERIFY_IS_VALID(zero
* zero
);
228 VERIFY(zero
* zero
== zero
);
229 VERIFY_IS_VALID(zero
* one
);
230 VERIFY(zero
* one
== zero
);
231 VERIFY_IS_VALID(one
* zero
);
232 VERIFY(one
* zero
== zero
);
233 VERIFY_IS_VALID(one
* one
);
234 VERIFY(one
* one
== one
);
235 VERIFY_IS_VALID(one
* three
);
236 VERIFY(one
* three
== three
);
237 VERIFY_IS_VALID(two
* two
);
238 VERIFY(two
* two
== four
);
240 VERIFY_IS_INVALID(max
* max
);
241 VERIFY_IS_INVALID(maxOverTwo
* max
);
242 VERIFY_IS_INVALID(maxOverTwo
* maxOverTwo
);
244 const CheckedInt
<T
> maxApproxSqrt(T(T(1) << (CHAR_BIT
* sizeof(T
) / 2)));
246 VERIFY_IS_VALID(maxApproxSqrt
);
247 VERIFY_IS_VALID(maxApproxSqrt
* two
);
248 VERIFY_IS_INVALID(maxApproxSqrt
* maxApproxSqrt
);
249 VERIFY_IS_INVALID(maxApproxSqrt
* maxApproxSqrt
* maxApproxSqrt
);
252 VERIFY_IS_INVALID(min
* min
);
253 VERIFY_IS_INVALID(minOverTwo
* min
);
254 VERIFY_IS_INVALID(minOverTwo
* minOverTwo
);
256 const CheckedInt
<T
> minApproxSqrt
= -maxApproxSqrt
;
258 VERIFY_IS_VALID(minApproxSqrt
);
259 VERIFY_IS_VALID(minApproxSqrt
* two
);
260 VERIFY_IS_INVALID(minApproxSqrt
* maxApproxSqrt
);
261 VERIFY_IS_INVALID(minApproxSqrt
* minApproxSqrt
);
264 // make sure to check all 4 paths in signed multiplication validity check.
265 // test positive * positive
266 VERIFY_IS_VALID(max
* one
);
267 VERIFY(max
* one
== max
);
268 VERIFY_IS_INVALID(max
* two
);
269 VERIFY_IS_VALID(maxOverTwo
* two
);
270 VERIFY((maxOverTwo
+ maxOverTwo
) == (maxOverTwo
* two
));
273 // test positive * negative
274 VERIFY_IS_VALID(max
* negOne
);
275 VERIFY_IS_VALID(-max
);
276 VERIFY(max
* negOne
== -max
);
277 VERIFY_IS_VALID(one
* min
);
278 VERIFY_IS_INVALID(max
* negTwo
);
279 VERIFY_IS_VALID(maxOverTwo
* negTwo
);
280 VERIFY_IS_VALID(two
* minOverTwo
);
281 VERIFY_IS_VALID((maxOverTwo
+ one
) * negTwo
);
282 VERIFY_IS_INVALID((maxOverTwo
+ two
) * negTwo
);
283 VERIFY_IS_INVALID(two
* (minOverTwo
- one
));
285 // test negative * positive
286 VERIFY_IS_VALID(min
* one
);
287 VERIFY_IS_VALID(minPlusOne
* one
);
288 VERIFY_IS_INVALID(min
* two
);
289 VERIFY_IS_VALID(minOverTwo
* two
);
290 VERIFY(minOverTwo
* two
== min
);
291 VERIFY_IS_INVALID((minOverTwo
- one
) * negTwo
);
292 VERIFY_IS_INVALID(negTwo
* max
);
293 VERIFY_IS_VALID(minOverTwo
* two
);
294 VERIFY(minOverTwo
* two
== min
);
295 VERIFY_IS_VALID(negTwo
* maxOverTwo
);
296 VERIFY_IS_INVALID((minOverTwo
- one
) * two
);
297 VERIFY_IS_VALID(negTwo
* (maxOverTwo
+ one
));
298 VERIFY_IS_INVALID(negTwo
* (maxOverTwo
+ two
));
300 // test negative * negative
301 VERIFY_IS_INVALID(min
* negOne
);
302 VERIFY_IS_VALID(minPlusOne
* negOne
);
303 VERIFY(minPlusOne
* negOne
== max
);
304 VERIFY_IS_INVALID(min
* negTwo
);
305 VERIFY_IS_INVALID(minOverTwo
* negTwo
);
306 VERIFY_IS_INVALID(negOne
* min
);
307 VERIFY_IS_VALID(negOne
* minPlusOne
);
308 VERIFY(negOne
* minPlusOne
== max
);
309 VERIFY_IS_INVALID(negTwo
* min
);
310 VERIFY_IS_INVALID(negTwo
* minOverTwo
);
313 /* Division checks */
315 VERIFY_IS_VALID(one
/ one
);
316 VERIFY(one
/ one
== one
);
317 VERIFY_IS_VALID(three
/ three
);
318 VERIFY(three
/ three
== one
);
319 VERIFY_IS_VALID(four
/ two
);
320 VERIFY(four
/ two
== two
);
321 VERIFY((four
* three
) / four
== three
);
323 // Check that div by zero is invalid
324 VERIFY_IS_INVALID(zero
/ zero
);
325 VERIFY_IS_INVALID(one
/ zero
);
326 VERIFY_IS_INVALID(two
/ zero
);
327 VERIFY_IS_INVALID(negOne
/ zero
);
328 VERIFY_IS_INVALID(max
/ zero
);
329 VERIFY_IS_INVALID(min
/ zero
);
332 // Check that min / -1 is invalid
333 VERIFY_IS_INVALID(min
/ negOne
);
335 // Check that the test for div by -1 isn't banning other numerators than min
336 VERIFY_IS_VALID(one
/ negOne
);
337 VERIFY_IS_VALID(zero
/ negOne
);
338 VERIFY_IS_VALID(negOne
/ negOne
);
339 VERIFY_IS_VALID(max
/ negOne
);
342 /* Check that invalidity is correctly preserved by arithmetic ops */
344 const CheckedInt
<T
> someInvalid
= max
+ max
;
345 VERIFY_IS_INVALID(someInvalid
+ zero
);
346 VERIFY_IS_INVALID(someInvalid
- zero
);
347 VERIFY_IS_INVALID(zero
+ someInvalid
);
348 VERIFY_IS_INVALID(zero
- someInvalid
);
349 VERIFY_IS_INVALID(-someInvalid
);
350 VERIFY_IS_INVALID(someInvalid
* zero
);
351 VERIFY_IS_INVALID(someInvalid
* one
);
352 VERIFY_IS_INVALID(zero
* someInvalid
);
353 VERIFY_IS_INVALID(one
* someInvalid
);
354 VERIFY_IS_INVALID(someInvalid
/ zero
);
355 VERIFY_IS_INVALID(someInvalid
/ one
);
356 VERIFY_IS_INVALID(zero
/ someInvalid
);
357 VERIFY_IS_INVALID(one
/ someInvalid
);
358 VERIFY_IS_INVALID(someInvalid
% zero
);
359 VERIFY_IS_INVALID(someInvalid
% one
);
360 VERIFY_IS_INVALID(zero
% someInvalid
);
361 VERIFY_IS_INVALID(one
% someInvalid
);
362 VERIFY_IS_INVALID(someInvalid
+ someInvalid
);
363 VERIFY_IS_INVALID(someInvalid
- someInvalid
);
364 VERIFY_IS_INVALID(someInvalid
* someInvalid
);
365 VERIFY_IS_INVALID(someInvalid
/ someInvalid
);
366 VERIFY_IS_INVALID(someInvalid
% someInvalid
);
368 // Check that mixing checked integers with plain integers in expressions is
371 VERIFY(one
+ T(2) == three
);
372 VERIFY(2 + one
== three
);
374 CheckedInt
<T
> x
= one
;
378 VERIFY(two
- 1 == one
);
379 VERIFY(2 - one
== one
);
381 CheckedInt
<T
> x
= two
;
385 VERIFY(one
* 2 == two
);
386 VERIFY(2 * one
== two
);
388 CheckedInt
<T
> x
= one
;
392 VERIFY(four
/ 2 == two
);
393 VERIFY(4 / two
== two
);
395 CheckedInt
<T
> x
= four
;
399 VERIFY(three
% 2 == one
);
400 VERIFY(3 % two
== one
);
402 CheckedInt
<T
> x
= three
;
409 VERIFY_IS_FALSE(two
== 1);
410 VERIFY_IS_FALSE(1 == two
);
411 VERIFY_IS_FALSE(someInvalid
== 1);
412 VERIFY_IS_FALSE(1 == someInvalid
);
414 // Check that compound operators work when both sides of the expression
415 // are checked integers
417 CheckedInt
<T
> x
= one
;
422 CheckedInt
<T
> x
= two
;
427 CheckedInt
<T
> x
= one
;
432 CheckedInt
<T
> x
= four
;
437 CheckedInt
<T
> x
= three
;
442 // Check that compound operators work when both sides of the expression
443 // are checked integers and the right-hand side is invalid
445 CheckedInt
<T
> x
= one
;
447 VERIFY_IS_INVALID(x
);
450 CheckedInt
<T
> x
= two
;
452 VERIFY_IS_INVALID(x
);
455 CheckedInt
<T
> x
= one
;
457 VERIFY_IS_INVALID(x
);
460 CheckedInt
<T
> x
= four
;
462 VERIFY_IS_INVALID(x
);
465 CheckedInt
<T
> x
= three
;
467 VERIFY_IS_INVALID(x
);
470 // Check simple casting between different signedness and sizes.
472 CheckedInt
<uint8_t> foo
= CheckedInt
<uint16_t>(2).toChecked
<uint8_t>();
473 VERIFY_IS_VALID(foo
);
477 CheckedInt
<uint8_t> foo
= CheckedInt
<uint16_t>(255).toChecked
<uint8_t>();
478 VERIFY_IS_VALID(foo
);
482 CheckedInt
<uint8_t> foo
= CheckedInt
<uint16_t>(256).toChecked
<uint8_t>();
483 VERIFY_IS_INVALID(foo
);
486 CheckedInt
<uint8_t> foo
= CheckedInt
<int8_t>(-2).toChecked
<uint8_t>();
487 VERIFY_IS_INVALID(foo
);
490 // Check that construction of CheckedInt from an integer value of a
491 // mismatched type is checked Also check casting between all types.
493 #define VERIFY_CONSTRUCTION_FROM_INTEGER_TYPE2(U, V, PostVExpr) \
495 bool isUSigned = std::is_signed_v<U>; \
496 VERIFY_IS_VALID(CheckedInt<T>(V(0) PostVExpr)); \
497 VERIFY_IS_VALID(CheckedInt<T>(V(1) PostVExpr)); \
498 VERIFY_IS_VALID(CheckedInt<T>(V(100) PostVExpr)); \
500 VERIFY_IS_VALID_IF(CheckedInt<T>(V(-1) PostVExpr), isTSigned); \
502 if (sizeof(U) > sizeof(T)) { \
503 VERIFY_IS_INVALID(CheckedInt<T>( \
504 V(std::numeric_limits<T>::max()) PostVExpr + one.value())); \
506 VERIFY_IS_VALID_IF( \
507 CheckedInt<T>(std::numeric_limits<U>::max()), \
508 (sizeof(T) > sizeof(U) || \
509 ((sizeof(T) == sizeof(U)) && (isUSigned || !isTSigned)))); \
510 VERIFY_IS_VALID_IF(CheckedInt<T>(std::numeric_limits<U>::min()), \
511 isUSigned == false ? 1 \
512 : bool(isTSigned) == false ? 0 \
513 : sizeof(T) >= sizeof(U)); \
515 #define VERIFY_CONSTRUCTION_FROM_INTEGER_TYPE(U) \
516 VERIFY_CONSTRUCTION_FROM_INTEGER_TYPE2(U, U, +zero) \
517 VERIFY_CONSTRUCTION_FROM_INTEGER_TYPE2(U, CheckedInt<U>, .toChecked<T>())
519 VERIFY_CONSTRUCTION_FROM_INTEGER_TYPE(int8_t)
520 VERIFY_CONSTRUCTION_FROM_INTEGER_TYPE(uint8_t)
521 VERIFY_CONSTRUCTION_FROM_INTEGER_TYPE(int16_t)
522 VERIFY_CONSTRUCTION_FROM_INTEGER_TYPE(uint16_t)
523 VERIFY_CONSTRUCTION_FROM_INTEGER_TYPE(int32_t)
524 VERIFY_CONSTRUCTION_FROM_INTEGER_TYPE(uint32_t)
525 VERIFY_CONSTRUCTION_FROM_INTEGER_TYPE(int64_t)
526 VERIFY_CONSTRUCTION_FROM_INTEGER_TYPE(uint64_t)
528 typedef signed char signedChar
;
529 typedef unsigned char unsignedChar
;
530 typedef unsigned short unsignedShort
;
531 typedef unsigned int unsignedInt
;
532 typedef unsigned long unsignedLong
;
533 typedef long long longLong
;
534 typedef unsigned long long unsignedLongLong
;
536 VERIFY_CONSTRUCTION_FROM_INTEGER_TYPE(char)
537 VERIFY_CONSTRUCTION_FROM_INTEGER_TYPE(signedChar
)
538 VERIFY_CONSTRUCTION_FROM_INTEGER_TYPE(unsignedChar
)
539 VERIFY_CONSTRUCTION_FROM_INTEGER_TYPE(short)
540 VERIFY_CONSTRUCTION_FROM_INTEGER_TYPE(unsignedShort
)
541 VERIFY_CONSTRUCTION_FROM_INTEGER_TYPE(int)
542 VERIFY_CONSTRUCTION_FROM_INTEGER_TYPE(unsignedInt
)
543 VERIFY_CONSTRUCTION_FROM_INTEGER_TYPE(long)
544 VERIFY_CONSTRUCTION_FROM_INTEGER_TYPE(unsignedLong
)
545 VERIFY_CONSTRUCTION_FROM_INTEGER_TYPE(longLong
)
546 VERIFY_CONSTRUCTION_FROM_INTEGER_TYPE(unsignedLongLong
)
548 /* Test increment/decrement operators */
568 VERIFY_IS_VALID(x
++);
570 VERIFY_IS_INVALID(++x
);
572 VERIFY_IS_VALID(x
--);
574 VERIFY_IS_INVALID(--x
);
576 gIntegerTypesTested
++;
591 test
<unsigned char>();
593 test
<unsigned short>();
595 test
<unsigned int>();
597 test
<unsigned long>();
599 test
<unsigned long long>();
601 const int MIN_TYPES_TESTED
= 9;
602 if (gIntegerTypesTested
< MIN_TYPES_TESTED
) {
603 std::cerr
<< "Only " << gIntegerTypesTested
<< " have been tested. "
604 << "This should not be less than " << MIN_TYPES_TESTED
<< "."
609 std::cerr
<< gTestsFailed
<< " tests failed, " << gTestsPassed
610 << " tests passed out of " << gTestsFailed
+ gTestsPassed
611 << " tests, covering " << gIntegerTypesTested
612 << " distinct integer types." << std::endl
;
614 return gTestsFailed
> 0;