Index: components/scheduler/promises/single_thread_promise_executor_unittest.cc |
diff --git a/components/scheduler/promises/single_thread_promise_executor_unittest.cc b/components/scheduler/promises/single_thread_promise_executor_unittest.cc |
new file mode 100644 |
index 0000000000000000000000000000000000000000..62cbe00c315aeb321eaf73b0d21069a13050e090 |
--- /dev/null |
+++ b/components/scheduler/promises/single_thread_promise_executor_unittest.cc |
@@ -0,0 +1,934 @@ |
+// Copyright 2016 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 "components/scheduler/promises/single_thread_promise_executor.h" |
+ |
+#include "base/test/simple_test_tick_clock.h" |
+#include "cc/test/ordered_simple_task_runner.h" |
+#include "components/scheduler/base/task_queue_manager.h" |
+#include "components/scheduler/base/test_time_source.h" |
+#include "components/scheduler/child/scheduler_tqm_delegate_for_test.h" |
+#include "testing/gmock/include/gmock/gmock.h" |
+#include "testing/gtest/include/gtest/gtest.h" |
+ |
+using testing::ElementsAre; |
+using testing::WhenSorted; |
+ |
+namespace promise { |
+ |
+class SingleThreadPromiseExecutorTest : public testing::Test { |
+ public: |
+ SingleThreadPromiseExecutorTest() {} |
+ ~SingleThreadPromiseExecutorTest() override {} |
+ |
+ void SetUp() override { |
+ clock_.reset(new base::SimpleTestTickClock()); |
+ clock_->Advance(base::TimeDelta::FromMicroseconds(5000)); |
+ |
+ test_time_source_.reset(new scheduler::TestTimeSource(clock_.get())); |
+ mock_task_runner_ = make_scoped_refptr( |
+ new cc::OrderedSimpleTaskRunner(clock_.get(), false)); |
+ main_task_runner_ = scheduler::SchedulerTqmDelegateForTest::Create( |
+ mock_task_runner_, |
+ make_scoped_ptr(new scheduler::TestTimeSource(clock_.get()))); |
+ manager_ = make_scoped_ptr(new scheduler::TaskQueueManager( |
+ main_task_runner_, "test.scheduler", "test.scheduler", |
+ "test.scheduler.debug")); |
+ task_runner_ = |
+ manager_->NewTaskQueue(scheduler::TaskQueue::Spec("task_runner")); |
+ promise_executor_.reset( |
+ new internal::SingleThreadPromiseExecutor(task_runner_)); |
+ } |
+ |
+ scoped_ptr<base::SimpleTestTickClock> clock_; |
+ scoped_ptr<scheduler::TestTimeSource> test_time_source_; |
+ scoped_refptr<cc::OrderedSimpleTaskRunner> mock_task_runner_; |
+ scoped_refptr<scheduler::SchedulerTqmDelegate> main_task_runner_; |
+ scoped_ptr<scheduler::TaskQueueManager> manager_; |
+ scoped_refptr<scheduler::TaskQueue> task_runner_; |
+ scoped_ptr<internal::SingleThreadPromiseExecutor> promise_executor_; |
+}; |
+ |
+namespace { |
+bool ReturnTrue() { |
+ return true; |
+} |
+ |
+int ReturnOne() { |
+ return 1; |
+} |
+ |
+int ReturnTwo() { |
+ return 2; |
+} |
+ |
+int ReturnTen() { |
+ return 10; |
+} |
+ |
+int Add(int i, int j) { |
+ return i + j; |
+} |
+ |
+int CondTimesThree(int i, bool do_smth) { |
+ if (do_smth) |
+ return i * 3; |
+ return i; |
+} |
+ |
+int ReturnZero() { |
+ return 0; |
+} |
+ |
+void RecordParam(int* out, int in) { |
+ *out = in; |
+} |
+ |
+Promise<int> Choose(Promise<int> p1, Promise<int> p2, int i) { |
+ return i ? p1 : p2; |
+} |
+ |
+void RecordOrder(int value, std::vector<int>* out_result) { |
+ out_result->push_back(value); |
+} |
+ |
+} // namespace |
+ |
+TEST_F(SingleThreadPromiseExecutorTest, NonVoidPromise) { |
+ Promise<int> promise(promise::Create(base::Bind(&ReturnOne))); |
+ |
+ promise_executor_->StartResolve(promise); |
+ mock_task_runner_->RunUntilIdle(); |
+ EXPECT_EQ(1, promise.GetResolved()); |
+} |
+ |
+TEST_F(SingleThreadPromiseExecutorTest, AssignPromise) { |
+ Promise<int> promise = promise::Create(base::Bind(&ReturnOne)); |
+ |
+ promise_executor_->StartResolve(promise); |
+ mock_task_runner_->RunUntilIdle(); |
+ EXPECT_EQ(1, promise.GetResolved()); |
+} |
+ |
+TEST_F(SingleThreadPromiseExecutorTest, Then) { |
+ Promise<int> promise( |
+ promise::Create(base::Bind(&ReturnOne)).Then(base::Bind(&Add, 1))); |
+ |
+ promise_executor_->StartResolve(promise); |
+ mock_task_runner_->RunUntilIdle(); |
+ EXPECT_EQ(2, promise.GetResolved()); |
+} |
+ |
+TEST_F(SingleThreadPromiseExecutorTest, AssignThen) { |
+ Promise<int> promise = |
+ promise::Create(base::Bind(&ReturnOne)).Then(base::Bind(&Add, 1)); |
+ |
+ promise_executor_->StartResolve(promise); |
+ mock_task_runner_->RunUntilIdle(); |
+ EXPECT_EQ(2, promise.GetResolved()); |
+} |
+ |
+TEST_F(SingleThreadPromiseExecutorTest, ThenVoid) { |
+ int value = 0; |
+ Promise<void> promise(promise::Create(base::Bind(&ReturnOne)) |
+ .Then(base::Bind(&RecordParam, &value))); |
+ |
+ promise_executor_->StartResolve(promise); |
+ mock_task_runner_->RunUntilIdle(); |
+ EXPECT_EQ(1, value); |
+} |
+ |
+TEST_F(SingleThreadPromiseExecutorTest, VoidThenVoid) { |
+ int value = 0; |
+ int value2 = 0; |
+ Promise<void> promise(promise::Create(base::Bind(&RecordParam, &value, 1)) |
+ .Then(base::Bind(&RecordParam, &value2, 2))); |
+ |
+ promise_executor_->StartResolve(promise); |
+ mock_task_runner_->RunUntilIdle(); |
+ EXPECT_EQ(1, value); |
+ EXPECT_EQ(2, value2); |
+} |
+ |
+TEST_F(SingleThreadPromiseExecutorTest, VoidThenInt) { |
+ int value = 0; |
+ Promise<int> promise(promise::Create(base::Bind(&RecordParam, &value, 2)) |
+ .Then(base::Bind(&ReturnOne))); |
+ |
+ promise_executor_->StartResolve(promise); |
+ mock_task_runner_->RunUntilIdle(); |
+ EXPECT_EQ(2, value); |
+ EXPECT_EQ(1, promise.GetResolved()); |
+} |
+ |
+TEST_F(SingleThreadPromiseExecutorTest, ThenChaining) { |
+ Promise<int> promise(promise::Create(base::Bind(&ReturnOne)) |
+ .Then(base::Bind(&Add, 1)) |
+ .Then(base::Bind(&Add, 1)) |
+ .Then(base::Bind(&Add, 1))); |
+ |
+ promise_executor_->StartResolve(promise); |
+ mock_task_runner_->RunUntilIdle(); |
+ EXPECT_EQ(4, promise.GetResolved()); |
+} |
+ |
+TEST_F(SingleThreadPromiseExecutorTest, PromiseReuse) { |
+ Promise<int> promise10(promise::Create(base::Bind(&ReturnTen))); |
+ Promise<int> promise11(promise10.Then(base::Bind(&Add, 1))); |
+ Promise<int> promise12(promise10.Then(base::Bind(&Add, 2))); |
+ Promise<int> promise13(promise10.Then(base::Bind(&Add, 3))); |
+ Promise<int> promise14(promise10.Then(base::Bind(&Add, 4))); |
+ |
+ promise_executor_->StartResolve(promise11); |
+ promise_executor_->StartResolve(promise12); |
+ promise_executor_->StartResolve(promise13); |
+ promise_executor_->StartResolve(promise14); |
+ mock_task_runner_->RunUntilIdle(); |
+ |
+ EXPECT_EQ(11, promise11.GetResolved()); |
+ EXPECT_EQ(12, promise12.GetResolved()); |
+ EXPECT_EQ(13, promise13.GetResolved()); |
+ EXPECT_EQ(14, promise14.GetResolved()); |
+} |
+ |
+TEST_F(SingleThreadPromiseExecutorTest, PromiseReuseResolvedPromise_TypeOne) { |
+ Promise<int> promise10(promise::Create(10)); |
+ Promise<int> promise11(promise10.Then(base::Bind(&Add, 1))); |
+ Promise<int> promise12(promise10.Then(base::Bind(&Add, 2))); |
+ Promise<int> promise13(promise10.Then(base::Bind(&Add, 3))); |
+ Promise<int> promise14(promise10.Then(base::Bind(&Add, 4))); |
+ |
+ promise_executor_->StartResolve(promise11); |
+ promise_executor_->StartResolve(promise12); |
+ promise_executor_->StartResolve(promise13); |
+ promise_executor_->StartResolve(promise14); |
+ mock_task_runner_->RunUntilIdle(); |
+ |
+ EXPECT_EQ(11, promise11.GetResolved()); |
+ EXPECT_EQ(12, promise12.GetResolved()); |
+ EXPECT_EQ(13, promise13.GetResolved()); |
+ EXPECT_EQ(14, promise14.GetResolved()); |
+} |
+ |
+TEST_F(SingleThreadPromiseExecutorTest, PromiseReuseResolvedPromise_TypeTwo) { |
+ Promise<int> promise10(promise::Create(10)); |
+ Promise<int> promise11(promise10.Then(base::Bind(&Add, 1))); |
+ Promise<int> promise12(promise10.Then(base::Bind(&Add, 2))); |
+ Promise<int> promise13(promise10.Then(base::Bind(&Add, 3))); |
+ Promise<int> promise14(promise10.Then(base::Bind(&Add, 4))); |
+ |
+ promise_executor_->StartResolve(promise10); |
+ mock_task_runner_->RunUntilIdle(); |
+ |
+ promise_executor_->StartResolve(promise11); |
+ promise_executor_->StartResolve(promise12); |
+ promise_executor_->StartResolve(promise13); |
+ promise_executor_->StartResolve(promise14); |
+ mock_task_runner_->RunUntilIdle(); |
+ |
+ EXPECT_EQ(11, promise11.GetResolved()); |
+ EXPECT_EQ(12, promise12.GetResolved()); |
+ EXPECT_EQ(13, promise13.GetResolved()); |
+ EXPECT_EQ(14, promise14.GetResolved()); |
+} |
+ |
+TEST_F(SingleThreadPromiseExecutorTest, AllThen) { |
+ Promise<int> promise(promise::All(promise::Create(base::Bind(&ReturnOne)), |
+ promise::Create(base::Bind(&ReturnTrue))) |
+ .Then(base::Bind(&CondTimesThree))); |
+ |
+ promise_executor_->StartResolve(promise); |
+ mock_task_runner_->RunUntilIdle(); |
+ EXPECT_EQ(3, promise.GetResolved()); |
+} |
+ |
+TEST_F(SingleThreadPromiseExecutorTest, AssignAllThen) { |
+ Promise<int> promise = promise::All(promise::Create(base::Bind(&ReturnOne)), |
+ promise::Create(base::Bind(&ReturnTrue))) |
+ .Then(base::Bind(&CondTimesThree)); |
+ |
+ promise_executor_->StartResolve(promise); |
+ mock_task_runner_->RunUntilIdle(); |
+ EXPECT_EQ(3, promise.GetResolved()); |
+} |
+ |
+TEST_F(SingleThreadPromiseExecutorTest, EagerTasksExecutedFirst) { |
+ std::vector<int> run_order; |
+ |
+ Promise<void> promiseA( |
+ promise::Create(base::Bind(&RecordOrder, 0, &run_order)) |
+ .Then(base::Bind(&RecordOrder, 1, &run_order)) |
+ .Then(base::Bind(&RecordOrder, 2, &run_order)) |
+ .Then(base::Bind(&RecordOrder, 3, &run_order)) |
+ .Then(base::Bind(&RecordOrder, 4, &run_order))); |
+ |
+ Promise<void> promiseB( |
+ promise::Create(base::Bind(&RecordOrder, 10, &run_order)) |
+ .Then(base::Bind(&RecordOrder, 11, &run_order)) |
+ .Then(base::Bind(&RecordOrder, 12, &run_order)) |
+ .Then(base::Bind(&RecordOrder, 13, &run_order)) |
+ .Then(base::Bind(&RecordOrder, 14, &run_order))); |
+ |
+ promiseB.SetEager(true); |
+ |
+ promise_executor_->StartResolve(promiseA); |
+ promise_executor_->StartResolve(promiseB); |
+ mock_task_runner_->RunUntilIdle(); |
+ |
+ EXPECT_THAT(run_order, ElementsAre(10, 11, 12, 13, 14, 0, 1, 2, 3, 4)); |
+} |
+ |
+TEST_F(SingleThreadPromiseExecutorTest, DynamicChangingOfEagerness) { |
+ std::vector<int> run_order; |
+ |
+ Promise<void> promiseA( |
+ promise::Create(base::Bind(&RecordOrder, 0, &run_order)) |
+ .Then(base::Bind(&RecordOrder, 1, &run_order)) |
+ .Then(base::Bind(&RecordOrder, 2, &run_order)) |
+ .Then(base::Bind(&RecordOrder, 3, &run_order)) |
+ .Then(base::Bind(&RecordOrder, 4, &run_order))); |
+ |
+ Promise<void> promiseB( |
+ promise::Create(base::Bind(&RecordOrder, 10, &run_order)) |
+ .Then(base::Bind(&RecordOrder, 11, &run_order)) |
+ .Then(base::Bind(&RecordOrder, 12, &run_order)) |
+ .Then(base::Bind(&RecordOrder, 13, &run_order)) |
+ .Then(base::Bind(&RecordOrder, 14, &run_order))); |
+ |
+ promiseB.SetEager(true); |
+ |
+ promise_executor_->StartResolve(promiseA); |
+ promise_executor_->StartResolve(promiseB); |
+ |
+ promise_executor_->ResolveOnePromise(); |
+ |
+ promiseB.SetEager(false); |
+ promiseA.SetEager(true); |
+ |
+ mock_task_runner_->RunUntilIdle(); |
+ |
+ EXPECT_THAT(run_order, ElementsAre(10, 0, 1, 2, 3, 4, 11, 12, 13, 14)); |
+} |
+ |
+TEST_F(SingleThreadPromiseExecutorTest, MultipleThens) { |
+ std::vector<int> run_order; |
+ |
+ Promise<void> promiseA( |
+ promise::Create(base::Bind(&RecordOrder, 0, &run_order)) |
+ .Then(base::Bind(&RecordOrder, 1, &run_order))); |
+ |
+ Promise<void> promiseB(promiseA.Then(base::Bind(&RecordOrder, 2, &run_order)) |
+ .Then(base::Bind(&RecordOrder, 3, &run_order))); |
+ |
+ Promise<void> promiseC(promiseA.Then(base::Bind(&RecordOrder, 4, &run_order)) |
+ .Then(base::Bind(&RecordOrder, 5, &run_order))); |
+ |
+ promise_executor_->StartResolve(promiseB); |
+ promise_executor_->StartResolve(promiseC); |
+ mock_task_runner_->RunUntilIdle(); |
+ |
+ // The interleaving of promiseB and promiseC execution is undefined. |
+ EXPECT_THAT(run_order, WhenSorted(ElementsAre(0, 1, 2, 3, 4, 5))); |
+} |
+ |
+TEST_F(SingleThreadPromiseExecutorTest, Cancel) { |
+ std::vector<int> run_order; |
+ |
+ Promise<void> promise( |
+ promise::Create(base::Bind(&RecordOrder, 1, &run_order))); |
+ |
+ promise_executor_->StartResolve(promise); |
+ promise.Cancel(); |
+ |
+ mock_task_runner_->RunUntilIdle(); |
+ |
+ EXPECT_TRUE(run_order.empty()); |
+} |
+ |
+TEST_F(SingleThreadPromiseExecutorTest, CancelChainOfTasks) { |
+ std::vector<int> run_order; |
+ |
+ Promise<void> promiseA( |
+ promise::Create(base::Bind(&RecordOrder, 0, &run_order)) |
+ .Then(base::Bind(&RecordOrder, 1, &run_order)) |
+ .Then(base::Bind(&RecordOrder, 2, &run_order)) |
+ .Then(base::Bind(&RecordOrder, 3, &run_order)) |
+ .Then(base::Bind(&RecordOrder, 4, &run_order))); |
+ |
+ Promise<void> promiseB( |
+ promise::Create(base::Bind(&RecordOrder, 10, &run_order)) |
+ .Then(base::Bind(&RecordOrder, 11, &run_order)) |
+ .Then(base::Bind(&RecordOrder, 12, &run_order)) |
+ .Then(base::Bind(&RecordOrder, 13, &run_order)) |
+ .Then(base::Bind(&RecordOrder, 14, &run_order))); |
+ |
+ promise_executor_->StartResolve(promiseA); |
+ promise_executor_->StartResolve(promiseB); |
+ |
+ promiseB.Cancel(); |
+ |
+ mock_task_runner_->RunUntilIdle(); |
+ |
+ EXPECT_THAT(run_order, ElementsAre(0, 1, 2, 3, 4)); |
+} |
+ |
+TEST_F(SingleThreadPromiseExecutorTest, CancelOneBranch) { |
+ std::vector<int> run_order; |
+ |
+ Promise<void> promiseA( |
+ promise::Create(base::Bind(&RecordOrder, 0, &run_order)) |
+ .Then(base::Bind(&RecordOrder, 1, &run_order))); |
+ |
+ Promise<void> promiseB(promiseA.Then(base::Bind(&RecordOrder, 2, &run_order)) |
+ .Then(base::Bind(&RecordOrder, 3, &run_order))); |
+ |
+ Promise<void> promiseC(promiseA.Then(base::Bind(&RecordOrder, 4, &run_order)) |
+ .Then(base::Bind(&RecordOrder, 5, &run_order))); |
+ |
+ promise_executor_->StartResolve(promiseB); |
+ promise_executor_->StartResolve(promiseC); |
+ |
+ promiseB.Cancel(); |
+ |
+ mock_task_runner_->RunUntilIdle(); |
+ |
+ EXPECT_THAT(run_order, ElementsAre(0, 1, 4, 5)); |
+} |
+ |
+TEST_F(SingleThreadPromiseExecutorTest, CancelAndReresolve) { |
+ std::vector<int> run_order; |
+ |
+ Promise<void> promise( |
+ promise::Create(base::Bind(&RecordOrder, 1, &run_order))); |
+ |
+ promise_executor_->StartResolve(promise); |
+ promise.Cancel(); |
+ |
+ mock_task_runner_->RunUntilIdle(); |
+ |
+ EXPECT_TRUE(run_order.empty()); |
+ |
+ promise_executor_->StartResolve(promise); |
+ mock_task_runner_->RunUntilIdle(); |
+ |
+ EXPECT_THAT(run_order, ElementsAre(1)); |
+} |
+ |
+TEST_F(SingleThreadPromiseExecutorTest, CancelChainOfTasksAndReresolve) { |
+ std::vector<int> run_order; |
+ |
+ Promise<void> promiseA( |
+ promise::Create(base::Bind(&RecordOrder, 0, &run_order)) |
+ .Then(base::Bind(&RecordOrder, 1, &run_order)) |
+ .Then(base::Bind(&RecordOrder, 2, &run_order)) |
+ .Then(base::Bind(&RecordOrder, 3, &run_order)) |
+ .Then(base::Bind(&RecordOrder, 4, &run_order))); |
+ |
+ Promise<void> promiseB( |
+ promise::Create(base::Bind(&RecordOrder, 10, &run_order)) |
+ .Then(base::Bind(&RecordOrder, 11, &run_order)) |
+ .Then(base::Bind(&RecordOrder, 12, &run_order)) |
+ .Then(base::Bind(&RecordOrder, 13, &run_order)) |
+ .Then(base::Bind(&RecordOrder, 14, &run_order))); |
+ |
+ promise_executor_->StartResolve(promiseA); |
+ promise_executor_->StartResolve(promiseB); |
+ |
+ promiseB.Cancel(); |
+ |
+ mock_task_runner_->RunUntilIdle(); |
+ |
+ EXPECT_THAT(run_order, ElementsAre(0, 1, 2, 3, 4)); |
+ |
+ promise_executor_->StartResolve(promiseB); |
+ mock_task_runner_->RunUntilIdle(); |
+ |
+ EXPECT_THAT(run_order, ElementsAre(0, 1, 2, 3, 4, 10, 11, 12, 13, 14)); |
+} |
+ |
+TEST_F(SingleThreadPromiseExecutorTest, CancelOneBranchAndReresolve) { |
+ std::vector<int> run_order; |
+ |
+ Promise<void> promiseA( |
+ promise::Create(base::Bind(&RecordOrder, 0, &run_order)) |
+ .Then(base::Bind(&RecordOrder, 1, &run_order))); |
+ |
+ Promise<void> promiseB(promiseA.Then(base::Bind(&RecordOrder, 2, &run_order)) |
+ .Then(base::Bind(&RecordOrder, 3, &run_order))); |
+ |
+ Promise<void> promiseC(promiseA.Then(base::Bind(&RecordOrder, 4, &run_order)) |
+ .Then(base::Bind(&RecordOrder, 5, &run_order))); |
+ |
+ promise_executor_->StartResolve(promiseB); |
+ promise_executor_->StartResolve(promiseC); |
+ |
+ promiseB.Cancel(); |
+ |
+ mock_task_runner_->RunUntilIdle(); |
+ |
+ EXPECT_THAT(run_order, ElementsAre(0, 1, 4, 5)); |
+ |
+ promise_executor_->StartResolve(promiseB); |
+ mock_task_runner_->RunUntilIdle(); |
+ |
+ EXPECT_THAT(run_order, ElementsAre(0, 1, 4, 5, 2, 3)); |
+} |
+ |
+TEST_F(SingleThreadPromiseExecutorTest, Choose) { |
+ Promise<int> promise_two(promise::Create(base::Bind(&ReturnTwo))); |
+ Promise<int> promise_ten(promise::Create(base::Bind(&ReturnTen))); |
+ Promise<int> promiseA( |
+ promise::Create(base::Bind(&ReturnZero)) |
+ .Then(base::Bind(&Choose, promise_two, promise_ten))); |
+ |
+ Promise<int> promiseB( |
+ promise::Create(base::Bind(&ReturnOne)) |
+ .Then(base::Bind(&Choose, promise_two, promise_ten))); |
+ |
+ promise_executor_->StartResolve(promiseA); |
+ promise_executor_->StartResolve(promiseB); |
+ mock_task_runner_->RunUntilIdle(); |
+ EXPECT_EQ(10, promiseA.GetResolved()); |
+ EXPECT_EQ(2, promiseB.GetResolved()); |
+} |
+ |
+TEST_F(SingleThreadPromiseExecutorTest, ChooseAndAddOne) { |
+ Promise<int> promise_two(promise::Create(base::Bind(&ReturnTwo))); |
+ Promise<int> promise_ten(promise::Create(base::Bind(&ReturnTen))); |
+ Promise<int> promiseA(promise::Create(base::Bind(&ReturnZero)) |
+ .Then(base::Bind(&Choose, promise_two, promise_ten)) |
+ .Then(base::Bind(&Add, 1))); |
+ |
+ Promise<int> promiseB(promise::Create(base::Bind(&ReturnOne)) |
+ .Then(base::Bind(&Choose, promise_two, promise_ten)) |
+ .Then(base::Bind(&Add, 1))); |
+ |
+ promise_executor_->StartResolve(promiseA); |
+ promise_executor_->StartResolve(promiseB); |
+ mock_task_runner_->RunUntilIdle(); |
+ EXPECT_EQ(11, promiseA.GetResolved()); |
+ EXPECT_EQ(3, promiseB.GetResolved()); |
+} |
+ |
+TEST_F(SingleThreadPromiseExecutorTest, ChooseResolved) { |
+ Promise<int> promise_two(promise::Create(2)); |
+ Promise<int> promise_ten(promise::Create(10)); |
+ Promise<int> promiseA( |
+ promise::Create(base::Bind(&ReturnZero)) |
+ .Then(base::Bind(&Choose, promise_two, promise_ten))); |
+ |
+ Promise<int> promiseB( |
+ promise::Create(base::Bind(&ReturnOne)) |
+ .Then(base::Bind(&Choose, promise_two, promise_ten))); |
+ |
+ promise_executor_->StartResolve(promiseA); |
+ promise_executor_->StartResolve(promiseB); |
+ mock_task_runner_->RunUntilIdle(); |
+ EXPECT_EQ(10, promiseA.GetResolved()); |
+ EXPECT_EQ(2, promiseB.GetResolved()); |
+} |
+ |
+TEST_F(SingleThreadPromiseExecutorTest, ChooseResolvedAndAddOne) { |
+ Promise<int> promise_two(promise::Create<int>(2)); |
+ Promise<int> promise_ten(promise::Create<int>(10)); |
+ Promise<int> promiseA(promise::Create(base::Bind(&ReturnZero)) |
+ .Then(base::Bind(&Choose, promise_two, promise_ten)) |
+ .Then(base::Bind(&Add, 1))); |
+ |
+ Promise<int> promiseB(promise::Create(base::Bind(&ReturnOne)) |
+ .Then(base::Bind(&Choose, promise_two, promise_ten)) |
+ .Then(base::Bind(&Add, 1))); |
+ |
+ promise_executor_->StartResolve(promiseA); |
+ promise_executor_->StartResolve(promiseB); |
+ mock_task_runner_->RunUntilIdle(); |
+ EXPECT_EQ(11, promiseA.GetResolved()); |
+ EXPECT_EQ(3, promiseB.GetResolved()); |
+} |
+ |
+namespace { |
+class BlockingResolveFixture { |
+ public: |
+ void Root() { run_order_.push_back("Root"); } |
+ |
+ void L() { run_order_.push_back("L"); } |
+ |
+ void LL() { run_order_.push_back("LL"); } |
+ |
+ void LR() { run_order_.push_back("LR"); } |
+ |
+ void R() { run_order_.push_back("R"); } |
+ |
+ void RL() { run_order_.push_back("RL"); } |
+ |
+ void RR() { run_order_.push_back("RL"); } |
+ |
+ std::vector<std::string> run_order_; |
+}; |
+} // namespace |
+ |
+TEST_F(SingleThreadPromiseExecutorTest, BlockingResolve) { |
+ BlockingResolveFixture fixture; |
+ |
+ Promise<void> promise_l( |
+ promise::All(promise::Create(base::Bind(&BlockingResolveFixture::LL, |
+ base::Unretained(&fixture))), |
+ promise::Create(base::Bind(&BlockingResolveFixture::LR, |
+ base::Unretained(&fixture)))) |
+ .Then(base::Bind(&BlockingResolveFixture::L, |
+ base::Unretained(&fixture)))); |
+ |
+ Promise<void> blocking_promise(promise::Create<void>()); |
+ |
+ Promise<void> promise_r( |
+ promise::All(promise::Create(base::Bind(&BlockingResolveFixture::RL, |
+ base::Unretained(&fixture))), |
+ promise::Create(base::Bind(&BlockingResolveFixture::RR, |
+ base::Unretained(&fixture))), |
+ blocking_promise) |
+ .Then(base::Bind(&BlockingResolveFixture::R, |
+ base::Unretained(&fixture)))); |
+ |
+ Promise<void> promise_root(promise::All(promise_l, promise_r) |
+ .Then(base::Bind(&BlockingResolveFixture::Root, |
+ base::Unretained(&fixture)))); |
+ |
+ promise_executor_->StartResolve(promise_root); |
+ mock_task_runner_->RunUntilIdle(); |
+ EXPECT_THAT(fixture.run_order_, |
+ WhenSorted(ElementsAre(std::string("L"), std::string("LL"), |
+ std::string("LR"), std::string("RL"), |
+ std::string("RL")))); |
+ |
+ fixture.run_order_.clear(); |
+ blocking_promise.Resolve(); |
+ mock_task_runner_->RunUntilIdle(); |
+ EXPECT_THAT(fixture.run_order_, |
+ ElementsAre(std::string("R"), std::string("Root"))); |
+} |
+ |
+TEST_F(SingleThreadPromiseExecutorTest, AnyIntToInt) { |
+ Promise<int> promiseA(promise::Create<int>()); |
+ Promise<int> promiseB(promise::Create<int>()); |
+ Promise<int> promiseC(promise::Create<int>()); |
+ Promise<int> promiseD(promise::Create<int>()); |
+ |
+ Promise<int> promise(promise::Race(promiseA, promiseB, promiseC, promiseD) |
+ .Then(base::Bind(&Add, 1))); |
+ |
+ promise_executor_->StartResolve(promise); |
+ |
+ promiseB.Resolve(10); |
+ mock_task_runner_->RunUntilIdle(); |
+ |
+ EXPECT_EQ(11, promise.GetResolved()); |
+} |
+ |
+TEST_F(SingleThreadPromiseExecutorTest, AnyIntToVoid) { |
+ Promise<int> promiseA(promise::Create<int>()); |
+ Promise<int> promiseB(promise::Create<int>()); |
+ Promise<int> promiseC(promise::Create<int>()); |
+ |
+ int chosen = 0; |
+ Promise<void> promise(promise::Race(promiseA, promiseB, promiseC) |
+ .Then(base::Bind(&RecordParam, &chosen))); |
+ |
+ promise_executor_->StartResolve(promise); |
+ |
+ promiseB.Resolve(10); |
+ mock_task_runner_->RunUntilIdle(); |
+ |
+ EXPECT_EQ(10, chosen); |
+} |
+ |
+TEST_F(SingleThreadPromiseExecutorTest, AnyAllVoid) { |
+ Promise<void> promiseA(promise::Create<void>()); |
+ Promise<void> promiseB(promise::Create<void>()); |
+ Promise<void> promiseC(promise::Create<void>()); |
+ |
+ int chosen = 0; |
+ Promise<void> promise(promise::Race(promiseA, promiseB, promiseC) |
+ .Then(base::Bind(&RecordParam, &chosen, 1))); |
+ |
+ promise_executor_->StartResolve(promise); |
+ |
+ promiseB.Resolve(); |
+ mock_task_runner_->RunUntilIdle(); |
+ |
+ EXPECT_EQ(1, chosen); |
+} |
+ |
+namespace { |
+Promise<int> ReturnAPromise(int value) { |
+ return promise::Create(value + 1); |
+} |
+} |
+ |
+TEST_F(SingleThreadPromiseExecutorTest, AnyIntToIntPromise) { |
+ Promise<int> promiseA(promise::Create<int>()); |
+ Promise<int> promiseB(promise::Create<int>()); |
+ Promise<int> promiseC(promise::Create<int>()); |
+ Promise<int> promiseD(promise::Create<int>()); |
+ |
+ Promise<int> promise(promise::Race(promiseA, promiseB, promiseC, promiseD) |
+ .Then(base::Bind(&ReturnAPromise))); |
+ |
+ promise_executor_->StartResolve(promise); |
+ |
+ promiseD.Resolve(10); |
+ mock_task_runner_->RunUntilIdle(); |
+ |
+ EXPECT_EQ(11, promise.GetResolved()); |
+} |
+ |
+TEST_F(SingleThreadPromiseExecutorTest, FirstPromiseRegisteredWins) { |
+ Promise<int> promiseA(promise::Create<int>()); |
+ Promise<int> promiseB(promise::Create<int>()); |
+ Promise<int> promiseC(promise::Create<int>()); |
+ Promise<int> promiseD(promise::Create<int>()); |
+ |
+ Promise<int> promise(promise::Race(promiseA, promiseB, promiseC, promiseD) |
+ .Then(base::Bind(&ReturnAPromise))); |
+ |
+ promise_executor_->StartResolve(promise); |
+ |
+ promiseD.Resolve(0); |
+ promiseC.Resolve(10); |
+ promiseB.Resolve(100); |
+ promiseA.Resolve(1000); |
+ |
+ mock_task_runner_->RunUntilIdle(); |
+ |
+ EXPECT_EQ(1001, promise.GetResolved()); |
+} |
+ |
+namespace { |
+Promise<void> ReturnAVoidPromise(int* out_value, int value) { |
+ return promise::Create(base::Bind(&RecordParam, out_value, value)); |
+} |
+} |
+ |
+TEST_F(SingleThreadPromiseExecutorTest, AnyIntToVoidPromise) { |
+ Promise<int> promiseA(promise::Create<int>()); |
+ Promise<int> promiseB(promise::Create<int>()); |
+ Promise<int> promiseC(promise::Create<int>()); |
+ Promise<int> promiseD(promise::Create<int>()); |
+ |
+ int value = 0; |
+ Promise<void> promise(promise::Race(promiseA, promiseB, promiseC, promiseD) |
+ .Then(base::Bind(&ReturnAVoidPromise, &value))); |
+ |
+ promise_executor_->StartResolve(promise); |
+ |
+ promiseD.Resolve(15); |
+ mock_task_runner_->RunUntilIdle(); |
+ |
+ EXPECT_EQ(15, value); |
+} |
+ |
+TEST_F(SingleThreadPromiseExecutorTest, AnyVoidToIntPromise) { |
+ Promise<void> promiseA(promise::Create<void>()); |
+ Promise<void> promiseB(promise::Create<void>()); |
+ Promise<void> promiseC(promise::Create<void>()); |
+ Promise<void> promiseD(promise::Create<void>()); |
+ |
+ Promise<int> promise(promise::Race(promiseA, promiseB, promiseC, promiseD) |
+ .Then(base::Bind(&ReturnAPromise, 8))); |
+ |
+ promise_executor_->StartResolve(promise); |
+ |
+ promiseD.Resolve(); |
+ mock_task_runner_->RunUntilIdle(); |
+ |
+ EXPECT_EQ(9, promise.GetResolved()); |
+} |
+ |
+TEST_F(SingleThreadPromiseExecutorTest, AnyVoidToVoidPromise) { |
+ Promise<void> promiseA(promise::Create<void>()); |
+ Promise<void> promiseB(promise::Create<void>()); |
+ Promise<void> promiseC(promise::Create<void>()); |
+ Promise<void> promiseD(promise::Create<void>()); |
+ |
+ int value; |
+ Promise<void> promise(promise::Race(promiseA, promiseB, promiseC, promiseD) |
+ .Then(base::Bind(&ReturnAVoidPromise, &value, 8))); |
+ |
+ promise_executor_->StartResolve(promise); |
+ |
+ promiseD.Resolve(); |
+ mock_task_runner_->RunUntilIdle(); |
+ |
+ EXPECT_EQ(8, value); |
+} |
+ |
+namespace { |
+Promise<void> GenerateNewTask(std::vector<int>* out_result) { |
+ out_result->push_back(1); |
+ |
+ return promise::Create(base::Bind(&RecordOrder, 2, out_result)) |
+ .Then(base::Bind(&RecordOrder, 3, out_result)); |
+} |
+} // namespace |
+ |
+TEST_F(SingleThreadPromiseExecutorTest, NewPromiseFromWithinPromise) { |
+ std::vector<int> run_order; |
+ |
+ Promise<void> promise(promise::Create(base::Bind(&RecordOrder, 0, &run_order)) |
+ .Then(base::Bind(&GenerateNewTask, &run_order)) |
+ .Then(base::Bind(&RecordOrder, 4, &run_order))); |
+ |
+ promise_executor_->StartResolve(promise); |
+ |
+ mock_task_runner_->RunUntilIdle(); |
+ |
+ EXPECT_THAT(run_order, ElementsAre(0, 1, 2, 3, 4)); |
+} |
+ |
+TEST_F(SingleThreadPromiseExecutorTest, ResolvePromiseWithAPromise) { |
+ Promise<int> promise(promise::Create<int>()); |
+ |
+ promise.Resolve(promise::Create(base::Bind(&ReturnTen))); |
+ |
+ promise_executor_->StartResolve(promise); |
+ mock_task_runner_->RunUntilIdle(); |
+ |
+ EXPECT_EQ(10, promise.GetResolved()); |
+} |
+ |
+TEST_F(SingleThreadPromiseExecutorTest, ResolvePromiseWithAVoidPromise) { |
+ Promise<void> promise(promise::Create<void>()); |
+ |
+ int value = 0; |
+ promise.Resolve(promise::Create(base::Bind(&RecordParam, &value, 5))); |
+ |
+ promise_executor_->StartResolve(promise); |
+ mock_task_runner_->RunUntilIdle(); |
+ |
+ EXPECT_EQ(5, value); |
+} |
+ |
+namespace { |
+class MoveOnlyType { |
+ public: |
+ MoveOnlyType() {} |
+ MoveOnlyType(MoveOnlyType&& other) {} |
+ |
+ void operator=(MoveOnlyType&& other) {} |
+ |
+ private: |
+ DISALLOW_COPY_AND_ASSIGN(MoveOnlyType); |
+}; |
+} // namespace |
+ |
+TEST_F(SingleThreadPromiseExecutorTest, MoveOnlyType_ResolvedPromise_ViaMove) { |
+ MoveOnlyType src; |
+ Promise<MoveOnlyType> promise = promise::Create(std::move(src)); |
+ |
+ promise_executor_->StartResolve(promise); |
+ mock_task_runner_->RunUntilIdle(); |
+ |
+ MoveOnlyType dest = std::move(promise.GetResolved()); |
+} |
+ |
+TEST_F(SingleThreadPromiseExecutorTest, |
+ MoveOnlyType_ResolvedPromise_Constructed) { |
+ Promise<MoveOnlyType> promise = promise::Create(MoveOnlyType()); |
+ |
+ promise_executor_->StartResolve(promise); |
+ mock_task_runner_->RunUntilIdle(); |
+ |
+ MoveOnlyType dest = std::move(promise.GetResolved()); |
+} |
+ |
+TEST_F(SingleThreadPromiseExecutorTest, MoveOnlyType_ManuallyResolved) { |
+ Promise<MoveOnlyType> promise = promise::Create<MoveOnlyType>(); |
+ |
+ MoveOnlyType src; |
+ promise.Resolve(std::move(src)); |
+ |
+ MoveOnlyType dest = std::move(promise.GetResolved()); |
+} |
+ |
+namespace { |
+MoveOnlyType ReturnMoveOnlyType() { |
+ return MoveOnlyType(); |
+} |
+} // namespace |
+ |
+TEST_F(SingleThreadPromiseExecutorTest, MoveOnlyType_ReturnedFromClosure) { |
+ Promise<MoveOnlyType> promise = |
+ promise::Create(base::Bind(&ReturnMoveOnlyType)); |
+ |
+ promise_executor_->StartResolve(promise); |
+ mock_task_runner_->RunUntilIdle(); |
+ MoveOnlyType dest = std::move(promise.GetResolved()); |
+} |
+ |
+namespace { |
+void TakeMoveOnlyType(MoveOnlyType type) { |
+ MoveOnlyType dest = std::move(type); |
+} |
+} // namespace |
+ |
+TEST_F(SingleThreadPromiseExecutorTest, MoveOnlyType_PassedToThenClosure) { |
+ Promise<void> promise = promise::Create(base::Bind(&ReturnMoveOnlyType)) |
+ .Then(base::Bind(&TakeMoveOnlyType)); |
+ |
+ promise_executor_->StartResolve(promise); |
+ mock_task_runner_->RunUntilIdle(); |
+} |
+ |
+namespace { |
+MoveOnlyType PassMoveOnlyType(MoveOnlyType type) { |
+ return type; |
+} |
+} // namespace |
+ |
+TEST_F(SingleThreadPromiseExecutorTest, |
+ MoveOnlyType_PassedToAndReturnedFromThenClosure) { |
+ Promise<MoveOnlyType> promise = |
+ promise::Create(base::Bind(&ReturnMoveOnlyType)) |
+ .Then(base::Bind(&PassMoveOnlyType)); |
+ |
+ promise_executor_->StartResolve(promise); |
+ mock_task_runner_->RunUntilIdle(); |
+ |
+ MoveOnlyType dest = std::move(promise.GetResolved()); |
+} |
+ |
+TEST_F(SingleThreadPromiseExecutorTest, MoveOnlyType_AnyThen) { |
+ Promise<MoveOnlyType> promise = |
+ promise::Race(promise::Create(base::Bind(&ReturnMoveOnlyType)), |
+ promise::Create(base::Bind(&ReturnMoveOnlyType)), |
+ promise::Create(base::Bind(&ReturnMoveOnlyType))) |
+ .Then(base::Bind(&PassMoveOnlyType)); |
+ |
+ promise_executor_->StartResolve(promise); |
+ mock_task_runner_->RunUntilIdle(); |
+ |
+ MoveOnlyType dest = std::move(promise.GetResolved()); |
+} |
+ |
+namespace { |
+MoveOnlyType PassFirstMoveOnlyType(MoveOnlyType type, |
+ MoveOnlyType type2, |
+ MoveOnlyType type3) { |
+ return type; |
+} |
+} // namespace |
+ |
+TEST_F(SingleThreadPromiseExecutorTest, MoveOnlyType_AllThen) { |
+ Promise<MoveOnlyType> promise = |
+ promise::All(promise::Create(base::Bind(&ReturnMoveOnlyType)), |
+ promise::Create(base::Bind(&ReturnMoveOnlyType)), |
+ promise::Create(base::Bind(&ReturnMoveOnlyType))) |
+ .Then(base::Bind(&PassFirstMoveOnlyType)); |
+ |
+ promise_executor_->StartResolve(promise); |
+ mock_task_runner_->RunUntilIdle(); |
+ |
+ MoveOnlyType dest = std::move(promise.GetResolved()); |
+} |
+ |
+} // namespace promise |