diff options
Diffstat (limited to 'mfbt/tests/TestSaturate.cpp')
-rw-r--r-- | mfbt/tests/TestSaturate.cpp | 215 |
1 files changed, 215 insertions, 0 deletions
diff --git a/mfbt/tests/TestSaturate.cpp b/mfbt/tests/TestSaturate.cpp new file mode 100644 index 000000000..06573ba4a --- /dev/null +++ b/mfbt/tests/TestSaturate.cpp @@ -0,0 +1,215 @@ +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* vim: set ts=8 sts=2 et sw=2 tw=80: */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this file, + * You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#include <mozilla/Saturate.h> + +#include <mozilla/Assertions.h> + +#include <limits> + +using mozilla::detail::Saturate; + +#define A(a) MOZ_RELEASE_ASSERT(a, "Test \'" #a "\' failed.") + +static const unsigned long sNumOps = 32; + +template<typename T> +static T +StartValue() +{ + // Specialize |StartValue| for the given type. + A(false); +} + +template<> +int8_t +StartValue<int8_t>() +{ + return 0; +} + +template<> +int16_t +StartValue<int16_t>() +{ + return 0; +} + +template<> +int32_t +StartValue<int32_t>() +{ + return 0; +} + +template<> +uint8_t +StartValue<uint8_t>() +{ + // Picking a value near middle of uint8_t's range. + return static_cast<uint8_t>(std::numeric_limits<int8_t>::max()); +} + +template<> +uint16_t +StartValue<uint16_t>() +{ + // Picking a value near middle of uint16_t's range. + return static_cast<uint8_t>(std::numeric_limits<int16_t>::max()); +} + +template<> +uint32_t +StartValue<uint32_t>() +{ + // Picking a value near middle of uint32_t's range. + return static_cast<uint8_t>(std::numeric_limits<int32_t>::max()); +} + +// Add +// + +template<typename T> +static void +TestPrefixIncr() +{ + T value = StartValue<T>(); + Saturate<T> satValue(value); + + for (T i = 0; i < static_cast<T>(sNumOps); ++i) { + A(++value == ++satValue); + } +} + +template<typename T> +static void +TestPostfixIncr() +{ + T value = StartValue<T>(); + Saturate<T> satValue(value); + + for (T i = 0; i < static_cast<T>(sNumOps); ++i) { + A(value++ == satValue++); + } +} + +template<typename T> +static void +TestAdd() +{ + T value = StartValue<T>(); + Saturate<T> satValue(value); + + for (T i = 0; i < static_cast<T>(sNumOps); ++i) { + A((value + i) == (satValue + i)); + } +} + +// Subtract +// + +template<typename T> +static void +TestPrefixDecr() +{ + T value = StartValue<T>(); + Saturate<T> satValue(value); + + for (T i = 0; i < static_cast<T>(sNumOps); ++i) { + A(--value == --satValue); + } +} + +template<typename T> +static void +TestPostfixDecr() +{ + T value = StartValue<T>(); + Saturate<T> satValue(value); + + for (T i = 0; i < static_cast<T>(sNumOps); ++i) { + A(value-- == satValue--); + } +} + +template<typename T> +static void +TestSub() +{ + T value = StartValue<T>(); + Saturate<T> satValue(value); + + for (T i = 0; i < static_cast<T>(sNumOps); ++i) { + A((value - i) == (satValue - i)); + } +} + +// Corner cases near bounds +// + +template<typename T> +static void +TestUpperBound() +{ + Saturate<T> satValue(std::numeric_limits<T>::max()); + + A(--satValue == (std::numeric_limits<T>::max() - 1)); + A(++satValue == (std::numeric_limits<T>::max())); + A(++satValue == (std::numeric_limits<T>::max())); // don't overflow here + A(++satValue == (std::numeric_limits<T>::max())); // don't overflow here + A(--satValue == (std::numeric_limits<T>::max() - 1)); // back at (max - 1) + A(--satValue == (std::numeric_limits<T>::max() - 2)); +} + +template<typename T> +static void +TestLowerBound() +{ + Saturate<T> satValue(std::numeric_limits<T>::min()); + + A(++satValue == (std::numeric_limits<T>::min() + 1)); + A(--satValue == (std::numeric_limits<T>::min())); + A(--satValue == (std::numeric_limits<T>::min())); // don't overflow here + A(--satValue == (std::numeric_limits<T>::min())); // don't overflow here + A(++satValue == (std::numeric_limits<T>::min() + 1)); // back at (max + 1) + A(++satValue == (std::numeric_limits<T>::min() + 2)); +} + +// Framework +// + +template<typename T> +static void +TestAll() +{ + // Assert that we don't accidently hit type's range limits in tests. + const T value = StartValue<T>(); + A(std::numeric_limits<T>::min() + static_cast<T>(sNumOps) <= value); + A(std::numeric_limits<T>::max() - static_cast<T>(sNumOps) >= value); + + TestPrefixIncr<T>(); + TestPostfixIncr<T>(); + TestAdd<T>(); + + TestPrefixDecr<T>(); + TestPostfixDecr<T>(); + TestSub<T>(); + + TestUpperBound<T>(); + TestLowerBound<T>(); +} + +int +main() +{ + TestAll<int8_t>(); + TestAll<int16_t>(); + TestAll<int32_t>(); + TestAll<uint8_t>(); + TestAll<uint16_t>(); + TestAll<uint32_t>(); + return 0; +} |