| Index: third_party/WebKit/Source/core/html/HTMLMediaElementEventListenersTest.cpp
|
| diff --git a/third_party/WebKit/Source/core/html/HTMLMediaElementEventListenersTest.cpp b/third_party/WebKit/Source/core/html/HTMLMediaElementEventListenersTest.cpp
|
| new file mode 100644
|
| index 0000000000000000000000000000000000000000..2d525dc9c88896bf2f6421657d4b35037d4b0716
|
| --- /dev/null
|
| +++ b/third_party/WebKit/Source/core/html/HTMLMediaElementEventListenersTest.cpp
|
| @@ -0,0 +1,175 @@
|
| +// Copyright 2017 The Chromium Authors. All rights reserved.
|
| +// Use of this source code is governed by a BSD-style license that can be
|
| +// found in the LICENSE file.
|
| +
|
| +#include "core/html/HTMLMediaElement.h"
|
| +
|
| +#include "core/dom/DocumentUserGestureToken.h"
|
| +#include "core/dom/Fullscreen.h"
|
| +#include "core/html/HTMLVideoElement.h"
|
| +#include "core/html/MediaCustomControlsFullscreenDetector.h"
|
| +#include "core/html/shadow/MediaControls.h"
|
| +#include "core/loader/EmptyClients.h"
|
| +#include "core/testing/DummyPageHolder.h"
|
| +#include "platform/UserGestureIndicator.h"
|
| +#include "platform/testing/EmptyWebMediaPlayer.h"
|
| +#include "platform/testing/UnitTestHelpers.h"
|
| +#include "testing/gmock/include/gmock/gmock.h"
|
| +#include "testing/gtest/include/gtest/gtest.h"
|
| +
|
| +namespace blink {
|
| +
|
| +namespace {
|
| +
|
| +class MockWebMediaPlayer final : public EmptyWebMediaPlayer {
|
| + public:
|
| + MOCK_METHOD1(setIsEffectivelyFullscreen, void(bool));
|
| +};
|
| +
|
| +class StubLocalFrameClient : public EmptyLocalFrameClient {
|
| + public:
|
| + static StubLocalFrameClient* create() { return new StubLocalFrameClient; }
|
| +
|
| + std::unique_ptr<WebMediaPlayer> createWebMediaPlayer(
|
| + HTMLMediaElement&,
|
| + const WebMediaPlayerSource&,
|
| + WebMediaPlayerClient*) override {
|
| + return WTF::wrapUnique(new MockWebMediaPlayer());
|
| + }
|
| +};
|
| +
|
| +using ::testing::_;
|
| +using ::testing::Invoke;
|
| +
|
| +} // anonymous namespace
|
| +
|
| +class HTMLMediaElementEventListenersTest : public ::testing::Test {
|
| + protected:
|
| + void SetUp() override {
|
| + m_pageHolder = DummyPageHolder::create(IntSize(800, 600), nullptr,
|
| + StubLocalFrameClient::create());
|
| + }
|
| +
|
| + Document& document() { return m_pageHolder->document(); }
|
| + void destroyDocument() { m_pageHolder.reset(); }
|
| + HTMLVideoElement* video() {
|
| + return toHTMLVideoElement(document().querySelector("video"));
|
| + }
|
| + MockWebMediaPlayer* webMediaPlayer() {
|
| + return static_cast<MockWebMediaPlayer*>(video()->webMediaPlayer());
|
| + }
|
| + MediaControls* controls() { return video()->mediaControls(); }
|
| + void simulateReadyState(HTMLMediaElement::ReadyState state) {
|
| + video()->setReadyState(state);
|
| + }
|
| + MediaCustomControlsFullscreenDetector* fullscreenDetector() {
|
| + return video()->m_customControlsFullscreenDetector;
|
| + }
|
| + bool isCheckViewportIntersectionTimerActive(
|
| + MediaCustomControlsFullscreenDetector* detector) {
|
| + return detector->m_checkViewportIntersectionTimer.isActive();
|
| + }
|
| +
|
| + private:
|
| + std::unique_ptr<DummyPageHolder> m_pageHolder;
|
| +};
|
| +
|
| +TEST_F(HTMLMediaElementEventListenersTest, RemovingFromDocumentCollectsAll) {
|
| + EXPECT_EQ(video(), nullptr);
|
| + document().body()->setInnerHTML("<body><video controls></video></body>");
|
| + EXPECT_NE(video(), nullptr);
|
| + EXPECT_TRUE(video()->hasEventListeners());
|
| + EXPECT_NE(controls(), nullptr);
|
| + EXPECT_TRUE(document().hasEventListeners());
|
| +
|
| + WeakPersistent<HTMLVideoElement> weakPersistentVideo = video();
|
| + WeakPersistent<MediaControls> weakPersistentControls = controls();
|
| + {
|
| + Persistent<HTMLVideoElement> persistentVideo = video();
|
| + document().body()->setInnerHTML("");
|
| +
|
| + // When removed from the document, the event listeners should have been
|
| + // dropped.
|
| + EXPECT_FALSE(document().hasEventListeners());
|
| + // The video element should still have some event listeners.
|
| + EXPECT_TRUE(persistentVideo->hasEventListeners());
|
| + }
|
| +
|
| + ThreadState::current()->collectAllGarbage();
|
| +
|
| + // They have been GC'd.
|
| + EXPECT_EQ(weakPersistentVideo, nullptr);
|
| + EXPECT_EQ(weakPersistentControls, nullptr);
|
| +}
|
| +
|
| +TEST_F(HTMLMediaElementEventListenersTest,
|
| + ReInsertingInDocumentCollectsControls) {
|
| + EXPECT_EQ(video(), nullptr);
|
| + document().body()->setInnerHTML("<body><video controls></video></body>");
|
| + EXPECT_NE(video(), nullptr);
|
| + EXPECT_TRUE(video()->hasEventListeners());
|
| + EXPECT_NE(controls(), nullptr);
|
| + EXPECT_TRUE(document().hasEventListeners());
|
| +
|
| + // This should be a no-op. We keep a reference on the VideoElement to avoid an
|
| + // unexpected GC.
|
| + {
|
| + Persistent<HTMLVideoElement> videoHolder = video();
|
| + document().body()->removeChild(video());
|
| + document().body()->appendChild(videoHolder.get());
|
| + }
|
| +
|
| + EXPECT_TRUE(document().hasEventListeners());
|
| + EXPECT_TRUE(video()->hasEventListeners());
|
| +
|
| + ThreadState::current()->collectAllGarbage();
|
| +
|
| + EXPECT_NE(video(), nullptr);
|
| + EXPECT_NE(controls(), nullptr);
|
| + EXPECT_EQ(controls(), video()->mediaControls());
|
| +}
|
| +
|
| +TEST_F(HTMLMediaElementEventListenersTest,
|
| + FullscreenDetectorTimerCancelledOnContextDestroy) {
|
| + EXPECT_EQ(video(), nullptr);
|
| + document().body()->setInnerHTML("<body><video></video</body>");
|
| + video()->setSrc("http://example.com");
|
| +
|
| + testing::runPendingTasks();
|
| +
|
| + EXPECT_NE(webMediaPlayer(), nullptr);
|
| +
|
| + // Set ReadyState as HaveMetadata and go fullscreen, so the timer is fired.
|
| + EXPECT_NE(video(), nullptr);
|
| + simulateReadyState(HTMLMediaElement::kHaveMetadata);
|
| + UserGestureIndicator gestureIndicator(
|
| + DocumentUserGestureToken::create(&document()));
|
| + Fullscreen::requestFullscreen(*video());
|
| + Fullscreen::from(document()).didEnterFullscreen();
|
| +
|
| + testing::runPendingTasks();
|
| +
|
| + Persistent<Document> persistentDocument = &document();
|
| + Persistent<MediaCustomControlsFullscreenDetector> detector =
|
| + fullscreenDetector();
|
| +
|
| + std::vector<bool> observedResults;
|
| +
|
| + ON_CALL(*webMediaPlayer(), setIsEffectivelyFullscreen(_))
|
| + .WillByDefault(Invoke(
|
| + [&](bool isFullscreen) { observedResults.push_back(isFullscreen); }));
|
| +
|
| + destroyDocument();
|
| +
|
| + testing::runPendingTasks();
|
| +
|
| + // Document should not have listeners as the ExecutionContext is destroyed.
|
| + EXPECT_FALSE(persistentDocument->hasEventListeners());
|
| + // The timer should be cancelled when the ExecutionContext is destroyed.
|
| + EXPECT_FALSE(isCheckViewportIntersectionTimerActive(detector));
|
| + // Should only notify the false value when ExecutionContext is destroyed.
|
| + EXPECT_EQ(1u, observedResults.size());
|
| + EXPECT_FALSE(observedResults[0]);
|
| +}
|
| +
|
| +} // namespace blink
|
|
|