summaryrefslogtreecommitdiffstats
path: root/mfbt/tests/TestSaturate.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'mfbt/tests/TestSaturate.cpp')
-rw-r--r--mfbt/tests/TestSaturate.cpp215
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;
+}