| 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
|
|
|