Upstream version 9.38.198.0
[platform/framework/web/crosswalk.git] / src / mojo / public / cpp / utility / tests / run_loop_unittest.cc
1 // Copyright 2014 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 "mojo/public/cpp/utility/run_loop.h"
6
7 #include <string>
8
9 #include "mojo/public/cpp/system/core.h"
10 #include "mojo/public/cpp/test_support/test_utils.h"
11 #include "mojo/public/cpp/utility/run_loop_handler.h"
12 #include "testing/gtest/include/gtest/gtest.h"
13
14 namespace mojo {
15 namespace {
16
17 class TestRunLoopHandler : public RunLoopHandler {
18  public:
19   TestRunLoopHandler()
20       : ready_count_(0),
21         error_count_(0),
22         last_error_result_(MOJO_RESULT_OK) {
23   }
24   virtual ~TestRunLoopHandler() {}
25
26   void clear_ready_count() { ready_count_ = 0; }
27   int ready_count() const { return ready_count_; }
28
29   void clear_error_count() { error_count_ = 0; }
30   int error_count() const { return error_count_; }
31
32   MojoResult last_error_result() const { return last_error_result_; }
33
34   // RunLoopHandler:
35   virtual void OnHandleReady(const Handle& handle) MOJO_OVERRIDE {
36     ready_count_++;
37   }
38   virtual void OnHandleError(const Handle& handle, MojoResult result)
39       MOJO_OVERRIDE {
40     error_count_++;
41     last_error_result_ = result;
42   }
43
44  private:
45   int ready_count_;
46   int error_count_;
47   MojoResult last_error_result_;
48
49   MOJO_DISALLOW_COPY_AND_ASSIGN(TestRunLoopHandler);
50 };
51
52 class RunLoopTest : public testing::Test {
53  public:
54   RunLoopTest() {}
55
56   virtual void SetUp() MOJO_OVERRIDE {
57     Test::SetUp();
58     RunLoop::SetUp();
59   }
60   virtual void TearDown() MOJO_OVERRIDE {
61     RunLoop::TearDown();
62     Test::TearDown();
63   }
64
65  private:
66   MOJO_DISALLOW_COPY_AND_ASSIGN(RunLoopTest);
67 };
68
69 // Trivial test to verify Run() with no added handles returns.
70 TEST_F(RunLoopTest, ExitsWithNoHandles) {
71   RunLoop run_loop;
72   run_loop.Run();
73 }
74
75 class RemoveOnReadyRunLoopHandler : public TestRunLoopHandler {
76  public:
77   RemoveOnReadyRunLoopHandler() : run_loop_(NULL) {
78   }
79   virtual ~RemoveOnReadyRunLoopHandler() {}
80
81   void set_run_loop(RunLoop* run_loop) { run_loop_ = run_loop; }
82
83   // RunLoopHandler:
84   virtual void OnHandleReady(const Handle& handle) MOJO_OVERRIDE {
85     run_loop_->RemoveHandler(handle);
86     TestRunLoopHandler::OnHandleReady(handle);
87   }
88
89  private:
90   RunLoop* run_loop_;
91
92   MOJO_DISALLOW_COPY_AND_ASSIGN(RemoveOnReadyRunLoopHandler);
93 };
94
95 // Verifies RunLoop quits when no more handles (handle is removed when ready).
96 TEST_F(RunLoopTest, HandleReady) {
97   RemoveOnReadyRunLoopHandler handler;
98   MessagePipe test_pipe;
99   EXPECT_TRUE(test::WriteTextMessage(test_pipe.handle1.get(), std::string()));
100
101   RunLoop run_loop;
102   handler.set_run_loop(&run_loop);
103   run_loop.AddHandler(&handler, test_pipe.handle0.get(),
104                       MOJO_HANDLE_SIGNAL_READABLE, MOJO_DEADLINE_INDEFINITE);
105   run_loop.Run();
106   EXPECT_EQ(1, handler.ready_count());
107   EXPECT_EQ(0, handler.error_count());
108   EXPECT_FALSE(run_loop.HasHandler(test_pipe.handle0.get()));
109 }
110
111 class QuitOnReadyRunLoopHandler : public TestRunLoopHandler {
112  public:
113   QuitOnReadyRunLoopHandler() : run_loop_(NULL) {
114   }
115   virtual ~QuitOnReadyRunLoopHandler() {}
116
117   void set_run_loop(RunLoop* run_loop) { run_loop_ = run_loop; }
118
119   // RunLoopHandler:
120   virtual void OnHandleReady(const Handle& handle) MOJO_OVERRIDE {
121     run_loop_->Quit();
122     TestRunLoopHandler::OnHandleReady(handle);
123   }
124
125  private:
126   RunLoop* run_loop_;
127
128   MOJO_DISALLOW_COPY_AND_ASSIGN(QuitOnReadyRunLoopHandler);
129 };
130
131 // Verifies Quit() from OnHandleReady() quits the loop.
132 TEST_F(RunLoopTest, QuitFromReady) {
133   QuitOnReadyRunLoopHandler handler;
134   MessagePipe test_pipe;
135   EXPECT_TRUE(test::WriteTextMessage(test_pipe.handle1.get(), std::string()));
136
137   RunLoop run_loop;
138   handler.set_run_loop(&run_loop);
139   run_loop.AddHandler(&handler, test_pipe.handle0.get(),
140                       MOJO_HANDLE_SIGNAL_READABLE, MOJO_DEADLINE_INDEFINITE);
141   run_loop.Run();
142   EXPECT_EQ(1, handler.ready_count());
143   EXPECT_EQ(0, handler.error_count());
144   EXPECT_TRUE(run_loop.HasHandler(test_pipe.handle0.get()));
145 }
146
147 class QuitOnErrorRunLoopHandler : public TestRunLoopHandler {
148  public:
149   QuitOnErrorRunLoopHandler() : run_loop_(NULL) {
150   }
151   virtual ~QuitOnErrorRunLoopHandler() {}
152
153   void set_run_loop(RunLoop* run_loop) { run_loop_ = run_loop; }
154
155   // RunLoopHandler:
156   virtual void OnHandleError(const Handle& handle, MojoResult result)
157       MOJO_OVERRIDE {
158     run_loop_->Quit();
159     TestRunLoopHandler::OnHandleError(handle, result);
160   }
161
162  private:
163   RunLoop* run_loop_;
164
165   MOJO_DISALLOW_COPY_AND_ASSIGN(QuitOnErrorRunLoopHandler);
166 };
167
168 // Verifies Quit() when the deadline is reached works.
169 TEST_F(RunLoopTest, QuitWhenDeadlineExpired) {
170   QuitOnErrorRunLoopHandler handler;
171   MessagePipe test_pipe;
172   RunLoop run_loop;
173   handler.set_run_loop(&run_loop);
174   run_loop.AddHandler(&handler, test_pipe.handle0.get(),
175                       MOJO_HANDLE_SIGNAL_READABLE,
176                       static_cast<MojoDeadline>(10000));
177   run_loop.Run();
178   EXPECT_EQ(0, handler.ready_count());
179   EXPECT_EQ(1, handler.error_count());
180   EXPECT_EQ(MOJO_RESULT_DEADLINE_EXCEEDED, handler.last_error_result());
181   EXPECT_FALSE(run_loop.HasHandler(test_pipe.handle0.get()));
182 }
183
184 TEST_F(RunLoopTest, Current) {
185   EXPECT_TRUE(RunLoop::current() == NULL);
186   {
187     RunLoop run_loop;
188     EXPECT_EQ(&run_loop, RunLoop::current());
189   }
190   EXPECT_TRUE(RunLoop::current() == NULL);
191 }
192
193 class NestingRunLoopHandler : public TestRunLoopHandler {
194  public:
195   static const size_t kDepthLimit;
196   static const char kSignalMagic;
197
198   NestingRunLoopHandler()
199       : run_loop_(NULL),
200         pipe_(NULL),
201         depth_(0),
202         reached_depth_limit_(false) {}
203
204   virtual ~NestingRunLoopHandler() {}
205
206   void set_run_loop(RunLoop* run_loop) { run_loop_ = run_loop; }
207   void set_pipe(MessagePipe* pipe) { pipe_ = pipe; }
208   bool reached_depth_limit() const { return reached_depth_limit_; }
209
210   // RunLoopHandler:
211   virtual void OnHandleReady(const Handle& handle) MOJO_OVERRIDE {
212     TestRunLoopHandler::OnHandleReady(handle);
213     EXPECT_EQ(handle.value(), pipe_->handle0.get().value());
214
215     ReadSignal();
216     size_t current_depth = ++depth_;
217     if (current_depth < kDepthLimit) {
218       WriteSignal();
219       run_loop_->Run();
220       if (current_depth == kDepthLimit - 1) {
221         // The topmost loop Quit()-ed, so its parent takes back the
222         // control without exeeding deadline.
223         EXPECT_EQ(error_count(), 0);
224       } else {
225         EXPECT_EQ(error_count(), 1);
226       }
227
228     } else {
229       EXPECT_EQ(current_depth, kDepthLimit);
230       reached_depth_limit_ = true;
231       run_loop_->Quit();
232     }
233     --depth_;
234   }
235
236   void WriteSignal() {
237     char write_byte = kSignalMagic;
238     MojoResult write_result = WriteMessageRaw(
239         pipe_->handle1.get(),
240         &write_byte, 1, NULL, 0, MOJO_WRITE_MESSAGE_FLAG_NONE);
241     EXPECT_EQ(write_result, MOJO_RESULT_OK);
242   }
243
244   void ReadSignal() {
245     char read_byte = 0;
246     uint32_t bytes_read = 1;
247     uint32_t handles_read = 0;
248     MojoResult read_result = ReadMessageRaw(
249         pipe_->handle0.get(),
250         &read_byte, &bytes_read, NULL, &handles_read,
251         MOJO_READ_MESSAGE_FLAG_NONE);
252     EXPECT_EQ(read_result, MOJO_RESULT_OK);
253     EXPECT_EQ(read_byte, kSignalMagic);
254   }
255
256  private:
257   RunLoop* run_loop_;
258   MessagePipe* pipe_;
259   size_t depth_;
260   bool reached_depth_limit_;
261
262   MOJO_DISALLOW_COPY_AND_ASSIGN(NestingRunLoopHandler);
263 };
264
265 const size_t NestingRunLoopHandler::kDepthLimit = 10;
266 const char NestingRunLoopHandler::kSignalMagic = 'X';
267
268 TEST_F(RunLoopTest, NestedRun) {
269   NestingRunLoopHandler handler;
270   MessagePipe test_pipe;
271   RunLoop run_loop;
272   handler.set_run_loop(&run_loop);
273   handler.set_pipe(&test_pipe);
274   run_loop.AddHandler(&handler, test_pipe.handle0.get(),
275                       MOJO_HANDLE_SIGNAL_READABLE,
276                       static_cast<MojoDeadline>(10000));
277   handler.WriteSignal();
278   run_loop.Run();
279
280   EXPECT_TRUE(handler.reached_depth_limit());
281   // Got MOJO_RESULT_DEADLINE_EXCEEDED once then removed from the
282   // RunLoop's handler list.
283   EXPECT_EQ(handler.error_count(), 1);
284   EXPECT_EQ(handler.last_error_result(), MOJO_RESULT_DEADLINE_EXCEEDED);
285 }
286
287 struct Task {
288   Task(int num, std::vector<int>* sequence) : num(num), sequence(sequence) {}
289
290   void Run() const { sequence->push_back(num); }
291
292   int num;
293   std::vector<int>* sequence;
294 };
295
296 TEST_F(RunLoopTest, DelayedTaskOrder) {
297   std::vector<int> sequence;
298   RunLoop run_loop;
299   run_loop.PostDelayedTask(Closure(Task(1, &sequence)), 0);
300   run_loop.PostDelayedTask(Closure(Task(2, &sequence)), 0);
301   run_loop.PostDelayedTask(Closure(Task(3, &sequence)), 0);
302   run_loop.RunUntilIdle();
303
304   ASSERT_EQ(3u, sequence.size());
305   EXPECT_EQ(1, sequence[0]);
306   EXPECT_EQ(2, sequence[1]);
307   EXPECT_EQ(3, sequence[2]);
308 }
309
310 }  // namespace
311 }  // namespace mojo