diff options
author | Lorry Tar Creator <lorry-tar-importer@baserock.org> | 2013-12-11 22:24:18 +0000 |
---|---|---|
committer | <> | 2014-07-24 09:30:59 +0000 |
commit | 59e2936f588aa945e8dcd6c737523c299067e9d0 (patch) | |
tree | 97e74980cc54baa19de5faa11f5a50a0121a48ea /mfbt/tests | |
download | mozjs24-master.tar.gz |
Imported from /home/lorry/working-area/delta_mozilla_mozjs24/mozjs-24.2.0.tar.bz2.HEADmozjs-24.2.0master
Diffstat (limited to 'mfbt/tests')
-rw-r--r-- | mfbt/tests/Makefile.in | 47 | ||||
-rw-r--r-- | mfbt/tests/TestAtomics.cpp | 159 | ||||
-rw-r--r-- | mfbt/tests/TestBloomFilter.cpp | 102 | ||||
-rw-r--r-- | mfbt/tests/TestCasting.cpp | 107 | ||||
-rw-r--r-- | mfbt/tests/TestCheckedInt.cpp | 567 | ||||
-rw-r--r-- | mfbt/tests/TestEndian.cpp | 398 | ||||
-rw-r--r-- | mfbt/tests/TestEnumSet.cpp | 232 | ||||
-rw-r--r-- | mfbt/tests/TestPoisonArea.cpp | 654 | ||||
-rw-r--r-- | mfbt/tests/TestSHA1.cpp | 204 | ||||
-rw-r--r-- | mfbt/tests/TestTypeTraits.cpp | 213 | ||||
-rw-r--r-- | mfbt/tests/TestWeakPtr.cpp | 77 | ||||
-rw-r--r-- | mfbt/tests/moz.build | 6 |
12 files changed, 2766 insertions, 0 deletions
diff --git a/mfbt/tests/Makefile.in b/mfbt/tests/Makefile.in new file mode 100644 index 0000000..faac3bc --- /dev/null +++ b/mfbt/tests/Makefile.in @@ -0,0 +1,47 @@ +# 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/. + +DEPTH = @DEPTH@ +topsrcdir = @top_srcdir@ +srcdir = @srcdir@ +VPATH = @srcdir@ + +include $(DEPTH)/config/autoconf.mk + +STL_FLAGS = + +CPP_UNIT_TESTS = \ + TestAtomics.cpp \ + TestBloomFilter.cpp \ + TestCasting.cpp \ + TestCheckedInt.cpp \ + TestEndian.cpp \ + TestEnumSet.cpp \ + TestSHA1.cpp \ + TestTypeTraits.cpp \ + TestWeakPtr.cpp \ + $(NULL) + +# These tests don't work with AddressSanitizer enabled +ifndef MOZ_ASAN +CPP_UNIT_TESTS += \ + TestPoisonArea.cpp \ + $(NULL) +endif + +# in order to prevent rules.mk from trying to link to libraries that are +# not available to MFBT, we have to reset these MOZ_GLUE*_LDFLAGS before including it +# and LIBS_ after including it. For WRAP_LDFLAGS, it shouldn't matter. +# See later comments in bug 732875. + +MOZ_GLUE_PROGRAM_LDFLAGS= +MOZ_GLUE_LDFLAGS = +WRAP_LDFLAGS= + +# Since we link directly with MFBT object files, define IMPL_MFBT +DEFINES += -DIMPL_MFBT + +include $(topsrcdir)/config/rules.mk + +LIBS= $(call EXPAND_LIBNAME_PATH,mfbt,$(DEPTH)/mfbt) diff --git a/mfbt/tests/TestAtomics.cpp b/mfbt/tests/TestAtomics.cpp new file mode 100644 index 0000000..3e05893 --- /dev/null +++ b/mfbt/tests/TestAtomics.cpp @@ -0,0 +1,159 @@ +/* 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/Assertions.h" +#include "mozilla/Atomics.h" +#include "mozilla/DebugOnly.h" + +#include <stdint.h> + +using mozilla::Atomic; +using mozilla::DebugOnly; +using mozilla::MemoryOrdering; +using mozilla::Relaxed; +using mozilla::ReleaseAcquire; +using mozilla::SequentiallyConsistent; + +template <typename T, MemoryOrdering Order> +static void +TestTypeWithOrdering() +{ + Atomic<T, Order> atomic(5); + MOZ_ASSERT(atomic == 5, "Atomic variable did not initialize"); + + // Test atomic increment + MOZ_ASSERT(++atomic == T(6), "Atomic increment did not work"); + MOZ_ASSERT(atomic++ == T(6), "Atomic post-increment did not work"); + MOZ_ASSERT(atomic == T(7), "Atomic post-increment did not work"); + + // Test atomic decrement + MOZ_ASSERT(--atomic == 6, "Atomic decrement did not work"); + MOZ_ASSERT(atomic-- == 6, "Atomic post-decrement did not work"); + MOZ_ASSERT(atomic == 5, "Atomic post-decrement did not work"); + + // Test other arithmetic. + DebugOnly<T> result; + result = (atomic += T(5)); + MOZ_ASSERT(atomic == T(10), "Atomic += did not work"); + MOZ_ASSERT(result == T(10), "Atomic += returned the wrong value"); + result = (atomic -= T(3)); + MOZ_ASSERT(atomic == T(7), "Atomic -= did not work"); + MOZ_ASSERT(result == T(7), "Atomic -= returned the wrong value"); + + // Test assignment + result = (atomic = T(5)); + MOZ_ASSERT(atomic == T(5), "Atomic assignment failed"); + MOZ_ASSERT(result == T(5), "Atomic assignment returned the wrong value"); + + // Test logical operations. + result = (atomic ^= T(2)); + MOZ_ASSERT(atomic == T(7), "Atomic ^= did not work"); + MOZ_ASSERT(result == T(7), "Atomic ^= returned the wrong value"); + result = (atomic ^= T(4)); + MOZ_ASSERT(atomic == T(3), "Atomic ^= did not work"); + MOZ_ASSERT(result == T(3), "Atomic ^= returned the wrong value"); + result = (atomic |= T(8)); + MOZ_ASSERT(atomic == T(11), "Atomic |= did not work"); + MOZ_ASSERT(result == T(11), "Atomic |= returned the wrong value"); + result = (atomic |= T(8)); + MOZ_ASSERT(atomic == T(11), "Atomic |= did not work"); + MOZ_ASSERT(result == T(11), "Atomic |= returned the wrong value"); + result = (atomic &= T(12)); + MOZ_ASSERT(atomic == T(8), "Atomic &= did not work"); + MOZ_ASSERT(result == T(8), "Atomic &= returned the wrong value"); + + // Test exchange. + atomic = T(30); + result = atomic.exchange(42); + MOZ_ASSERT(atomic == T(42), "Atomic exchange did not work"); + MOZ_ASSERT(result == T(30), "Atomic exchange returned the wrong value"); + + // Test CAS. + atomic = T(1); + DebugOnly<bool> boolResult = atomic.compareExchange(0, 2); + MOZ_ASSERT(!boolResult, "CAS should have returned false."); + MOZ_ASSERT(atomic == T(1), "CAS shouldn't have done anything."); + + boolResult = atomic.compareExchange(1, 42); + MOZ_ASSERT(boolResult, "CAS should have succeeded."); + MOZ_ASSERT(atomic == T(42), "CAS should have changed atomic's value."); +} + +template<typename T, MemoryOrdering Order> +static void +TestPointerWithOrdering() +{ + T array1[10]; + Atomic<T*, Order> atomic(array1); + MOZ_ASSERT(atomic == array1, "Atomic variable did not initialize"); + + // Test atomic increment + MOZ_ASSERT(++atomic == array1 + 1, "Atomic increment did not work"); + MOZ_ASSERT(atomic++ == array1 + 1, "Atomic post-increment did not work"); + MOZ_ASSERT(atomic == array1 + 2, "Atomic post-increment did not work"); + + // Test atomic decrement + MOZ_ASSERT(--atomic == array1 + 1, "Atomic decrement did not work"); + MOZ_ASSERT(atomic-- == array1 + 1, "Atomic post-decrement did not work"); + MOZ_ASSERT(atomic == array1, "Atomic post-decrement did not work"); + + // Test other arithmetic operations + DebugOnly<T*> result; + result = (atomic += 2); + MOZ_ASSERT(atomic == array1 + 2, "Atomic += did not work"); + MOZ_ASSERT(result == array1 + 2, "Atomic += returned the wrong value"); + result = (atomic -= 1); + MOZ_ASSERT(atomic == array1 + 1, "Atomic -= did not work"); + MOZ_ASSERT(result == array1 + 1, "Atomic -= returned the wrong value"); + + // Test stores + result = (atomic = array1); + MOZ_ASSERT(atomic == array1, "Atomic assignment did not work"); + MOZ_ASSERT(result == array1, "Atomic assignment returned the wrong value"); + + // Test exchange + atomic = array1 + 2; + result = atomic.exchange(array1); + MOZ_ASSERT(atomic == array1, "Atomic exchange did not work"); + MOZ_ASSERT(result == array1 + 2, "Atomic exchange returned the wrong value"); + + atomic = array1; + DebugOnly<bool> boolResult = atomic.compareExchange(array1 + 1, array1 + 2); + MOZ_ASSERT(!boolResult, "CAS should have returned false."); + MOZ_ASSERT(atomic == array1, "CAS shouldn't have done anything."); + + boolResult = atomic.compareExchange(array1, array1 + 3); + MOZ_ASSERT(boolResult, "CAS should have succeeded."); + MOZ_ASSERT(atomic == array1 + 3, "CAS should have changed atomic's value."); +} + +template <typename T> +static void +TestType() +{ + TestTypeWithOrdering<T, SequentiallyConsistent>(); + TestTypeWithOrdering<T, ReleaseAcquire>(); + TestTypeWithOrdering<T, Relaxed>(); +} + +template<typename T> +static void +TestPointer() +{ + TestPointerWithOrdering<T, SequentiallyConsistent>(); + TestPointerWithOrdering<T, ReleaseAcquire>(); + TestPointerWithOrdering<T, Relaxed>(); +} + +int main() +{ + TestType<uint32_t>(); + TestType<int32_t>(); + TestType<intptr_t>(); + TestType<uintptr_t>(); + TestPointer<int>(); + TestPointer<float>(); + TestPointer<uint16_t*>(); + TestPointer<uint32_t*>(); +} diff --git a/mfbt/tests/TestBloomFilter.cpp b/mfbt/tests/TestBloomFilter.cpp new file mode 100644 index 0000000..7a8a0ec --- /dev/null +++ b/mfbt/tests/TestBloomFilter.cpp @@ -0,0 +1,102 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* 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/Assertions.h" +#include "mozilla/BloomFilter.h" + +#include <stddef.h> +#include <stdio.h> + +using mozilla::BloomFilter; + +class FilterChecker +{ + public: + FilterChecker(uint32_t hash) : mHash(hash) { } + + uint32_t hash() const { return mHash; } + + private: + uint32_t mHash; +}; + +int +main() +{ + BloomFilter<12, FilterChecker> *filter = new BloomFilter<12, FilterChecker>(); + MOZ_ASSERT(filter); + + FilterChecker one(1); + FilterChecker two(0x20000); + FilterChecker many(0x10000); + FilterChecker multiple(0x20001); + + filter->add(&one); + MOZ_ASSERT(filter->mightContain(&one), + "Filter should contain 'one'"); + + MOZ_ASSERT(!filter->mightContain(&multiple), + "Filter claims to contain 'multiple' when it should not"); + + MOZ_ASSERT(filter->mightContain(&many), + "Filter should contain 'many' (false positive)"); + + filter->add(&two); + MOZ_ASSERT(filter->mightContain(&multiple), + "Filter should contain 'multiple' (false positive)"); + + // Test basic removals + filter->remove(&two); + MOZ_ASSERT(!filter->mightContain(&multiple), + "Filter claims to contain 'multiple' when it should not after two " + "was removed"); + + // Test multiple addition/removal + const size_t FILTER_SIZE = 255; + for (size_t i = 0; i < FILTER_SIZE - 1; ++i) + filter->add(&two); + + MOZ_ASSERT(filter->mightContain(&multiple), + "Filter should contain 'multiple' after 'two' added lots of times " + "(false positive)"); + + for (size_t i = 0; i < FILTER_SIZE - 1; ++i) + filter->remove(&two); + + MOZ_ASSERT(!filter->mightContain(&multiple), + "Filter claims to contain 'multiple' when it should not after two " + "was removed lots of times"); + + // Test overflowing the filter buckets + for (size_t i = 0; i < FILTER_SIZE + 1; ++i) + filter->add(&two); + + MOZ_ASSERT(filter->mightContain(&multiple), + "Filter should contain 'multiple' after 'two' added lots more " + "times (false positive)"); + + for (size_t i = 0; i < FILTER_SIZE + 1; ++i) + filter->remove(&two); + + MOZ_ASSERT(filter->mightContain(&multiple), + "Filter claims to not contain 'multiple' even though we should " + "have run out of space in the buckets (false positive)"); + MOZ_ASSERT(filter->mightContain(&two), + "Filter claims to not contain 'two' even though we should have " + "run out of space in the buckets (false positive)"); + + filter->remove(&one); + + MOZ_ASSERT(!filter->mightContain(&one), + "Filter should not contain 'one', because we didn't overflow its " + "bucket"); + + filter->clear(); + + MOZ_ASSERT(!filter->mightContain(&multiple), + "clear() failed to work"); + + return 0; +} diff --git a/mfbt/tests/TestCasting.cpp b/mfbt/tests/TestCasting.cpp new file mode 100644 index 0000000..1e19b07 --- /dev/null +++ b/mfbt/tests/TestCasting.cpp @@ -0,0 +1,107 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* 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/Casting.h" +#include "mozilla/StandardInteger.h" + +using mozilla::BitwiseCast; +using mozilla::detail::IsInBounds; + +template<typename Uint, typename Ulong, bool = (sizeof(Uint) == sizeof(Ulong))> +struct UintUlongBitwiseCast; + +template<typename Uint, typename Ulong> +struct UintUlongBitwiseCast<Uint, Ulong, true> +{ + static void test() { + MOZ_ASSERT(BitwiseCast<Ulong>(Uint(8675309)) == Ulong(8675309)); + } +}; + +template<typename Uint, typename Ulong> +struct UintUlongBitwiseCast<Uint, Ulong, false> +{ + static void test() { } +}; + +static void +TestBitwiseCast() +{ + MOZ_ASSERT(BitwiseCast<int>(int(8675309)) == int(8675309)); + UintUlongBitwiseCast<unsigned int, unsigned long>::test(); +} + +static void +TestSameSize() +{ + MOZ_ASSERT((IsInBounds<int16_t, int16_t>(int16_t(0)))); + MOZ_ASSERT((IsInBounds<int16_t, int16_t>(int16_t(INT16_MIN)))); + MOZ_ASSERT((IsInBounds<int16_t, int16_t>(int16_t(INT16_MAX)))); + MOZ_ASSERT((IsInBounds<uint16_t, uint16_t>(uint16_t(UINT16_MAX)))); + MOZ_ASSERT((IsInBounds<uint16_t, int16_t>(uint16_t(0)))); + MOZ_ASSERT((!IsInBounds<uint16_t, int16_t>(uint16_t(-1)))); + MOZ_ASSERT((!IsInBounds<int16_t, uint16_t>(int16_t(-1)))); + MOZ_ASSERT((IsInBounds<int16_t, uint16_t>(int16_t(INT16_MAX)))); + MOZ_ASSERT((!IsInBounds<int16_t, uint16_t>(int16_t(INT16_MIN)))); + MOZ_ASSERT((IsInBounds<int32_t, uint32_t>(int32_t(INT32_MAX)))); + MOZ_ASSERT((!IsInBounds<int32_t, uint32_t>(int32_t(INT32_MIN)))); +} + +static void +TestToBiggerSize() +{ + MOZ_ASSERT((IsInBounds<int16_t, int32_t>(int16_t(0)))); + MOZ_ASSERT((IsInBounds<int16_t, int32_t>(int16_t(INT16_MIN)))); + MOZ_ASSERT((IsInBounds<int16_t, int32_t>(int16_t(INT16_MAX)))); + MOZ_ASSERT((IsInBounds<uint16_t, uint32_t>(uint16_t(UINT16_MAX)))); + MOZ_ASSERT((IsInBounds<uint16_t, int32_t>(uint16_t(0)))); + MOZ_ASSERT((IsInBounds<uint16_t, int32_t>(uint16_t(-1)))); + MOZ_ASSERT((!IsInBounds<int16_t, uint32_t>(int16_t(-1)))); + MOZ_ASSERT((IsInBounds<int16_t, uint32_t>(int16_t(INT16_MAX)))); + MOZ_ASSERT((!IsInBounds<int16_t, uint32_t>(int16_t(INT16_MIN)))); + MOZ_ASSERT((IsInBounds<int32_t, uint64_t>(int32_t(INT32_MAX)))); + MOZ_ASSERT((!IsInBounds<int32_t, uint64_t>(int32_t(INT32_MIN)))); +} + +static void +TestToSmallerSize() +{ + MOZ_ASSERT((IsInBounds<int16_t, int8_t>(int16_t(0)))); + MOZ_ASSERT((!IsInBounds<int16_t, int8_t>(int16_t(INT16_MIN)))); + MOZ_ASSERT((!IsInBounds<int16_t, int8_t>(int16_t(INT16_MAX)))); + MOZ_ASSERT((!IsInBounds<uint16_t, uint8_t>(uint16_t(UINT16_MAX)))); + MOZ_ASSERT((IsInBounds<uint16_t, int8_t>(uint16_t(0)))); + MOZ_ASSERT((!IsInBounds<uint16_t, int8_t>(uint16_t(-1)))); + MOZ_ASSERT((!IsInBounds<int16_t, uint8_t>(int16_t(-1)))); + MOZ_ASSERT((!IsInBounds<int16_t, uint8_t>(int16_t(INT16_MAX)))); + MOZ_ASSERT((!IsInBounds<int16_t, uint8_t>(int16_t(INT16_MIN)))); + MOZ_ASSERT((!IsInBounds<int32_t, uint16_t>(int32_t(INT32_MAX)))); + MOZ_ASSERT((!IsInBounds<int32_t, uint16_t>(int32_t(INT32_MIN)))); + + // Boundary cases + MOZ_ASSERT((!IsInBounds<int64_t, int32_t>(int64_t(INT32_MIN) - 1))); + MOZ_ASSERT((IsInBounds<int64_t, int32_t>(int64_t(INT32_MIN)))); + MOZ_ASSERT((IsInBounds<int64_t, int32_t>(int64_t(INT32_MIN) + 1))); + MOZ_ASSERT((IsInBounds<int64_t, int32_t>(int64_t(INT32_MAX) - 1))); + MOZ_ASSERT((IsInBounds<int64_t, int32_t>(int64_t(INT32_MAX)))); + MOZ_ASSERT((!IsInBounds<int64_t, int32_t>(int64_t(INT32_MAX) + 1))); + + MOZ_ASSERT((!IsInBounds<int64_t, uint32_t>(int64_t(-1)))); + MOZ_ASSERT((IsInBounds<int64_t, uint32_t>(int64_t(0)))); + MOZ_ASSERT((IsInBounds<int64_t, uint32_t>(int64_t(1)))); + MOZ_ASSERT((IsInBounds<int64_t, uint32_t>(int64_t(UINT32_MAX) - 1))); + MOZ_ASSERT((IsInBounds<int64_t, uint32_t>(int64_t(UINT32_MAX)))); + MOZ_ASSERT((!IsInBounds<int64_t, uint32_t>(int64_t(UINT32_MAX) + 1))); +} + +int +main() +{ + TestBitwiseCast(); + + TestSameSize(); + TestToBiggerSize(); + TestToSmallerSize(); +} diff --git a/mfbt/tests/TestCheckedInt.cpp b/mfbt/tests/TestCheckedInt.cpp new file mode 100644 index 0000000..5a9cba7 --- /dev/null +++ b/mfbt/tests/TestCheckedInt.cpp @@ -0,0 +1,567 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* 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/CheckedInt.h" + +#include <iostream> +#include <climits> + +#ifndef MOZ_CHECKEDINT_USE_MFBT +# error "MOZ_CHECKEDINT_USE_MFBT should be defined by CheckedInt.h" +#endif + +using namespace mozilla; + +int gIntegerTypesTested = 0; +int gTestsPassed = 0; +int gTestsFailed = 0; + +void verifyImplFunction(bool x, bool expected, + const char* file, int line, + int size, bool isTSigned) +{ + if (x == expected) { + gTestsPassed++; + } else { + gTestsFailed++; + std::cerr << "Test failed at " << file << ":" << line; + std::cerr << " with T a "; + if (isTSigned) + std::cerr << "signed"; + else + std::cerr << "unsigned"; + std::cerr << " " << CHAR_BIT*size << "-bit integer type" << std::endl; + } +} + +#define VERIFY_IMPL(x, expected) \ + verifyImplFunction((x), \ + (expected), \ + __FILE__, \ + __LINE__, \ + sizeof(T), \ + detail::IsSigned<T>::value) + +#define VERIFY(x) VERIFY_IMPL(x, true) +#define VERIFY_IS_FALSE(x) VERIFY_IMPL(x, false) +#define VERIFY_IS_VALID(x) VERIFY_IMPL((x).isValid(), true) +#define VERIFY_IS_INVALID(x) VERIFY_IMPL((x).isValid(), false) +#define VERIFY_IS_VALID_IF(x,condition) VERIFY_IMPL((x).isValid(), (condition)) + +template<typename T, size_t Size = sizeof(T)> +struct testTwiceBiggerType +{ + static void run() + { + VERIFY(detail::IsSupported<typename detail::TwiceBiggerType<T>::Type>::value); + VERIFY(sizeof(typename detail::TwiceBiggerType<T>::Type) + == 2 * sizeof(T)); + VERIFY(bool(detail::IsSigned<typename detail::TwiceBiggerType<T>::Type>::value) + == bool(detail::IsSigned<T>::value)); + } +}; + +template<typename T> +struct testTwiceBiggerType<T, 8> +{ + static void run() + { + VERIFY_IS_FALSE(detail::IsSupported< + typename detail::TwiceBiggerType<T>::Type + >::value); + } +}; + + +template<typename T> +void test() +{ + static bool alreadyRun = false; + // Integer types from different families may just be typedefs for types from other families. + // e.g. int32_t might be just a typedef for int. No point re-running the same tests then. + if (alreadyRun) + return; + alreadyRun = true; + + VERIFY(detail::IsSupported<T>::value); + const bool isTSigned = detail::IsSigned<T>::value; + VERIFY(bool(isTSigned) == !bool(T(-1) > T(0))); + + testTwiceBiggerType<T>::run(); + + typedef typename detail::UnsignedType<T>::Type unsignedT; + + VERIFY(sizeof(unsignedT) == sizeof(T)); + VERIFY(detail::IsSigned<unsignedT>::value == false); + + const CheckedInt<T> max(detail::MaxValue<T>::value); + const CheckedInt<T> min(detail::MinValue<T>::value); + + // Check MinValue and MaxValue, since they are custom implementations and a mistake there + // could potentially NOT be caught by any other tests... while making everything wrong! + + unsignedT bit = 1; + unsignedT unsignedMinValue(min.value()); + unsignedT unsignedMaxValue(max.value()); + for (size_t i = 0; i < sizeof(T) * CHAR_BIT - 1; i++) + { + VERIFY((unsignedMinValue & bit) == 0); + bit <<= 1; + } + VERIFY((unsignedMinValue & bit) == (isTSigned ? bit : unsignedT(0))); + VERIFY(unsignedMaxValue == unsignedT(~unsignedMinValue)); + + const CheckedInt<T> zero(0); + const CheckedInt<T> one(1); + const CheckedInt<T> two(2); + const CheckedInt<T> three(3); + const CheckedInt<T> four(4); + + /* Addition / subtraction checks */ + + VERIFY_IS_VALID(zero + zero); + VERIFY(zero + zero == zero); + VERIFY_IS_FALSE(zero + zero == one); // Check that == doesn't always return true + VERIFY_IS_VALID(zero + one); + VERIFY(zero + one == one); + VERIFY_IS_VALID(one + one); + VERIFY(one + one == two); + + const CheckedInt<T> maxMinusOne = max - one; + const CheckedInt<T> maxMinusTwo = max - two; + VERIFY_IS_VALID(maxMinusOne); + VERIFY_IS_VALID(maxMinusTwo); + VERIFY_IS_VALID(maxMinusOne + one); + VERIFY_IS_VALID(maxMinusTwo + one); + VERIFY_IS_VALID(maxMinusTwo + two); + VERIFY(maxMinusOne + one == max); + VERIFY(maxMinusTwo + one == maxMinusOne); + VERIFY(maxMinusTwo + two == max); + + VERIFY_IS_VALID(max + zero); + VERIFY_IS_VALID(max - zero); + VERIFY_IS_INVALID(max + one); + VERIFY_IS_INVALID(max + two); + VERIFY_IS_INVALID(max + maxMinusOne); + VERIFY_IS_INVALID(max + max); + + const CheckedInt<T> minPlusOne = min + one; + const CheckedInt<T> minPlusTwo = min + two; + VERIFY_IS_VALID(minPlusOne); + VERIFY_IS_VALID(minPlusTwo); + VERIFY_IS_VALID(minPlusOne - one); + VERIFY_IS_VALID(minPlusTwo - one); + VERIFY_IS_VALID(minPlusTwo - two); + VERIFY(minPlusOne - one == min); + VERIFY(minPlusTwo - one == minPlusOne); + VERIFY(minPlusTwo - two == min); + + const CheckedInt<T> minMinusOne = min - one; + VERIFY_IS_VALID(min + zero); + VERIFY_IS_VALID(min - zero); + VERIFY_IS_INVALID(min - one); + VERIFY_IS_INVALID(min - two); + VERIFY_IS_INVALID(min - minMinusOne); + VERIFY_IS_VALID(min - min); + + const CheckedInt<T> maxOverTwo = max / two; + VERIFY_IS_VALID(maxOverTwo + maxOverTwo); + VERIFY_IS_VALID(maxOverTwo + one); + VERIFY((maxOverTwo + one) - one == maxOverTwo); + VERIFY_IS_VALID(maxOverTwo - maxOverTwo); + VERIFY(maxOverTwo - maxOverTwo == zero); + + const CheckedInt<T> minOverTwo = min / two; + VERIFY_IS_VALID(minOverTwo + minOverTwo); + VERIFY_IS_VALID(minOverTwo + one); + VERIFY((minOverTwo + one) - one == minOverTwo); + VERIFY_IS_VALID(minOverTwo - minOverTwo); + VERIFY(minOverTwo - minOverTwo == zero); + + VERIFY_IS_INVALID(min - one); + VERIFY_IS_INVALID(min - two); + + if (isTSigned) { + VERIFY_IS_INVALID(min + min); + VERIFY_IS_INVALID(minOverTwo + minOverTwo + minOverTwo); + VERIFY_IS_INVALID(zero - min + min); + VERIFY_IS_INVALID(one - min + min); + } + + /* Modulo checks */ + VERIFY_IS_INVALID(zero % zero); + VERIFY_IS_INVALID(one % zero); + VERIFY_IS_VALID(zero % one); + VERIFY_IS_VALID(zero % max); + VERIFY_IS_VALID(one % max); + VERIFY_IS_VALID(max % one); + VERIFY_IS_VALID(max % max); + if (isTSigned) { + const CheckedInt<T> minusOne = zero - one; + VERIFY_IS_INVALID(minusOne % minusOne); + VERIFY_IS_INVALID(zero % minusOne); + VERIFY_IS_INVALID(one % minusOne); + VERIFY_IS_INVALID(minusOne % one); + + VERIFY_IS_INVALID(min % min); + VERIFY_IS_INVALID(zero % min); + VERIFY_IS_INVALID(min % one); + } + + /* Unary operator- checks */ + + const CheckedInt<T> negOne = -one; + const CheckedInt<T> negTwo = -two; + + if (isTSigned) { + VERIFY_IS_VALID(-max); + VERIFY_IS_INVALID(-min); + VERIFY(-max - min == one); + VERIFY_IS_VALID(-max - one); + VERIFY_IS_VALID(negOne); + VERIFY_IS_VALID(-max + negOne); + VERIFY_IS_VALID(negOne + one); + VERIFY(negOne + one == zero); + VERIFY_IS_VALID(negTwo); + VERIFY_IS_VALID(negOne + negOne); + VERIFY(negOne + negOne == negTwo); + } else { + VERIFY_IS_INVALID(-max); + VERIFY_IS_VALID(-min); + VERIFY(min == zero); + VERIFY_IS_INVALID(negOne); + } + + /* multiplication checks */ + + VERIFY_IS_VALID(zero * zero); + VERIFY(zero * zero == zero); + VERIFY_IS_VALID(zero * one); + VERIFY(zero * one == zero); + VERIFY_IS_VALID(one * zero); + VERIFY(one * zero == zero); + VERIFY_IS_VALID(one * one); + VERIFY(one * one == one); + VERIFY_IS_VALID(one * three); + VERIFY(one * three == three); + VERIFY_IS_VALID(two * two); + VERIFY(two * two == four); + + VERIFY_IS_INVALID(max * max); + VERIFY_IS_INVALID(maxOverTwo * max); + VERIFY_IS_INVALID(maxOverTwo * maxOverTwo); + + const CheckedInt<T> maxApproxSqrt(T(T(1) << (CHAR_BIT*sizeof(T)/2))); + + VERIFY_IS_VALID(maxApproxSqrt); + VERIFY_IS_VALID(maxApproxSqrt * two); + VERIFY_IS_INVALID(maxApproxSqrt * maxApproxSqrt); + VERIFY_IS_INVALID(maxApproxSqrt * maxApproxSqrt * maxApproxSqrt); + + if (isTSigned) { + VERIFY_IS_INVALID(min * min); + VERIFY_IS_INVALID(minOverTwo * min); + VERIFY_IS_INVALID(minOverTwo * minOverTwo); + + const CheckedInt<T> minApproxSqrt = -maxApproxSqrt; + + VERIFY_IS_VALID(minApproxSqrt); + VERIFY_IS_VALID(minApproxSqrt * two); + VERIFY_IS_INVALID(minApproxSqrt * maxApproxSqrt); + VERIFY_IS_INVALID(minApproxSqrt * minApproxSqrt); + } + + // make sure to check all 4 paths in signed multiplication validity check. + // test positive * positive + VERIFY_IS_VALID(max * one); + VERIFY(max * one == max); + VERIFY_IS_INVALID(max * two); + VERIFY_IS_VALID(maxOverTwo * two); + VERIFY((maxOverTwo + maxOverTwo) == (maxOverTwo * two)); + + if (isTSigned) { + // test positive * negative + VERIFY_IS_VALID(max * negOne); + VERIFY_IS_VALID(-max); + VERIFY(max * negOne == -max); + VERIFY_IS_VALID(one * min); + VERIFY_IS_INVALID(max * negTwo); + VERIFY_IS_VALID(maxOverTwo * negTwo); + VERIFY_IS_VALID(two * minOverTwo); + VERIFY_IS_VALID((maxOverTwo + one) * negTwo); + VERIFY_IS_INVALID((maxOverTwo + two) * negTwo); + VERIFY_IS_INVALID(two * (minOverTwo - one)); + + // test negative * positive + VERIFY_IS_VALID(min * one); + VERIFY_IS_VALID(minPlusOne * one); + VERIFY_IS_INVALID(min * two); + VERIFY_IS_VALID(minOverTwo * two); + VERIFY(minOverTwo * two == min); + VERIFY_IS_INVALID((minOverTwo - one) * negTwo); + VERIFY_IS_INVALID(negTwo * max); + VERIFY_IS_VALID(minOverTwo * two); + VERIFY(minOverTwo * two == min); + VERIFY_IS_VALID(negTwo * maxOverTwo); + VERIFY_IS_INVALID((minOverTwo - one) * two); + VERIFY_IS_VALID(negTwo * (maxOverTwo + one)); + VERIFY_IS_INVALID(negTwo * (maxOverTwo + two)); + + // test negative * negative + VERIFY_IS_INVALID(min * negOne); + VERIFY_IS_VALID(minPlusOne * negOne); + VERIFY(minPlusOne * negOne == max); + VERIFY_IS_INVALID(min * negTwo); + VERIFY_IS_INVALID(minOverTwo * negTwo); + VERIFY_IS_INVALID(negOne * min); + VERIFY_IS_VALID(negOne * minPlusOne); + VERIFY(negOne * minPlusOne == max); + VERIFY_IS_INVALID(negTwo * min); + VERIFY_IS_INVALID(negTwo * minOverTwo); + } + + /* Division checks */ + + VERIFY_IS_VALID(one / one); + VERIFY(one / one == one); + VERIFY_IS_VALID(three / three); + VERIFY(three / three == one); + VERIFY_IS_VALID(four / two); + VERIFY(four / two == two); + VERIFY((four*three)/four == three); + + // Check that div by zero is invalid + VERIFY_IS_INVALID(zero / zero); + VERIFY_IS_INVALID(one / zero); + VERIFY_IS_INVALID(two / zero); + VERIFY_IS_INVALID(negOne / zero); + VERIFY_IS_INVALID(max / zero); + VERIFY_IS_INVALID(min / zero); + + if (isTSigned) { + // Check that min / -1 is invalid + VERIFY_IS_INVALID(min / negOne); + + // Check that the test for div by -1 isn't banning other numerators than min + VERIFY_IS_VALID(one / negOne); + VERIFY_IS_VALID(zero / negOne); + VERIFY_IS_VALID(negOne / negOne); + VERIFY_IS_VALID(max / negOne); + } + + /* Check that invalidity is correctly preserved by arithmetic ops */ + + const CheckedInt<T> someInvalid = max + max; + VERIFY_IS_INVALID(someInvalid + zero); + VERIFY_IS_INVALID(someInvalid - zero); + VERIFY_IS_INVALID(zero + someInvalid); + VERIFY_IS_INVALID(zero - someInvalid); + VERIFY_IS_INVALID(-someInvalid); + VERIFY_IS_INVALID(someInvalid * zero); + VERIFY_IS_INVALID(someInvalid * one); + VERIFY_IS_INVALID(zero * someInvalid); + VERIFY_IS_INVALID(one * someInvalid); + VERIFY_IS_INVALID(someInvalid / zero); + VERIFY_IS_INVALID(someInvalid / one); + VERIFY_IS_INVALID(zero / someInvalid); + VERIFY_IS_INVALID(one / someInvalid); + VERIFY_IS_INVALID(someInvalid % zero); + VERIFY_IS_INVALID(someInvalid % one); + VERIFY_IS_INVALID(zero % someInvalid); + VERIFY_IS_INVALID(one % someInvalid); + VERIFY_IS_INVALID(someInvalid + someInvalid); + VERIFY_IS_INVALID(someInvalid - someInvalid); + VERIFY_IS_INVALID(someInvalid * someInvalid); + VERIFY_IS_INVALID(someInvalid / someInvalid); + VERIFY_IS_INVALID(someInvalid % someInvalid); + + /* Check that mixing checked integers with plain integers in expressions is allowed */ + + VERIFY(one + T(2) == three); + VERIFY(2 + one == three); + { + CheckedInt<T> x = one; + x += 2; + VERIFY(x == three); + } + VERIFY(two - 1 == one); + VERIFY(2 - one == one); + { + CheckedInt<T> x = two; + x -= 1; + VERIFY(x == one); + } + VERIFY(one * 2 == two); + VERIFY(2 * one == two); + { + CheckedInt<T> x = one; + x *= 2; + VERIFY(x == two); + } + VERIFY(four / 2 == two); + VERIFY(4 / two == two); + { + CheckedInt<T> x = four; + x /= 2; + VERIFY(x == two); + } + VERIFY(three % 2 == one); + VERIFY(3 % two == one); + { + CheckedInt<T> x = three; + x %= 2; + VERIFY(x == one); + } + + VERIFY(one == 1); + VERIFY(1 == one); + VERIFY_IS_FALSE(two == 1); + VERIFY_IS_FALSE(1 == two); + VERIFY_IS_FALSE(someInvalid == 1); + VERIFY_IS_FALSE(1 == someInvalid); + + // Check simple casting between different signedness and sizes. + { + CheckedInt<uint8_t> foo = CheckedInt<uint16_t>(2).toChecked<uint8_t>(); + VERIFY_IS_VALID(foo); + VERIFY(foo == 2); + } + { + CheckedInt<uint8_t> foo = CheckedInt<uint16_t>(255).toChecked<uint8_t>(); + VERIFY_IS_VALID(foo); + VERIFY(foo == 255); + } + { + CheckedInt<uint8_t> foo = CheckedInt<uint16_t>(256).toChecked<uint8_t>(); + VERIFY_IS_INVALID(foo); + } + { + CheckedInt<uint8_t> foo = CheckedInt<int8_t>(-2).toChecked<uint8_t>(); + VERIFY_IS_INVALID(foo); + } + + // Check that construction of CheckedInt from an integer value of a mismatched type is checked + // Also check casting between all types. + + #define VERIFY_CONSTRUCTION_FROM_INTEGER_TYPE2(U,V,PostVExpr) \ + { \ + bool isUSigned = detail::IsSigned<U>::value; \ + VERIFY_IS_VALID(CheckedInt<T>(V( 0)PostVExpr)); \ + VERIFY_IS_VALID(CheckedInt<T>(V( 1)PostVExpr)); \ + VERIFY_IS_VALID(CheckedInt<T>(V(100)PostVExpr)); \ + if (isUSigned) \ + VERIFY_IS_VALID_IF(CheckedInt<T>(V(-1)PostVExpr), isTSigned); \ + if (sizeof(U) > sizeof(T)) \ + VERIFY_IS_INVALID(CheckedInt<T>(V(detail::MaxValue<T>::value)PostVExpr + one.value())); \ + VERIFY_IS_VALID_IF(CheckedInt<T>(detail::MaxValue<U>::value), \ + (sizeof(T) > sizeof(U) || ((sizeof(T) == sizeof(U)) && (isUSigned || !isTSigned)))); \ + VERIFY_IS_VALID_IF(CheckedInt<T>(detail::MinValue<U>::value), \ + isUSigned == false ? 1 \ + : bool(isTSigned) == false ? 0 \ + : sizeof(T) >= sizeof(U)); \ + } + #define VERIFY_CONSTRUCTION_FROM_INTEGER_TYPE(U) \ + VERIFY_CONSTRUCTION_FROM_INTEGER_TYPE2(U,U,+0) \ + VERIFY_CONSTRUCTION_FROM_INTEGER_TYPE2(U,CheckedInt<U>,.toChecked<T>()) + + VERIFY_CONSTRUCTION_FROM_INTEGER_TYPE(int8_t) + VERIFY_CONSTRUCTION_FROM_INTEGER_TYPE(uint8_t) + VERIFY_CONSTRUCTION_FROM_INTEGER_TYPE(int16_t) + VERIFY_CONSTRUCTION_FROM_INTEGER_TYPE(uint16_t) + VERIFY_CONSTRUCTION_FROM_INTEGER_TYPE(int32_t) + VERIFY_CONSTRUCTION_FROM_INTEGER_TYPE(uint32_t) + VERIFY_CONSTRUCTION_FROM_INTEGER_TYPE(int64_t) + VERIFY_CONSTRUCTION_FROM_INTEGER_TYPE(uint64_t) + + typedef signed char signedChar; + typedef unsigned char unsignedChar; + typedef unsigned short unsignedShort; + typedef unsigned int unsignedInt; + typedef unsigned long unsignedLong; + typedef long long longLong; + typedef unsigned long long unsignedLongLong; + + VERIFY_CONSTRUCTION_FROM_INTEGER_TYPE(char) + VERIFY_CONSTRUCTION_FROM_INTEGER_TYPE(signedChar) + VERIFY_CONSTRUCTION_FROM_INTEGER_TYPE(unsignedChar) + VERIFY_CONSTRUCTION_FROM_INTEGER_TYPE(short) + VERIFY_CONSTRUCTION_FROM_INTEGER_TYPE(unsignedShort) + VERIFY_CONSTRUCTION_FROM_INTEGER_TYPE(int) + VERIFY_CONSTRUCTION_FROM_INTEGER_TYPE(unsignedInt) + VERIFY_CONSTRUCTION_FROM_INTEGER_TYPE(long) + VERIFY_CONSTRUCTION_FROM_INTEGER_TYPE(unsignedLong) + VERIFY_CONSTRUCTION_FROM_INTEGER_TYPE(longLong) + VERIFY_CONSTRUCTION_FROM_INTEGER_TYPE(unsignedLongLong) + + /* Test increment/decrement operators */ + + CheckedInt<T> x, y; + x = one; + y = x++; + VERIFY(x == two); + VERIFY(y == one); + x = one; + y = ++x; + VERIFY(x == two); + VERIFY(y == two); + x = one; + y = x--; + VERIFY(x == zero); + VERIFY(y == one); + x = one; + y = --x; + VERIFY(x == zero); + VERIFY(y == zero); + x = max; + VERIFY_IS_VALID(x++); + x = max; + VERIFY_IS_INVALID(++x); + x = min; + VERIFY_IS_VALID(x--); + x = min; + VERIFY_IS_INVALID(--x); + + gIntegerTypesTested++; +} + +int main() +{ + test<int8_t>(); + test<uint8_t>(); + test<int16_t>(); + test<uint16_t>(); + test<int32_t>(); + test<uint32_t>(); + test<int64_t>(); + test<uint64_t>(); + + test<char>(); + test<signed char>(); + test<unsigned char>(); + test<short>(); + test<unsigned short>(); + test<int>(); + test<unsigned int>(); + test<long>(); + test<unsigned long>(); + test<long long>(); + test<unsigned long long>(); + + const int MIN_TYPES_TESTED = 9; + if (gIntegerTypesTested < MIN_TYPES_TESTED) { + std::cerr << "Only " << gIntegerTypesTested << " have been tested. " + << "This should not be less than " << MIN_TYPES_TESTED << "." + << std::endl; + gTestsFailed++; + } + + std::cerr << gTestsFailed << " tests failed, " + << gTestsPassed << " tests passed out of " + << gTestsFailed + gTestsPassed + << " tests, covering " << gIntegerTypesTested + << " distinct integer types." << std::endl; + + return gTestsFailed > 0; +} diff --git a/mfbt/tests/TestEndian.cpp b/mfbt/tests/TestEndian.cpp new file mode 100644 index 0000000..1ec520d --- /dev/null +++ b/mfbt/tests/TestEndian.cpp @@ -0,0 +1,398 @@ +/* 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/Assertions.h" +#include "mozilla/DebugOnly.h" +#include "mozilla/Endian.h" + +using mozilla::BigEndian; +using mozilla::DebugOnly; +using mozilla::LittleEndian; +using mozilla::NativeEndian; + +template<typename T> +void +TestSingleSwap(T value, T swappedValue) +{ +#if MOZ_LITTLE_ENDIAN + MOZ_ASSERT(NativeEndian::swapToBigEndian(value) == swappedValue); + MOZ_ASSERT(NativeEndian::swapFromBigEndian(value) == swappedValue); + MOZ_ASSERT(NativeEndian::swapToNetworkOrder(value) == swappedValue); + MOZ_ASSERT(NativeEndian::swapFromNetworkOrder(value) == swappedValue); +#else + MOZ_ASSERT(NativeEndian::swapToLittleEndian(value) == swappedValue); + MOZ_ASSERT(NativeEndian::swapFromLittleEndian(value) == swappedValue); +#endif +} + +template<typename T> +void +TestSingleNoSwap(T value, T notSwappedValue) +{ +#if MOZ_LITTLE_ENDIAN + MOZ_ASSERT(NativeEndian::swapToLittleEndian(value) == notSwappedValue); + MOZ_ASSERT(NativeEndian::swapFromLittleEndian(value) == notSwappedValue); +#else + MOZ_ASSERT(NativeEndian::swapToBigEndian(value) == notSwappedValue); + MOZ_ASSERT(NativeEndian::swapFromBigEndian(value) == notSwappedValue); + MOZ_ASSERT(NativeEndian::swapToNetworkOrder(value) == notSwappedValue); + MOZ_ASSERT(NativeEndian::swapFromNetworkOrder(value) == notSwappedValue); +#endif +} + +// Endian.h functions are declared as protected in an base class and +// then re-exported as public in public derived classes. The +// standardese around explicit instantiation of templates is not clear +// in such cases. Provide these wrappers to make things more explicit. +// For your own enlightenment, you may wish to peruse: +// http://gcc.gnu.org/bugzilla/show_bug.cgi?id=56152 and subsequently +// http://j.mp/XosS6S . +#define WRAP_COPYTO(NAME) \ + template<typename T> \ + void \ + NAME(void* dst, const T* src, unsigned int count) \ + { \ + NativeEndian::NAME<T>(dst, src, count); \ + } + +WRAP_COPYTO(copyAndSwapToLittleEndian) +WRAP_COPYTO(copyAndSwapToBigEndian) +WRAP_COPYTO(copyAndSwapToNetworkOrder) + +#define WRAP_COPYFROM(NAME) \ + template<typename T> \ + void \ + NAME(T* dst, const void* src, unsigned int count) \ + { \ + NativeEndian::NAME<T>(dst, src, count); \ + } + +WRAP_COPYFROM(copyAndSwapFromLittleEndian) +WRAP_COPYFROM(copyAndSwapFromBigEndian) +WRAP_COPYFROM(copyAndSwapFromNetworkOrder) + +#define WRAP_IN_PLACE(NAME) \ + template<typename T> \ + void \ + NAME(T* p, unsigned int count) \ + { \ + NativeEndian::NAME<T>(p, count); \ + } +WRAP_IN_PLACE(swapToLittleEndianInPlace) +WRAP_IN_PLACE(swapFromLittleEndianInPlace) +WRAP_IN_PLACE(swapToBigEndianInPlace) +WRAP_IN_PLACE(swapFromBigEndianInPlace) +WRAP_IN_PLACE(swapToNetworkOrderInPlace) +WRAP_IN_PLACE(swapFromNetworkOrderInPlace) + +enum SwapExpectation { + Swap, + NoSwap +}; + +template<typename T, size_t count> +void +TestBulkSwapToSub(enum SwapExpectation expectSwap, + const T (&values)[count], + void (*swapperFunc)(void*, const T*, unsigned int), + T (*readerFunc)(const void*)) +{ + const size_t arraySize = 2 * count; + const size_t bufferSize = arraySize * sizeof(T); + static uint8_t buffer[bufferSize]; + const uint8_t fillValue = 0xa5; + static uint8_t checkBuffer[bufferSize]; + + MOZ_ASSERT(bufferSize > 2 * sizeof(T)); + + memset(checkBuffer, fillValue, bufferSize); + + for (size_t startPosition = 0; startPosition < sizeof(T); ++startPosition) { + for (size_t nValues = 0; nValues < count; ++nValues) { + memset(buffer, fillValue, bufferSize); + swapperFunc(buffer + startPosition, values, nValues); + + MOZ_ASSERT(memcmp(buffer, checkBuffer, startPosition) == 0); + DebugOnly<size_t> valuesEndPosition = startPosition + sizeof(T) * nValues; + MOZ_ASSERT(memcmp(buffer + valuesEndPosition, + checkBuffer + valuesEndPosition, + bufferSize - valuesEndPosition) == 0); + if (expectSwap == NoSwap) { + MOZ_ASSERT(memcmp(buffer + startPosition, values, + nValues * sizeof(T)) == 0); + } + for (size_t i = 0; i < nValues; ++i) { + MOZ_ASSERT(readerFunc(buffer + startPosition + sizeof(T) * i) == + values[i]); + } + } + } +} + +template<typename T, size_t count> +void +TestBulkSwapFromSub(enum SwapExpectation expectSwap, + const T (&values)[count], + void (*swapperFunc)(T*, const void*, unsigned int), + T (*readerFunc)(const void*)) +{ + const size_t arraySize = 2 * count; + const size_t bufferSize = arraySize * sizeof(T); + static T buffer[arraySize]; + const uint8_t fillValue = 0xa5; + static T checkBuffer[arraySize]; + + memset(checkBuffer, fillValue, bufferSize); + + for (size_t startPosition = 0; startPosition < count; ++startPosition) { + for (size_t nValues = 0; nValues < (count - startPosition); ++nValues) { + memset(buffer, fillValue, bufferSize); + swapperFunc(buffer + startPosition, values, nValues); + + MOZ_ASSERT(memcmp(buffer, checkBuffer, startPosition * sizeof(T)) == 0); + DebugOnly<size_t> valuesEndPosition = startPosition + nValues; + MOZ_ASSERT(memcmp(buffer + valuesEndPosition, + checkBuffer + valuesEndPosition, + (arraySize - valuesEndPosition) * sizeof(T)) == 0); + if (expectSwap == NoSwap) { + MOZ_ASSERT(memcmp(buffer + startPosition, values, + nValues * sizeof(T)) == 0); + } + for (size_t i = 0; i < nValues; ++i) + MOZ_ASSERT(readerFunc(buffer + startPosition + i) == values[i]); + } + } +} + + +template<typename T, size_t count> +void +TestBulkInPlaceSub(enum SwapExpectation expectSwap, + const T (&values)[count], + void (*swapperFunc)(T* p, unsigned int), + T (*readerFunc)(const void*)) +{ + const size_t bufferCount = 4 * count; + const size_t bufferSize = bufferCount * sizeof(T); + static T buffer[bufferCount]; + const T fillValue = 0xa5; + static T checkBuffer[bufferCount]; + + MOZ_ASSERT(bufferSize > 2 * sizeof(T)); + + memset(checkBuffer, fillValue, bufferSize); + + for (size_t startPosition = 0; startPosition < count; ++startPosition) { + for (size_t nValues = 0; nValues < count; ++nValues) { + memset(buffer, fillValue, bufferSize); + memcpy(buffer + startPosition, values, nValues * sizeof(T)); + swapperFunc(buffer + startPosition, nValues); + + MOZ_ASSERT(memcmp(buffer, checkBuffer, startPosition * sizeof(T)) == 0); + DebugOnly<size_t> valuesEndPosition = startPosition + nValues; + MOZ_ASSERT(memcmp(buffer + valuesEndPosition, + checkBuffer + valuesEndPosition, + bufferSize - valuesEndPosition * sizeof(T)) == 0); + if (expectSwap == NoSwap) { + MOZ_ASSERT(memcmp(buffer + startPosition, values, + nValues * sizeof(T)) == 0); + } + for (size_t i = 0; i < nValues; ++i) + MOZ_ASSERT(readerFunc(buffer + startPosition + i) == values[i]); + } + } +} + +template<typename T> +struct Reader +{ +}; + +#define SPECIALIZE_READER(TYPE, READ_FUNC) \ + template<> \ + struct Reader<TYPE> \ + { \ + static TYPE readLE(const void* p) { return LittleEndian::READ_FUNC(p); } \ + static TYPE readBE(const void* p) { return BigEndian::READ_FUNC(p); } \ + }; + +SPECIALIZE_READER(uint16_t, readUint16) +SPECIALIZE_READER(uint32_t, readUint32) +SPECIALIZE_READER(uint64_t, readUint64) +SPECIALIZE_READER(int16_t, readInt16) +SPECIALIZE_READER(int32_t, readInt32) +SPECIALIZE_READER(int64_t, readInt64) + +template<typename T, size_t count> +void +TestBulkSwap(const T (&bytes)[count]) +{ +#if MOZ_LITTLE_ENDIAN + TestBulkSwapToSub(Swap, bytes, copyAndSwapToBigEndian<T>, Reader<T>::readBE); + TestBulkSwapFromSub(Swap, bytes, copyAndSwapFromBigEndian<T>, Reader<T>::readBE); + TestBulkSwapToSub(Swap, bytes, copyAndSwapToNetworkOrder<T>, Reader<T>::readBE); + TestBulkSwapFromSub(Swap, bytes, copyAndSwapFromNetworkOrder<T>, Reader<T>::readBE); +#else + TestBulkSwapToSub(Swap, bytes, copyAndSwapToLittleEndian<T>, Reader<T>::readLE); + TestBulkSwapFromSub(Swap, bytes, copyAndSwapFromLittleEndian<T>, Reader<T>::readLE); +#endif +} + +template<typename T, size_t count> +void +TestBulkNoSwap(const T (&bytes)[count]) +{ +#if MOZ_LITTLE_ENDIAN + TestBulkSwapToSub(NoSwap, bytes, copyAndSwapToLittleEndian<T>, Reader<T>::readLE); + TestBulkSwapFromSub(NoSwap, bytes, copyAndSwapFromLittleEndian<T>, Reader<T>::readLE); +#else + TestBulkSwapToSub(NoSwap, bytes, copyAndSwapToBigEndian<T>, Reader<T>::readBE); + TestBulkSwapFromSub(NoSwap, bytes, copyAndSwapFromBigEndian<T>, Reader<T>::readBE); + TestBulkSwapToSub(NoSwap, bytes, copyAndSwapToNetworkOrder<T>, Reader<T>::readBE); + TestBulkSwapFromSub(NoSwap, bytes, copyAndSwapFromNetworkOrder<T>, Reader<T>::readBE); +#endif +} + +template<typename T, size_t count> +void +TestBulkInPlaceSwap(const T (&bytes)[count]) +{ +#if MOZ_LITTLE_ENDIAN + TestBulkInPlaceSub(Swap, bytes, swapToBigEndianInPlace<T>, Reader<T>::readBE); + TestBulkInPlaceSub(Swap, bytes, swapFromBigEndianInPlace<T>, Reader<T>::readBE); + TestBulkInPlaceSub(Swap, bytes, swapToNetworkOrderInPlace<T>, Reader<T>::readBE); + TestBulkInPlaceSub(Swap, bytes, swapFromNetworkOrderInPlace<T>, Reader<T>::readBE); +#else + TestBulkInPlaceSub(Swap, bytes, swapToLittleEndianInPlace<T>, Reader<T>::readLE); + TestBulkInPlaceSub(Swap, bytes, swapFromLittleEndianInPlace<T>, Reader<T>::readLE); +#endif +} + +template<typename T, size_t count> +void +TestBulkInPlaceNoSwap(const T (&bytes)[count]) +{ +#if MOZ_LITTLE_ENDIAN + TestBulkInPlaceSub(NoSwap, bytes, swapToLittleEndianInPlace<T>, Reader<T>::readLE); + TestBulkInPlaceSub(NoSwap, bytes, swapFromLittleEndianInPlace<T>, Reader<T>::readLE); +#else + TestBulkInPlaceSub(NoSwap, bytes, swapToBigEndianInPlace<T>, Reader<T>::readBE); + TestBulkInPlaceSub(NoSwap, bytes, swapFromBigEndianInPlace<T>, Reader<T>::readBE); + TestBulkInPlaceSub(NoSwap, bytes, swapToNetworkOrderInPlace<T>, Reader<T>::readBE); + TestBulkInPlaceSub(NoSwap, bytes, swapFromNetworkOrderInPlace<T>, Reader<T>::readBE); +#endif +} + +int +main() +{ + static const uint8_t unsigned_bytes[16] = { 0x1, 0x2, 0x3, 0x4, 0x5, 0x6, 0x7, 0x8, + 0x1, 0x2, 0x3, 0x4, 0x5, 0x6, 0x7, 0x8 }; + static const int8_t signed_bytes[16] = { -0x0f, -0x0e, -0x0d, -0x0c, -0x0b, -0x0a, -0x09, -0x08, + -0x0f, -0x0e, -0x0d, -0x0c, -0x0b, -0x0a, -0x09, -0x08 }; + static const uint16_t uint16_values[8] = { 0x102, 0x304, 0x506, 0x708, 0x102, 0x304, 0x506, 0x708 }; + static const int16_t int16_values[8] = { int16_t(0xf1f2), int16_t(0xf3f4), int16_t(0xf5f6), int16_t(0xf7f8), + int16_t(0xf1f2), int16_t(0xf3f4), int16_t(0xf5f6), int16_t(0xf7f8) }; + static const uint32_t uint32_values[4] = { 0x1020304, 0x5060708, 0x1020304, 0x5060708 }; + static const int32_t int32_values[4] = { int32_t(0xf1f2f3f4), int32_t(0xf5f6f7f8), + int32_t(0xf1f2f3f4), int32_t(0xf5f6f7f8) }; + static const uint64_t uint64_values[2] = { 0x102030405060708, 0x102030405060708 }; + static const int64_t int64_values[2] = { int64_t(0xf1f2f3f4f5f6f7f8), + int64_t(0xf1f2f3f4f5f6f7f8) }; + uint8_t buffer[8]; + + MOZ_ASSERT(LittleEndian::readUint16(&unsigned_bytes[0]) == 0x201); + MOZ_ASSERT(BigEndian::readUint16(&unsigned_bytes[0]) == 0x102); + + MOZ_ASSERT(LittleEndian::readUint32(&unsigned_bytes[0]) == 0x4030201U); + MOZ_ASSERT(BigEndian::readUint32(&unsigned_bytes[0]) == 0x1020304U); + + MOZ_ASSERT(LittleEndian::readUint64(&unsigned_bytes[0]) == 0x807060504030201ULL); + MOZ_ASSERT(BigEndian::readUint64(&unsigned_bytes[0]) == 0x102030405060708ULL); + + LittleEndian::writeUint16(&buffer[0], 0x201); + MOZ_ASSERT(memcmp(&unsigned_bytes[0], &buffer[0], sizeof(uint16_t)) == 0); + BigEndian::writeUint16(&buffer[0], 0x102); + MOZ_ASSERT(memcmp(&unsigned_bytes[0], &buffer[0], sizeof(uint16_t)) == 0); + + LittleEndian::writeUint32(&buffer[0], 0x4030201U); + MOZ_ASSERT(memcmp(&unsigned_bytes[0], &buffer[0], sizeof(uint32_t)) == 0); + BigEndian::writeUint32(&buffer[0], 0x1020304U); + MOZ_ASSERT(memcmp(&unsigned_bytes[0], &buffer[0], sizeof(uint32_t)) == 0); + + LittleEndian::writeUint64(&buffer[0], 0x807060504030201ULL); + MOZ_ASSERT(memcmp(&unsigned_bytes[0], &buffer[0], sizeof(uint64_t)) == 0); + BigEndian::writeUint64(&buffer[0], 0x102030405060708ULL); + MOZ_ASSERT(memcmp(&unsigned_bytes[0], &buffer[0], sizeof(uint64_t)) == 0); + + MOZ_ASSERT(LittleEndian::readInt16(&signed_bytes[0]) == int16_t(0xf2f1)); + MOZ_ASSERT(BigEndian::readInt16(&signed_bytes[0]) == int16_t(0xf1f2)); + + MOZ_ASSERT(LittleEndian::readInt32(&signed_bytes[0]) == int32_t(0xf4f3f2f1)); + MOZ_ASSERT(BigEndian::readInt32(&signed_bytes[0]) == int32_t(0xf1f2f3f4)); + + MOZ_ASSERT(LittleEndian::readInt64(&signed_bytes[0]) == int64_t(0xf8f7f6f5f4f3f2f1LL)); + MOZ_ASSERT(BigEndian::readInt64(&signed_bytes[0]) == int64_t(0xf1f2f3f4f5f6f7f8LL)); + + LittleEndian::writeInt16(&buffer[0], 0xf2f1); + MOZ_ASSERT(memcmp(&signed_bytes[0], &buffer[0], sizeof(int16_t)) == 0); + BigEndian::writeInt16(&buffer[0], 0xf1f2); + MOZ_ASSERT(memcmp(&signed_bytes[0], &buffer[0], sizeof(int16_t)) == 0); + + LittleEndian::writeInt32(&buffer[0], 0xf4f3f2f1); + MOZ_ASSERT(memcmp(&signed_bytes[0], &buffer[0], sizeof(int32_t)) == 0); + BigEndian::writeInt32(&buffer[0], 0xf1f2f3f4); + MOZ_ASSERT(memcmp(&signed_bytes[0], &buffer[0], sizeof(int32_t)) == 0); + + LittleEndian::writeInt64(&buffer[0], 0xf8f7f6f5f4f3f2f1LL); + MOZ_ASSERT(memcmp(&signed_bytes[0], &buffer[0], sizeof(int64_t)) == 0); + BigEndian::writeInt64(&buffer[0], 0xf1f2f3f4f5f6f7f8LL); + MOZ_ASSERT(memcmp(&signed_bytes[0], &buffer[0], sizeof(int64_t)) == 0); + + TestSingleSwap(uint16_t(0xf2f1), uint16_t(0xf1f2)); + TestSingleSwap(uint32_t(0xf4f3f2f1), uint32_t(0xf1f2f3f4)); + TestSingleSwap(uint64_t(0xf8f7f6f5f4f3f2f1), uint64_t(0xf1f2f3f4f5f6f7f8)); + + TestSingleSwap(int16_t(0xf2f1), int16_t(0xf1f2)); + TestSingleSwap(int32_t(0xf4f3f2f1), int32_t(0xf1f2f3f4)); + TestSingleSwap(int64_t(0xf8f7f6f5f4f3f2f1), int64_t(0xf1f2f3f4f5f6f7f8)); + + TestSingleNoSwap(uint16_t(0xf2f1), uint16_t(0xf2f1)); + TestSingleNoSwap(uint32_t(0xf4f3f2f1), uint32_t(0xf4f3f2f1)); + TestSingleNoSwap(uint64_t(0xf8f7f6f5f4f3f2f1), uint64_t(0xf8f7f6f5f4f3f2f1)); + + TestSingleNoSwap(int16_t(0xf2f1), int16_t(0xf2f1)); + TestSingleNoSwap(int32_t(0xf4f3f2f1), int32_t(0xf4f3f2f1)); + TestSingleNoSwap(int64_t(0xf8f7f6f5f4f3f2f1), int64_t(0xf8f7f6f5f4f3f2f1)); + + TestBulkSwap(uint16_values); + TestBulkSwap(int16_values); + TestBulkSwap(uint32_values); + TestBulkSwap(int32_values); + TestBulkSwap(uint64_values); + TestBulkSwap(int64_values); + + TestBulkNoSwap(uint16_values); + TestBulkNoSwap(int16_values); + TestBulkNoSwap(uint32_values); + TestBulkNoSwap(int32_values); + TestBulkNoSwap(uint64_values); + TestBulkNoSwap(int64_values); + + TestBulkInPlaceSwap(uint16_values); + TestBulkInPlaceSwap(int16_values); + TestBulkInPlaceSwap(uint32_values); + TestBulkInPlaceSwap(int32_values); + TestBulkInPlaceSwap(uint64_values); + TestBulkInPlaceSwap(int64_values); + + TestBulkInPlaceNoSwap(uint16_values); + TestBulkInPlaceNoSwap(int16_values); + TestBulkInPlaceNoSwap(uint32_values); + TestBulkInPlaceNoSwap(int32_values); + TestBulkInPlaceNoSwap(uint64_values); + TestBulkInPlaceNoSwap(int64_values); + + return 0; +} diff --git a/mfbt/tests/TestEnumSet.cpp b/mfbt/tests/TestEnumSet.cpp new file mode 100644 index 0000000..dc43fe3 --- /dev/null +++ b/mfbt/tests/TestEnumSet.cpp @@ -0,0 +1,232 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* 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/EnumSet.h" + +using namespace mozilla; + +enum SeaBird { + PENGUIN, + ALBATROSS, + FULMAR, + PRION, + SHEARWATER, + GADFLY_PETREL, + TRUE_PETREL, + DIVING_PETREL, + STORM_PETREL, + PELICAN, + GANNET, + BOOBY, + CORMORANT, + FRIGATEBIRD, + TROPICBIRD, + SKUA, + GULL, + TERN, + SKIMMER, + AUK +}; + +class EnumSetSuite { + public: + EnumSetSuite() + : mAlcidae(), + mDiomedeidae(ALBATROSS), + mPetrelProcellariidae(GADFLY_PETREL, TRUE_PETREL), + mNonPetrelProcellariidae(FULMAR, PRION, SHEARWATER), + mPetrels(GADFLY_PETREL, TRUE_PETREL, DIVING_PETREL, STORM_PETREL) + { } + + void runTests() { + testSize(); + testContains(); + testAddTo(); + testAdd(); + testAddAll(); + testUnion(); + testRemoveFrom(); + testRemove(); + testRemoveAllFrom(); + testRemoveAll(); + testIntersect(); + testInsersection(); + testEquality(); + testDuplicates(); + } + + private: + void testSize() { + MOZ_ASSERT(mAlcidae.size() == 0); + MOZ_ASSERT(mDiomedeidae.size() == 1); + MOZ_ASSERT(mPetrelProcellariidae.size() == 2); + MOZ_ASSERT(mNonPetrelProcellariidae.size() == 3); + MOZ_ASSERT(mPetrels.size() == 4); + } + + void testContains() { + MOZ_ASSERT(!mPetrels.contains(PENGUIN)); + MOZ_ASSERT(!mPetrels.contains(ALBATROSS)); + MOZ_ASSERT(!mPetrels.contains(FULMAR)); + MOZ_ASSERT(!mPetrels.contains(PRION)); + MOZ_ASSERT(!mPetrels.contains(SHEARWATER)); + MOZ_ASSERT(mPetrels.contains(GADFLY_PETREL)); + MOZ_ASSERT(mPetrels.contains(TRUE_PETREL)); + MOZ_ASSERT(mPetrels.contains(DIVING_PETREL)); + MOZ_ASSERT(mPetrels.contains(STORM_PETREL)); + MOZ_ASSERT(!mPetrels.contains(PELICAN)); + MOZ_ASSERT(!mPetrels.contains(GANNET)); + MOZ_ASSERT(!mPetrels.contains(BOOBY)); + MOZ_ASSERT(!mPetrels.contains(CORMORANT)); + MOZ_ASSERT(!mPetrels.contains(FRIGATEBIRD)); + MOZ_ASSERT(!mPetrels.contains(TROPICBIRD)); + MOZ_ASSERT(!mPetrels.contains(SKUA)); + MOZ_ASSERT(!mPetrels.contains(GULL)); + MOZ_ASSERT(!mPetrels.contains(TERN)); + MOZ_ASSERT(!mPetrels.contains(SKIMMER)); + MOZ_ASSERT(!mPetrels.contains(AUK)); + } + + void testCopy() { + EnumSet<SeaBird> likes = mPetrels; + likes -= TRUE_PETREL; + MOZ_ASSERT(mPetrels.size() == 4); + MOZ_ASSERT(mPetrels.contains(TRUE_PETREL)); + + MOZ_ASSERT(likes.size() == 3); + MOZ_ASSERT(likes.contains(GADFLY_PETREL)); + MOZ_ASSERT(likes.contains(DIVING_PETREL)); + MOZ_ASSERT(likes.contains(STORM_PETREL)); + } + + void testAddTo() { + EnumSet<SeaBird> seen = mPetrels; + seen += CORMORANT; + seen += TRUE_PETREL; + MOZ_ASSERT(mPetrels.size() == 4); + MOZ_ASSERT(!mPetrels.contains(CORMORANT)); + MOZ_ASSERT(seen.size() == 5); + MOZ_ASSERT(seen.contains(GADFLY_PETREL)); + MOZ_ASSERT(seen.contains(TRUE_PETREL)); + MOZ_ASSERT(seen.contains(DIVING_PETREL)); + MOZ_ASSERT(seen.contains(STORM_PETREL)); + MOZ_ASSERT(seen.contains(CORMORANT)); + } + + void testAdd() { + EnumSet<SeaBird> seen = mPetrels + CORMORANT + + STORM_PETREL; + MOZ_ASSERT(mPetrels.size() == 4); + MOZ_ASSERT(!mPetrels.contains(CORMORANT)); + MOZ_ASSERT(seen.size() == 5); + MOZ_ASSERT(seen.contains(GADFLY_PETREL)); + MOZ_ASSERT(seen.contains(TRUE_PETREL)); + MOZ_ASSERT(seen.contains(DIVING_PETREL)); + MOZ_ASSERT(seen.contains(STORM_PETREL)); + MOZ_ASSERT(seen.contains(CORMORANT)); + } + + void testAddAll() { + EnumSet<SeaBird> procellariidae; + procellariidae += mPetrelProcellariidae; + procellariidae += mNonPetrelProcellariidae; + MOZ_ASSERT(procellariidae.size() == 5); + + // Both procellariidae and mPetrels include GADFLY_PERTEL and TRUE_PETREL + EnumSet<SeaBird> procellariiformes; + procellariiformes += mDiomedeidae; + procellariiformes += procellariidae; + procellariiformes += mPetrels; + MOZ_ASSERT(procellariiformes.size() == 8); + } + + void testUnion() { + EnumSet<SeaBird> procellariidae = mPetrelProcellariidae + + mNonPetrelProcellariidae; + MOZ_ASSERT(procellariidae.size() == 5); + + // Both procellariidae and mPetrels include GADFLY_PETREL and TRUE_PETREL + EnumSet<SeaBird> procellariiformes = mDiomedeidae + procellariidae + + mPetrels; + MOZ_ASSERT(procellariiformes.size() == 8); + } + + void testRemoveFrom() { + EnumSet<SeaBird> likes = mPetrels; + likes -= TRUE_PETREL; + likes -= DIVING_PETREL; + MOZ_ASSERT(likes.size() == 2); + MOZ_ASSERT(likes.contains(GADFLY_PETREL)); + MOZ_ASSERT(likes.contains(STORM_PETREL)); + } + + void testRemove() { + EnumSet<SeaBird> likes = mPetrels - TRUE_PETREL - + DIVING_PETREL; + MOZ_ASSERT(likes.size() == 2); + MOZ_ASSERT(likes.contains(GADFLY_PETREL)); + MOZ_ASSERT(likes.contains(STORM_PETREL)); + } + + void testRemoveAllFrom() { + EnumSet<SeaBird> likes = mPetrels; + likes -= mPetrelProcellariidae; + MOZ_ASSERT(likes.size() == 2); + MOZ_ASSERT(likes.contains(DIVING_PETREL)); + MOZ_ASSERT(likes.contains(STORM_PETREL)); + } + + void testRemoveAll() { + EnumSet<SeaBird> likes = mPetrels - mPetrelProcellariidae; + MOZ_ASSERT(likes.size() == 2); + MOZ_ASSERT(likes.contains(DIVING_PETREL)); + MOZ_ASSERT(likes.contains(STORM_PETREL)); + } + + void testIntersect() { + EnumSet<SeaBird> likes = mPetrels; + likes &= mPetrelProcellariidae; + MOZ_ASSERT(likes.size() == 2); + MOZ_ASSERT(likes.contains(GADFLY_PETREL)); + MOZ_ASSERT(likes.contains(TRUE_PETREL)); + } + + void testInsersection() { + EnumSet<SeaBird> likes = mPetrels & mPetrelProcellariidae; + MOZ_ASSERT(likes.size() == 2); + MOZ_ASSERT(likes.contains(GADFLY_PETREL)); + MOZ_ASSERT(likes.contains(TRUE_PETREL)); + } + + void testEquality() { + EnumSet<SeaBird> likes = mPetrels & mPetrelProcellariidae; + MOZ_ASSERT(likes == EnumSet<SeaBird>(GADFLY_PETREL, + TRUE_PETREL)); + } + + void testDuplicates() { + EnumSet<SeaBird> likes = mPetrels; + likes += GADFLY_PETREL; + likes += TRUE_PETREL; + likes += DIVING_PETREL; + likes += STORM_PETREL; + MOZ_ASSERT(likes.size() == 4); + MOZ_ASSERT(likes == mPetrels); + } + + + EnumSet<SeaBird> mAlcidae; + EnumSet<SeaBird> mDiomedeidae; + EnumSet<SeaBird> mPetrelProcellariidae; + EnumSet<SeaBird> mNonPetrelProcellariidae; + EnumSet<SeaBird> mPetrels; +}; + +int main() +{ + EnumSetSuite suite; + suite.runTests(); + return 0; +} diff --git a/mfbt/tests/TestPoisonArea.cpp b/mfbt/tests/TestPoisonArea.cpp new file mode 100644 index 0000000..cf2417a --- /dev/null +++ b/mfbt/tests/TestPoisonArea.cpp @@ -0,0 +1,654 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* vim:set ts=2 sw=2 sts=2 et cindent: */ +/* 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/. + */ + +/* Code in this file needs to be kept in sync with code in nsPresArena.cpp. + * + * We want to use a fixed address for frame poisoning so that it is readily + * identifiable in crash dumps. Whether such an address is available + * without any special setup depends on the system configuration. + * + * All current 64-bit CPUs (with the possible exception of PowerPC64) + * reserve the vast majority of the virtual address space for future + * hardware extensions; valid addresses must be below some break point + * between 2**48 and 2**54, depending on exactly which chip you have. Some + * chips (notably amd64) also allow the use of the *highest* 2**48 -- 2**54 + * addresses. Thus, if user space pointers are 64 bits wide, we can just + * use an address outside this range, and no more is required. To + * accommodate the chips that allow very high addresses to be valid, the + * value chosen is close to 2**63 (that is, in the middle of the space). + * + * In most cases, a purely 32-bit operating system must reserve some + * fraction of the address space for its own use. Contemporary 32-bit OSes + * tend to take the high gigabyte or so (0xC000_0000 on up). If we can + * prove that high addresses are reserved to the kernel, we can use an + * address in that region. Unfortunately, not all 32-bit OSes do this; + * OSX 10.4 might not, and it is unclear what mobile OSes are like + * (some 32-bit CPUs make it very easy for the kernel to exist in its own + * private address space). + * + * Furthermore, when a 32-bit user space process is running on a 64-bit + * kernel, the operating system has no need to reserve any of the space that + * the process can see, and generally does not do so. This is the scenario + * of greatest concern, since it covers all contemporary OSX iterations + * (10.5+) as well as Windows Vista and 7 on newer amd64 hardware. Linux on + * amd64 is generally run as a pure 64-bit environment, but its 32-bit + * compatibility mode also has this property. + * + * Thus, when user space pointers are 32 bits wide, we need to validate + * our chosen address, and possibly *make* it a good poison address by + * allocating a page around it and marking it inaccessible. The algorithm + * for this is: + * + * 1. Attempt to make the page surrounding the poison address a reserved, + * inaccessible memory region using OS primitives. On Windows, this is + * done with VirtualAlloc(MEM_RESERVE); on Unix, mmap(PROT_NONE). + * + * 2. If mmap/VirtualAlloc failed, there are two possible reasons: either + * the region is reserved to the kernel and no further action is + * required, or there is already usable memory in this area and we have + * to pick a different address. The tricky part is knowing which case + * we have, without attempting to access the region. On Windows, we + * rely on GetSystemInfo()'s reported upper and lower bounds of the + * application memory area. On Unix, there is nothing devoted to the + * purpose, but seeing if madvise() fails is close enough (it *might* + * disrupt someone else's use of the memory region, but not by as much + * as anything else available). + * + * Be aware of these gotchas: + * + * 1. We cannot use mmap() with MAP_FIXED. MAP_FIXED is defined to + * _replace_ any existing mapping in the region, if necessary to satisfy + * the request. Obviously, as we are blindly attempting to acquire a + * page at a constant address, we must not do this, lest we overwrite + * someone else's allocation. + * + * 2. For the same reason, we cannot blindly use mprotect() if mmap() fails. + * + * 3. madvise() may fail when applied to a 'magic' memory region provided as + * a kernel/user interface. Fortunately, the only such case I know about + * is the "vsyscall" area (not to be confused with the "vdso" area) for + * *64*-bit processes on Linux - and we don't even run this code for + * 64-bit processes. + * + * 4. VirtualQuery() does not produce any useful information if + * applied to kernel memory - in fact, it doesn't write its output + * at all. Thus, it is not used here. + */ + +// MAP_ANON(YMOUS) is not in any standard, and the C99 PRI* macros are +// not in C++98. Add defines as necessary. +#define __STDC_FORMAT_MACROS +#define _GNU_SOURCE 1 +#define _DARWIN_C_SOURCE 1 + +#include <stddef.h> + +#ifndef _WIN32 +#include <inttypes.h> +#else +#define PRIxPTR "Ix" +typedef unsigned int uint32_t; +// MSVC defines uintptr_t in <crtdefs.h> which is brought in implicitly +#endif + +#include <errno.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> + +#ifdef _WIN32 +#include <windows.h> +#elif defined(__OS2__) +#include <sys/types.h> +#include <unistd.h> +#include <setjmp.h> +#define INCL_DOS +#include <os2.h> +#else +#include <sys/types.h> +#include <fcntl.h> +#include <signal.h> +#include <unistd.h> +#include <sys/stat.h> +#include <sys/wait.h> + +#include <sys/mman.h> +#ifndef MAP_ANON +#ifdef MAP_ANONYMOUS +#define MAP_ANON MAP_ANONYMOUS +#else +#error "Don't know how to get anonymous memory" +#endif +#endif +#endif + +#define SIZxPTR ((int)(sizeof(uintptr_t)*2)) + +/* This program assumes that a whole number of return instructions fit into + * 32 bits, and that 32-bit alignment is sufficient for a branch destination. + * For architectures where this is not true, fiddling with RETURN_INSTR_TYPE + * can be enough. + */ + +#if defined __i386__ || defined __x86_64__ || \ + defined __i386 || defined __x86_64 || \ + defined _M_IX86 || defined _M_AMD64 +#define RETURN_INSTR 0xC3C3C3C3 /* ret; ret; ret; ret */ + +#elif defined __arm__ || defined _M_ARM +#define RETURN_INSTR 0xE12FFF1E /* bx lr */ + +// PPC has its own style of CPU-id #defines. There is no Windows for +// PPC as far as I know, so no _M_ variant. +#elif defined _ARCH_PPC || defined _ARCH_PWR || defined _ARCH_PWR2 +#define RETURN_INSTR 0x4E800020 /* blr */ + +#elif defined __sparc || defined __sparcv9 +#define RETURN_INSTR 0x81c3e008 /* retl */ + +#elif defined __alpha +#define RETURN_INSTR 0x6bfa8001 /* ret */ + +#elif defined __hppa +#define RETURN_INSTR 0xe840c002 /* bv,n r0(rp) */ + +#elif defined __mips +#define RETURN_INSTR 0x03e00008 /* jr ra */ + +#ifdef __MIPSEL +/* On mipsel, jr ra needs to be followed by a nop. + 0x03e00008 as a 64 bits integer just does that */ +#define RETURN_INSTR_TYPE uint64_t +#endif + +#elif defined __s390__ +#define RETURN_INSTR 0x07fe0000 /* br %r14 */ + +#elif defined __ia64 +struct ia64_instr { uint32_t i[4]; }; +static const ia64_instr _return_instr = + {{ 0x00000011, 0x00000001, 0x80000200, 0x00840008 }}; /* br.ret.sptk.many b0 */ + +#define RETURN_INSTR _return_instr +#define RETURN_INSTR_TYPE ia64_instr + +#else +#error "Need return instruction for this architecture" +#endif + +#ifndef RETURN_INSTR_TYPE +#define RETURN_INSTR_TYPE uint32_t +#endif + +// Miscellaneous Windows/Unix portability gumph + +#ifdef _WIN32 +// Uses of this function deliberately leak the string. +static LPSTR +StrW32Error(DWORD errcode) +{ + LPSTR errmsg; + FormatMessageA(FORMAT_MESSAGE_ALLOCATE_BUFFER | + FORMAT_MESSAGE_FROM_SYSTEM | + FORMAT_MESSAGE_IGNORE_INSERTS, + NULL, errcode, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), + (LPSTR) &errmsg, 0, NULL); + + // FormatMessage puts an unwanted newline at the end of the string + size_t n = strlen(errmsg)-1; + while (errmsg[n] == '\r' || errmsg[n] == '\n') n--; + errmsg[n+1] = '\0'; + return errmsg; +} +#define LastErrMsg() (StrW32Error(GetLastError())) + +// Because we use VirtualAlloc in MEM_RESERVE mode, the "page size" we want +// is the allocation granularity. +static SYSTEM_INFO _sinfo; +#undef PAGESIZE +#define PAGESIZE (_sinfo.dwAllocationGranularity) + + +static void * +ReserveRegion(uintptr_t request, bool accessible) +{ + return VirtualAlloc((void *)request, PAGESIZE, + accessible ? MEM_RESERVE|MEM_COMMIT : MEM_RESERVE, + accessible ? PAGE_EXECUTE_READWRITE : PAGE_NOACCESS); +} + +static void +ReleaseRegion(void *page) +{ + VirtualFree(page, PAGESIZE, MEM_RELEASE); +} + +static bool +ProbeRegion(uintptr_t page) +{ + if (page >= (uintptr_t)_sinfo.lpMaximumApplicationAddress && + page + PAGESIZE >= (uintptr_t)_sinfo.lpMaximumApplicationAddress) { + return true; + } else { + return false; + } +} + +static bool +MakeRegionExecutable(void *) +{ + return false; +} + +#undef MAP_FAILED +#define MAP_FAILED 0 + +#elif defined(__OS2__) + +// page size is always 4k +#undef PAGESIZE +#define PAGESIZE 0x1000 +static unsigned long rc = 0; + +char * LastErrMsg() +{ + char * errmsg = (char *)malloc(16); + sprintf(errmsg, "rc= %ld", rc); + rc = 0; + return errmsg; +} + +static void * +ReserveRegion(uintptr_t request, bool accessible) +{ + // OS/2 doesn't support allocation at an arbitrary address, + // so return an address that is known to be invalid. + if (request) { + return (void*)0xFFFD0000; + } + void * mem = 0; + rc = DosAllocMem(&mem, PAGESIZE, + (accessible ? PAG_COMMIT : 0) | PAG_READ | PAG_WRITE); + return rc ? 0 : mem; +} + +static void +ReleaseRegion(void *page) +{ + return; +} + +static bool +ProbeRegion(uintptr_t page) +{ + // There's no reliable way to probe an address in the system + // arena other than by touching it and seeing if a trap occurs. + return false; +} + +static bool +MakeRegionExecutable(void *page) +{ + rc = DosSetMem(page, PAGESIZE, PAG_READ | PAG_WRITE | PAG_EXECUTE); + return rc ? true : false; +} + +typedef struct _XCPT { + EXCEPTIONREGISTRATIONRECORD regrec; + jmp_buf jmpbuf; +} XCPT; + +static unsigned long _System +ExceptionHandler(PEXCEPTIONREPORTRECORD pReport, + PEXCEPTIONREGISTRATIONRECORD pRegRec, + PCONTEXTRECORD pContext, PVOID pVoid) +{ + if (pReport->fHandlerFlags == 0) { + longjmp(((XCPT*)pRegRec)->jmpbuf, pReport->ExceptionNum); + } + return XCPT_CONTINUE_SEARCH; +} + +#undef MAP_FAILED +#define MAP_FAILED 0 + +#else // Unix + +#define LastErrMsg() (strerror(errno)) + +static unsigned long _pagesize; +#define PAGESIZE _pagesize + +static void * +ReserveRegion(uintptr_t request, bool accessible) +{ + return mmap(reinterpret_cast<void*>(request), PAGESIZE, + accessible ? PROT_READ|PROT_WRITE : PROT_NONE, + MAP_PRIVATE|MAP_ANON, -1, 0); +} + +static void +ReleaseRegion(void *page) +{ + munmap(page, PAGESIZE); +} + +static bool +ProbeRegion(uintptr_t page) +{ + if (madvise(reinterpret_cast<void*>(page), PAGESIZE, MADV_NORMAL)) { + return true; + } else { + return false; + } +} + +static int +MakeRegionExecutable(void *page) +{ + return mprotect((caddr_t)page, PAGESIZE, PROT_READ|PROT_WRITE|PROT_EXEC); +} + +#endif + +static uintptr_t +ReservePoisonArea() +{ + if (sizeof(uintptr_t) == 8) { + // Use the hardware-inaccessible region. + // We have to avoid 64-bit constants and shifts by 32 bits, since this + // code is compiled in 32-bit mode, although it is never executed there. + uintptr_t result = (((uintptr_t(0x7FFFFFFFu) << 31) << 1 | + uintptr_t(0xF0DEAFFFu)) & + ~uintptr_t(PAGESIZE-1)); + printf("INFO | poison area assumed at 0x%.*" PRIxPTR "\n", SIZxPTR, result); + return result; + } else { + // First see if we can allocate the preferred poison address from the OS. + uintptr_t candidate = (0xF0DEAFFF & ~(PAGESIZE-1)); + void *result = ReserveRegion(candidate, false); + if (result == (void *)candidate) { + // success - inaccessible page allocated + printf("INFO | poison area allocated at 0x%.*" PRIxPTR + " (preferred addr)\n", SIZxPTR, (uintptr_t)result); + return candidate; + } + + // That didn't work, so see if the preferred address is within a range + // of permanently inacessible memory. + if (ProbeRegion(candidate)) { + // success - selected page cannot be usable memory + if (result != MAP_FAILED) + ReleaseRegion(result); + printf("INFO | poison area assumed at 0x%.*" PRIxPTR + " (preferred addr)\n", SIZxPTR, candidate); + return candidate; + } + + // The preferred address is already in use. Did the OS give us a + // consolation prize? + if (result != MAP_FAILED) { + printf("INFO | poison area allocated at 0x%.*" PRIxPTR + " (consolation prize)\n", SIZxPTR, (uintptr_t)result); + return (uintptr_t)result; + } + + // It didn't, so try to allocate again, without any constraint on + // the address. + result = ReserveRegion(0, false); + if (result != MAP_FAILED) { + printf("INFO | poison area allocated at 0x%.*" PRIxPTR + " (fallback)\n", SIZxPTR, (uintptr_t)result); + return (uintptr_t)result; + } + + printf("ERROR | no usable poison area found\n"); + return 0; + } +} + +/* The "positive control" area confirms that we can allocate a page with the + * proper characteristics. + */ +static uintptr_t +ReservePositiveControl() +{ + + void *result = ReserveRegion(0, false); + if (result == MAP_FAILED) { + printf("ERROR | allocating positive control | %s\n", LastErrMsg()); + return 0; + } + printf("INFO | positive control allocated at 0x%.*" PRIxPTR "\n", + SIZxPTR, (uintptr_t)result); + return (uintptr_t)result; +} + +/* The "negative control" area confirms that our probe logic does detect a + * page that is readable, writable, or executable. + */ +static uintptr_t +ReserveNegativeControl() +{ + void *result = ReserveRegion(0, true); + if (result == MAP_FAILED) { + printf("ERROR | allocating negative control | %s\n", LastErrMsg()); + return 0; + } + + // Fill the page with return instructions. + RETURN_INSTR_TYPE *p = (RETURN_INSTR_TYPE *)result; + RETURN_INSTR_TYPE *limit = (RETURN_INSTR_TYPE *)(((char *)result) + PAGESIZE); + while (p < limit) + *p++ = RETURN_INSTR; + + // Now mark it executable as well as readable and writable. + // (mmap(PROT_EXEC) may fail when applied to anonymous memory.) + + if (MakeRegionExecutable(result)) { + printf("ERROR | making negative control executable | %s\n", LastErrMsg()); + return 0; + } + + printf("INFO | negative control allocated at 0x%.*" PRIxPTR "\n", + SIZxPTR, (uintptr_t)result); + return (uintptr_t)result; +} + +static void +JumpTo(uintptr_t opaddr) +{ +#ifdef __ia64 + struct func_call { + uintptr_t func; + uintptr_t gp; + } call = { opaddr, }; + ((void (*)())&call)(); +#else + ((void (*)())opaddr)(); +#endif +} + +#ifdef _WIN32 +static BOOL +IsBadExecPtr(uintptr_t ptr) +{ + BOOL ret = false; + +#ifdef _MSC_VER + __try { + JumpTo(ptr); + } __except (EXCEPTION_EXECUTE_HANDLER) { + ret = true; + } +#else + printf("INFO | exec test not supported on MinGW build\n"); + // We do our best + ret = IsBadReadPtr((const void*)ptr, 1); +#endif + return ret; +} +#endif + +/* Test each page. */ +static bool +TestPage(const char *pagelabel, uintptr_t pageaddr, int should_succeed) +{ + const char *oplabel; + uintptr_t opaddr; + + bool failed = false; + for (unsigned int test = 0; test < 3; test++) { + switch (test) { + // The execute test must be done before the write test, because the + // write test will clobber memory at the target address. + case 0: oplabel = "reading"; opaddr = pageaddr + PAGESIZE/2 - 1; break; + case 1: oplabel = "executing"; opaddr = pageaddr + PAGESIZE/2; break; + case 2: oplabel = "writing"; opaddr = pageaddr + PAGESIZE/2 - 1; break; + default: abort(); + } + +#ifdef _WIN32 + BOOL badptr; + + switch (test) { + case 0: badptr = IsBadReadPtr((const void*)opaddr, 1); break; + case 1: badptr = IsBadExecPtr(opaddr); break; + case 2: badptr = IsBadWritePtr((void*)opaddr, 1); break; + default: abort(); + } + + if (badptr) { + if (should_succeed) { + printf("TEST-UNEXPECTED-FAIL | %s %s\n", oplabel, pagelabel); + failed = true; + } else { + printf("TEST-PASS | %s %s\n", oplabel, pagelabel); + } + } else { + // if control reaches this point the probe succeeded + if (should_succeed) { + printf("TEST-PASS | %s %s\n", oplabel, pagelabel); + } else { + printf("TEST-UNEXPECTED-FAIL | %s %s\n", oplabel, pagelabel); + failed = true; + } + } +#elif defined(__OS2__) + XCPT xcpt; + volatile int code = setjmp(xcpt.jmpbuf); + + if (!code) { + xcpt.regrec.prev_structure = 0; + xcpt.regrec.ExceptionHandler = ExceptionHandler; + DosSetExceptionHandler(&xcpt.regrec); + unsigned char scratch; + switch (test) { + case 0: scratch = *(volatile unsigned char *)opaddr; break; + case 1: ((void (*)())opaddr)(); break; + case 2: *(volatile unsigned char *)opaddr = 0; break; + default: abort(); + } + } + + if (code) { + if (should_succeed) { + printf("TEST-UNEXPECTED-FAIL | %s %s | exception code %x\n", + oplabel, pagelabel, code); + failed = true; + } else { + printf("TEST-PASS | %s %s | exception code %x\n", + oplabel, pagelabel, code); + } + } else { + if (should_succeed) { + printf("TEST-PASS | %s %s\n", oplabel, pagelabel); + } else { + printf("TEST-UNEXPECTED-FAIL | %s %s\n", oplabel, pagelabel); + failed = true; + } + DosUnsetExceptionHandler(&xcpt.regrec); + } +#else + pid_t pid = fork(); + if (pid == -1) { + printf("ERROR | %s %s | fork=%s\n", oplabel, pagelabel, + LastErrMsg()); + exit(2); + } else if (pid == 0) { + volatile unsigned char scratch; + switch (test) { + case 0: scratch = *(volatile unsigned char *)opaddr; break; + case 1: JumpTo(opaddr); break; + case 2: *(volatile unsigned char *)opaddr = 0; break; + default: abort(); + } + (void)scratch; + _exit(0); + } else { + int status; + if (waitpid(pid, &status, 0) != pid) { + printf("ERROR | %s %s | wait=%s\n", oplabel, pagelabel, + LastErrMsg()); + exit(2); + } + + if (WIFEXITED(status) && WEXITSTATUS(status) == 0) { + if (should_succeed) { + printf("TEST-PASS | %s %s\n", oplabel, pagelabel); + } else { + printf("TEST-UNEXPECTED-FAIL | %s %s | unexpected successful exit\n", + oplabel, pagelabel); + failed = true; + } + } else if (WIFEXITED(status)) { + printf("ERROR | %s %s | unexpected exit code %d\n", + oplabel, pagelabel, WEXITSTATUS(status)); + exit(2); + } else if (WIFSIGNALED(status)) { + if (should_succeed) { + printf("TEST-UNEXPECTED-FAIL | %s %s | unexpected signal %d\n", + oplabel, pagelabel, WTERMSIG(status)); + failed = true; + } else { + printf("TEST-PASS | %s %s | signal %d (as expected)\n", + oplabel, pagelabel, WTERMSIG(status)); + } + } else { + printf("ERROR | %s %s | unexpected exit status %d\n", + oplabel, pagelabel, status); + exit(2); + } + } +#endif + } + return failed; +} + +int +main() +{ +#ifdef _WIN32 + GetSystemInfo(&_sinfo); +#elif !defined(__OS2__) + _pagesize = sysconf(_SC_PAGESIZE); +#endif + + uintptr_t ncontrol = ReserveNegativeControl(); + uintptr_t pcontrol = ReservePositiveControl(); + uintptr_t poison = ReservePoisonArea(); + + if (!ncontrol || !pcontrol || !poison) + return 2; + + bool failed = false; + failed |= TestPage("negative control", ncontrol, 1); + failed |= TestPage("positive control", pcontrol, 0); + failed |= TestPage("poison area", poison, 0); + + return failed ? 1 : 0; +} diff --git a/mfbt/tests/TestSHA1.cpp b/mfbt/tests/TestSHA1.cpp new file mode 100644 index 0000000..0d30dbe --- /dev/null +++ b/mfbt/tests/TestSHA1.cpp @@ -0,0 +1,204 @@ +/* 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/Assertions.h" +#include "mozilla/SHA1.h" + +using mozilla::SHA1Sum; + +static unsigned int testV[1024] = { + 0x048edc1a, 0x4345588c, 0x0ef03cbf, 0x1d6438f5, 0x094e0a1e, 0x68535f60, + 0x14e8c927, 0x60190043, 0x5d640ab7, 0x73dc7c62, 0x364223f9, 0x47320292, + 0x3924cae0, 0x5f6b26d3, 0x5efa04ef, 0x7aab361e, 0x2773b1aa, 0x1631b07d, + 0x385b5dd1, 0x26c809b0, 0x28ad3a9f, 0x0315292a, 0x1a544e67, 0x1e79dcb9, + 0x787683e8, 0x3a591c75, 0x1dd338c7, 0x01c539e5, 0x1c15b23e, 0x0697c25c, + 0x4df5fd45, 0x672aa324, 0x39f74e6e, 0x269cdd5f, 0x087b6fce, 0x293509db, + 0x0aef54a9, 0x210c4cc5, 0x29d6dc4a, 0x16320825, 0x3ab7b181, 0x56d6fd25, + 0x6837fda2, 0x3e7994c2, 0x37f77529, 0x48c85472, 0x424fd84d, 0x00aba7fa, + 0x6d8475de, 0x354634a7, 0x0c73bb49, 0x0a335de6, 0x0a9ea542, 0x5ffb31f1, + 0x00a6a3f2, 0x76b14a03, 0x1e436a37, 0x173b766a, 0x33cf3ca0, 0x34eb0f1a, + 0x4ca073ee, 0x27591fe6, 0x5eaf3356, 0x10c24493, 0x1bad88b6, 0x676f2309, + 0x7f5e2d91, 0x74bd4c83, 0x66549b43, 0x52ffdf24, 0x2dfa0a83, 0x7c3e1cbf, + 0x1edf87fc, 0x1f6fa930, 0x7c29bc74, 0x374bcd2f, 0x5b43de94, 0x0d09a3a6, + 0x7437ecb0, 0x635117f8, 0x2aa78f65, 0x2c788958, 0x098cb9f3, 0x13ed5b3f, + 0x41b7c7ba, 0x696b2d88, 0x42e20d63, 0x69585b1d, 0x4a9b027c, 0x0c761cba, + 0x563bdbc4, 0x3bde2f5b, 0x0bab9730, 0x7740104c, 0x11641702, 0x26f03c32, + 0x011a87c6, 0x2c5e4e6c, 0x46c34200, 0x6a167e84, 0x34205728, 0x0e8a6152, + 0x0014604b, 0x6793bacd, 0x442bca9c, 0x6f2018ce, 0x4313e07e, 0x77f2c69c, + 0x62621441, 0x47bf6358, 0x59c45e04, 0x16ba3426, 0x6ac0c19d, 0x20218c6b, + 0x510b4ddc, 0x585f6c9d, 0x1ed02b0c, 0x366bf0a9, 0x131c7f59, 0x0ebcd320, + 0x00ca858a, 0x5efbcb77, 0x2a7a1859, 0x64bb5afd, 0x76258886, 0x6505c895, + 0x602cfa32, 0x17040942, 0x783df744, 0x3838e0ae, 0x6a021e39, 0x4c8c9c5a, + 0x4a5e96b6, 0x10f4477d, 0x247fda4f, 0x4c390400, 0x0cbe048c, 0x7b547d26, + 0x1e2e6897, 0x4ba7e01b, 0x5cfea1bb, 0x39a2d199, 0x45aee64a, 0x12615500, + 0x0151615f, 0x1a9f5d33, 0x4542ed44, 0x101357eb, 0x35a16b1f, 0x3420b3e1, + 0x6442bac7, 0x1c0f2a8c, 0x68d642f1, 0x45744fc4, 0x048e60cb, 0x5f217f44, + 0x6cc7d151, 0x27f41984, 0x2d01eb09, 0x2bb15aea, 0x6dda49f8, 0x590dd6bc, + 0x280cc20b, 0x7e2592b5, 0x043642f0, 0x292b5d29, 0x2e0a9b69, 0x41162471, + 0x1e55db6b, 0x648b96fe, 0x05f8f9d1, 0x4a9d4cbb, 0x38517039, 0x2b0f8917, + 0x4d1e67bb, 0x713e0974, 0x64fdf214, 0x11223963, 0x2bd09d24, 0x19924092, + 0x4b4a70f0, 0x1ece6b03, 0x1780c9c1, 0x09b4c3ac, 0x58ac7e73, 0x5c9a4747, + 0x321f943b, 0x41167667, 0x3a19cf8c, 0x53f4144d, 0x03a498de, 0x6fb4b742, + 0x54d793cb, 0x7ee164e2, 0x501af74c, 0x43201e7f, 0x0ad581be, 0x497f046a, + 0x3b1d2a9f, 0x53b88eb0, 0x2c3a26c5, 0x5ae970ba, 0x7d7ee4ff, 0x471366c5, + 0x46119703, 0x3bfc2e58, 0x456d6c4f, 0x4b6bb181, 0x45d7c872, 0x0d023221, + 0x021176d1, 0x4195ad44, 0x4621ec90, 0x3ae68279, 0x57952f71, 0x1796080c, + 0x228077bb, 0x5e2b7fee, 0x3d71dd88, 0x4a651849, 0x7f1c8081, 0x04c333fc, + 0x1f99bff6, 0x11b7754c, 0x740be324, 0x069bf2e2, 0x0802f3e0, 0x371cf30e, + 0x1d44dda5, 0x6033b9e5, 0x5639a9b0, 0x6526bfff, 0x14d7d9b7, 0x4182b6a7, + 0x01a5fa76, 0x7aa5e581, 0x762465e6, 0x386b3a2e, 0x495a3ab0, 0x04421b2e, + 0x46e04591, 0x472af458, 0x6a007dd3, 0x2e8be484, 0x18660abe, 0x7969af82, + 0x5a242a83, 0x581b5f72, 0x5f0eff6d, 0x38aea98c, 0x2acb5853, 0x6d650b35, + 0x10b750d7, 0x18fdcd14, 0x09b4816c, 0x3ceef016, 0x6957153c, 0x27cf39fb, + 0x60e3495d, 0x381e1da6, 0x4b5be02d, 0x14b6f309, 0x6380c589, 0x1a31f436, + 0x4b5e50c1, 0x493ac048, 0x314baad1, 0x71e24ab7, 0x718af49c, 0x022f4658, + 0x1a419d5b, 0x1854610d, 0x2ec4e99a, 0x7096ce50, 0x5467ba00, 0x404aab4c, + 0x1a5ab015, 0x217580f7, 0x2d50071e, 0x71a9f437, 0x27f758b5, 0x11cd8b3f, + 0x63b089c9, 0x53c860c1, 0x2fa6b7d7, 0x61e54771, 0x5c0ba6b9, 0x3138f796, + 0x5c7359cd, 0x4c2c5654, 0x549d581c, 0x3129ebf7, 0x4958a248, 0x1a460541, + 0x68e64964, 0x597c0609, 0x57afcbab, 0x2f1c6479, 0x57a0ad5c, 0x5936938f, + 0x536a5cbe, 0x29aacf0b, 0x43eca70d, 0x6e7a3e4e, 0x563c1e3b, 0x32f23909, + 0x12faa42d, 0x28b0bbde, 0x797e2842, 0x1b827bdf, 0x0df96a6e, 0x542ef7f4, + 0x6226d368, 0x01cb4258, 0x77bcba08, 0x7e6dc041, 0x0571eda3, 0x0fdf5065, + 0x5c9b9f7a, 0x2b496dd6, 0x02d3b40b, 0x3a5752db, 0x4843a293, 0x6fdc9c3f, + 0x42963996, 0x39c9e4eb, 0x01db58ad, 0x7e79381c, 0x5bb207bb, 0x2df5de51, + 0x1549ec82, 0x64f01e70, 0x536eb0d0, 0x10fa6e03, 0x5b7f9a20, 0x2d8b625d, + 0x397410c7, 0x7778284e, 0x1ab75170, 0x254f304e, 0x395ba877, 0x0c2e2815, + 0x5c723dec, 0x63b91327, 0x7c5954b5, 0x67dd69a3, 0x21d220c7, 0x5a287fcd, + 0x0d0b9c59, 0x22444c9f, 0x6305cb43, 0x12f717cc, 0x77c11945, 0x0e79bda8, + 0x6e014391, 0x441d0179, 0x5e17dd2f, 0x53e57a5c, 0x692f4b9a, 0x76c1e94b, + 0x5a872d81, 0x044f7e7e, 0x0970844f, 0x25e34e73, 0x57865d3c, 0x640771d2, + 0x12d410ed, 0x1424e079, 0x3e1c7fd7, 0x0e89295a, 0x48dcf262, 0x55a29550, + 0x0fd4d360, 0x7494d449, 0x41e6f260, 0x2230d4e7, 0x5ad1cd49, 0x7f8dd428, + 0x7722b48a, 0x7a14848d, 0x2a83335a, 0x548c0d9b, 0x24f5d43b, 0x33a417cb, + 0x3061e078, 0x1a1bc935, 0x5aedb5df, 0x6755f3e4, 0x795e4cdb, 0x64dfcd1c, + 0x6d5164fc, 0x34a3df0e, 0x2cc92142, 0x2569127d, 0x130f3d86, 0x43617cc2, + 0x25eaf1fa, 0x044ae792, 0x4b47ee17, 0x6879ea87, 0x7eb455fa, 0x54481e19, + 0x13bba2f0, 0x6da3fe79, 0x19c306ff, 0x42591e38, 0x2b0e205d, 0x60bd48bc, + 0x550aa0ce, 0x2296a6ef, 0x551eb052, 0x76df1b8e, 0x242a2d22, 0x0ada0b06, + 0x58b661ec, 0x490bec94, 0x20bd7c59, 0x760de8c3, 0x7a048ee8, 0x44ba6dcd, + 0x3816abd9, 0x47e8527e, 0x2194a188, 0x6967a480, 0x7f7e2083, 0x0ec455f3, + 0x78198eab, 0x3d710773, 0x05969198, 0x76ffcffe, 0x54be4797, 0x11105781, + 0x3a851719, 0x516284b8, 0x4295de1c, 0x3905be43, 0x6d4e7d6a, 0x0877796d, + 0x0b9e986a, 0x5e2b853f, 0x7e6c79cd, 0x4a44a54c, 0x1e28b9a2, 0x5b1e408e, + 0x6a1c8eac, 0x62a87929, 0x4f075dac, 0x5c030e8c, 0x3df73ce9, 0x321c3c69, + 0x2325cc45, 0x4eaf0759, 0x486a31fb, 0x12d04b94, 0x714e15d5, 0x420d1910, + 0x092dc45b, 0x0119beac, 0x68b2bfdb, 0x74863a17, 0x3c7ab8e5, 0x035bc2df, + 0x4e7a7965, 0x017f58d6, 0x6414074e, 0x3a1e64ae, 0x2d6725d8, 0x0f22f82a, + 0x0a0affa0, 0x4159f31e, 0x4002cb9d, 0x234e393f, 0x6028169f, 0x3b804078, + 0x0c16e2e1, 0x0e198020, 0x24b13c40, 0x1ceb2143, 0x38dd4246, 0x6f483590, + 0x69b20a6e, 0x105580b1, 0x5d60f184, 0x065d18eb, 0x09a28739, 0x70345728, + 0x595a5934, 0x14a78a43, 0x449f05c7, 0x6556fcfc, 0x260bc0b2, 0x3afb600e, + 0x1f47bb91, 0x145c14b6, 0x541832fe, 0x54f10f23, 0x3013650e, 0x6c0d32ba, + 0x4f202c8d, 0x66bcc661, 0x6131dc7f, 0x04828b25, 0x1737565d, 0x520e967f, + 0x16cf0438, 0x6f2bc19e, 0x553c3dda, 0x356906b0, 0x333916d5, 0x2887c195, + 0x11e7440b, 0x6354f182, 0x06b2f977, 0x6d2c9a5c, 0x2d02bfb7, 0x74fafcf6, + 0x2b955161, 0x74035c38, 0x6e9bc991, 0x09a3a5b9, 0x460f416a, 0x11afabfc, + 0x66e32d10, 0x4a56ac6e, 0x6448afa8, 0x680b0044, 0x05d0e296, 0x49569eac, + 0x0adb563b, 0x4a9da168, 0x4f857004, 0x0f234600, 0x6db386ec, 0x280b94bf, + 0x7cd258a5, 0x6165fd88, 0x3bf2aac9, 0x2cb47c44, 0x2381c2a4, 0x4fe42552, + 0x21d4c81e, 0x24baa9af, 0x365231cb, 0x11b7fc81, 0x419748fb, 0x38ff637e, + 0x065f3365, 0x21f1aba8, 0x2df41ace, 0x5cec1d95, 0x22c078a8, 0x7bb894fc, + 0x2d66fc53, 0x7ed82ccc, 0x4485c9d7, 0x1af210fc, 0x5d2faa09, 0x3b33412e, + 0x79d12ea8, 0x7bb8103b, 0x5cea1a7b, 0x2779db45, 0x1250ed5b, 0x0c4d8964, + 0x6c18e9f5, 0x501ddc60, 0x3de43ae4, 0x6c0e8577, 0x0adfb426, 0x7ec718f5, + 0x1991f387, 0x101ccb9c, 0x632360b4, 0x7d52ce4d, 0x0b58c91c, 0x1fa59d53, + 0x0b0b48b0, 0x297315d0, 0x7f3132ff, 0x323b85d1, 0x2f852141, 0x23e84bdc, + 0x3732cb25, 0x1274eb57, 0x21a882c3, 0x095288a9, 0x2120e253, 0x617799ce, + 0x5e4926b3, 0x52575363, 0x696722e0, 0x509c9117, 0x3b60f14f, 0x423310fa, + 0x4e694e80, 0x000a647e, 0x453e283a, 0x3f1d21ef, 0x527c91f0, 0x7ac2e88a, + 0x1ba3b840, 0x1c3f253a, 0x04c40280, 0x437dc361, 0x7247859c, 0x61e5b34c, + 0x20746a53, 0x58cfc2df, 0x79edf48e, 0x5b48e723, 0x7b08baac, 0x1d1035ea, + 0x023fc918, 0x2de0427c, 0x71540904, 0x4030e8f5, 0x2b0961f6, 0x4ec98ef0, + 0x781076ee, 0x0dac959b, 0x16f66214, 0x273411e5, 0x02334297, 0x3b568cd1, + 0x7cf4e8c0, 0x0f4c2c91, 0x2d8dd28e, 0x4a7b3fb0, 0x237969ae, 0x363d6cb6, + 0x75fee60a, 0x5825f4df, 0x29f79f9d, 0x22de4f33, 0x2309590e, 0x1977c2bd, + 0x67f7bebe, 0x452b8330, 0x5dc70832, 0x5cddbea4, 0x59091e0b, 0x4d287830, + 0x2bbc2ce6, 0x420ee023, 0x02d6e086, 0x228a7a14, 0x48207207, 0x1d5ccc5a, + 0x37d32cdc, 0x50dc6508, 0x0b795304, 0x5b9fd543, 0x2a3f2925, 0x72e71606, + 0x0dc8ba42, 0x3279a910, 0x6bd2c2e2, 0x775065d8, 0x547c59a6, 0x4b5374cf, + 0x0c45cd18, 0x532096d6, 0x351c9bd1, 0x107fdce0, 0x3ae69075, 0x5dddd5de, + 0x3bb0ba8b, 0x0b1a0019, 0x6c226525, 0x109e9002, 0x312191be, 0x16fa3de8, + 0x4a5197aa, 0x0931b2d2, 0x79ee6e1b, 0x657a142b, 0x6ab74d38, 0x77440cff, + 0x11e37956, 0x5c335799, 0x269d3be3, 0x18923cfd, 0x4dd71b00, 0x77c58014, + 0x07145324, 0x1678546a, 0x5dfd4f6a, 0x207f4e13, 0x6b0a98c0, 0x015bc2cf, + 0x1636d8fe, 0x7bc5f038, 0x183a0661, 0x573ec5f3, 0x54cf2255, 0x2fcc905c, + 0x71bb70b9, 0x2b122a89, 0x59f86e5b, 0x5528273d, 0x464cf857, 0x27efdeec, + 0x1d0bcfcc, 0x64d7837f, 0x1e7a659a, 0x02aa611c, 0x53969ad5, 0x0e83f59f, + 0x50a6d11b, 0x79513c59, 0x0e5c3c98, 0x2ed7bbcf, 0x117de9d9, 0x375ec696, + 0x19c830aa, 0x66950511, 0x2b6dbbaa, 0x5ca18c9b, 0x0a487514, 0x6f44a887, + 0x6921bc6e, 0x3ef8130b, 0x26f6cde3, 0x686d7605, 0x6583553a, 0x29bcf7cc, + 0x55d42201, 0x1c93497c, 0x64c53231, 0x32088f6e, 0x381c5770, 0x617574d8, + 0x09757952, 0x1a616eb0, 0x1140e8aa, 0x0ff66ffb, 0x32039001, 0x5a455e7c, + 0x0027b906, 0x21cf154c, 0x67d3527f, 0x56fd7602, 0x150f8b25, 0x2ae8e4c8, + 0x0bf10aec, 0x3d26a40f, 0x5c4c8ffc, 0x3c291322, 0x737fd02c, 0x4b506209, + 0x484ddaa4, 0x00b44669, 0x5974bdd1, 0x7d39d617, 0x12995404, 0x48f00bbe, + 0x44f7c59a, 0x23cb9292, 0x6476f20b, 0x034fbd59, 0x2893161c, 0x1dbae8c0, + 0x50348c2e, 0x797f0957, 0x685ddeaf, 0x36fb8a2e, 0x0fceb6f4, 0x10347ab4, + 0x72720bfc, 0x292a4304, 0x0cbf8a27, 0x3cea6db7, 0x4b0c6b15, 0x57e8e716, + 0x4e9c54cc, 0x4fc7f7ca, 0x49a6d3e2, 0x10fc2df3, 0x73db387e, 0x72cb89c3, + 0x71dba437, 0x4b14048c, 0x6e1af265, 0x1084b213, 0x3842107d, 0x6ecdc171, + 0x647919b2, 0x41a80841, 0x7b387c76, 0x46bc094b, 0x331b312a, 0x2f140cc4, + 0x355d0a11, 0x19390200, 0x69b05263, 0x582963fa, 0x44897e31, 0x66a473f0, + 0x0374f08d, 0x35879e45, 0x5e1dd7ef, 0x34d6a311, 0x6e4e18eb, 0x7b44734b, + 0x0e421333, 0x3da026d8, 0x5becbf4b, 0x56db4a1f, 0x1f2089bc, 0x28c733f2, + 0x04b0975d, 0x6156f224, 0x12d1f40f, 0x7f4d30f4, 0x2c0b9861, 0x769a083b, + 0x739544fb, 0x1dbd1067, 0x0e8cd717, 0x4c246fb2, 0x115eff39, 0x19e22f2a, + 0x4563ba61, 0x5d33a617, 0x54af83cf, 0x030bde73, 0x54b4736d, 0x0f01dfec, + 0x08869c01, 0x4e9e4d7b, 0x4739855a, 0x62d964a3, 0x26948fde, 0x30adf212, + 0x1f57b400, 0x3766c914, 0x1e7f9d1c, 0x33258b59, 0x522ab2c2, 0x3dc99798, + 0x15f53fe2, 0x05636669, 0x354b59c3, 0x1c37ebd4, 0x0bb7ebf9, 0x0e4e87f9, + 0x680d3124, 0x2770d549, 0x0c5e112e, 0x74aaa7ed, 0x06c0b550, 0x342b5922, + 0x4532ab5b, 0x4257dbee, 0x087f32a9, 0x45ada3e3, 0x7a854272, 0x061625f2, + 0x47c85a91, 0x25ad375d, 0x2809bd9d, 0x168b9348, 0x4381b0a3, 0x6f2dc6ca, + 0x122e54f6, 0x6c3228a6, 0x653c1652, 0x60b60584, 0x1d304b77, 0x4cc74c58, + 0x087e3dd5, 0x79bd540e, 0x79ab7a70, 0x26fcd1c9, 0x342abaaf, 0x644716b0, + 0x01f076cb, 0x73628937, 0x20b01ff8, 0x5832b80b, 0x2f77fc92, 0x4468d962, + 0x2bac2679, 0x7f850778, 0x47d2997c, 0x02690cb7, 0x7de54951, 0x54d80b14, + 0x5e0c6854, 0x313cc749, 0x622b86ba, 0x38dbf6d3, 0x045d3e52, 0x574f87fd, + 0x09f1b078, 0x31784f71, 0x4f01dd2f, 0x1874c9f9, 0x5837c7af, 0x2372f768, + 0x531bd1e8, 0x61816c0b, 0x4592995f, 0x156463c0, 0x250c5afe, 0x40c83178, + 0x4396f6b7, 0x29bdbec0, 0x43ea8ca5, 0x5c474696, 0x2c869192, 0x2ff2f51a, + 0x7c963fe5, 0x294319c1, 0x019fbe26, 0x72fa8e68, 0x245ca463, 0x4ca88208, + 0x72ac845a, 0x25307181, 0x2cdf88f7, 0x0adbfebd, 0x2eea465b, 0x52e4eee0, + 0x084daacd, 0x717ce67e, 0x594087c2, 0x2b8ee5c7, 0x4558f811, 0x76b65ba4, + 0x5de05e09, 0x3db76e27, 0x3c75110d, 0x04ca67e7, 0x51cd6d09, 0x7b4e9c3e, + 0x7cdda4d2, 0x674fb021, 0x7d372d2d, 0x13f7978b, 0x5fb106b1, 0x034377d1, + 0x2e5336f3, 0x099bb17d, 0x04e6755e, 0x34f73c1e, 0x004e0a0d, 0x7f2c32e2, + 0x1fc8f910, 0x67d0859d, 0x76462b25, 0x59fa9a17, 0x028e53ef, 0x3d6d5fdd, + 0x79a4671e, 0x5cbec506, 0x2c23ee6d, 0x628a2c1e, 0x4dae87bd, 0x07a189ea, + 0x3a414a96, 0x5915f622, 0x6bea011e, 0x412674cf, 0x07ecc314, 0x6a7dbce8, + 0x7e176f10, 0x68e60d47, 0x079ea970, 0x79f3b55c, 0x65a46098, 0x56155533, + 0x7e5d0272, 0x795bfad5, 0x094da770, 0x05ba427c, 0x152e430e, 0x187d8470, + 0x08e607bc, 0x45ce5ef9, 0x654231ae, 0x38d8cb48, 0x605632f8, 0x25cf8ee9, + 0x11497170, 0x171a3b00, 0x0f103d49, 0x24826483, 0x2848e187, 0x7498919b, + 0x1bb788cb, 0x791ad5c7, 0x5129330e, 0x016c4436, 0x430f05bf, 0x1f06b5cd, + 0x62df1378, 0x0423b9b4, 0x0341acaf, 0x3189543c, 0x7b96b2ea, 0x6c4865c3, + 0x4cc7adc3, 0x78a2bff6, 0x642db7c7, 0x70d02300, 0x7cd43ac0, 0x4f5fe414, + 0x333b52c2, 0x500d3c74, 0x65782c01, 0x3f72a2c5, 0x278f59d8, 0x493bf7f8, + 0x16bf51a0, 0x6cc70ced, 0x6ed15979, 0x1a77abae, 0x08cadbb7, 0x2f2e0bc0, + 0x236f5e8d, 0x1a4b4495, 0x360bd008, 0x32227d40 +}; + +int +main() +{ + SHA1Sum sum; + SHA1Sum::Hash hash; + sum.update(reinterpret_cast<const uint8_t*>(testV), sizeof(testV)); + sum.finish(hash); + + static const uint8_t expected[20] = + { 0xc8, 0xf2, 0x09, 0x59, 0x4e, 0x64, 0x40, 0xaa, 0x7b, 0xf7, 0xb8, 0xe0, + 0xfa, 0x44, 0xb2, 0x31, 0x95, 0xad, 0x94, 0x81 }; + + MOZ_STATIC_ASSERT(sizeof(expected) == sizeof(SHA1Sum::Hash), + "expected-data size should be the same as the actual hash " + "size"); + + for (size_t i = 0; i < SHA1Sum::HashSize; i++) + MOZ_ASSERT(hash[i] == expected[i]); + + return 0; +} diff --git a/mfbt/tests/TestTypeTraits.cpp b/mfbt/tests/TestTypeTraits.cpp new file mode 100644 index 0000000..6c424ed --- /dev/null +++ b/mfbt/tests/TestTypeTraits.cpp @@ -0,0 +1,213 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* 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/Assertions.h" +#include "mozilla/TypeTraits.h" + +using mozilla::IsBaseOf; +using mozilla::IsConvertible; +using mozilla::IsSame; +using mozilla::IsSigned; +using mozilla::IsUnsigned; +using mozilla::MakeSigned; +using mozilla::MakeUnsigned; + +MOZ_STATIC_ASSERT(!IsSigned<bool>::value, "bool shouldn't be signed"); +MOZ_STATIC_ASSERT(IsUnsigned<bool>::value, "bool should be unsigned"); + +MOZ_STATIC_ASSERT(!IsSigned<const bool>::value, "const bool shouldn't be signed"); +MOZ_STATIC_ASSERT(IsUnsigned<const bool>::value, "const bool should be unsigned"); + +MOZ_STATIC_ASSERT(!IsSigned<volatile bool>::value, "volatile bool shouldn't be signed"); +MOZ_STATIC_ASSERT(IsUnsigned<volatile bool>::value, "volatile bool should be unsigned"); + +MOZ_STATIC_ASSERT(!IsSigned<unsigned char>::value, "unsigned char shouldn't be signed"); +MOZ_STATIC_ASSERT(IsUnsigned<unsigned char>::value, "unsigned char should be unsigned"); +MOZ_STATIC_ASSERT(IsSigned<signed char>::value, "signed char should be signed"); +MOZ_STATIC_ASSERT(!IsUnsigned<signed char>::value, "signed char shouldn't be unsigned"); + +MOZ_STATIC_ASSERT(!IsSigned<unsigned short>::value, "unsigned short shouldn't be signed"); +MOZ_STATIC_ASSERT(IsUnsigned<unsigned short>::value, "unsigned short should be unsigned"); +MOZ_STATIC_ASSERT(IsSigned<short>::value, "short should be signed"); +MOZ_STATIC_ASSERT(!IsUnsigned<short>::value, "short shouldn't be unsigned"); + +MOZ_STATIC_ASSERT(!IsSigned<unsigned int>::value, "unsigned int shouldn't be signed"); +MOZ_STATIC_ASSERT(IsUnsigned<unsigned int>::value, "unsigned int should be unsigned"); +MOZ_STATIC_ASSERT(IsSigned<int>::value, "int should be signed"); +MOZ_STATIC_ASSERT(!IsUnsigned<int>::value, "int shouldn't be unsigned"); + +MOZ_STATIC_ASSERT(!IsSigned<unsigned long>::value, "unsigned long shouldn't be signed"); +MOZ_STATIC_ASSERT(IsUnsigned<unsigned long>::value, "unsigned long should be unsigned"); +MOZ_STATIC_ASSERT(IsSigned<long>::value, "long should be signed"); +MOZ_STATIC_ASSERT(!IsUnsigned<long>::value, "long shouldn't be unsigned"); + +MOZ_STATIC_ASSERT(IsSigned<float>::value, "float should be signed"); +MOZ_STATIC_ASSERT(!IsUnsigned<float>::value, "float shouldn't be unsigned"); + +MOZ_STATIC_ASSERT(IsSigned<const float>::value, "const float should be signed"); +MOZ_STATIC_ASSERT(!IsUnsigned<const float>::value, "const float shouldn't be unsigned"); + +MOZ_STATIC_ASSERT(IsSigned<double>::value, "double should be signed"); +MOZ_STATIC_ASSERT(!IsUnsigned<double>::value, "double shouldn't be unsigned"); + +MOZ_STATIC_ASSERT(IsSigned<volatile double>::value, "volatile double should be signed"); +MOZ_STATIC_ASSERT(!IsUnsigned<volatile double>::value, "volatile double shouldn't be unsigned"); + +MOZ_STATIC_ASSERT(IsSigned<long double>::value, "long double should be signed"); +MOZ_STATIC_ASSERT(!IsUnsigned<long double>::value, "long double shouldn't be unsigned"); + +MOZ_STATIC_ASSERT(IsSigned<const volatile long double>::value, + "const volatile long double should be signed"); +MOZ_STATIC_ASSERT(!IsUnsigned<const volatile long double>::value, + "const volatile long double shouldn't be unsigned"); + +namespace CPlusPlus11IsBaseOf { + +// Adapted from C++11 ยง 20.9.6. +struct B {}; +struct B1 : B {}; +struct B2 : B {}; +struct D : private B1, private B2 {}; + +static void +StandardIsBaseOfTests() +{ + MOZ_ASSERT((IsBaseOf<B, D>::value) == true); + MOZ_ASSERT((IsBaseOf<const B, D>::value) == true); + MOZ_ASSERT((IsBaseOf<B, const D>::value) == true); + MOZ_ASSERT((IsBaseOf<B, const B>::value) == true); + MOZ_ASSERT((IsBaseOf<D, B>::value) == false); + MOZ_ASSERT((IsBaseOf<B&, D&>::value) == false); + MOZ_ASSERT((IsBaseOf<B[3], D[3]>::value) == false); + // We fail at the following test. To fix it, we need to specialize IsBaseOf + // for all built-in types. + // MOZ_ASSERT((IsBaseOf<int, int>::value) == false); +} + +} /* namespace CPlusPlus11IsBaseOf */ + +class A { }; +class B : public A { }; +class C : private A { }; +class D { }; +class E : public A { }; +class F : public B, public E { }; + +static void +TestIsBaseOf() +{ + MOZ_ASSERT((IsBaseOf<A, B>::value), + "A is a base of B"); + MOZ_ASSERT((!IsBaseOf<B, A>::value), + "B is not a base of A"); + MOZ_ASSERT((IsBaseOf<A, C>::value), + "A is a base of C"); + MOZ_ASSERT((!IsBaseOf<C, A>::value), + "C is not a base of A"); + MOZ_ASSERT((IsBaseOf<A, F>::value), + "A is a base of F"); + MOZ_ASSERT((!IsBaseOf<F, A>::value), + "F is not a base of A"); + MOZ_ASSERT((!IsBaseOf<A, D>::value), + "A is not a base of D"); + MOZ_ASSERT((!IsBaseOf<D, A>::value), + "D is not a base of A"); + MOZ_ASSERT((IsBaseOf<B, B>::value), + "B is the same as B (and therefore, a base of B)"); +} + +static void +TestIsConvertible() +{ + // Pointer type convertibility + MOZ_ASSERT((IsConvertible<A*, A*>::value), + "A* should convert to A*"); + MOZ_ASSERT((IsConvertible<B*, A*>::value), + "B* should convert to A*"); + MOZ_ASSERT((!IsConvertible<A*, B*>::value), + "A* shouldn't convert to B*"); + MOZ_ASSERT((!IsConvertible<A*, C*>::value), + "A* shouldn't convert to C*"); + MOZ_ASSERT((!IsConvertible<A*, D*>::value), + "A* shouldn't convert to unrelated D*"); + MOZ_ASSERT((!IsConvertible<D*, A*>::value), + "D* shouldn't convert to unrelated A*"); + + // Instance type convertibility + MOZ_ASSERT((IsConvertible<A, A>::value), + "A is A"); + MOZ_ASSERT((IsConvertible<B, A>::value), + "B converts to A"); + MOZ_ASSERT((!IsConvertible<D, A>::value), + "D and A are unrelated"); + MOZ_ASSERT((!IsConvertible<A, D>::value), + "A and D are unrelated"); + + // These cases seem to require C++11 support to properly implement them, so + // for now just disable them. + //MOZ_ASSERT((!IsConvertible<C*, A*>::value), + // "C* shouldn't convert to A* (private inheritance)"); + //MOZ_ASSERT((!IsConvertible<C, A>::value), + // "C doesn't convert to A (private inheritance)"); +} + +MOZ_STATIC_ASSERT((IsSame<MakeSigned<const unsigned char>::Type, const signed char>::value), + "const unsigned char won't signify correctly"); +MOZ_STATIC_ASSERT((IsSame<MakeSigned<volatile unsigned short>::Type, volatile signed short>::value), + "volatile unsigned short won't signify correctly"); +MOZ_STATIC_ASSERT((IsSame<MakeSigned<const volatile unsigned int>::Type, const volatile signed int>::value), + "const volatile unsigned int won't signify correctly"); +MOZ_STATIC_ASSERT((IsSame<MakeSigned<unsigned long>::Type, signed long>::value), + "unsigned long won't signify correctly"); +MOZ_STATIC_ASSERT((IsSame<MakeSigned<const signed char>::Type, const signed char>::value), + "const signed char won't signify correctly"); + +MOZ_STATIC_ASSERT((IsSame<MakeSigned<volatile signed short>::Type, volatile signed short>::value), + "volatile signed short won't signify correctly"); +MOZ_STATIC_ASSERT((IsSame<MakeSigned<const volatile signed int>::Type, const volatile signed int>::value), + "const volatile signed int won't signify correctly"); +MOZ_STATIC_ASSERT((IsSame<MakeSigned<signed long>::Type, signed long>::value), + "signed long won't signify correctly"); + +MOZ_STATIC_ASSERT((IsSame<MakeSigned<char>::Type, signed char>::value), + "char won't signify correctly"); +MOZ_STATIC_ASSERT((IsSame<MakeSigned<volatile char>::Type, volatile signed char>::value), + "volatile char won't signify correctly"); +MOZ_STATIC_ASSERT((IsSame<MakeSigned<const char>::Type, const signed char>::value), + "const char won't signify correctly"); + +MOZ_STATIC_ASSERT((IsSame<MakeUnsigned<const signed char>::Type, const unsigned char>::value), + "const signed char won't unsignify correctly"); +MOZ_STATIC_ASSERT((IsSame<MakeUnsigned<volatile signed short>::Type, volatile unsigned short>::value), + "volatile signed short won't unsignify correctly"); +MOZ_STATIC_ASSERT((IsSame<MakeUnsigned<const volatile signed int>::Type, const volatile unsigned int>::value), + "const volatile signed int won't unsignify correctly"); +MOZ_STATIC_ASSERT((IsSame<MakeUnsigned<signed long>::Type, unsigned long>::value), + "signed long won't unsignify correctly"); + +MOZ_STATIC_ASSERT((IsSame<MakeUnsigned<const unsigned char>::Type, const unsigned char>::value), + "const unsigned char won't unsignify correctly"); + +MOZ_STATIC_ASSERT((IsSame<MakeUnsigned<volatile unsigned short>::Type, volatile unsigned short>::value), + "volatile unsigned short won't unsignify correctly"); +MOZ_STATIC_ASSERT((IsSame<MakeUnsigned<const volatile unsigned int>::Type, const volatile unsigned int>::value), + "const volatile unsigned int won't unsignify correctly"); +MOZ_STATIC_ASSERT((IsSame<MakeUnsigned<unsigned long>::Type, unsigned long>::value), + "signed long won't unsignify correctly"); + +MOZ_STATIC_ASSERT((IsSame<MakeUnsigned<char>::Type, unsigned char>::value), + "char won't unsignify correctly"); +MOZ_STATIC_ASSERT((IsSame<MakeUnsigned<volatile char>::Type, volatile unsigned char>::value), + "volatile char won't unsignify correctly"); +MOZ_STATIC_ASSERT((IsSame<MakeUnsigned<const char>::Type, const unsigned char>::value), + "const char won't unsignify correctly"); + +int +main() +{ + CPlusPlus11IsBaseOf::StandardIsBaseOfTests(); + TestIsBaseOf(); + TestIsConvertible(); +} diff --git a/mfbt/tests/TestWeakPtr.cpp b/mfbt/tests/TestWeakPtr.cpp new file mode 100644 index 0000000..510dd06 --- /dev/null +++ b/mfbt/tests/TestWeakPtr.cpp @@ -0,0 +1,77 @@ +/* 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/WeakPtr.h" + +using mozilla::SupportsWeakPtr; +using mozilla::WeakPtr; + +// To have a class C support weak pointers, inherit from SupportsWeakPtr<C>. +class C : public SupportsWeakPtr<C> +{ + public: + int num; + void act() {} +}; + +static void +Example() +{ + + C* ptr = new C(); + + // Get weak pointers to ptr. The first time asWeakPtr is called + // a reference counted WeakReference object is created that + // can live beyond the lifetime of 'ptr'. The WeakReference + // object will be notified of 'ptr's destruction. + WeakPtr<C> weak = ptr->asWeakPtr(); + WeakPtr<C> other = ptr->asWeakPtr(); + + // Test a weak pointer for validity before using it. + if (weak) { + weak->num = 17; + weak->act(); + } + + // Destroying the underlying object clears weak pointers to it. + delete ptr; + + MOZ_ASSERT(!weak, "Deleting |ptr| clears weak pointers to it."); + MOZ_ASSERT(!other, "Deleting |ptr| clears all weak pointers to it."); +} + +struct A : public SupportsWeakPtr<A> +{ + int data; +}; + + +int +main() +{ + + A* a = new A; + + // a2 is unused to test the case when we haven't initialized + // the internal WeakReference pointer. + A* a2 = new A; + + a->data = 5; + WeakPtr<A> ptr = a->asWeakPtr(); + { + WeakPtr<A> ptr2 = a->asWeakPtr(); + MOZ_ASSERT(ptr->data == 5); + WeakPtr<A> ptr3 = a->asWeakPtr(); + MOZ_ASSERT(ptr->data == 5); + } + + delete a; + MOZ_ASSERT(!ptr); + + delete a2; + + Example(); + + return 0; +} diff --git a/mfbt/tests/moz.build b/mfbt/tests/moz.build new file mode 100644 index 0000000..895d119 --- /dev/null +++ b/mfbt/tests/moz.build @@ -0,0 +1,6 @@ +# -*- Mode: python; c-basic-offset: 4; indent-tabs-mode: nil; tab-width: 40 -*- +# vim: set filetype=python: +# 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/. + |