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