Index: content/common/startup_task_runner_unittest.cc |
diff --git a/content/common/startup_task_runner_unittest.cc b/content/common/startup_task_runner_unittest.cc |
new file mode 100644 |
index 0000000000000000000000000000000000000000..7a9ffc065f4d284083cfb58ba501445679fe8b5b |
--- /dev/null |
+++ b/content/common/startup_task_runner_unittest.cc |
@@ -0,0 +1,200 @@ |
+// Copyright (c) 2013 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 "content/public/common/startup_task_runner.h" |
+ |
+#include "base/bind.h" |
+#include "base/callback.h" |
+#include "base/location.h" |
+#include "base/run_loop.h" |
+#include "base/task_runner.h" |
+ |
+#include "testing/gmock/include/gmock/gmock.h" |
+#include "testing/gtest/include/gtest/gtest.h" |
+ |
+namespace content { |
+namespace { |
+ |
+using base::Closure; |
+using testing::_; |
+using testing::Assign; |
+using testing::Invoke; |
+using testing::WithArg; |
+ |
+class StartupTaskRunnerTest : public testing::Test { |
+ private: |
+ |
+ int last_task_; |
+ |
+ public: |
+ |
+ virtual void SetUp() { last_task_ = 0; } |
+ |
+ void Task1() { last_task_ = 1; } |
+ |
+ void Task2() { last_task_ = 2; } |
+ |
+ int GetLastTask() { return last_task_; } |
+}; |
+ |
+class MockObserver : public StartupTaskRunner::Observer { |
+ public: |
+ MOCK_METHOD0(AllStartupTasksRan, void()); |
+}; |
+ |
+// We can't use the real message loop, even if we want to, since doing so on |
+// Android requires a complex Java infrastructure. The test would have to built |
+// as a content_shell test; but content_shell startup invokes the class we are |
+// trying to test. |
+// |
+// The mocks are not directly in TaskRunnerProxy because reference counted |
+// objects seem to confuse the mocking framework |
+ |
+class MockTaskRunner { |
+ public: |
+ MOCK_METHOD3( |
+ PostDelayedTask, |
+ bool(const tracked_objects::Location&, const Closure&, base::TimeDelta)); |
+ MOCK_METHOD3( |
+ PostNonNestableDelayedTask, |
+ bool(const tracked_objects::Location&, const Closure&, base::TimeDelta)); |
+}; |
+ |
+class TaskRunnerProxy : public base::SingleThreadTaskRunner { |
+ public: |
+ TaskRunnerProxy(MockTaskRunner* mock) : mock_(mock) {} |
+ bool RunsTasksOnCurrentThread() const { return true; } |
+ bool PostDelayedTask(const tracked_objects::Location& location, |
+ const Closure& closure, |
+ base::TimeDelta delta) { |
+ return mock_->PostDelayedTask(location, closure, delta); |
+ } |
+ bool PostNonNestableDelayedTask(const tracked_objects::Location& location, |
+ const Closure& closure, |
+ base::TimeDelta delta) { |
+ return mock_->PostNonNestableDelayedTask(location, closure, delta); |
+ } |
+ |
+ private: |
+ MockTaskRunner* mock_; |
+}; |
+ |
+TEST_F(StartupTaskRunnerTest, ImmediateExecution) { |
+ |
+ MockTaskRunner mock_runner; |
+ scoped_refptr<TaskRunnerProxy> proxy = new TaskRunnerProxy(&mock_runner); |
+ |
+ EXPECT_CALL(mock_runner, PostDelayedTask(_, _, _)).Times(0); |
+ EXPECT_CALL(mock_runner, PostNonNestableDelayedTask(_, _, _)).Times(0); |
+ |
+ scoped_refptr<StartupTaskRunner> runner = |
+ new StartupTaskRunner(StartupTaskRunner::IMMEDIATE, NULL); |
+ |
+ runner->SetProxy(proxy); |
+ |
+ base::Closure task1 = |
+ base::Bind(&StartupTaskRunnerTest::Task1, base::Unretained(this)); |
+ runner->AddTask(task1); |
+ EXPECT_EQ(GetLastTask(), 0); |
+ base::Closure task2 = |
+ base::Bind(&StartupTaskRunnerTest::Task2, base::Unretained(this)); |
+ runner->AddTask(task2); |
+ |
+ // Nothing should run until we tell them to. |
+ EXPECT_EQ(GetLastTask(), 0); |
+ runner->StartRunningTasks(); |
+ |
+ // On an immediate StartupTaskRunner the tasks should now all have run. |
+ EXPECT_EQ(GetLastTask(), 2); |
+} |
+ |
+TEST_F(StartupTaskRunnerTest, ImmediateExecutionObserved) { |
+ MockTaskRunner mock_runner; |
+ scoped_refptr<TaskRunnerProxy> proxy = new TaskRunnerProxy(&mock_runner); |
+ |
+ MockObserver observer; |
+ EXPECT_CALL(observer, AllStartupTasksRan()).Times(1); |
+ |
+ EXPECT_CALL(mock_runner, PostDelayedTask(_, _, _)).Times(0); |
+ EXPECT_CALL(mock_runner, PostNonNestableDelayedTask(_, _, _)).Times(0); |
+ |
+ scoped_refptr<StartupTaskRunner> runner = |
+ new StartupTaskRunner(StartupTaskRunner::IMMEDIATE, &observer); |
+ |
+ runner->SetProxy(proxy); |
+ |
+ base::Closure task1 = |
+ base::Bind(&StartupTaskRunnerTest::Task1, base::Unretained(this)); |
+ runner->AddTask(task1); |
+ EXPECT_EQ(GetLastTask(), 0); |
+ base::Closure task2 = |
+ base::Bind(&StartupTaskRunnerTest::Task2, base::Unretained(this)); |
+ runner->AddTask(task2); |
+ |
+ // Nothing should run until we tell them to. |
+ EXPECT_EQ(GetLastTask(), 0); |
+ runner->StartRunningTasks(); |
+ |
+ // On an immediate StartupTaskRunner the tasks should now all have run. |
+ EXPECT_EQ(GetLastTask(), 2); |
+} |
+ |
+base::Closure task; |
+ |
+// I couldn't get gMock's SaveArg to compile, hence had to save the argument |
+// this way |
+bool SaveTaskArg(const Closure& arg) { |
+ task = arg; |
+ return true; |
+} |
+ |
+TEST_F(StartupTaskRunnerTest, IncrementalExecution) { |
+ |
+ MockTaskRunner mock_runner; |
+ scoped_refptr<TaskRunnerProxy> proxy = new TaskRunnerProxy(&mock_runner); |
+ |
+ bool done = false; |
+ ; |
+ |
+ MockObserver observer; |
+ |
+ EXPECT_CALL(observer, AllStartupTasksRan()).WillOnce(Assign(&done, true)); |
+ EXPECT_CALL(mock_runner, PostDelayedTask(_, _, _)).Times(0); |
+ EXPECT_CALL( |
+ mock_runner, |
+ PostNonNestableDelayedTask(_, _, base::TimeDelta::FromMilliseconds(0))) |
+ .Times(3).WillRepeatedly(WithArg<1>(Invoke(SaveTaskArg))); |
+ |
+ scoped_refptr<StartupTaskRunner> runner = |
+ new StartupTaskRunner(StartupTaskRunner::INCREMENTAL, &observer); |
+ |
+ runner->SetProxy(proxy); |
+ |
+ base::Closure task1 = |
+ base::Bind(&StartupTaskRunnerTest::Task1, base::Unretained(this)); |
+ runner->AddTask(task1); |
+ base::Closure task2 = |
+ base::Bind(&StartupTaskRunnerTest::Task2, base::Unretained(this)); |
+ runner->AddTask(task2); |
+ |
+ // Nothing should run until we tell them to. |
+ EXPECT_EQ(GetLastTask(), 0); |
+ runner->StartRunningTasks(); |
+ |
+ // No tasks should have run yet, since we the message loop hasn't run. |
+ EXPECT_EQ(GetLastTask(), 0); |
+ |
+ // Fake the actual message loop. Each time a task is run a new task should |
+ // be added to the queue, hence updating "task". The loop should actually run |
+ // three times, the "4" is a backstop. |
+ for (int i = 0; i < 4 && !done; i++) { |
+ task.Run(); |
+ if (!done) { |
+ EXPECT_EQ(i + 1, GetLastTask()); |
+ } |
+ } |
+} |
+ |
+} // namespace |
+} // namespace content |