michael@0: /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ michael@0: /* This Source Code Form is subject to the terms of the Mozilla Public michael@0: * License, v. 2.0. If a copy of the MPL was not distributed with this file, michael@0: * You can obtain one at http://mozilla.org/MPL/2.0/. */ michael@0: michael@0: #include "mozilla/CheckedInt.h" michael@0: michael@0: #include michael@0: #include michael@0: michael@0: using namespace mozilla; michael@0: michael@0: int gIntegerTypesTested = 0; michael@0: int gTestsPassed = 0; michael@0: int gTestsFailed = 0; michael@0: michael@0: void verifyImplFunction(bool x, bool expected, michael@0: const char* file, int line, michael@0: int size, bool isTSigned) michael@0: { michael@0: if (x == expected) { michael@0: gTestsPassed++; michael@0: } else { michael@0: gTestsFailed++; michael@0: std::cerr << "Test failed at " << file << ":" << line; michael@0: std::cerr << " with T a "; michael@0: if (isTSigned) michael@0: std::cerr << "signed"; michael@0: else michael@0: std::cerr << "unsigned"; michael@0: std::cerr << " " << CHAR_BIT*size << "-bit integer type" << std::endl; michael@0: } michael@0: } michael@0: michael@0: #define VERIFY_IMPL(x, expected) \ michael@0: verifyImplFunction((x), \ michael@0: (expected), \ michael@0: __FILE__, \ michael@0: __LINE__, \ michael@0: sizeof(T), \ michael@0: IsSigned::value) michael@0: michael@0: #define VERIFY(x) VERIFY_IMPL(x, true) michael@0: #define VERIFY_IS_FALSE(x) VERIFY_IMPL(x, false) michael@0: #define VERIFY_IS_VALID(x) VERIFY_IMPL((x).isValid(), true) michael@0: #define VERIFY_IS_INVALID(x) VERIFY_IMPL((x).isValid(), false) michael@0: #define VERIFY_IS_VALID_IF(x,condition) VERIFY_IMPL((x).isValid(), (condition)) michael@0: michael@0: template michael@0: struct testTwiceBiggerType michael@0: { michael@0: static void run() michael@0: { michael@0: VERIFY(detail::IsSupported::Type>::value); michael@0: VERIFY(sizeof(typename detail::TwiceBiggerType::Type) michael@0: == 2 * sizeof(T)); michael@0: VERIFY(bool(IsSigned::Type>::value) michael@0: == bool(IsSigned::value)); michael@0: } michael@0: }; michael@0: michael@0: template michael@0: struct testTwiceBiggerType michael@0: { michael@0: static void run() michael@0: { michael@0: VERIFY_IS_FALSE(detail::IsSupported< michael@0: typename detail::TwiceBiggerType::Type michael@0: >::value); michael@0: } michael@0: }; michael@0: michael@0: michael@0: template michael@0: void test() michael@0: { michael@0: static bool alreadyRun = false; michael@0: // Integer types from different families may just be typedefs for types from other families. michael@0: // e.g. int32_t might be just a typedef for int. No point re-running the same tests then. michael@0: if (alreadyRun) michael@0: return; michael@0: alreadyRun = true; michael@0: michael@0: VERIFY(detail::IsSupported::value); michael@0: const bool isTSigned = IsSigned::value; michael@0: VERIFY(bool(isTSigned) == !bool(T(-1) > T(0))); michael@0: michael@0: testTwiceBiggerType::run(); michael@0: michael@0: typedef typename MakeUnsigned::Type unsignedT; michael@0: michael@0: VERIFY(sizeof(unsignedT) == sizeof(T)); michael@0: VERIFY(IsSigned::value == false); michael@0: michael@0: const CheckedInt max(MaxValue::value); michael@0: const CheckedInt min(MinValue::value); michael@0: michael@0: // Check MinValue and MaxValue, since they are custom implementations and a mistake there michael@0: // could potentially NOT be caught by any other tests... while making everything wrong! michael@0: michael@0: unsignedT bit = 1; michael@0: unsignedT unsignedMinValue(min.value()); michael@0: unsignedT unsignedMaxValue(max.value()); michael@0: for (size_t i = 0; i < sizeof(T) * CHAR_BIT - 1; i++) michael@0: { michael@0: VERIFY((unsignedMinValue & bit) == 0); michael@0: bit <<= 1; michael@0: } michael@0: VERIFY((unsignedMinValue & bit) == (isTSigned ? bit : unsignedT(0))); michael@0: VERIFY(unsignedMaxValue == unsignedT(~unsignedMinValue)); michael@0: michael@0: const CheckedInt zero(0); michael@0: const CheckedInt one(1); michael@0: const CheckedInt two(2); michael@0: const CheckedInt three(3); michael@0: const CheckedInt four(4); michael@0: michael@0: /* Addition / subtraction checks */ michael@0: michael@0: VERIFY_IS_VALID(zero + zero); michael@0: VERIFY(zero + zero == zero); michael@0: VERIFY_IS_FALSE(zero + zero == one); // Check that == doesn't always return true michael@0: VERIFY_IS_VALID(zero + one); michael@0: VERIFY(zero + one == one); michael@0: VERIFY_IS_VALID(one + one); michael@0: VERIFY(one + one == two); michael@0: michael@0: const CheckedInt maxMinusOne = max - one; michael@0: const CheckedInt maxMinusTwo = max - two; michael@0: VERIFY_IS_VALID(maxMinusOne); michael@0: VERIFY_IS_VALID(maxMinusTwo); michael@0: VERIFY_IS_VALID(maxMinusOne + one); michael@0: VERIFY_IS_VALID(maxMinusTwo + one); michael@0: VERIFY_IS_VALID(maxMinusTwo + two); michael@0: VERIFY(maxMinusOne + one == max); michael@0: VERIFY(maxMinusTwo + one == maxMinusOne); michael@0: VERIFY(maxMinusTwo + two == max); michael@0: michael@0: VERIFY_IS_VALID(max + zero); michael@0: VERIFY_IS_VALID(max - zero); michael@0: VERIFY_IS_INVALID(max + one); michael@0: VERIFY_IS_INVALID(max + two); michael@0: VERIFY_IS_INVALID(max + maxMinusOne); michael@0: VERIFY_IS_INVALID(max + max); michael@0: michael@0: const CheckedInt minPlusOne = min + one; michael@0: const CheckedInt minPlusTwo = min + two; michael@0: VERIFY_IS_VALID(minPlusOne); michael@0: VERIFY_IS_VALID(minPlusTwo); michael@0: VERIFY_IS_VALID(minPlusOne - one); michael@0: VERIFY_IS_VALID(minPlusTwo - one); michael@0: VERIFY_IS_VALID(minPlusTwo - two); michael@0: VERIFY(minPlusOne - one == min); michael@0: VERIFY(minPlusTwo - one == minPlusOne); michael@0: VERIFY(minPlusTwo - two == min); michael@0: michael@0: const CheckedInt minMinusOne = min - one; michael@0: VERIFY_IS_VALID(min + zero); michael@0: VERIFY_IS_VALID(min - zero); michael@0: VERIFY_IS_INVALID(min - one); michael@0: VERIFY_IS_INVALID(min - two); michael@0: VERIFY_IS_INVALID(min - minMinusOne); michael@0: VERIFY_IS_VALID(min - min); michael@0: michael@0: const CheckedInt maxOverTwo = max / two; michael@0: VERIFY_IS_VALID(maxOverTwo + maxOverTwo); michael@0: VERIFY_IS_VALID(maxOverTwo + one); michael@0: VERIFY((maxOverTwo + one) - one == maxOverTwo); michael@0: VERIFY_IS_VALID(maxOverTwo - maxOverTwo); michael@0: VERIFY(maxOverTwo - maxOverTwo == zero); michael@0: michael@0: const CheckedInt minOverTwo = min / two; michael@0: VERIFY_IS_VALID(minOverTwo + minOverTwo); michael@0: VERIFY_IS_VALID(minOverTwo + one); michael@0: VERIFY((minOverTwo + one) - one == minOverTwo); michael@0: VERIFY_IS_VALID(minOverTwo - minOverTwo); michael@0: VERIFY(minOverTwo - minOverTwo == zero); michael@0: michael@0: VERIFY_IS_INVALID(min - one); michael@0: VERIFY_IS_INVALID(min - two); michael@0: michael@0: if (isTSigned) { michael@0: VERIFY_IS_INVALID(min + min); michael@0: VERIFY_IS_INVALID(minOverTwo + minOverTwo + minOverTwo); michael@0: VERIFY_IS_INVALID(zero - min + min); michael@0: VERIFY_IS_INVALID(one - min + min); michael@0: } michael@0: michael@0: /* Modulo checks */ michael@0: VERIFY_IS_INVALID(zero % zero); michael@0: VERIFY_IS_INVALID(one % zero); michael@0: VERIFY_IS_VALID(zero % one); michael@0: VERIFY_IS_VALID(zero % max); michael@0: VERIFY_IS_VALID(one % max); michael@0: VERIFY_IS_VALID(max % one); michael@0: VERIFY_IS_VALID(max % max); michael@0: if (isTSigned) { michael@0: const CheckedInt minusOne = zero - one; michael@0: VERIFY_IS_INVALID(minusOne % minusOne); michael@0: VERIFY_IS_INVALID(zero % minusOne); michael@0: VERIFY_IS_INVALID(one % minusOne); michael@0: VERIFY_IS_INVALID(minusOne % one); michael@0: michael@0: VERIFY_IS_INVALID(min % min); michael@0: VERIFY_IS_INVALID(zero % min); michael@0: VERIFY_IS_INVALID(min % one); michael@0: } michael@0: michael@0: /* Unary operator- checks */ michael@0: michael@0: const CheckedInt negOne = -one; michael@0: const CheckedInt negTwo = -two; michael@0: michael@0: if (isTSigned) { michael@0: VERIFY_IS_VALID(-max); michael@0: VERIFY_IS_INVALID(-min); michael@0: VERIFY(-max - min == one); michael@0: VERIFY_IS_VALID(-max - one); michael@0: VERIFY_IS_VALID(negOne); michael@0: VERIFY_IS_VALID(-max + negOne); michael@0: VERIFY_IS_VALID(negOne + one); michael@0: VERIFY(negOne + one == zero); michael@0: VERIFY_IS_VALID(negTwo); michael@0: VERIFY_IS_VALID(negOne + negOne); michael@0: VERIFY(negOne + negOne == negTwo); michael@0: } else { michael@0: VERIFY_IS_INVALID(-max); michael@0: VERIFY_IS_VALID(-min); michael@0: VERIFY(min == zero); michael@0: VERIFY_IS_INVALID(negOne); michael@0: } michael@0: michael@0: /* multiplication checks */ michael@0: michael@0: VERIFY_IS_VALID(zero * zero); michael@0: VERIFY(zero * zero == zero); michael@0: VERIFY_IS_VALID(zero * one); michael@0: VERIFY(zero * one == zero); michael@0: VERIFY_IS_VALID(one * zero); michael@0: VERIFY(one * zero == zero); michael@0: VERIFY_IS_VALID(one * one); michael@0: VERIFY(one * one == one); michael@0: VERIFY_IS_VALID(one * three); michael@0: VERIFY(one * three == three); michael@0: VERIFY_IS_VALID(two * two); michael@0: VERIFY(two * two == four); michael@0: michael@0: VERIFY_IS_INVALID(max * max); michael@0: VERIFY_IS_INVALID(maxOverTwo * max); michael@0: VERIFY_IS_INVALID(maxOverTwo * maxOverTwo); michael@0: michael@0: const CheckedInt maxApproxSqrt(T(T(1) << (CHAR_BIT*sizeof(T)/2))); michael@0: michael@0: VERIFY_IS_VALID(maxApproxSqrt); michael@0: VERIFY_IS_VALID(maxApproxSqrt * two); michael@0: VERIFY_IS_INVALID(maxApproxSqrt * maxApproxSqrt); michael@0: VERIFY_IS_INVALID(maxApproxSqrt * maxApproxSqrt * maxApproxSqrt); michael@0: michael@0: if (isTSigned) { michael@0: VERIFY_IS_INVALID(min * min); michael@0: VERIFY_IS_INVALID(minOverTwo * min); michael@0: VERIFY_IS_INVALID(minOverTwo * minOverTwo); michael@0: michael@0: const CheckedInt minApproxSqrt = -maxApproxSqrt; michael@0: michael@0: VERIFY_IS_VALID(minApproxSqrt); michael@0: VERIFY_IS_VALID(minApproxSqrt * two); michael@0: VERIFY_IS_INVALID(minApproxSqrt * maxApproxSqrt); michael@0: VERIFY_IS_INVALID(minApproxSqrt * minApproxSqrt); michael@0: } michael@0: michael@0: // make sure to check all 4 paths in signed multiplication validity check. michael@0: // test positive * positive michael@0: VERIFY_IS_VALID(max * one); michael@0: VERIFY(max * one == max); michael@0: VERIFY_IS_INVALID(max * two); michael@0: VERIFY_IS_VALID(maxOverTwo * two); michael@0: VERIFY((maxOverTwo + maxOverTwo) == (maxOverTwo * two)); michael@0: michael@0: if (isTSigned) { michael@0: // test positive * negative michael@0: VERIFY_IS_VALID(max * negOne); michael@0: VERIFY_IS_VALID(-max); michael@0: VERIFY(max * negOne == -max); michael@0: VERIFY_IS_VALID(one * min); michael@0: VERIFY_IS_INVALID(max * negTwo); michael@0: VERIFY_IS_VALID(maxOverTwo * negTwo); michael@0: VERIFY_IS_VALID(two * minOverTwo); michael@0: VERIFY_IS_VALID((maxOverTwo + one) * negTwo); michael@0: VERIFY_IS_INVALID((maxOverTwo + two) * negTwo); michael@0: VERIFY_IS_INVALID(two * (minOverTwo - one)); michael@0: michael@0: // test negative * positive michael@0: VERIFY_IS_VALID(min * one); michael@0: VERIFY_IS_VALID(minPlusOne * one); michael@0: VERIFY_IS_INVALID(min * two); michael@0: VERIFY_IS_VALID(minOverTwo * two); michael@0: VERIFY(minOverTwo * two == min); michael@0: VERIFY_IS_INVALID((minOverTwo - one) * negTwo); michael@0: VERIFY_IS_INVALID(negTwo * max); michael@0: VERIFY_IS_VALID(minOverTwo * two); michael@0: VERIFY(minOverTwo * two == min); michael@0: VERIFY_IS_VALID(negTwo * maxOverTwo); michael@0: VERIFY_IS_INVALID((minOverTwo - one) * two); michael@0: VERIFY_IS_VALID(negTwo * (maxOverTwo + one)); michael@0: VERIFY_IS_INVALID(negTwo * (maxOverTwo + two)); michael@0: michael@0: // test negative * negative michael@0: VERIFY_IS_INVALID(min * negOne); michael@0: VERIFY_IS_VALID(minPlusOne * negOne); michael@0: VERIFY(minPlusOne * negOne == max); michael@0: VERIFY_IS_INVALID(min * negTwo); michael@0: VERIFY_IS_INVALID(minOverTwo * negTwo); michael@0: VERIFY_IS_INVALID(negOne * min); michael@0: VERIFY_IS_VALID(negOne * minPlusOne); michael@0: VERIFY(negOne * minPlusOne == max); michael@0: VERIFY_IS_INVALID(negTwo * min); michael@0: VERIFY_IS_INVALID(negTwo * minOverTwo); michael@0: } michael@0: michael@0: /* Division checks */ michael@0: michael@0: VERIFY_IS_VALID(one / one); michael@0: VERIFY(one / one == one); michael@0: VERIFY_IS_VALID(three / three); michael@0: VERIFY(three / three == one); michael@0: VERIFY_IS_VALID(four / two); michael@0: VERIFY(four / two == two); michael@0: VERIFY((four*three)/four == three); michael@0: michael@0: // Check that div by zero is invalid michael@0: VERIFY_IS_INVALID(zero / zero); michael@0: VERIFY_IS_INVALID(one / zero); michael@0: VERIFY_IS_INVALID(two / zero); michael@0: VERIFY_IS_INVALID(negOne / zero); michael@0: VERIFY_IS_INVALID(max / zero); michael@0: VERIFY_IS_INVALID(min / zero); michael@0: michael@0: if (isTSigned) { michael@0: // Check that min / -1 is invalid michael@0: VERIFY_IS_INVALID(min / negOne); michael@0: michael@0: // Check that the test for div by -1 isn't banning other numerators than min michael@0: VERIFY_IS_VALID(one / negOne); michael@0: VERIFY_IS_VALID(zero / negOne); michael@0: VERIFY_IS_VALID(negOne / negOne); michael@0: VERIFY_IS_VALID(max / negOne); michael@0: } michael@0: michael@0: /* Check that invalidity is correctly preserved by arithmetic ops */ michael@0: michael@0: const CheckedInt someInvalid = max + max; michael@0: VERIFY_IS_INVALID(someInvalid + zero); michael@0: VERIFY_IS_INVALID(someInvalid - zero); michael@0: VERIFY_IS_INVALID(zero + someInvalid); michael@0: VERIFY_IS_INVALID(zero - someInvalid); michael@0: VERIFY_IS_INVALID(-someInvalid); michael@0: VERIFY_IS_INVALID(someInvalid * zero); michael@0: VERIFY_IS_INVALID(someInvalid * one); michael@0: VERIFY_IS_INVALID(zero * someInvalid); michael@0: VERIFY_IS_INVALID(one * someInvalid); michael@0: VERIFY_IS_INVALID(someInvalid / zero); michael@0: VERIFY_IS_INVALID(someInvalid / one); michael@0: VERIFY_IS_INVALID(zero / someInvalid); michael@0: VERIFY_IS_INVALID(one / someInvalid); michael@0: VERIFY_IS_INVALID(someInvalid % zero); michael@0: VERIFY_IS_INVALID(someInvalid % one); michael@0: VERIFY_IS_INVALID(zero % someInvalid); michael@0: VERIFY_IS_INVALID(one % someInvalid); michael@0: VERIFY_IS_INVALID(someInvalid + someInvalid); michael@0: VERIFY_IS_INVALID(someInvalid - someInvalid); michael@0: VERIFY_IS_INVALID(someInvalid * someInvalid); michael@0: VERIFY_IS_INVALID(someInvalid / someInvalid); michael@0: VERIFY_IS_INVALID(someInvalid % someInvalid); michael@0: michael@0: /* Check that mixing checked integers with plain integers in expressions is allowed */ michael@0: michael@0: VERIFY(one + T(2) == three); michael@0: VERIFY(2 + one == three); michael@0: { michael@0: CheckedInt x = one; michael@0: x += 2; michael@0: VERIFY(x == three); michael@0: } michael@0: VERIFY(two - 1 == one); michael@0: VERIFY(2 - one == one); michael@0: { michael@0: CheckedInt x = two; michael@0: x -= 1; michael@0: VERIFY(x == one); michael@0: } michael@0: VERIFY(one * 2 == two); michael@0: VERIFY(2 * one == two); michael@0: { michael@0: CheckedInt x = one; michael@0: x *= 2; michael@0: VERIFY(x == two); michael@0: } michael@0: VERIFY(four / 2 == two); michael@0: VERIFY(4 / two == two); michael@0: { michael@0: CheckedInt x = four; michael@0: x /= 2; michael@0: VERIFY(x == two); michael@0: } michael@0: VERIFY(three % 2 == one); michael@0: VERIFY(3 % two == one); michael@0: { michael@0: CheckedInt x = three; michael@0: x %= 2; michael@0: VERIFY(x == one); michael@0: } michael@0: michael@0: VERIFY(one == 1); michael@0: VERIFY(1 == one); michael@0: VERIFY_IS_FALSE(two == 1); michael@0: VERIFY_IS_FALSE(1 == two); michael@0: VERIFY_IS_FALSE(someInvalid == 1); michael@0: VERIFY_IS_FALSE(1 == someInvalid); michael@0: michael@0: // Check simple casting between different signedness and sizes. michael@0: { michael@0: CheckedInt foo = CheckedInt(2).toChecked(); michael@0: VERIFY_IS_VALID(foo); michael@0: VERIFY(foo == 2); michael@0: } michael@0: { michael@0: CheckedInt foo = CheckedInt(255).toChecked(); michael@0: VERIFY_IS_VALID(foo); michael@0: VERIFY(foo == 255); michael@0: } michael@0: { michael@0: CheckedInt foo = CheckedInt(256).toChecked(); michael@0: VERIFY_IS_INVALID(foo); michael@0: } michael@0: { michael@0: CheckedInt foo = CheckedInt(-2).toChecked(); michael@0: VERIFY_IS_INVALID(foo); michael@0: } michael@0: michael@0: // Check that construction of CheckedInt from an integer value of a mismatched type is checked michael@0: // Also check casting between all types. michael@0: michael@0: #define VERIFY_CONSTRUCTION_FROM_INTEGER_TYPE2(U,V,PostVExpr) \ michael@0: { \ michael@0: bool isUSigned = IsSigned::value; \ michael@0: VERIFY_IS_VALID(CheckedInt(V( 0)PostVExpr)); \ michael@0: VERIFY_IS_VALID(CheckedInt(V( 1)PostVExpr)); \ michael@0: VERIFY_IS_VALID(CheckedInt(V(100)PostVExpr)); \ michael@0: if (isUSigned) \ michael@0: VERIFY_IS_VALID_IF(CheckedInt(V(-1)PostVExpr), isTSigned); \ michael@0: if (sizeof(U) > sizeof(T)) \ michael@0: VERIFY_IS_INVALID(CheckedInt(V(MaxValue::value)PostVExpr + one.value())); \ michael@0: VERIFY_IS_VALID_IF(CheckedInt(MaxValue::value), \ michael@0: (sizeof(T) > sizeof(U) || ((sizeof(T) == sizeof(U)) && (isUSigned || !isTSigned)))); \ michael@0: VERIFY_IS_VALID_IF(CheckedInt(MinValue::value), \ michael@0: isUSigned == false ? 1 \ michael@0: : bool(isTSigned) == false ? 0 \ michael@0: : sizeof(T) >= sizeof(U)); \ michael@0: } michael@0: #define VERIFY_CONSTRUCTION_FROM_INTEGER_TYPE(U) \ michael@0: VERIFY_CONSTRUCTION_FROM_INTEGER_TYPE2(U,U,+0) \ michael@0: VERIFY_CONSTRUCTION_FROM_INTEGER_TYPE2(U,CheckedInt,.toChecked()) michael@0: michael@0: VERIFY_CONSTRUCTION_FROM_INTEGER_TYPE(int8_t) michael@0: VERIFY_CONSTRUCTION_FROM_INTEGER_TYPE(uint8_t) michael@0: VERIFY_CONSTRUCTION_FROM_INTEGER_TYPE(int16_t) michael@0: VERIFY_CONSTRUCTION_FROM_INTEGER_TYPE(uint16_t) michael@0: VERIFY_CONSTRUCTION_FROM_INTEGER_TYPE(int32_t) michael@0: VERIFY_CONSTRUCTION_FROM_INTEGER_TYPE(uint32_t) michael@0: VERIFY_CONSTRUCTION_FROM_INTEGER_TYPE(int64_t) michael@0: VERIFY_CONSTRUCTION_FROM_INTEGER_TYPE(uint64_t) michael@0: michael@0: typedef signed char signedChar; michael@0: typedef unsigned char unsignedChar; michael@0: typedef unsigned short unsignedShort; michael@0: typedef unsigned int unsignedInt; michael@0: typedef unsigned long unsignedLong; michael@0: typedef long long longLong; michael@0: typedef unsigned long long unsignedLongLong; michael@0: michael@0: VERIFY_CONSTRUCTION_FROM_INTEGER_TYPE(char) michael@0: VERIFY_CONSTRUCTION_FROM_INTEGER_TYPE(signedChar) michael@0: VERIFY_CONSTRUCTION_FROM_INTEGER_TYPE(unsignedChar) michael@0: VERIFY_CONSTRUCTION_FROM_INTEGER_TYPE(short) michael@0: VERIFY_CONSTRUCTION_FROM_INTEGER_TYPE(unsignedShort) michael@0: VERIFY_CONSTRUCTION_FROM_INTEGER_TYPE(int) michael@0: VERIFY_CONSTRUCTION_FROM_INTEGER_TYPE(unsignedInt) michael@0: VERIFY_CONSTRUCTION_FROM_INTEGER_TYPE(long) michael@0: VERIFY_CONSTRUCTION_FROM_INTEGER_TYPE(unsignedLong) michael@0: VERIFY_CONSTRUCTION_FROM_INTEGER_TYPE(longLong) michael@0: VERIFY_CONSTRUCTION_FROM_INTEGER_TYPE(unsignedLongLong) michael@0: michael@0: /* Test increment/decrement operators */ michael@0: michael@0: CheckedInt x, y; michael@0: x = one; michael@0: y = x++; michael@0: VERIFY(x == two); michael@0: VERIFY(y == one); michael@0: x = one; michael@0: y = ++x; michael@0: VERIFY(x == two); michael@0: VERIFY(y == two); michael@0: x = one; michael@0: y = x--; michael@0: VERIFY(x == zero); michael@0: VERIFY(y == one); michael@0: x = one; michael@0: y = --x; michael@0: VERIFY(x == zero); michael@0: VERIFY(y == zero); michael@0: x = max; michael@0: VERIFY_IS_VALID(x++); michael@0: x = max; michael@0: VERIFY_IS_INVALID(++x); michael@0: x = min; michael@0: VERIFY_IS_VALID(x--); michael@0: x = min; michael@0: VERIFY_IS_INVALID(--x); michael@0: michael@0: gIntegerTypesTested++; michael@0: } michael@0: michael@0: int main() michael@0: { michael@0: test(); michael@0: test(); michael@0: test(); michael@0: test(); michael@0: test(); michael@0: test(); michael@0: test(); michael@0: test(); michael@0: michael@0: test(); michael@0: test(); michael@0: test(); michael@0: test(); michael@0: test(); michael@0: test(); michael@0: test(); michael@0: test(); michael@0: test(); michael@0: test(); michael@0: test(); michael@0: michael@0: const int MIN_TYPES_TESTED = 9; michael@0: if (gIntegerTypesTested < MIN_TYPES_TESTED) { michael@0: std::cerr << "Only " << gIntegerTypesTested << " have been tested. " michael@0: << "This should not be less than " << MIN_TYPES_TESTED << "." michael@0: << std::endl; michael@0: gTestsFailed++; michael@0: } michael@0: michael@0: std::cerr << gTestsFailed << " tests failed, " michael@0: << gTestsPassed << " tests passed out of " michael@0: << gTestsFailed + gTestsPassed michael@0: << " tests, covering " << gIntegerTypesTested michael@0: << " distinct integer types." << std::endl; michael@0: michael@0: return gTestsFailed > 0; michael@0: }