- add sources.
[platform/framework/web/crosswalk.git] / src / base / mac / libdispatch_task_runner_unittest.cc
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.
4
5 #include "base/mac/libdispatch_task_runner.h"
6
7 #include "base/bind.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"
12
13 class LibDispatchTaskRunnerTest : public testing::Test {
14  public:
15   virtual void SetUp() OVERRIDE {
16     task_runner_ = new base::mac::LibDispatchTaskRunner(
17         "org.chromium.LibDispatchTaskRunnerTest");
18   }
19
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());
26     });
27     message_loop_.Run();
28     task_runner_->Shutdown();
29   }
30
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();
36
37     for (size_t i = 0; i < num_expectations; ++i) {
38       if (i >= actual_size) {
39         EXPECT_LE(i, actual_size) << "Expected " << expectations[i];
40         continue;
41       }
42
43       EXPECT_EQ(expectations[i], task_order_[i]);
44     }
45
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 << ")";
50       }
51     }
52   }
53
54   // The message loop for the test main thread.
55   base::MessageLoop message_loop_;
56
57   // The task runner under test.
58   scoped_refptr<base::mac::LibDispatchTaskRunner> task_runner_;
59
60   // Vector that records data from TaskOrderMarker.
61   std::vector<std::string> task_order_;
62 };
63
64 // Scoper that records the beginning and end of a running task.
65 class TaskOrderMarker {
66  public:
67   TaskOrderMarker(LibDispatchTaskRunnerTest* test, const std::string& name)
68       : test_(test),
69         name_(name) {
70     test->task_order_.push_back(std::string("BEGIN ") + name);
71   }
72   ~TaskOrderMarker() {
73     test_->task_order_.push_back(std::string("END ") + name_);
74   }
75
76  private:
77   LibDispatchTaskRunnerTest* test_;
78   std::string name_;
79 };
80
81 void RecordTaskOrder(LibDispatchTaskRunnerTest* test, const std::string& name) {
82   TaskOrderMarker marker(test, name);
83 }
84
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);
89 }
90
91 TEST_F(LibDispatchTaskRunnerTest, PostTask) {
92   task_runner_->PostTask(FROM_HERE, BoundRecordTaskOrder(this, "Basic Task"));
93   DispatchLastTask();
94   const char* const expectations[] = {
95     "BEGIN Basic Task",
96     "END Basic Task"
97   };
98   VerifyTaskOrder(expectations, arraysize(expectations));
99 }
100
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"));
105   }));
106   DispatchLastTask();
107
108   const char* const expectations[] = {
109     "BEGIN Outer",
110     "END Outer",
111     "BEGIN Inner",
112     "END Inner"
113   };
114   VerifyTaskOrder(expectations, arraysize(expectations));
115 }
116
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()));
121   }));
122   DispatchLastTask();
123
124   const char* const expectations[] = {
125     "BEGIN MessageLoop = 0x0",
126     "END MessageLoop = 0x0"
127   };
128   VerifyTaskOrder(expectations, arraysize(expectations));
129 }
130
131 TEST_F(LibDispatchTaskRunnerTest, DispatchAndPostTasks) {
132   dispatch_async(task_runner_->GetDispatchQueue(), ^{
133       TaskOrderMarker marker(this, "First Block");
134   });
135   task_runner_->PostTask(FROM_HERE, BoundRecordTaskOrder(this, "First Task"));
136   dispatch_async(task_runner_->GetDispatchQueue(), ^{
137       TaskOrderMarker marker(this, "Second Block");
138   });
139   task_runner_->PostTask(FROM_HERE, BoundRecordTaskOrder(this, "Second Task"));
140   DispatchLastTask();
141
142   const char* const expectations[] = {
143     "BEGIN First Block",
144     "END First Block",
145     "BEGIN First Task",
146     "END First Task",
147     "BEGIN Second Block",
148     "END Second Block",
149     "BEGIN Second Task",
150     "END Second Task",
151   };
152   VerifyTaskOrder(expectations, arraysize(expectations));
153 }
154
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());
162       }));
163   }));
164   message_loop_.Run();
165   task_runner_->Shutdown();
166
167   const char* const expectations[] = {
168     "BEGIN First",
169     "END First",
170     "BEGIN Second NonNestable",
171     "END Second NonNestable"
172   };
173   VerifyTaskOrder(expectations, arraysize(expectations));
174 }
175
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);
180
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());
188   }), delta);
189   task_runner_->PostTask(FROM_HERE, BoundRecordTaskOrder(this, "Second"));
190   message_loop_.Run();
191   task_runner_->Shutdown();
192
193   const char* const expectations[] = {
194     "BEGIN First",
195     "END First",
196     "BEGIN Second",
197     "END Second",
198     "BEGIN Timed",
199     "END Timed",
200   };
201   VerifyTaskOrder(expectations, arraysize(expectations));
202
203   EXPECT_GE(run_time, post_time + delta);
204 }
205
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";
215   })));
216
217   const char* const expectations[] = {
218     "BEGIN First",
219     "END First",
220     "BEGIN Second",
221     "END Second"
222   };
223   VerifyTaskOrder(expectations, arraysize(expectations));
224 }