| /* |
| * Copyright (C) 2013 Google Inc. All Rights Reserved. |
| * |
| * Redistribution and use in source and binary forms, with or without |
| * modification, are permitted provided that the following conditions |
| * are met: |
| * 1. Redistributions of source code must retain the above copyright |
| * notice, this list of conditions and the following disclaimer. |
| * 2. Redistributions in binary form must reproduce the above copyright |
| * notice, this list of conditions and the following disclaimer in the |
| * documentation and/or other materials provided with the distribution. |
| * |
| * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY |
| * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE |
| * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR |
| * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR |
| * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, |
| * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, |
| * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR |
| * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY |
| * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
| * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE |
| * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
| * |
| */ |
| |
| #include "platform/LifecycleNotifier.h" |
| #include "platform/LifecycleObserver.h" |
| #include "platform/heap/Handle.h" |
| #include "testing/gtest/include/gtest/gtest.h" |
| |
| namespace blink { |
| |
| class TestingObserver; |
| |
| class DummyContext final : public NoBaseWillBeGarbageCollectedFinalized<DummyContext>, public LifecycleNotifier<DummyContext, TestingObserver> { |
| WILL_BE_USING_GARBAGE_COLLECTED_MIXIN(DummyContext); |
| public: |
| static PassOwnPtrWillBeRawPtr<DummyContext> create() |
| { |
| return adoptPtrWillBeNoop(new DummyContext()); |
| } |
| |
| DEFINE_INLINE_TRACE() |
| { |
| LifecycleNotifier<DummyContext, TestingObserver>::trace(visitor); |
| } |
| }; |
| |
| class TestingObserver final : public NoBaseWillBeGarbageCollectedFinalized<TestingObserver>, public LifecycleObserver<DummyContext, TestingObserver, DummyContext> { |
| WILL_BE_USING_GARBAGE_COLLECTED_MIXIN(TestingObserver); |
| public: |
| static PassOwnPtrWillBeRawPtr<TestingObserver> create(DummyContext* context) |
| { |
| return adoptPtrWillBeNoop(new TestingObserver(context)); |
| } |
| |
| void contextDestroyed() override |
| { |
| LifecycleObserver::contextDestroyed(); |
| if (m_observerToRemoveOnDestruct) { |
| lifecycleContext()->removeObserver(m_observerToRemoveOnDestruct.get()); |
| m_observerToRemoveOnDestruct.clear(); |
| } |
| m_contextDestroyedCalled = true; |
| } |
| |
| DEFINE_INLINE_TRACE() |
| { |
| visitor->trace(m_observerToRemoveOnDestruct); |
| LifecycleObserver::trace(visitor); |
| } |
| |
| 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(context) |
| , m_contextDestroyedCalled(false) |
| { |
| } |
| |
| OwnPtrWillBeMember<TestingObserver> m_observerToRemoveOnDestruct; |
| bool m_contextDestroyedCalled; |
| }; |
| |
| TEST(LifecycleContextTest, shouldObserveContextDestroyed) |
| { |
| OwnPtrWillBeRawPtr<DummyContext> context = DummyContext::create(); |
| OwnPtrWillBePersistent<TestingObserver> observer = TestingObserver::create(context.get()); |
| |
| EXPECT_EQ(observer->lifecycleContext(), context.get()); |
| EXPECT_FALSE(observer->contextDestroyedCalled()); |
| context->notifyContextDestroyed(); |
| context = nullptr; |
| Heap::collectAllGarbage(); |
| EXPECT_EQ(observer->lifecycleContext(), static_cast<DummyContext*>(0)); |
| EXPECT_TRUE(observer->contextDestroyedCalled()); |
| } |
| |
| TEST(LifecycleContextTest, shouldNotObserveContextDestroyedIfUnobserve) |
| { |
| 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->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 |