blob: f5cf582b10afa5caa7f0638066d5ed9f6dee2da8 [file] [log] [blame]
// Copyright 2015 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 "config.h"
#include "core/dom/ScriptRunner.h"
#include "core/dom/Document.h"
#include "core/dom/Element.h"
#include "core/dom/ScriptLoader.h"
#include "platform/scheduler/CancellableTaskFactory.h"
#include "public/platform/Platform.h"
#include <gmock/gmock.h>
#include <gtest/gtest.h>
using ::testing::Invoke;
using ::testing::ElementsAre;
using ::testing::Return;
namespace blink {
class MockScriptLoader final : public ScriptLoader {
public:
static PassOwnPtrWillBeRawPtr<MockScriptLoader> create(Element* element)
{
return adoptPtrWillBeNoop(new MockScriptLoader(element));
}
~MockScriptLoader() override { }
MOCK_METHOD0(execute, void());
MOCK_CONST_METHOD0(isReady, bool());
private:
explicit MockScriptLoader(Element* element) : ScriptLoader(element, false, false)
{
}
};
class MockWebThread : public WebThread {
public:
explicit MockWebThread(WebScheduler* webScheduler) : m_webScheduler(webScheduler) { }
~MockWebThread() override { }
bool isCurrentThread() const override
{
ASSERT_NOT_REACHED();
return false;
}
PlatformThreadId threadId() const override
{
ASSERT_NOT_REACHED();
return 0;
}
WebTaskRunner* taskRunner() override
{
ASSERT_NOT_REACHED();
return nullptr;
}
void addTaskObserver(TaskObserver*) override { ASSERT_NOT_REACHED(); }
void removeTaskObserver(TaskObserver*) override { ASSERT_NOT_REACHED(); }
WebScheduler* scheduler() const override { return m_webScheduler; }
private:
WebScheduler* m_webScheduler;
};
class MockWebTaskRunner : public WebTaskRunner {
public:
explicit MockWebTaskRunner(Deque<OwnPtr<WebTaskRunner::Task>>* tasks) : m_tasks(tasks) { }
~MockWebTaskRunner() override { }
virtual void postTask(const WebTraceLocation&, Task* task)
{
m_tasks->append(adoptPtr(task));
}
void postDelayedTask(const WebTraceLocation&, Task* task, double delayMs) override
{
ASSERT_NOT_REACHED();
}
Deque<OwnPtr<WebTaskRunner::Task>>* m_tasks; // NOT OWNED
};
class MockPlatform : public Platform, private WebScheduler {
public:
MockPlatform()
: m_mockWebThread(this)
, m_mockWebTaskRunner(&m_tasks)
, m_shouldYield(false)
, m_shouldYieldEveryOtherTime(false) { }
void cryptographicallyRandomValues(unsigned char* buffer, size_t length) override { }
WebThread* currentThread() override { return &m_mockWebThread; }
WebTaskRunner* loadingTaskRunner() override
{
return &m_mockWebTaskRunner;
}
WebTaskRunner* timerTaskRunner() override
{
ASSERT_NOT_REACHED();
return nullptr;
}
void runSingleTask()
{
if (m_tasks.isEmpty())
return;
m_tasks.takeFirst()->run();
}
void runAllTasks()
{
while (!m_tasks.isEmpty())
m_tasks.takeFirst()->run();
}
bool shouldYieldForHighPriorityWork() override
{
if (m_shouldYieldEveryOtherTime)
m_shouldYield = !m_shouldYield;
return m_shouldYield;
}
void setShouldYield(bool shouldYield)
{
m_shouldYield = shouldYield;
}
// NOTE if we yield 100% of the time, nothing will get run.
void setShouldYieldEveryOtherTime(bool shouldYieldEveryOtherTime)
{
m_shouldYieldEveryOtherTime = shouldYieldEveryOtherTime;
}
private:
MockWebThread m_mockWebThread;
Deque<OwnPtr<WebTaskRunner::Task>> m_tasks;
MockWebTaskRunner m_mockWebTaskRunner;
bool m_shouldYield;
bool m_shouldYieldEveryOtherTime;
};
class ScriptRunnerTest : public testing::Test {
public:
void SetUp() override
{
m_document = Document::create();
m_element = m_document->createElement("foo", ASSERT_NO_EXCEPTION);
m_scriptRunner = ScriptRunner::create(m_document.get());
m_oldPlatform = Platform::current();
// Force Platform::initialize to create a new one pointing at MockPlatform.
Platform::initialize(&m_platform);
m_platform.setShouldYield(false);
m_platform.setShouldYieldEveryOtherTime(false);
}
void TearDown() override
{
m_scriptRunner.release();
Platform::initialize(m_oldPlatform);
}
RefPtrWillBePersistent<Document> m_document;
RefPtrWillBePersistent<Element> m_element;
OwnPtrWillBePersistent<ScriptRunner> m_scriptRunner;
std::vector<int> m_order; // gmock matchers don't work nicely with WTF::Vector
MockPlatform m_platform;
Platform* m_oldPlatform; // NOT OWNED
};
TEST_F(ScriptRunnerTest, QueueSingleScript_Async)
{
OwnPtrWillBeRawPtr<MockScriptLoader> scriptLoader = MockScriptLoader::create(m_element.get());
m_scriptRunner->queueScriptForExecution(scriptLoader.get(), ScriptRunner::ASYNC_EXECUTION);
m_scriptRunner->notifyScriptReady(scriptLoader.get(), ScriptRunner::ASYNC_EXECUTION);
EXPECT_CALL(*scriptLoader, execute());
m_platform.runAllTasks();
}
TEST_F(ScriptRunnerTest, QueueSingleScript_InOrder)
{
OwnPtrWillBeRawPtr<MockScriptLoader> scriptLoader = MockScriptLoader::create(m_element.get());
m_scriptRunner->queueScriptForExecution(scriptLoader.get(), ScriptRunner::IN_ORDER_EXECUTION);
m_scriptRunner->resume();
EXPECT_CALL(*scriptLoader, isReady()).WillOnce(Return(true));
EXPECT_CALL(*scriptLoader, execute());
m_platform.runAllTasks();
}
TEST_F(ScriptRunnerTest, QueueMultipleScripts_InOrder)
{
OwnPtrWillBeRawPtr<MockScriptLoader> scriptLoader1 = MockScriptLoader::create(m_element.get());
OwnPtrWillBeRawPtr<MockScriptLoader> scriptLoader2 = MockScriptLoader::create(m_element.get());
OwnPtrWillBeRawPtr<MockScriptLoader> scriptLoader3 = MockScriptLoader::create(m_element.get());
m_scriptRunner->queueScriptForExecution(scriptLoader1.get(), ScriptRunner::IN_ORDER_EXECUTION);
m_scriptRunner->queueScriptForExecution(scriptLoader2.get(), ScriptRunner::IN_ORDER_EXECUTION);
m_scriptRunner->queueScriptForExecution(scriptLoader3.get(), ScriptRunner::IN_ORDER_EXECUTION);
EXPECT_CALL(*scriptLoader1, execute()).WillOnce(Invoke([this] {
m_order.push_back(1);
}));
EXPECT_CALL(*scriptLoader2, execute()).WillOnce(Invoke([this] {
m_order.push_back(2);
}));
EXPECT_CALL(*scriptLoader3, execute()).WillOnce(Invoke([this] {
m_order.push_back(3);
}));
// Make the scripts become ready in reverse order.
bool isReady[] = { false, false, false };
EXPECT_CALL(*scriptLoader1, isReady()).WillRepeatedly(Invoke([&isReady] {
return isReady[0];
}));
EXPECT_CALL(*scriptLoader2, isReady()).WillRepeatedly(Invoke([&isReady] {
return isReady[1];
}));
EXPECT_CALL(*scriptLoader3, isReady()).WillRepeatedly(Invoke([&isReady] {
return isReady[2];
}));
for (int i = 2; i >= 0; i--) {
isReady[i] = true;
m_scriptRunner->resume();
m_platform.runAllTasks();
}
// But ensure the scripts were run in the expected order.
EXPECT_THAT(m_order, ElementsAre(1, 2, 3));
}
TEST_F(ScriptRunnerTest, QueueMixedScripts)
{
OwnPtrWillBeRawPtr<MockScriptLoader> scriptLoader1 = MockScriptLoader::create(m_element.get());
OwnPtrWillBeRawPtr<MockScriptLoader> scriptLoader2 = MockScriptLoader::create(m_element.get());
OwnPtrWillBeRawPtr<MockScriptLoader> scriptLoader3 = MockScriptLoader::create(m_element.get());
OwnPtrWillBeRawPtr<MockScriptLoader> scriptLoader4 = MockScriptLoader::create(m_element.get());
OwnPtrWillBeRawPtr<MockScriptLoader> scriptLoader5 = MockScriptLoader::create(m_element.get());
EXPECT_CALL(*scriptLoader1, isReady()).WillRepeatedly(Return(true));
EXPECT_CALL(*scriptLoader2, isReady()).WillRepeatedly(Return(true));
EXPECT_CALL(*scriptLoader3, isReady()).WillRepeatedly(Return(true));
m_scriptRunner->queueScriptForExecution(scriptLoader1.get(), ScriptRunner::IN_ORDER_EXECUTION);
m_scriptRunner->queueScriptForExecution(scriptLoader2.get(), ScriptRunner::IN_ORDER_EXECUTION);
m_scriptRunner->queueScriptForExecution(scriptLoader3.get(), ScriptRunner::IN_ORDER_EXECUTION);
m_scriptRunner->queueScriptForExecution(scriptLoader4.get(), ScriptRunner::ASYNC_EXECUTION);
m_scriptRunner->queueScriptForExecution(scriptLoader5.get(), ScriptRunner::ASYNC_EXECUTION);
m_scriptRunner->notifyScriptReady(scriptLoader4.get(), ScriptRunner::ASYNC_EXECUTION);
m_scriptRunner->notifyScriptReady(scriptLoader5.get(), ScriptRunner::ASYNC_EXECUTION);
EXPECT_CALL(*scriptLoader1, execute()).WillOnce(Invoke([this] {
m_order.push_back(1);
}));
EXPECT_CALL(*scriptLoader2, execute()).WillOnce(Invoke([this] {
m_order.push_back(2);
}));
EXPECT_CALL(*scriptLoader3, execute()).WillOnce(Invoke([this] {
m_order.push_back(3);
}));
EXPECT_CALL(*scriptLoader4, execute()).WillOnce(Invoke([this] {
m_order.push_back(4);
}));
EXPECT_CALL(*scriptLoader5, execute()).WillOnce(Invoke([this] {
m_order.push_back(5);
}));
m_platform.runAllTasks();
// Make sure the async scripts were run before the in-order ones.
EXPECT_THAT(m_order, ElementsAre(4, 5, 1, 2, 3));
}
TEST_F(ScriptRunnerTest, QueueMixedScripts_YieldAfterEveryExecution)
{
OwnPtrWillBeRawPtr<MockScriptLoader> scriptLoader1 = MockScriptLoader::create(m_element.get());
OwnPtrWillBeRawPtr<MockScriptLoader> scriptLoader2 = MockScriptLoader::create(m_element.get());
OwnPtrWillBeRawPtr<MockScriptLoader> scriptLoader3 = MockScriptLoader::create(m_element.get());
OwnPtrWillBeRawPtr<MockScriptLoader> scriptLoader4 = MockScriptLoader::create(m_element.get());
OwnPtrWillBeRawPtr<MockScriptLoader> scriptLoader5 = MockScriptLoader::create(m_element.get());
m_platform.setShouldYieldEveryOtherTime(true);
EXPECT_CALL(*scriptLoader1, isReady()).WillRepeatedly(Return(true));
EXPECT_CALL(*scriptLoader2, isReady()).WillRepeatedly(Return(true));
EXPECT_CALL(*scriptLoader3, isReady()).WillRepeatedly(Return(true));
m_scriptRunner->queueScriptForExecution(scriptLoader1.get(), ScriptRunner::IN_ORDER_EXECUTION);
m_scriptRunner->queueScriptForExecution(scriptLoader2.get(), ScriptRunner::IN_ORDER_EXECUTION);
m_scriptRunner->queueScriptForExecution(scriptLoader3.get(), ScriptRunner::IN_ORDER_EXECUTION);
m_scriptRunner->queueScriptForExecution(scriptLoader4.get(), ScriptRunner::ASYNC_EXECUTION);
m_scriptRunner->queueScriptForExecution(scriptLoader5.get(), ScriptRunner::ASYNC_EXECUTION);
m_scriptRunner->notifyScriptReady(scriptLoader4.get(), ScriptRunner::ASYNC_EXECUTION);
m_scriptRunner->notifyScriptReady(scriptLoader5.get(), ScriptRunner::ASYNC_EXECUTION);
EXPECT_CALL(*scriptLoader1, execute()).WillOnce(Invoke([this] {
m_order.push_back(1);
}));
EXPECT_CALL(*scriptLoader2, execute()).WillOnce(Invoke([this] {
m_order.push_back(2);
}));
EXPECT_CALL(*scriptLoader3, execute()).WillOnce(Invoke([this] {
m_order.push_back(3);
}));
EXPECT_CALL(*scriptLoader4, execute()).WillOnce(Invoke([this] {
m_order.push_back(4);
}));
EXPECT_CALL(*scriptLoader5, execute()).WillOnce(Invoke([this] {
m_order.push_back(5);
}));
m_platform.runAllTasks();
// Make sure the async scripts were run before the in-order ones.
EXPECT_THAT(m_order, ElementsAre(4, 5, 1, 2, 3));
}
TEST_F(ScriptRunnerTest, QueueReentrantScript_Async)
{
OwnPtrWillBeRawPtr<MockScriptLoader> scriptLoader1 = MockScriptLoader::create(m_element.get());
OwnPtrWillBeRawPtr<MockScriptLoader> scriptLoader2 = MockScriptLoader::create(m_element.get());
OwnPtrWillBeRawPtr<MockScriptLoader> scriptLoader3 = MockScriptLoader::create(m_element.get());
m_scriptRunner->queueScriptForExecution(scriptLoader1.get(), ScriptRunner::ASYNC_EXECUTION);
m_scriptRunner->queueScriptForExecution(scriptLoader2.get(), ScriptRunner::ASYNC_EXECUTION);
m_scriptRunner->queueScriptForExecution(scriptLoader3.get(), ScriptRunner::ASYNC_EXECUTION);
m_scriptRunner->notifyScriptReady(scriptLoader1.get(), ScriptRunner::ASYNC_EXECUTION);
MockScriptLoader* scriptLoader = scriptLoader2.get();
EXPECT_CALL(*scriptLoader1, execute()).WillOnce(Invoke([scriptLoader, this] {
m_order.push_back(1);
m_scriptRunner->notifyScriptReady(scriptLoader, ScriptRunner::ASYNC_EXECUTION);
}));
scriptLoader = scriptLoader3.get();
EXPECT_CALL(*scriptLoader2, execute()).WillOnce(Invoke([scriptLoader, this] {
m_order.push_back(2);
m_scriptRunner->notifyScriptReady(scriptLoader, ScriptRunner::ASYNC_EXECUTION);
}));
EXPECT_CALL(*scriptLoader3, execute()).WillOnce(Invoke([this] {
m_order.push_back(3);
}));
// Make sure that re-entrant calls to notifyScriptReady don't cause ScriptRunner::execute to do
// more work than expected.
m_platform.runSingleTask();
EXPECT_THAT(m_order, ElementsAre(1));
m_platform.runSingleTask();
EXPECT_THAT(m_order, ElementsAre(1, 2));
m_platform.runSingleTask();
EXPECT_THAT(m_order, ElementsAre(1, 2, 3));
}
TEST_F(ScriptRunnerTest, QueueReentrantScript_InOrder)
{
OwnPtrWillBeRawPtr<MockScriptLoader> scriptLoader1 = MockScriptLoader::create(m_element.get());
OwnPtrWillBeRawPtr<MockScriptLoader> scriptLoader2 = MockScriptLoader::create(m_element.get());
OwnPtrWillBeRawPtr<MockScriptLoader> scriptLoader3 = MockScriptLoader::create(m_element.get());
EXPECT_CALL(*scriptLoader1, isReady()).WillRepeatedly(Return(true));
EXPECT_CALL(*scriptLoader2, isReady()).WillRepeatedly(Return(true));
EXPECT_CALL(*scriptLoader3, isReady()).WillRepeatedly(Return(true));
m_scriptRunner->queueScriptForExecution(scriptLoader1.get(), ScriptRunner::IN_ORDER_EXECUTION);
m_scriptRunner->resume();
MockScriptLoader* scriptLoader = scriptLoader2.get();
EXPECT_CALL(*scriptLoader1, execute()).WillOnce(Invoke([scriptLoader, this] {
m_order.push_back(1);
m_scriptRunner->queueScriptForExecution(scriptLoader, ScriptRunner::IN_ORDER_EXECUTION);
m_scriptRunner->resume();
}));
scriptLoader = scriptLoader3.get();
EXPECT_CALL(*scriptLoader2, execute()).WillOnce(Invoke([scriptLoader, this] {
m_order.push_back(2);
m_scriptRunner->queueScriptForExecution(scriptLoader, ScriptRunner::IN_ORDER_EXECUTION);
m_scriptRunner->resume();
}));
EXPECT_CALL(*scriptLoader3, execute()).WillOnce(Invoke([this] {
m_order.push_back(3);
}));
// Make sure that re-entrant calls to queueScriptForExecution don't cause ScriptRunner::execute to do
// more work than expected.
m_platform.runSingleTask();
EXPECT_THAT(m_order, ElementsAre(1));
m_platform.runSingleTask();
EXPECT_THAT(m_order, ElementsAre(1, 2));
m_platform.runSingleTask();
EXPECT_THAT(m_order, ElementsAre(1, 2, 3));
}
TEST_F(ScriptRunnerTest, ShouldYield_AsyncScripts)
{
OwnPtrWillBeRawPtr<MockScriptLoader> scriptLoader1 = MockScriptLoader::create(m_element.get());
OwnPtrWillBeRawPtr<MockScriptLoader> scriptLoader2 = MockScriptLoader::create(m_element.get());
OwnPtrWillBeRawPtr<MockScriptLoader> scriptLoader3 = MockScriptLoader::create(m_element.get());
m_scriptRunner->queueScriptForExecution(scriptLoader1.get(), ScriptRunner::ASYNC_EXECUTION);
m_scriptRunner->queueScriptForExecution(scriptLoader2.get(), ScriptRunner::ASYNC_EXECUTION);
m_scriptRunner->queueScriptForExecution(scriptLoader3.get(), ScriptRunner::ASYNC_EXECUTION);
m_scriptRunner->notifyScriptReady(scriptLoader1.get(), ScriptRunner::ASYNC_EXECUTION);
m_scriptRunner->notifyScriptReady(scriptLoader2.get(), ScriptRunner::ASYNC_EXECUTION);
m_scriptRunner->notifyScriptReady(scriptLoader3.get(), ScriptRunner::ASYNC_EXECUTION);
EXPECT_CALL(*scriptLoader1, execute()).WillOnce(Invoke([this] {
m_order.push_back(1);
m_platform.setShouldYield(true);
}));
EXPECT_CALL(*scriptLoader2, execute()).WillOnce(Invoke([this] {
m_order.push_back(2);
}));
EXPECT_CALL(*scriptLoader3, execute()).WillOnce(Invoke([this] {
m_order.push_back(3);
}));
m_platform.runSingleTask();
EXPECT_THAT(m_order, ElementsAre(1));
// Make sure the interrupted tasks are executed next 'tick'.
m_platform.setShouldYield(false);
m_platform.runSingleTask();
EXPECT_THAT(m_order, ElementsAre(1, 2, 3));
}
TEST_F(ScriptRunnerTest, QueueReentrantScript_ManyAsyncScripts)
{
OwnPtrWillBeRawPtr<MockScriptLoader> scriptLoaders[20];
for (int i = 0; i < 20; i++)
scriptLoaders[i] = nullptr;
for (int i = 0; i < 20; i++) {
scriptLoaders[i] = MockScriptLoader::create(m_element.get());
EXPECT_CALL(*scriptLoaders[i], isReady()).WillRepeatedly(Return(true));
m_scriptRunner->queueScriptForExecution(scriptLoaders[i].get(), ScriptRunner::ASYNC_EXECUTION);
if (i > 0) {
EXPECT_CALL(*scriptLoaders[i], execute()).WillOnce(Invoke([this, i] {
m_order.push_back(i);
}));
}
}
m_scriptRunner->notifyScriptReady(scriptLoaders[0].get(), ScriptRunner::ASYNC_EXECUTION);
m_scriptRunner->notifyScriptReady(scriptLoaders[1].get(), ScriptRunner::ASYNC_EXECUTION);
m_scriptRunner->resume();
EXPECT_CALL(*scriptLoaders[0], execute()).WillOnce(Invoke([&scriptLoaders, this] {
for (int i = 2; i < 20; i++)
m_scriptRunner->notifyScriptReady(scriptLoaders[i].get(), ScriptRunner::ASYNC_EXECUTION);
m_scriptRunner->resume();
m_order.push_back(0);
}));
m_platform.runAllTasks();
int expected[] = {
0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19
};
EXPECT_THAT(m_order, testing::ElementsAreArray(expected));
}
TEST_F(ScriptRunnerTest, ShouldYield_InOrderScripts)
{
OwnPtrWillBeRawPtr<MockScriptLoader> scriptLoader1 = MockScriptLoader::create(m_element.get());
OwnPtrWillBeRawPtr<MockScriptLoader> scriptLoader2 = MockScriptLoader::create(m_element.get());
OwnPtrWillBeRawPtr<MockScriptLoader> scriptLoader3 = MockScriptLoader::create(m_element.get());
EXPECT_CALL(*scriptLoader1, isReady()).WillRepeatedly(Return(true));
EXPECT_CALL(*scriptLoader2, isReady()).WillRepeatedly(Return(true));
EXPECT_CALL(*scriptLoader3, isReady()).WillRepeatedly(Return(true));
m_scriptRunner->queueScriptForExecution(scriptLoader1.get(), ScriptRunner::IN_ORDER_EXECUTION);
m_scriptRunner->queueScriptForExecution(scriptLoader2.get(), ScriptRunner::IN_ORDER_EXECUTION);
m_scriptRunner->queueScriptForExecution(scriptLoader3.get(), ScriptRunner::IN_ORDER_EXECUTION);
m_scriptRunner->resume();
EXPECT_CALL(*scriptLoader1, execute()).WillOnce(Invoke([this] {
m_order.push_back(1);
m_platform.setShouldYield(true);
}));
EXPECT_CALL(*scriptLoader2, execute()).WillOnce(Invoke([this] {
m_order.push_back(2);
}));
EXPECT_CALL(*scriptLoader3, execute()).WillOnce(Invoke([this] {
m_order.push_back(3);
}));
m_platform.runSingleTask();
EXPECT_THAT(m_order, ElementsAre(1));
// Make sure the interrupted tasks are executed next 'tick'.
m_platform.setShouldYield(false);
m_platform.runSingleTask();
EXPECT_THAT(m_order, ElementsAre(1, 2, 3));
}
TEST_F(ScriptRunnerTest, ShouldYield_RunsAtLastOneTask_AsyncScripts)
{
OwnPtrWillBeRawPtr<MockScriptLoader> scriptLoader1 = MockScriptLoader::create(m_element.get());
OwnPtrWillBeRawPtr<MockScriptLoader> scriptLoader2 = MockScriptLoader::create(m_element.get());
OwnPtrWillBeRawPtr<MockScriptLoader> scriptLoader3 = MockScriptLoader::create(m_element.get());
m_scriptRunner->queueScriptForExecution(scriptLoader1.get(), ScriptRunner::ASYNC_EXECUTION);
m_scriptRunner->queueScriptForExecution(scriptLoader2.get(), ScriptRunner::ASYNC_EXECUTION);
m_scriptRunner->queueScriptForExecution(scriptLoader3.get(), ScriptRunner::ASYNC_EXECUTION);
m_scriptRunner->notifyScriptReady(scriptLoader1.get(), ScriptRunner::ASYNC_EXECUTION);
m_scriptRunner->notifyScriptReady(scriptLoader2.get(), ScriptRunner::ASYNC_EXECUTION);
m_scriptRunner->notifyScriptReady(scriptLoader3.get(), ScriptRunner::ASYNC_EXECUTION);
m_platform.setShouldYield(true);
EXPECT_CALL(*scriptLoader1, execute()).Times(1);
EXPECT_CALL(*scriptLoader2, execute()).Times(0);
EXPECT_CALL(*scriptLoader3, execute()).Times(0);
m_platform.runSingleTask();
// We can't safely distruct ScriptRunner with unexecuted MockScriptLoaders (real ScriptLoader is fine) so drain them.
testing::Mock::VerifyAndClear(scriptLoader2.get());
testing::Mock::VerifyAndClear(scriptLoader3.get());
EXPECT_CALL(*scriptLoader2, execute()).Times(1);
EXPECT_CALL(*scriptLoader3, execute()).Times(1);
m_platform.runAllTasks();
}
TEST_F(ScriptRunnerTest, ShouldYield_RunsAtLastOneTask_InOrderScripts)
{
OwnPtrWillBeRawPtr<MockScriptLoader> scriptLoader1 = MockScriptLoader::create(m_element.get());
OwnPtrWillBeRawPtr<MockScriptLoader> scriptLoader2 = MockScriptLoader::create(m_element.get());
OwnPtrWillBeRawPtr<MockScriptLoader> scriptLoader3 = MockScriptLoader::create(m_element.get());
EXPECT_CALL(*scriptLoader1, isReady()).WillRepeatedly(Return(true));
EXPECT_CALL(*scriptLoader2, isReady()).WillRepeatedly(Return(true));
EXPECT_CALL(*scriptLoader3, isReady()).WillRepeatedly(Return(true));
m_scriptRunner->queueScriptForExecution(scriptLoader1.get(), ScriptRunner::IN_ORDER_EXECUTION);
m_scriptRunner->queueScriptForExecution(scriptLoader2.get(), ScriptRunner::IN_ORDER_EXECUTION);
m_scriptRunner->queueScriptForExecution(scriptLoader3.get(), ScriptRunner::IN_ORDER_EXECUTION);
m_scriptRunner->resume();
m_platform.setShouldYield(true);
EXPECT_CALL(*scriptLoader1, execute()).Times(1);
EXPECT_CALL(*scriptLoader2, execute()).Times(0);
EXPECT_CALL(*scriptLoader3, execute()).Times(0);
m_platform.runSingleTask();
// We can't safely distruct ScriptRunner with unexecuted MockScriptLoaders (real ScriptLoader is fine) so drain them.
testing::Mock::VerifyAndClear(scriptLoader2.get());
testing::Mock::VerifyAndClear(scriptLoader3.get());
EXPECT_CALL(*scriptLoader2, execute()).Times(1);
EXPECT_CALL(*scriptLoader3, execute()).Times(1);
EXPECT_CALL(*scriptLoader2, isReady()).WillRepeatedly(Return(true));
EXPECT_CALL(*scriptLoader3, isReady()).WillRepeatedly(Return(true));
m_platform.runAllTasks();
}
} // namespace blink