1 // Copyright (c) 2012 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 #include "base/mac/libdispatch_task_runner.h"
8 #include "base/mac/bind_objc_block.h"
9 #include "base/message_loop/message_loop.h"
10 #include "base/strings/stringprintf.h"
11 #include "testing/gtest/include/gtest/gtest.h"
13 class LibDispatchTaskRunnerTest
: public testing::Test
{
15 virtual void SetUp() override
{
16 task_runner_
= new base::mac::LibDispatchTaskRunner(
17 "org.chromium.LibDispatchTaskRunnerTest");
20 // DispatchLastTask is used to run the main test thread's MessageLoop until
21 // all non-delayed tasks are run on the LibDispatchTaskRunner.
22 void DispatchLastTask() {
23 dispatch_async(task_runner_
->GetDispatchQueue(), ^{
24 message_loop_
.PostTask(FROM_HERE
,
25 base::MessageLoop::QuitWhenIdleClosure());
28 task_runner_
->Shutdown();
31 // VerifyTaskOrder takes the expectations from TaskOrderMarkers and compares
32 // them against the recorded values.
33 void VerifyTaskOrder(const char* const expectations
[],
34 size_t num_expectations
) {
35 size_t actual_size
= task_order_
.size();
37 for (size_t i
= 0; i
< num_expectations
; ++i
) {
38 if (i
>= actual_size
) {
39 EXPECT_LE(i
, actual_size
) << "Expected " << expectations
[i
];
43 EXPECT_EQ(expectations
[i
], task_order_
[i
]);
46 if (actual_size
> num_expectations
) {
47 EXPECT_LE(actual_size
, num_expectations
) << "Extra tasks were run:";
48 for (size_t i
= num_expectations
; i
< actual_size
; ++i
) {
49 EXPECT_EQ("<none>", task_order_
[i
]) << " (i=" << i
<< ")";
54 // The message loop for the test main thread.
55 base::MessageLoop message_loop_
;
57 // The task runner under test.
58 scoped_refptr
<base::mac::LibDispatchTaskRunner
> task_runner_
;
60 // Vector that records data from TaskOrderMarker.
61 std::vector
<std::string
> task_order_
;
64 // Scoper that records the beginning and end of a running task.
65 class TaskOrderMarker
{
67 TaskOrderMarker(LibDispatchTaskRunnerTest
* test
, const std::string
& name
)
70 test
->task_order_
.push_back(std::string("BEGIN ") + name
);
73 test_
->task_order_
.push_back(std::string("END ") + name_
);
77 LibDispatchTaskRunnerTest
* test_
;
81 void RecordTaskOrder(LibDispatchTaskRunnerTest
* test
, const std::string
& name
) {
82 TaskOrderMarker
marker(test
, name
);
85 // Returns a closure that records the task order.
86 base::Closure
BoundRecordTaskOrder(LibDispatchTaskRunnerTest
* test
,
87 const std::string
& name
) {
88 return base::Bind(&RecordTaskOrder
, base::Unretained(test
), name
);
91 TEST_F(LibDispatchTaskRunnerTest
, PostTask
) {
92 task_runner_
->PostTask(FROM_HERE
, BoundRecordTaskOrder(this, "Basic Task"));
94 const char* const expectations
[] = {
98 VerifyTaskOrder(expectations
, arraysize(expectations
));
101 TEST_F(LibDispatchTaskRunnerTest
, PostTaskWithinTask
) {
102 task_runner_
->PostTask(FROM_HERE
, base::BindBlock(^{
103 TaskOrderMarker
marker(this, "Outer");
104 task_runner_
->PostTask(FROM_HERE
, BoundRecordTaskOrder(this, "Inner"));
108 const char* const expectations
[] = {
114 VerifyTaskOrder(expectations
, arraysize(expectations
));
117 TEST_F(LibDispatchTaskRunnerTest
, NoMessageLoop
) {
118 task_runner_
->PostTask(FROM_HERE
, base::BindBlock(^{
119 TaskOrderMarker
marker(this,
120 base::StringPrintf("MessageLoop = %p", base::MessageLoop::current()));
124 const char* const expectations
[] = {
125 "BEGIN MessageLoop = 0x0",
126 "END MessageLoop = 0x0"
128 VerifyTaskOrder(expectations
, arraysize(expectations
));
131 TEST_F(LibDispatchTaskRunnerTest
, DispatchAndPostTasks
) {
132 dispatch_async(task_runner_
->GetDispatchQueue(), ^{
133 TaskOrderMarker
marker(this, "First Block");
135 task_runner_
->PostTask(FROM_HERE
, BoundRecordTaskOrder(this, "First Task"));
136 dispatch_async(task_runner_
->GetDispatchQueue(), ^{
137 TaskOrderMarker
marker(this, "Second Block");
139 task_runner_
->PostTask(FROM_HERE
, BoundRecordTaskOrder(this, "Second Task"));
142 const char* const expectations
[] = {
147 "BEGIN Second Block",
152 VerifyTaskOrder(expectations
, arraysize(expectations
));
155 TEST_F(LibDispatchTaskRunnerTest
, NonNestable
) {
156 task_runner_
->PostTask(FROM_HERE
, base::BindBlock(^{
157 TaskOrderMarker
marker(this, "First");
158 task_runner_
->PostNonNestableTask(FROM_HERE
, base::BindBlock(^{
159 TaskOrderMarker
marker(this, "Second NonNestable");
160 message_loop_
.PostTask(FROM_HERE
,
161 base::MessageLoop::QuitWhenIdleClosure());
165 task_runner_
->Shutdown();
167 const char* const expectations
[] = {
170 "BEGIN Second NonNestable",
171 "END Second NonNestable"
173 VerifyTaskOrder(expectations
, arraysize(expectations
));
176 TEST_F(LibDispatchTaskRunnerTest
, PostDelayed
) {
177 base::TimeTicks post_time
;
178 __block
base::TimeTicks run_time
;
179 const base::TimeDelta delta
= base::TimeDelta::FromMilliseconds(50);
181 task_runner_
->PostTask(FROM_HERE
, BoundRecordTaskOrder(this, "First"));
182 post_time
= base::TimeTicks::Now();
183 task_runner_
->PostDelayedTask(FROM_HERE
, base::BindBlock(^{
184 TaskOrderMarker
marker(this, "Timed");
185 run_time
= base::TimeTicks::Now();
186 message_loop_
.PostTask(FROM_HERE
,
187 base::MessageLoop::QuitWhenIdleClosure());
189 task_runner_
->PostTask(FROM_HERE
, BoundRecordTaskOrder(this, "Second"));
191 task_runner_
->Shutdown();
193 const char* const expectations
[] = {
201 VerifyTaskOrder(expectations
, arraysize(expectations
));
203 EXPECT_GE(run_time
, post_time
+ delta
);
206 TEST_F(LibDispatchTaskRunnerTest
, PostAfterShutdown
) {
207 EXPECT_TRUE(task_runner_
->PostTask(FROM_HERE
,
208 BoundRecordTaskOrder(this, "First")));
209 EXPECT_TRUE(task_runner_
->PostTask(FROM_HERE
,
210 BoundRecordTaskOrder(this, "Second")));
211 task_runner_
->Shutdown();
212 EXPECT_FALSE(task_runner_
->PostTask(FROM_HERE
, base::BindBlock(^{
213 TaskOrderMarker
marker(this, "Not Run");
214 ADD_FAILURE() << "Should not run a task after Shutdown";
217 const char* const expectations
[] = {
223 VerifyTaskOrder(expectations
, arraysize(expectations
));