Index: Source/platform/LifecycleContextTest.cpp |
diff --git a/Source/platform/LifecycleContextTest.cpp b/Source/platform/LifecycleContextTest.cpp |
index eae437e48afbd5e7510c266afbf87dc6f9bd9feb..7998adfe22cd8bffef9967c90c532ebd363cc255 100644 |
--- a/Source/platform/LifecycleContextTest.cpp |
+++ b/Source/platform/LifecycleContextTest.cpp |
@@ -38,9 +38,9 @@ class TestingObserver; |
class DummyContext final : public NoBaseWillBeGarbageCollectedFinalized<DummyContext>, public LifecycleNotifier<DummyContext, TestingObserver> { |
public: |
- DummyContext() |
- : LifecycleNotifier<DummyContext, TestingObserver>(this) |
+ static PassOwnPtrWillBeRawPtr<DummyContext> create() |
{ |
+ return adoptPtrWillBeNoop(new DummyContext()); |
} |
void addObserver(TestingObserver* observer) |
@@ -57,58 +57,109 @@ public: |
{ |
LifecycleNotifier<DummyContext, TestingObserver>::trace(visitor); |
} |
+ |
+private: |
+ DummyContext() |
+ : LifecycleNotifier<DummyContext, TestingObserver>(this) |
+ { |
+ } |
}; |
class TestingObserver final : public NoBaseWillBeGarbageCollectedFinalized<TestingObserver>, public LifecycleObserver<DummyContext, TestingObserver, DummyContext> { |
WILL_BE_USING_GARBAGE_COLLECTED_MIXIN(TestingObserver); |
public: |
- explicit TestingObserver(DummyContext* context) |
- : LifecycleObserver<DummyContext, TestingObserver, DummyContext>(context) |
- , m_contextDestroyedCalled(false) |
+ static PassOwnPtrWillBeRawPtr<TestingObserver> create(DummyContext* context) |
{ |
- setContext(context); |
+ return adoptPtrWillBeNoop(new TestingObserver(context)); |
} |
virtual void contextDestroyed() override |
{ |
LifecycleObserver<DummyContext, TestingObserver, DummyContext>::contextDestroyed(); |
+ if (m_observerToRemoveOnDestruct) { |
+ lifecycleContext()->removeObserver(m_observerToRemoveOnDestruct.get()); |
+ m_observerToRemoveOnDestruct.clear(); |
+ } |
m_contextDestroyedCalled = true; |
} |
DEFINE_INLINE_TRACE() |
{ |
+ visitor->trace(m_observerToRemoveOnDestruct); |
LifecycleObserver<DummyContext, TestingObserver, DummyContext>::trace(visitor); |
} |
- bool m_contextDestroyedCalled; |
- |
void unobserve() { setContext(nullptr); } |
+ |
+ void setObserverToRemoveAndDestroy(PassOwnPtrWillBeRawPtr<TestingObserver> observerToRemoveOnDestruct) |
+ { |
+ ASSERT(!m_observerToRemoveOnDestruct); |
+ m_observerToRemoveOnDestruct = observerToRemoveOnDestruct; |
+ } |
+ |
+ TestingObserver* innerObserver() const { return m_observerToRemoveOnDestruct.get(); } |
+ bool contextDestroyedCalled() const { return m_contextDestroyedCalled; } |
+ |
+private: |
+ explicit TestingObserver(DummyContext* context) |
+ : LifecycleObserver<DummyContext, TestingObserver, DummyContext>(context) |
+ , m_contextDestroyedCalled(false) |
+ { |
+ setContext(context); |
+ } |
+ |
+ OwnPtrWillBeMember<TestingObserver> m_observerToRemoveOnDestruct; |
+ bool m_contextDestroyedCalled; |
}; |
TEST(LifecycleContextTest, shouldObserveContextDestroyed) |
{ |
- OwnPtrWillBeRawPtr<DummyContext> context = adoptPtrWillBeNoop(new DummyContext()); |
- OwnPtrWillBePersistent<TestingObserver> observer = adoptPtrWillBeNoop(new TestingObserver(context.get())); |
+ OwnPtrWillBeRawPtr<DummyContext> context = DummyContext::create(); |
+ OwnPtrWillBePersistent<TestingObserver> observer = TestingObserver::create(context.get()); |
EXPECT_EQ(observer->lifecycleContext(), context.get()); |
- EXPECT_FALSE(observer->m_contextDestroyedCalled); |
+ EXPECT_FALSE(observer->contextDestroyedCalled()); |
context->notifyContextDestroyed(); |
context = nullptr; |
Heap::collectAllGarbage(); |
EXPECT_EQ(observer->lifecycleContext(), static_cast<DummyContext*>(0)); |
- EXPECT_TRUE(observer->m_contextDestroyedCalled); |
+ EXPECT_TRUE(observer->contextDestroyedCalled()); |
} |
TEST(LifecycleContextTest, shouldNotObserveContextDestroyedIfUnobserve) |
{ |
- OwnPtrWillBeRawPtr<DummyContext> context = adoptPtrWillBeNoop(new DummyContext()); |
- OwnPtrWillBePersistent<TestingObserver> observer = adoptPtrWillBeNoop(new TestingObserver(context.get())); |
+ OwnPtrWillBeRawPtr<DummyContext> context = DummyContext::create(); |
+ OwnPtrWillBePersistent<TestingObserver> observer = TestingObserver::create(context.get()); |
observer->unobserve(); |
context->notifyContextDestroyed(); |
context = nullptr; |
Heap::collectAllGarbage(); |
EXPECT_EQ(observer->lifecycleContext(), static_cast<DummyContext*>(0)); |
- EXPECT_FALSE(observer->m_contextDestroyedCalled); |
+ EXPECT_FALSE(observer->contextDestroyedCalled()); |
} |
+TEST(LifecycleContextTest, observerRemovedDuringNotifyDestroyed) |
+{ |
+ // FIXME: Oilpan: this test can be removed when the LifecycleNotifier<T>::m_observers |
+ // hash set is on the heap and membership is handled implicitly by the garbage collector. |
+ OwnPtrWillBeRawPtr<DummyContext> context = DummyContext::create(); |
+ OwnPtrWillBePersistent<TestingObserver> observer = TestingObserver::create(context.get()); |
+ OwnPtrWillBeRawPtr<TestingObserver> innerObserver = TestingObserver::create(context.get()); |
+ // Attach the observer to the other. When 'observer' is notified |
+ // of destruction, it will remove & destroy 'innerObserver'. |
+ observer->setObserverToRemoveAndDestroy(innerObserver.release()); |
+ |
+ EXPECT_EQ(observer->lifecycleContext(), context.get()); |
+ EXPECT_EQ(observer->innerObserver()->lifecycleContext(), context.get()); |
+ EXPECT_FALSE(observer->contextDestroyedCalled()); |
+ EXPECT_FALSE(observer->innerObserver()->contextDestroyedCalled()); |
+ |
+ context->notifyContextDestroyed(); |
+ EXPECT_EQ(observer->innerObserver(), nullptr); |
+ context = nullptr; |
+ Heap::collectAllGarbage(); |
+ EXPECT_EQ(observer->lifecycleContext(), static_cast<DummyContext*>(0)); |
+ EXPECT_TRUE(observer->contextDestroyedCalled()); |
} |
+ |
+} // namespace blink |