Index: components/scheduler/promises/promise_unittest.cc |
diff --git a/components/scheduler/promises/promise_unittest.cc b/components/scheduler/promises/promise_unittest.cc |
new file mode 100644 |
index 0000000000000000000000000000000000000000..af810c69a01d457cb4c9b44a8cd9bc7f81b831b0 |
--- /dev/null |
+++ b/components/scheduler/promises/promise_unittest.cc |
@@ -0,0 +1,1198 @@ |
+// 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 <queue> |
+ |
+#include "base/bind.h" |
+#include "components/scheduler/promises/promise_executor.h" |
+#include "testing/gmock/include/gmock/gmock.h" |
+ |
+using testing::ElementsAre; |
+using testing::WhenSorted; |
+ |
+namespace promise { |
+ |
+class PromiseTest : public testing::Test { |
+ public: |
+ PromiseTest() {} |
+ ~PromiseTest() override {} |
+ |
+ void SetUp() override { executor_.reset(new internal::PromiseExecutor()); } |
+ |
+ scoped_ptr<internal::PromiseExecutor> 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(PromiseTest, NonVoidPromise) { |
+ Promise<int> promise(promise::Create(base::Bind(&ReturnOne))); |
+ |
+ executor_->StartResolve(promise); |
+ executor_->RunUntilIdle(); |
+ EXPECT_EQ(1, promise.GetResolved()); |
+} |
+ |
+TEST_F(PromiseTest, AssignPromise) { |
+ Promise<int> promise = promise::Create(base::Bind(&ReturnOne)); |
+ |
+ executor_->StartResolve(promise); |
+ executor_->RunUntilIdle(); |
+ EXPECT_EQ(1, promise.GetResolved()); |
+} |
+ |
+TEST_F(PromiseTest, Then) { |
+ Promise<int> promise( |
+ promise::Create(base::Bind(&ReturnOne)).Then(base::Bind(&Add, 1))); |
+ |
+ executor_->StartResolve(promise); |
+ executor_->RunUntilIdle(); |
+ EXPECT_EQ(2, promise.GetResolved()); |
+} |
+ |
+TEST_F(PromiseTest, AssignThen) { |
+ Promise<int> promise = |
+ promise::Create(base::Bind(&ReturnOne)).Then(base::Bind(&Add, 1)); |
+ |
+ executor_->StartResolve(promise); |
+ executor_->RunUntilIdle(); |
+ EXPECT_EQ(2, promise.GetResolved()); |
+} |
+ |
+TEST_F(PromiseTest, ThenVoid) { |
+ int value = 0; |
+ Promise<void> promise(promise::Create(base::Bind(&ReturnOne)) |
+ .Then(base::Bind(&RecordParam, &value))); |
+ |
+ executor_->StartResolve(promise); |
+ executor_->RunUntilIdle(); |
+ EXPECT_EQ(1, value); |
+} |
+ |
+TEST_F(PromiseTest, VoidThenVoid) { |
+ int value = 0; |
+ int value2 = 0; |
+ Promise<void> promise(promise::Create(base::Bind(&RecordParam, &value, 1)) |
+ .Then(base::Bind(&RecordParam, &value2, 2))); |
+ |
+ executor_->StartResolve(promise); |
+ executor_->RunUntilIdle(); |
+ EXPECT_EQ(1, value); |
+ EXPECT_EQ(2, value2); |
+} |
+ |
+TEST_F(PromiseTest, VoidThenInt) { |
+ int value = 0; |
+ Promise<int> promise(promise::Create(base::Bind(&RecordParam, &value, 2)) |
+ .Then(base::Bind(&ReturnOne))); |
+ |
+ executor_->StartResolve(promise); |
+ executor_->RunUntilIdle(); |
+ EXPECT_EQ(2, value); |
+ EXPECT_EQ(1, promise.GetResolved()); |
+} |
+ |
+TEST_F(PromiseTest, ThenChaining) { |
+ Promise<int> promise(promise::Create(base::Bind(&ReturnOne)) |
+ .Then(base::Bind(&Add, 1)) |
+ .Then(base::Bind(&Add, 1)) |
+ .Then(base::Bind(&Add, 1))); |
+ |
+ executor_->StartResolve(promise); |
+ executor_->RunUntilIdle(); |
+ EXPECT_EQ(4, promise.GetResolved()); |
+} |
+ |
+TEST_F(PromiseTest, 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))); |
+ |
+ executor_->StartResolve(promise11); |
+ executor_->StartResolve(promise12); |
+ executor_->StartResolve(promise13); |
+ executor_->StartResolve(promise14); |
+ executor_->RunUntilIdle(); |
+ |
+ EXPECT_EQ(11, promise11.GetResolved()); |
+ EXPECT_EQ(12, promise12.GetResolved()); |
+ EXPECT_EQ(13, promise13.GetResolved()); |
+ EXPECT_EQ(14, promise14.GetResolved()); |
+} |
+ |
+TEST_F(PromiseTest, 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))); |
+ |
+ executor_->StartResolve(promise11); |
+ executor_->StartResolve(promise12); |
+ executor_->StartResolve(promise13); |
+ executor_->StartResolve(promise14); |
+ executor_->RunUntilIdle(); |
+ |
+ EXPECT_EQ(11, promise11.GetResolved()); |
+ EXPECT_EQ(12, promise12.GetResolved()); |
+ EXPECT_EQ(13, promise13.GetResolved()); |
+ EXPECT_EQ(14, promise14.GetResolved()); |
+} |
+ |
+TEST_F(PromiseTest, 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))); |
+ |
+ executor_->StartResolve(promise10); |
+ executor_->RunUntilIdle(); |
+ |
+ executor_->StartResolve(promise11); |
+ executor_->StartResolve(promise12); |
+ executor_->StartResolve(promise13); |
+ executor_->StartResolve(promise14); |
+ executor_->RunUntilIdle(); |
+ |
+ EXPECT_EQ(11, promise11.GetResolved()); |
+ EXPECT_EQ(12, promise12.GetResolved()); |
+ EXPECT_EQ(13, promise13.GetResolved()); |
+ EXPECT_EQ(14, promise14.GetResolved()); |
+} |
+ |
+TEST_F(PromiseTest, AllThen) { |
+ Promise<int> promise(promise::All(promise::Create(base::Bind(&ReturnOne)), |
+ promise::Create(base::Bind(&ReturnTrue))) |
+ .Then(base::Bind(&CondTimesThree))); |
+ |
+ executor_->StartResolve(promise); |
+ executor_->RunUntilIdle(); |
+ EXPECT_EQ(3, promise.GetResolved()); |
+} |
+ |
+TEST_F(PromiseTest, AssignAllThen) { |
+ Promise<int> promise = promise::All(promise::Create(base::Bind(&ReturnOne)), |
+ promise::Create(base::Bind(&ReturnTrue))) |
+ .Then(base::Bind(&CondTimesThree)); |
+ |
+ executor_->StartResolve(promise); |
+ executor_->RunUntilIdle(); |
+ EXPECT_EQ(3, promise.GetResolved()); |
+} |
+ |
+TEST_F(PromiseTest, 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); |
+ |
+ executor_->StartResolve(promiseA); |
+ executor_->StartResolve(promiseB); |
+ executor_->RunUntilIdle(); |
+ |
+ EXPECT_THAT(run_order, ElementsAre(10, 11, 12, 13, 14, 0, 1, 2, 3, 4)); |
+} |
+ |
+TEST_F(PromiseTest, 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); |
+ |
+ executor_->StartResolve(promiseA); |
+ executor_->StartResolve(promiseB); |
+ |
+ executor_->ResolveOnePromise(); |
+ |
+ promiseB.SetEager(false); |
+ promiseA.SetEager(true); |
+ |
+ executor_->RunUntilIdle(); |
+ |
+ EXPECT_THAT(run_order, ElementsAre(10, 0, 1, 2, 3, 4, 11, 12, 13, 14)); |
+} |
+ |
+TEST_F(PromiseTest, 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))); |
+ |
+ executor_->StartResolve(promiseB); |
+ executor_->StartResolve(promiseC); |
+ executor_->RunUntilIdle(); |
+ |
+ // The interleaving of promiseB and promiseC execution is undefined. |
+ EXPECT_THAT(run_order, WhenSorted(ElementsAre(0, 1, 2, 3, 4, 5))); |
+} |
+ |
+TEST_F(PromiseTest, Cancel) { |
+ std::vector<int> run_order; |
+ |
+ Promise<void> promise( |
+ promise::Create(base::Bind(&RecordOrder, 1, &run_order))); |
+ |
+ executor_->StartResolve(promise); |
+ promise.Cancel(); |
+ |
+ executor_->RunUntilIdle(); |
+ |
+ EXPECT_TRUE(run_order.empty()); |
+} |
+ |
+TEST_F(PromiseTest, 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))); |
+ |
+ executor_->StartResolve(promiseA); |
+ executor_->StartResolve(promiseB); |
+ |
+ promiseB.Cancel(); |
+ |
+ executor_->RunUntilIdle(); |
+ |
+ EXPECT_THAT(run_order, ElementsAre(0, 1, 2, 3, 4)); |
+} |
+ |
+TEST_F(PromiseTest, 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))); |
+ |
+ executor_->StartResolve(promiseB); |
+ executor_->StartResolve(promiseC); |
+ |
+ promiseB.Cancel(); |
+ |
+ executor_->RunUntilIdle(); |
+ |
+ EXPECT_THAT(run_order, ElementsAre(0, 1, 4, 5)); |
+} |
+ |
+TEST_F(PromiseTest, CancelAndReresolve) { |
+ std::vector<int> run_order; |
+ |
+ Promise<void> promise( |
+ promise::Create(base::Bind(&RecordOrder, 1, &run_order))); |
+ |
+ executor_->StartResolve(promise); |
+ promise.Cancel(); |
+ |
+ executor_->RunUntilIdle(); |
+ |
+ EXPECT_TRUE(run_order.empty()); |
+ |
+ executor_->StartResolve(promise); |
+ executor_->RunUntilIdle(); |
+ |
+ EXPECT_THAT(run_order, ElementsAre(1)); |
+} |
+ |
+TEST_F(PromiseTest, 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))); |
+ |
+ executor_->StartResolve(promiseA); |
+ executor_->StartResolve(promiseB); |
+ |
+ promiseB.Cancel(); |
+ |
+ executor_->RunUntilIdle(); |
+ |
+ EXPECT_THAT(run_order, ElementsAre(0, 1, 2, 3, 4)); |
+ |
+ executor_->StartResolve(promiseB); |
+ executor_->RunUntilIdle(); |
+ |
+ EXPECT_THAT(run_order, ElementsAre(0, 1, 2, 3, 4, 10, 11, 12, 13, 14)); |
+} |
+ |
+TEST_F(PromiseTest, 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))); |
+ |
+ executor_->StartResolve(promiseB); |
+ executor_->StartResolve(promiseC); |
+ |
+ promiseB.Cancel(); |
+ |
+ executor_->RunUntilIdle(); |
+ |
+ EXPECT_THAT(run_order, ElementsAre(0, 1, 4, 5)); |
+ |
+ executor_->StartResolve(promiseB); |
+ executor_->RunUntilIdle(); |
+ |
+ EXPECT_THAT(run_order, ElementsAre(0, 1, 4, 5, 2, 3)); |
+} |
+ |
+TEST_F(PromiseTest, 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))); |
+ |
+ executor_->StartResolve(promiseA); |
+ executor_->StartResolve(promiseB); |
+ executor_->RunUntilIdle(); |
+ EXPECT_EQ(10, promiseA.GetResolved()); |
+ EXPECT_EQ(2, promiseB.GetResolved()); |
+} |
+ |
+TEST_F(PromiseTest, 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))); |
+ |
+ executor_->StartResolve(promiseA); |
+ executor_->StartResolve(promiseB); |
+ executor_->RunUntilIdle(); |
+ EXPECT_EQ(11, promiseA.GetResolved()); |
+ EXPECT_EQ(3, promiseB.GetResolved()); |
+} |
+ |
+TEST_F(PromiseTest, 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))); |
+ |
+ executor_->StartResolve(promiseA); |
+ executor_->StartResolve(promiseB); |
+ executor_->RunUntilIdle(); |
+ EXPECT_EQ(10, promiseA.GetResolved()); |
+ EXPECT_EQ(2, promiseB.GetResolved()); |
+} |
+ |
+TEST_F(PromiseTest, 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))); |
+ |
+ executor_->StartResolve(promiseA); |
+ executor_->StartResolve(promiseB); |
+ executor_->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(PromiseTest, 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)))); |
+ |
+ executor_->StartResolve(promise_root); |
+ executor_->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(); |
+ executor_->RunUntilIdle(); |
+ EXPECT_THAT(fixture.run_order_, |
+ ElementsAre(std::string("R"), std::string("Root"))); |
+} |
+ |
+TEST_F(PromiseTest, 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)); |
+ |
+ executor_->StartResolve(promise); |
+ |
+ promiseB.Resolve(10); |
+ executor_->RunUntilIdle(); |
+ |
+ EXPECT_EQ(11, promise.GetResolved()); |
+} |
+ |
+TEST_F(PromiseTest, 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))); |
+ |
+ executor_->StartResolve(promise); |
+ |
+ promiseB.Resolve(10); |
+ executor_->RunUntilIdle(); |
+ |
+ EXPECT_EQ(10, chosen); |
+} |
+ |
+TEST_F(PromiseTest, 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))); |
+ |
+ executor_->StartResolve(promise); |
+ |
+ promiseB.Resolve(); |
+ executor_->RunUntilIdle(); |
+ |
+ EXPECT_EQ(1, chosen); |
+} |
+ |
+namespace { |
+Promise<int> ReturnAPromise(int value) { |
+ return promise::Create(value + 1); |
+} |
+} |
+ |
+TEST_F(PromiseTest, 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))); |
+ |
+ executor_->StartResolve(promise); |
+ |
+ promiseD.Resolve(10); |
+ executor_->RunUntilIdle(); |
+ |
+ EXPECT_EQ(11, promise.GetResolved()); |
+} |
+ |
+TEST_F(PromiseTest, 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))); |
+ |
+ executor_->StartResolve(promise); |
+ |
+ promiseD.Resolve(0); |
+ promiseC.Resolve(10); |
+ promiseB.Resolve(100); |
+ promiseA.Resolve(1000); |
+ |
+ executor_->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(PromiseTest, 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))); |
+ |
+ executor_->StartResolve(promise); |
+ |
+ promiseD.Resolve(15); |
+ executor_->RunUntilIdle(); |
+ |
+ EXPECT_EQ(15, value); |
+} |
+ |
+TEST_F(PromiseTest, 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))); |
+ |
+ executor_->StartResolve(promise); |
+ |
+ promiseD.Resolve(); |
+ executor_->RunUntilIdle(); |
+ |
+ EXPECT_EQ(9, promise.GetResolved()); |
+} |
+ |
+TEST_F(PromiseTest, 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))); |
+ |
+ executor_->StartResolve(promise); |
+ |
+ promiseD.Resolve(); |
+ executor_->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(PromiseTest, 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))); |
+ |
+ executor_->StartResolve(promise); |
+ |
+ executor_->RunUntilIdle(); |
+ |
+ EXPECT_THAT(run_order, ElementsAre(0, 1, 2, 3, 4)); |
+} |
+ |
+TEST_F(PromiseTest, ResolvePromiseWithAPromise) { |
+ Promise<int> promise(promise::Create<int>()); |
+ |
+ promise.Resolve(promise::Create(base::Bind(&ReturnTen))); |
+ |
+ executor_->StartResolve(promise); |
+ executor_->RunUntilIdle(); |
+ |
+ EXPECT_EQ(10, promise.GetResolved()); |
+} |
+ |
+TEST_F(PromiseTest, ResolvePromiseWithAVoidPromise) { |
+ Promise<void> promise(promise::Create<void>()); |
+ |
+ int value = 0; |
+ promise.Resolve(promise::Create(base::Bind(&RecordParam, &value, 5))); |
+ |
+ executor_->StartResolve(promise); |
+ executor_->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(PromiseTest, MoveOnlyType_ResolvedPromise_ViaMove) { |
+ MoveOnlyType src; |
+ Promise<MoveOnlyType> promise = promise::Create(std::move(src)); |
+ |
+ executor_->StartResolve(promise); |
+ executor_->RunUntilIdle(); |
+ |
+ MoveOnlyType dest = std::move(promise.GetResolved()); |
+} |
+ |
+TEST_F(PromiseTest, MoveOnlyType_ResolvedPromise_Constructed) { |
+ Promise<MoveOnlyType> promise = promise::Create(MoveOnlyType()); |
+ |
+ executor_->StartResolve(promise); |
+ executor_->RunUntilIdle(); |
+ |
+ MoveOnlyType dest = std::move(promise.GetResolved()); |
+} |
+ |
+TEST_F(PromiseTest, 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(PromiseTest, MoveOnlyType_ReturnedFromClosure) { |
+ Promise<MoveOnlyType> promise = |
+ promise::Create(base::Bind(&ReturnMoveOnlyType)); |
+ |
+ executor_->StartResolve(promise); |
+ executor_->RunUntilIdle(); |
+ MoveOnlyType dest = std::move(promise.GetResolved()); |
+} |
+ |
+namespace { |
+void TakeMoveOnlyType(MoveOnlyType type) { |
+ MoveOnlyType dest = std::move(type); |
+} |
+} // namespace |
+ |
+TEST_F(PromiseTest, MoveOnlyType_PassedToThenClosure) { |
+ Promise<void> promise = promise::Create(base::Bind(&ReturnMoveOnlyType)) |
+ .Then(base::Bind(&TakeMoveOnlyType)); |
+ |
+ executor_->StartResolve(promise); |
+ executor_->RunUntilIdle(); |
+} |
+ |
+namespace { |
+MoveOnlyType PassMoveOnlyType(MoveOnlyType type) { |
+ return type; |
+} |
+} // namespace |
+ |
+TEST_F(PromiseTest, MoveOnlyType_PassedToAndReturnedFromThenClosure) { |
+ Promise<MoveOnlyType> promise = |
+ promise::Create(base::Bind(&ReturnMoveOnlyType)) |
+ .Then(base::Bind(&PassMoveOnlyType)); |
+ |
+ executor_->StartResolve(promise); |
+ executor_->RunUntilIdle(); |
+ |
+ MoveOnlyType dest = std::move(promise.GetResolved()); |
+} |
+ |
+TEST_F(PromiseTest, 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)); |
+ |
+ executor_->StartResolve(promise); |
+ executor_->RunUntilIdle(); |
+ |
+ MoveOnlyType dest = std::move(promise.GetResolved()); |
+} |
+ |
+namespace { |
+MoveOnlyType PassFirstMoveOnlyType(MoveOnlyType type, |
+ MoveOnlyType type2, |
+ MoveOnlyType type3) { |
+ return type; |
+} |
+} // namespace |
+ |
+TEST_F(PromiseTest, 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)); |
+ |
+ executor_->StartResolve(promise); |
+ executor_->RunUntilIdle(); |
+ |
+ MoveOnlyType dest = std::move(promise.GetResolved()); |
+} |
+ |
+namespace { |
+Rejectable<int, bool> ReturnIntResolve() { |
+ return Resolve(10); |
+} |
+ |
+Rejectable<int, bool> ReturnBoolReject() { |
+ return Reject(true); |
+} |
+} // namespace |
+ |
+TEST_F(PromiseTest, IntBoolRejectable_Resolve) { |
+ Rejectable<int, bool> rejectable = ReturnIntResolve(); |
+ |
+ EXPECT_TRUE(rejectable.is_resolved()); |
+ EXPECT_EQ(10, rejectable.resolved()); |
+} |
+ |
+TEST_F(PromiseTest, IntBoolRejectable_Reject) { |
+ Rejectable<int, bool> rejectable = ReturnBoolReject(); |
+ |
+ EXPECT_FALSE(rejectable.is_resolved()); |
+ EXPECT_TRUE(rejectable.reject_reason()); |
+} |
+ |
+namespace { |
+Rejectable<void, void> ReturnVoidResolve() { |
+ return Resolve(); |
+} |
+ |
+Rejectable<void, void> ReturnVoidReject() { |
+ return Reject(); |
+} |
+} // namespace |
+ |
+TEST_F(PromiseTest, VoidVoidRejectable_Resolve) { |
+ Rejectable<void, void> rejectable = ReturnVoidResolve(); |
+ |
+ EXPECT_TRUE(rejectable.is_resolved()); |
+} |
+ |
+TEST_F(PromiseTest, VoidVoidRejectable_Reject) { |
+ Rejectable<void, void> rejectable = ReturnVoidReject(); |
+ |
+ EXPECT_FALSE(rejectable.is_resolved()); |
+} |
+ |
+TEST_F(PromiseTest, RejectablePromise_Resolve) { |
+ Promise<Rejectable<int, bool>> promise( |
+ promise::Create<Rejectable<int, bool>>()); |
+ |
+ promise.Resolve(10); |
+ |
+ EXPECT_TRUE(promise.is_resolved()); |
+ EXPECT_FALSE(promise.is_rejected()); |
+ EXPECT_EQ(10, promise.GetResolved().resolved()); |
+} |
+ |
+TEST_F(PromiseTest, RejectablePromise_Reject) { |
+ Promise<Rejectable<int, bool>> promise( |
+ promise::Create<Rejectable<int, bool>>()); |
+ |
+ promise.Reject(true); |
+ |
+ EXPECT_FALSE(promise.is_resolved()); |
+ EXPECT_TRUE(promise.is_rejected()); |
+ EXPECT_TRUE(promise.GetResolved().reject_reason()); |
+} |
+ |
+namespace { |
+Rejectable<int, int> ResolveWithTenFunc() { |
+ return Resolve(10); |
+} |
+ |
+Rejectable<int, int> RejectWithTwentyFunc() { |
+ return Reject(20); |
+} |
+} |
+ |
+TEST_F(PromiseTest, RejectableFunction_Resolve) { |
+ Promise<Rejectable<int, int>> promise( |
+ promise::Create(base::Bind(&ResolveWithTenFunc))); |
+ executor_->StartResolve(promise); |
+ executor_->RunUntilIdle(); |
+ |
+ EXPECT_TRUE(promise.is_resolved()); |
+ EXPECT_FALSE(promise.is_rejected()); |
+ EXPECT_EQ(10, promise.GetResolved().resolved()); |
+} |
+ |
+TEST_F(PromiseTest, RejectableFunction_Reject) { |
+ Promise<Rejectable<int, int>> promise( |
+ promise::Create(base::Bind(&RejectWithTwentyFunc))); |
+ executor_->StartResolve(promise); |
+ executor_->RunUntilIdle(); |
+ |
+ EXPECT_FALSE(promise.is_resolved()); |
+ EXPECT_TRUE(promise.is_rejected()); |
+ EXPECT_EQ(20, promise.GetResolved().reject_reason()); |
+} |
+ |
+TEST_F(PromiseTest, RejectablePromise_ResolveWithPromiseThatResolves) { |
+ Promise<Rejectable<int, int>> promise = |
+ promise::Create<Rejectable<int, int>>(); |
+ executor_->StartResolve(promise); |
+ |
+ promise.Resolve(promise::Create(base::Bind(&ResolveWithTenFunc))); |
+ |
+ executor_->RunUntilIdle(); |
+ |
+ EXPECT_TRUE(promise.is_resolved()); |
+ EXPECT_FALSE(promise.is_rejected()); |
+ EXPECT_EQ(10, promise.GetResolved().resolved()); |
+} |
+ |
+TEST_F(PromiseTest, RejectablePromise_ResolveWithPromiseThatRejects) { |
+ Promise<Rejectable<int, int>> promise = |
+ promise::Create<Rejectable<int, int>>(); |
+ executor_->StartResolve(promise); |
+ |
+ promise.Resolve(promise::Create(base::Bind(&RejectWithTwentyFunc))); |
+ |
+ executor_->RunUntilIdle(); |
+ |
+ EXPECT_FALSE(promise.is_resolved()); |
+ EXPECT_TRUE(promise.is_rejected()); |
+ EXPECT_EQ(20, promise.GetResolved().reject_reason()); |
+} |
+ |
+TEST_F(PromiseTest, RejectablePromise_ResolveWithResolvedPromise) { |
+ Promise<Rejectable<int, int>> rejected_promise = |
+ promise::Create<Rejectable<int, int>>(); |
+ |
+ rejected_promise.Resolve(1337); |
+ |
+ Promise<Rejectable<int, int>> promise = |
+ promise::Create<Rejectable<int, int>>(); |
+ executor_->StartResolve(promise); |
+ |
+ promise.Resolve(rejected_promise); |
+ |
+ EXPECT_TRUE(promise.is_resolved()); |
+ EXPECT_FALSE(promise.is_rejected()); |
+ EXPECT_EQ(1337, promise.GetResolved().resolved()); |
+} |
+ |
+TEST_F(PromiseTest, RejectablePromise_ResolveWithRectedPromise) { |
+ Promise<Rejectable<int, int>> rejected_promise = |
+ promise::Create<Rejectable<int, int>>(); |
+ |
+ rejected_promise.Reject(123); |
+ |
+ Promise<Rejectable<int, int>> promise = |
+ promise::Create<Rejectable<int, int>>(); |
+ executor_->StartResolve(promise); |
+ |
+ promise.Resolve(rejected_promise); |
+ |
+ EXPECT_FALSE(promise.is_resolved()); |
+ EXPECT_TRUE(promise.is_rejected()); |
+ EXPECT_EQ(123, promise.GetResolved().reject_reason()); |
+} |
+ |
+namespace { |
+void OnRejectableIntBool(bool* was_rejected, |
+ int* resolved_result, |
+ bool* reject_reason, |
+ Rejectable<int, bool> result) { |
+ *was_rejected = result.is_rejected(); |
+ if (result.is_rejected()) { |
+ *reject_reason = result.reject_reason(); |
+ } else { |
+ *resolved_result = result.resolved(); |
+ } |
+} |
+} |
+ |
+TEST_F(PromiseTest, RejectablePromise_ThenResolve) { |
+ Promise<Rejectable<int, bool>> manually_resolved_promise( |
+ promise::Create<Rejectable<int, bool>>()); |
+ |
+ bool was_rejected = false; |
+ int resolved_result = 0; |
+ bool reject_reason = false; |
+ Promise<void> promise(manually_resolved_promise.Then(base::Bind( |
+ &OnRejectableIntBool, &was_rejected, &resolved_result, &reject_reason))); |
+ |
+ executor_->StartResolve(promise); |
+ |
+ manually_resolved_promise.Resolve(10); |
+ executor_->RunUntilIdle(); |
+ |
+ EXPECT_FALSE(was_rejected); |
+ EXPECT_EQ(10, resolved_result); |
+} |
+ |
+TEST_F(PromiseTest, RejectablePromise_ThenReject) { |
+ Promise<Rejectable<int, bool>> manually_resolved_promise( |
+ promise::Create<Rejectable<int, bool>>()); |
+ |
+ bool was_rejected = false; |
+ int resolved_result = 0; |
+ bool reject_reason = false; |
+ Promise<void> promise(manually_resolved_promise.Then(base::Bind( |
+ &OnRejectableIntBool, &was_rejected, &resolved_result, &reject_reason))); |
+ |
+ executor_->StartResolve(promise); |
+ |
+ manually_resolved_promise.Reject(true); |
+ executor_->RunUntilIdle(); |
+ |
+ EXPECT_TRUE(was_rejected); |
+ EXPECT_TRUE(reject_reason); |
+} |
+ |
+namespace { |
+int GetRejectionReason(Rejectable<void, int> a, |
+ Rejectable<void, int> b, |
+ Rejectable<void, int> c, |
+ Rejectable<void, int> d) { |
+ if (a.is_rejected()) |
+ return a.reject_reason(); |
+ if (b.is_rejected()) |
+ return b.reject_reason(); |
+ if (c.is_rejected()) |
+ return c.reject_reason(); |
+ if (d.is_rejected()) |
+ return d.reject_reason(); |
+ return -1; |
+} |
+} |
+ |
+TEST_F(PromiseTest, RejectablePromise_FastFail) { |
+ Promise<Rejectable<void, int>> promise1( |
+ promise::Create<Rejectable<void, int>>()); |
+ Promise<Rejectable<void, int>> promise2( |
+ promise::Create<Rejectable<void, int>>()); |
+ Promise<Rejectable<void, int>> promise3( |
+ promise::Create<Rejectable<void, int>>()); |
+ Promise<Rejectable<void, int>> promise4( |
+ promise::Create<Rejectable<void, int>>()); |
+ Promise<int> promise = promise::All(promise1, promise2, promise3, promise4) |
+ .Then(base::Bind(&GetRejectionReason)); |
+ |
+ executor_->StartResolve(promise); |
+ |
+ promise4.Reject(4); |
+ executor_->RunUntilIdle(); |
+ |
+ EXPECT_EQ(4, promise.GetResolved()); |
+} |
+ |
+namespace { |
+void OnRejectableIntInt(bool* was_rejected, |
+ int* resolved_result, |
+ int* reject_reason, |
+ Rejectable<int, int> result) { |
+ *was_rejected = result.is_rejected(); |
+ if (result.is_rejected()) { |
+ *reject_reason = result.reject_reason(); |
+ } else { |
+ DCHECK(result.is_resolved()); |
+ *resolved_result = result.resolved(); |
+ } |
+} |
+} |
+ |
+TEST_F(PromiseTest, RejectablePromise_Race) { |
+ Promise<Rejectable<int, int>> promise1( |
+ promise::Create<Rejectable<int, int>>()); |
+ Promise<Rejectable<int, int>> promise2( |
+ promise::Create<Rejectable<int, int>>()); |
+ Promise<Rejectable<int, int>> promise3( |
+ promise::Create<Rejectable<int, int>>()); |
+ Promise<Rejectable<int, int>> promise4( |
+ promise::Create<Rejectable<int, int>>()); |
+ |
+ bool was_rejected = false; |
+ int resolved_result = 0; |
+ int reject_reason = 0; |
+ Promise<void> promise = |
+ promise::Race(promise1, promise2, promise3, promise4) |
+ .Then(base::Bind(&OnRejectableIntInt, &was_rejected, &resolved_result, |
+ &reject_reason)); |
+ |
+ executor_->StartResolve(promise); |
+ |
+ promise3.Reject(3); |
+ executor_->RunUntilIdle(); |
+ |
+ EXPECT_TRUE(was_rejected); |
+ EXPECT_EQ(3, reject_reason); |
+} |
+ |
+} // namespace promise |