diff options
Diffstat (limited to 'mfbt/tests/TestWeakPtr.cpp')
-rw-r--r-- | mfbt/tests/TestWeakPtr.cpp | 123 |
1 files changed, 123 insertions, 0 deletions
diff --git a/mfbt/tests/TestWeakPtr.cpp b/mfbt/tests/TestWeakPtr.cpp new file mode 100644 index 000000000..15060f00d --- /dev/null +++ b/mfbt/tests/TestWeakPtr.cpp @@ -0,0 +1,123 @@ +/* -*- 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; + +// To have a class C support weak pointers, inherit from SupportsWeakPtr<C>. +class C : public SupportsWeakPtr<C> +{ +public: + MOZ_DECLARE_WEAKREFERENCE_TYPENAME(C) + + int mNum; + + C() + : mNum(0) + {} + + ~C() + { + // Setting mNum in the destructor allows us to test against use-after-free below + mNum = 0xDEAD; + } + + void act() {} + + bool isConst() { + return false; + } + + bool isConst() const { + return true; + } +}; + +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."); +} |