Fri, 16 Jan 2015 18:13:44 +0100
Integrate suggestion from review to improve consistency with existing code.
1 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /* This Source Code Form is subject to the terms of the Mozilla Public
3 * License, v. 2.0. If a copy of the MPL was not distributed with this file,
4 * You can obtain one at http://mozilla.org/MPL/2.0/. */
6 #include "mozilla/CheckedInt.h"
8 #include <iostream>
9 #include <climits>
11 using namespace mozilla;
13 int gIntegerTypesTested = 0;
14 int gTestsPassed = 0;
15 int gTestsFailed = 0;
17 void verifyImplFunction(bool x, bool expected,
18 const char* file, int line,
19 int size, bool isTSigned)
20 {
21 if (x == expected) {
22 gTestsPassed++;
23 } else {
24 gTestsFailed++;
25 std::cerr << "Test failed at " << file << ":" << line;
26 std::cerr << " with T a ";
27 if (isTSigned)
28 std::cerr << "signed";
29 else
30 std::cerr << "unsigned";
31 std::cerr << " " << CHAR_BIT*size << "-bit integer type" << std::endl;
32 }
33 }
35 #define VERIFY_IMPL(x, expected) \
36 verifyImplFunction((x), \
37 (expected), \
38 __FILE__, \
39 __LINE__, \
40 sizeof(T), \
41 IsSigned<T>::value)
43 #define VERIFY(x) VERIFY_IMPL(x, true)
44 #define VERIFY_IS_FALSE(x) VERIFY_IMPL(x, false)
45 #define VERIFY_IS_VALID(x) VERIFY_IMPL((x).isValid(), true)
46 #define VERIFY_IS_INVALID(x) VERIFY_IMPL((x).isValid(), false)
47 #define VERIFY_IS_VALID_IF(x,condition) VERIFY_IMPL((x).isValid(), (condition))
49 template<typename T, size_t Size = sizeof(T)>
50 struct testTwiceBiggerType
51 {
52 static void run()
53 {
54 VERIFY(detail::IsSupported<typename detail::TwiceBiggerType<T>::Type>::value);
55 VERIFY(sizeof(typename detail::TwiceBiggerType<T>::Type)
56 == 2 * sizeof(T));
57 VERIFY(bool(IsSigned<typename detail::TwiceBiggerType<T>::Type>::value)
58 == bool(IsSigned<T>::value));
59 }
60 };
62 template<typename T>
63 struct testTwiceBiggerType<T, 8>
64 {
65 static void run()
66 {
67 VERIFY_IS_FALSE(detail::IsSupported<
68 typename detail::TwiceBiggerType<T>::Type
69 >::value);
70 }
71 };
74 template<typename T>
75 void test()
76 {
77 static bool alreadyRun = false;
78 // Integer types from different families may just be typedefs for types from other families.
79 // e.g. int32_t might be just a typedef for int. No point re-running the same tests then.
80 if (alreadyRun)
81 return;
82 alreadyRun = true;
84 VERIFY(detail::IsSupported<T>::value);
85 const bool isTSigned = IsSigned<T>::value;
86 VERIFY(bool(isTSigned) == !bool(T(-1) > T(0)));
88 testTwiceBiggerType<T>::run();
90 typedef typename MakeUnsigned<T>::Type unsignedT;
92 VERIFY(sizeof(unsignedT) == sizeof(T));
93 VERIFY(IsSigned<unsignedT>::value == false);
95 const CheckedInt<T> max(MaxValue<T>::value);
96 const CheckedInt<T> min(MinValue<T>::value);
98 // Check MinValue and MaxValue, since they are custom implementations and a mistake there
99 // could potentially NOT be caught by any other tests... while making everything wrong!
101 unsignedT bit = 1;
102 unsignedT unsignedMinValue(min.value());
103 unsignedT unsignedMaxValue(max.value());
104 for (size_t i = 0; i < sizeof(T) * CHAR_BIT - 1; i++)
105 {
106 VERIFY((unsignedMinValue & bit) == 0);
107 bit <<= 1;
108 }
109 VERIFY((unsignedMinValue & bit) == (isTSigned ? bit : unsignedT(0)));
110 VERIFY(unsignedMaxValue == unsignedT(~unsignedMinValue));
112 const CheckedInt<T> zero(0);
113 const CheckedInt<T> one(1);
114 const CheckedInt<T> two(2);
115 const CheckedInt<T> three(3);
116 const CheckedInt<T> four(4);
118 /* Addition / subtraction checks */
120 VERIFY_IS_VALID(zero + zero);
121 VERIFY(zero + zero == zero);
122 VERIFY_IS_FALSE(zero + zero == one); // Check that == doesn't always return true
123 VERIFY_IS_VALID(zero + one);
124 VERIFY(zero + one == one);
125 VERIFY_IS_VALID(one + one);
126 VERIFY(one + one == two);
128 const CheckedInt<T> maxMinusOne = max - one;
129 const CheckedInt<T> maxMinusTwo = max - two;
130 VERIFY_IS_VALID(maxMinusOne);
131 VERIFY_IS_VALID(maxMinusTwo);
132 VERIFY_IS_VALID(maxMinusOne + one);
133 VERIFY_IS_VALID(maxMinusTwo + one);
134 VERIFY_IS_VALID(maxMinusTwo + two);
135 VERIFY(maxMinusOne + one == max);
136 VERIFY(maxMinusTwo + one == maxMinusOne);
137 VERIFY(maxMinusTwo + two == max);
139 VERIFY_IS_VALID(max + zero);
140 VERIFY_IS_VALID(max - zero);
141 VERIFY_IS_INVALID(max + one);
142 VERIFY_IS_INVALID(max + two);
143 VERIFY_IS_INVALID(max + maxMinusOne);
144 VERIFY_IS_INVALID(max + max);
146 const CheckedInt<T> minPlusOne = min + one;
147 const CheckedInt<T> minPlusTwo = min + two;
148 VERIFY_IS_VALID(minPlusOne);
149 VERIFY_IS_VALID(minPlusTwo);
150 VERIFY_IS_VALID(minPlusOne - one);
151 VERIFY_IS_VALID(minPlusTwo - one);
152 VERIFY_IS_VALID(minPlusTwo - two);
153 VERIFY(minPlusOne - one == min);
154 VERIFY(minPlusTwo - one == minPlusOne);
155 VERIFY(minPlusTwo - two == min);
157 const CheckedInt<T> minMinusOne = min - one;
158 VERIFY_IS_VALID(min + zero);
159 VERIFY_IS_VALID(min - zero);
160 VERIFY_IS_INVALID(min - one);
161 VERIFY_IS_INVALID(min - two);
162 VERIFY_IS_INVALID(min - minMinusOne);
163 VERIFY_IS_VALID(min - min);
165 const CheckedInt<T> maxOverTwo = max / two;
166 VERIFY_IS_VALID(maxOverTwo + maxOverTwo);
167 VERIFY_IS_VALID(maxOverTwo + one);
168 VERIFY((maxOverTwo + one) - one == maxOverTwo);
169 VERIFY_IS_VALID(maxOverTwo - maxOverTwo);
170 VERIFY(maxOverTwo - maxOverTwo == zero);
172 const CheckedInt<T> minOverTwo = min / two;
173 VERIFY_IS_VALID(minOverTwo + minOverTwo);
174 VERIFY_IS_VALID(minOverTwo + one);
175 VERIFY((minOverTwo + one) - one == minOverTwo);
176 VERIFY_IS_VALID(minOverTwo - minOverTwo);
177 VERIFY(minOverTwo - minOverTwo == zero);
179 VERIFY_IS_INVALID(min - one);
180 VERIFY_IS_INVALID(min - two);
182 if (isTSigned) {
183 VERIFY_IS_INVALID(min + min);
184 VERIFY_IS_INVALID(minOverTwo + minOverTwo + minOverTwo);
185 VERIFY_IS_INVALID(zero - min + min);
186 VERIFY_IS_INVALID(one - min + min);
187 }
189 /* Modulo checks */
190 VERIFY_IS_INVALID(zero % zero);
191 VERIFY_IS_INVALID(one % zero);
192 VERIFY_IS_VALID(zero % one);
193 VERIFY_IS_VALID(zero % max);
194 VERIFY_IS_VALID(one % max);
195 VERIFY_IS_VALID(max % one);
196 VERIFY_IS_VALID(max % max);
197 if (isTSigned) {
198 const CheckedInt<T> minusOne = zero - one;
199 VERIFY_IS_INVALID(minusOne % minusOne);
200 VERIFY_IS_INVALID(zero % minusOne);
201 VERIFY_IS_INVALID(one % minusOne);
202 VERIFY_IS_INVALID(minusOne % one);
204 VERIFY_IS_INVALID(min % min);
205 VERIFY_IS_INVALID(zero % min);
206 VERIFY_IS_INVALID(min % one);
207 }
209 /* Unary operator- checks */
211 const CheckedInt<T> negOne = -one;
212 const CheckedInt<T> negTwo = -two;
214 if (isTSigned) {
215 VERIFY_IS_VALID(-max);
216 VERIFY_IS_INVALID(-min);
217 VERIFY(-max - min == one);
218 VERIFY_IS_VALID(-max - one);
219 VERIFY_IS_VALID(negOne);
220 VERIFY_IS_VALID(-max + negOne);
221 VERIFY_IS_VALID(negOne + one);
222 VERIFY(negOne + one == zero);
223 VERIFY_IS_VALID(negTwo);
224 VERIFY_IS_VALID(negOne + negOne);
225 VERIFY(negOne + negOne == negTwo);
226 } else {
227 VERIFY_IS_INVALID(-max);
228 VERIFY_IS_VALID(-min);
229 VERIFY(min == zero);
230 VERIFY_IS_INVALID(negOne);
231 }
233 /* multiplication checks */
235 VERIFY_IS_VALID(zero * zero);
236 VERIFY(zero * zero == zero);
237 VERIFY_IS_VALID(zero * one);
238 VERIFY(zero * one == zero);
239 VERIFY_IS_VALID(one * zero);
240 VERIFY(one * zero == zero);
241 VERIFY_IS_VALID(one * one);
242 VERIFY(one * one == one);
243 VERIFY_IS_VALID(one * three);
244 VERIFY(one * three == three);
245 VERIFY_IS_VALID(two * two);
246 VERIFY(two * two == four);
248 VERIFY_IS_INVALID(max * max);
249 VERIFY_IS_INVALID(maxOverTwo * max);
250 VERIFY_IS_INVALID(maxOverTwo * maxOverTwo);
252 const CheckedInt<T> maxApproxSqrt(T(T(1) << (CHAR_BIT*sizeof(T)/2)));
254 VERIFY_IS_VALID(maxApproxSqrt);
255 VERIFY_IS_VALID(maxApproxSqrt * two);
256 VERIFY_IS_INVALID(maxApproxSqrt * maxApproxSqrt);
257 VERIFY_IS_INVALID(maxApproxSqrt * maxApproxSqrt * maxApproxSqrt);
259 if (isTSigned) {
260 VERIFY_IS_INVALID(min * min);
261 VERIFY_IS_INVALID(minOverTwo * min);
262 VERIFY_IS_INVALID(minOverTwo * minOverTwo);
264 const CheckedInt<T> minApproxSqrt = -maxApproxSqrt;
266 VERIFY_IS_VALID(minApproxSqrt);
267 VERIFY_IS_VALID(minApproxSqrt * two);
268 VERIFY_IS_INVALID(minApproxSqrt * maxApproxSqrt);
269 VERIFY_IS_INVALID(minApproxSqrt * minApproxSqrt);
270 }
272 // make sure to check all 4 paths in signed multiplication validity check.
273 // test positive * positive
274 VERIFY_IS_VALID(max * one);
275 VERIFY(max * one == max);
276 VERIFY_IS_INVALID(max * two);
277 VERIFY_IS_VALID(maxOverTwo * two);
278 VERIFY((maxOverTwo + maxOverTwo) == (maxOverTwo * two));
280 if (isTSigned) {
281 // test positive * negative
282 VERIFY_IS_VALID(max * negOne);
283 VERIFY_IS_VALID(-max);
284 VERIFY(max * negOne == -max);
285 VERIFY_IS_VALID(one * min);
286 VERIFY_IS_INVALID(max * negTwo);
287 VERIFY_IS_VALID(maxOverTwo * negTwo);
288 VERIFY_IS_VALID(two * minOverTwo);
289 VERIFY_IS_VALID((maxOverTwo + one) * negTwo);
290 VERIFY_IS_INVALID((maxOverTwo + two) * negTwo);
291 VERIFY_IS_INVALID(two * (minOverTwo - one));
293 // test negative * positive
294 VERIFY_IS_VALID(min * one);
295 VERIFY_IS_VALID(minPlusOne * one);
296 VERIFY_IS_INVALID(min * two);
297 VERIFY_IS_VALID(minOverTwo * two);
298 VERIFY(minOverTwo * two == min);
299 VERIFY_IS_INVALID((minOverTwo - one) * negTwo);
300 VERIFY_IS_INVALID(negTwo * max);
301 VERIFY_IS_VALID(minOverTwo * two);
302 VERIFY(minOverTwo * two == min);
303 VERIFY_IS_VALID(negTwo * maxOverTwo);
304 VERIFY_IS_INVALID((minOverTwo - one) * two);
305 VERIFY_IS_VALID(negTwo * (maxOverTwo + one));
306 VERIFY_IS_INVALID(negTwo * (maxOverTwo + two));
308 // test negative * negative
309 VERIFY_IS_INVALID(min * negOne);
310 VERIFY_IS_VALID(minPlusOne * negOne);
311 VERIFY(minPlusOne * negOne == max);
312 VERIFY_IS_INVALID(min * negTwo);
313 VERIFY_IS_INVALID(minOverTwo * negTwo);
314 VERIFY_IS_INVALID(negOne * min);
315 VERIFY_IS_VALID(negOne * minPlusOne);
316 VERIFY(negOne * minPlusOne == max);
317 VERIFY_IS_INVALID(negTwo * min);
318 VERIFY_IS_INVALID(negTwo * minOverTwo);
319 }
321 /* Division checks */
323 VERIFY_IS_VALID(one / one);
324 VERIFY(one / one == one);
325 VERIFY_IS_VALID(three / three);
326 VERIFY(three / three == one);
327 VERIFY_IS_VALID(four / two);
328 VERIFY(four / two == two);
329 VERIFY((four*three)/four == three);
331 // Check that div by zero is invalid
332 VERIFY_IS_INVALID(zero / zero);
333 VERIFY_IS_INVALID(one / zero);
334 VERIFY_IS_INVALID(two / zero);
335 VERIFY_IS_INVALID(negOne / zero);
336 VERIFY_IS_INVALID(max / zero);
337 VERIFY_IS_INVALID(min / zero);
339 if (isTSigned) {
340 // Check that min / -1 is invalid
341 VERIFY_IS_INVALID(min / negOne);
343 // Check that the test for div by -1 isn't banning other numerators than min
344 VERIFY_IS_VALID(one / negOne);
345 VERIFY_IS_VALID(zero / negOne);
346 VERIFY_IS_VALID(negOne / negOne);
347 VERIFY_IS_VALID(max / negOne);
348 }
350 /* Check that invalidity is correctly preserved by arithmetic ops */
352 const CheckedInt<T> someInvalid = max + max;
353 VERIFY_IS_INVALID(someInvalid + zero);
354 VERIFY_IS_INVALID(someInvalid - zero);
355 VERIFY_IS_INVALID(zero + someInvalid);
356 VERIFY_IS_INVALID(zero - someInvalid);
357 VERIFY_IS_INVALID(-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 / zero);
363 VERIFY_IS_INVALID(someInvalid / one);
364 VERIFY_IS_INVALID(zero / someInvalid);
365 VERIFY_IS_INVALID(one / someInvalid);
366 VERIFY_IS_INVALID(someInvalid % zero);
367 VERIFY_IS_INVALID(someInvalid % one);
368 VERIFY_IS_INVALID(zero % someInvalid);
369 VERIFY_IS_INVALID(one % someInvalid);
370 VERIFY_IS_INVALID(someInvalid + someInvalid);
371 VERIFY_IS_INVALID(someInvalid - someInvalid);
372 VERIFY_IS_INVALID(someInvalid * someInvalid);
373 VERIFY_IS_INVALID(someInvalid / someInvalid);
374 VERIFY_IS_INVALID(someInvalid % someInvalid);
376 /* Check that mixing checked integers with plain integers in expressions is allowed */
378 VERIFY(one + T(2) == three);
379 VERIFY(2 + one == three);
380 {
381 CheckedInt<T> x = one;
382 x += 2;
383 VERIFY(x == three);
384 }
385 VERIFY(two - 1 == one);
386 VERIFY(2 - one == one);
387 {
388 CheckedInt<T> x = two;
389 x -= 1;
390 VERIFY(x == one);
391 }
392 VERIFY(one * 2 == two);
393 VERIFY(2 * one == two);
394 {
395 CheckedInt<T> x = one;
396 x *= 2;
397 VERIFY(x == two);
398 }
399 VERIFY(four / 2 == two);
400 VERIFY(4 / two == two);
401 {
402 CheckedInt<T> x = four;
403 x /= 2;
404 VERIFY(x == two);
405 }
406 VERIFY(three % 2 == one);
407 VERIFY(3 % two == one);
408 {
409 CheckedInt<T> x = three;
410 x %= 2;
411 VERIFY(x == one);
412 }
414 VERIFY(one == 1);
415 VERIFY(1 == one);
416 VERIFY_IS_FALSE(two == 1);
417 VERIFY_IS_FALSE(1 == two);
418 VERIFY_IS_FALSE(someInvalid == 1);
419 VERIFY_IS_FALSE(1 == someInvalid);
421 // Check simple casting between different signedness and sizes.
422 {
423 CheckedInt<uint8_t> foo = CheckedInt<uint16_t>(2).toChecked<uint8_t>();
424 VERIFY_IS_VALID(foo);
425 VERIFY(foo == 2);
426 }
427 {
428 CheckedInt<uint8_t> foo = CheckedInt<uint16_t>(255).toChecked<uint8_t>();
429 VERIFY_IS_VALID(foo);
430 VERIFY(foo == 255);
431 }
432 {
433 CheckedInt<uint8_t> foo = CheckedInt<uint16_t>(256).toChecked<uint8_t>();
434 VERIFY_IS_INVALID(foo);
435 }
436 {
437 CheckedInt<uint8_t> foo = CheckedInt<int8_t>(-2).toChecked<uint8_t>();
438 VERIFY_IS_INVALID(foo);
439 }
441 // Check that construction of CheckedInt from an integer value of a mismatched type is checked
442 // Also check casting between all types.
444 #define VERIFY_CONSTRUCTION_FROM_INTEGER_TYPE2(U,V,PostVExpr) \
445 { \
446 bool isUSigned = IsSigned<U>::value; \
447 VERIFY_IS_VALID(CheckedInt<T>(V( 0)PostVExpr)); \
448 VERIFY_IS_VALID(CheckedInt<T>(V( 1)PostVExpr)); \
449 VERIFY_IS_VALID(CheckedInt<T>(V(100)PostVExpr)); \
450 if (isUSigned) \
451 VERIFY_IS_VALID_IF(CheckedInt<T>(V(-1)PostVExpr), isTSigned); \
452 if (sizeof(U) > sizeof(T)) \
453 VERIFY_IS_INVALID(CheckedInt<T>(V(MaxValue<T>::value)PostVExpr + one.value())); \
454 VERIFY_IS_VALID_IF(CheckedInt<T>(MaxValue<U>::value), \
455 (sizeof(T) > sizeof(U) || ((sizeof(T) == sizeof(U)) && (isUSigned || !isTSigned)))); \
456 VERIFY_IS_VALID_IF(CheckedInt<T>(MinValue<U>::value), \
457 isUSigned == false ? 1 \
458 : bool(isTSigned) == false ? 0 \
459 : sizeof(T) >= sizeof(U)); \
460 }
461 #define VERIFY_CONSTRUCTION_FROM_INTEGER_TYPE(U) \
462 VERIFY_CONSTRUCTION_FROM_INTEGER_TYPE2(U,U,+0) \
463 VERIFY_CONSTRUCTION_FROM_INTEGER_TYPE2(U,CheckedInt<U>,.toChecked<T>())
465 VERIFY_CONSTRUCTION_FROM_INTEGER_TYPE(int8_t)
466 VERIFY_CONSTRUCTION_FROM_INTEGER_TYPE(uint8_t)
467 VERIFY_CONSTRUCTION_FROM_INTEGER_TYPE(int16_t)
468 VERIFY_CONSTRUCTION_FROM_INTEGER_TYPE(uint16_t)
469 VERIFY_CONSTRUCTION_FROM_INTEGER_TYPE(int32_t)
470 VERIFY_CONSTRUCTION_FROM_INTEGER_TYPE(uint32_t)
471 VERIFY_CONSTRUCTION_FROM_INTEGER_TYPE(int64_t)
472 VERIFY_CONSTRUCTION_FROM_INTEGER_TYPE(uint64_t)
474 typedef signed char signedChar;
475 typedef unsigned char unsignedChar;
476 typedef unsigned short unsignedShort;
477 typedef unsigned int unsignedInt;
478 typedef unsigned long unsignedLong;
479 typedef long long longLong;
480 typedef unsigned long long unsignedLongLong;
482 VERIFY_CONSTRUCTION_FROM_INTEGER_TYPE(char)
483 VERIFY_CONSTRUCTION_FROM_INTEGER_TYPE(signedChar)
484 VERIFY_CONSTRUCTION_FROM_INTEGER_TYPE(unsignedChar)
485 VERIFY_CONSTRUCTION_FROM_INTEGER_TYPE(short)
486 VERIFY_CONSTRUCTION_FROM_INTEGER_TYPE(unsignedShort)
487 VERIFY_CONSTRUCTION_FROM_INTEGER_TYPE(int)
488 VERIFY_CONSTRUCTION_FROM_INTEGER_TYPE(unsignedInt)
489 VERIFY_CONSTRUCTION_FROM_INTEGER_TYPE(long)
490 VERIFY_CONSTRUCTION_FROM_INTEGER_TYPE(unsignedLong)
491 VERIFY_CONSTRUCTION_FROM_INTEGER_TYPE(longLong)
492 VERIFY_CONSTRUCTION_FROM_INTEGER_TYPE(unsignedLongLong)
494 /* Test increment/decrement operators */
496 CheckedInt<T> x, y;
497 x = one;
498 y = x++;
499 VERIFY(x == two);
500 VERIFY(y == one);
501 x = one;
502 y = ++x;
503 VERIFY(x == two);
504 VERIFY(y == two);
505 x = one;
506 y = x--;
507 VERIFY(x == zero);
508 VERIFY(y == one);
509 x = one;
510 y = --x;
511 VERIFY(x == zero);
512 VERIFY(y == zero);
513 x = max;
514 VERIFY_IS_VALID(x++);
515 x = max;
516 VERIFY_IS_INVALID(++x);
517 x = min;
518 VERIFY_IS_VALID(x--);
519 x = min;
520 VERIFY_IS_INVALID(--x);
522 gIntegerTypesTested++;
523 }
525 int main()
526 {
527 test<int8_t>();
528 test<uint8_t>();
529 test<int16_t>();
530 test<uint16_t>();
531 test<int32_t>();
532 test<uint32_t>();
533 test<int64_t>();
534 test<uint64_t>();
536 test<char>();
537 test<signed char>();
538 test<unsigned char>();
539 test<short>();
540 test<unsigned short>();
541 test<int>();
542 test<unsigned int>();
543 test<long>();
544 test<unsigned long>();
545 test<long long>();
546 test<unsigned long long>();
548 const int MIN_TYPES_TESTED = 9;
549 if (gIntegerTypesTested < MIN_TYPES_TESTED) {
550 std::cerr << "Only " << gIntegerTypesTested << " have been tested. "
551 << "This should not be less than " << MIN_TYPES_TESTED << "."
552 << std::endl;
553 gTestsFailed++;
554 }
556 std::cerr << gTestsFailed << " tests failed, "
557 << gTestsPassed << " tests passed out of "
558 << gTestsFailed + gTestsPassed
559 << " tests, covering " << gIntegerTypesTested
560 << " distinct integer types." << std::endl;
562 return gTestsFailed > 0;
563 }