diff options
Diffstat (limited to '')
-rw-r--r-- | mfbt/tests/TestWeakPtr.cpp | 145 |
1 files changed, 145 insertions, 0 deletions
diff --git a/mfbt/tests/TestWeakPtr.cpp b/mfbt/tests/TestWeakPtr.cpp new file mode 100644 index 0000000000..0599975a9c --- /dev/null +++ b/mfbt/tests/TestWeakPtr.cpp @@ -0,0 +1,145 @@ +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* vim: set ts=8 sts=2 et sw=2 tw=80: */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#include "mozilla/WeakPtr.h" + +using mozilla::SupportsWeakPtr; +using mozilla::WeakPtr; + +static char IamB[] = "B"; +static char IamC[] = "C"; +static char IamD[] = "D"; + +class B : public SupportsWeakPtr { + public: + char const* whoAmI() const { return IamB; } +}; + +// To have a class C support weak pointers, inherit from SupportsWeakPtr. +class C : public SupportsWeakPtr { + public: + int mNum; + + C() : mNum(0) {} + + ~C() { + // Setting mNum in the destructor allows us to test against use-after-free + // below + mNum = 0xDEAD; + } + + char const* whoAmI() const { return IamC; } + + void act() {} + + bool isConst() { return false; } + + bool isConst() const { return true; } +}; + +// Derived from a class that supports weakptr, but doesn't implement itself +// To check upcast works as expected +class D : public B { + public: + char const* whoAmI() const { return IamD; } +}; + +bool isConst(C*) { return false; } + +bool isConst(const C*) { return true; } + +int main() { + C* c1 = new C; + MOZ_RELEASE_ASSERT(c1->mNum == 0); + + // Get weak pointers to c1. The first time, + // a reference-counted WeakReference object is created that + // can live beyond the lifetime of 'c1'. The WeakReference + // object will be notified of 'c1's destruction. + WeakPtr<C> w1 = c1; + // Test a weak pointer for validity before using it. + MOZ_RELEASE_ASSERT(w1); + MOZ_RELEASE_ASSERT(w1 == c1); + w1->mNum = 1; + w1->act(); + + // Test taking another WeakPtr<C> to c1 + WeakPtr<C> w2 = c1; + MOZ_RELEASE_ASSERT(w2); + MOZ_RELEASE_ASSERT(w2 == c1); + MOZ_RELEASE_ASSERT(w2 == w1); + MOZ_RELEASE_ASSERT(w2->mNum == 1); + + // Test a WeakPtr<const C> + WeakPtr<const C> w3const = c1; + MOZ_RELEASE_ASSERT(w3const); + MOZ_RELEASE_ASSERT(w3const == c1); + MOZ_RELEASE_ASSERT(w3const == w1); + MOZ_RELEASE_ASSERT(w3const == w2); + MOZ_RELEASE_ASSERT(w3const->mNum == 1); + + // Test const-correctness of operator-> and operator T* + MOZ_RELEASE_ASSERT(!w1->isConst()); + MOZ_RELEASE_ASSERT(w3const->isConst()); + MOZ_RELEASE_ASSERT(!isConst(w1)); + MOZ_RELEASE_ASSERT(isConst(w3const)); + + // Test that when a WeakPtr is destroyed, it does not destroy the object that + // it points to, and it does not affect other WeakPtrs pointing to the same + // object (e.g. it does not destroy the WeakReference object). + { + WeakPtr<C> w4local = c1; + MOZ_RELEASE_ASSERT(w4local == c1); + } + // Now w4local has gone out of scope. If that had destroyed c1, then the + // following would fail for sure (see C::~C()). + MOZ_RELEASE_ASSERT(c1->mNum == 1); + // Check that w4local going out of scope hasn't affected other WeakPtr's + // pointing to c1 + MOZ_RELEASE_ASSERT(w1 == c1); + MOZ_RELEASE_ASSERT(w2 == c1); + + // Now construct another C object and test changing what object a WeakPtr + // points to + C* c2 = new C; + c2->mNum = 2; + MOZ_RELEASE_ASSERT(w2->mNum == 1); // w2 was pointing to c1 + w2 = c2; + MOZ_RELEASE_ASSERT(w2); + MOZ_RELEASE_ASSERT(w2 == c2); + MOZ_RELEASE_ASSERT(w2 != c1); + MOZ_RELEASE_ASSERT(w2 != w1); + MOZ_RELEASE_ASSERT(w2->mNum == 2); + + // Destroying the underlying object clears weak pointers to it. + // It should not affect pointers that are not currently pointing to it. + delete c1; + MOZ_RELEASE_ASSERT(!w1, "Deleting an object should clear WeakPtr's to it."); + MOZ_RELEASE_ASSERT(!w3const, + "Deleting an object should clear WeakPtr's to it."); + MOZ_RELEASE_ASSERT(w2, + "Deleting an object should not clear WeakPtr that are not " + "pointing to it."); + + delete c2; + MOZ_RELEASE_ASSERT(!w2, "Deleting an object should clear WeakPtr's to it."); + + // Check that we correctly upcast to the base class supporting weakptr + D* d = new D; + WeakPtr<B> db = d; + + // You should be able to use WeakPtr<D> even if it's a base class which + // implements SupportsWeakPtr. + WeakPtr<D> weakd = d; + + MOZ_RELEASE_ASSERT(db->whoAmI() == IamB); + MOZ_RELEASE_ASSERT(weakd.get() == db.get()); + + delete d; + + MOZ_RELEASE_ASSERT(!db); + MOZ_RELEASE_ASSERT(!weakd); +} |