Upstream version 9.38.198.0
[platform/framework/web/crosswalk.git] / src / mojo / public / cpp / utility / tests / run_loop_unittest.cc
index ba17fe8..5f59aa2 100644 (file)
@@ -190,7 +190,122 @@ TEST_F(RunLoopTest, Current) {
   EXPECT_TRUE(RunLoop::current() == NULL);
 }
 
-// TODO(darin): Add tests for nested calls to RunLoop::Run(). See crbug/384633.
+class NestingRunLoopHandler : public TestRunLoopHandler {
+ public:
+  static const size_t kDepthLimit;
+  static const char kSignalMagic;
+
+  NestingRunLoopHandler()
+      : run_loop_(NULL),
+        pipe_(NULL),
+        depth_(0),
+        reached_depth_limit_(false) {}
+
+  virtual ~NestingRunLoopHandler() {}
+
+  void set_run_loop(RunLoop* run_loop) { run_loop_ = run_loop; }
+  void set_pipe(MessagePipe* pipe) { pipe_ = pipe; }
+  bool reached_depth_limit() const { return reached_depth_limit_; }
+
+  // RunLoopHandler:
+  virtual void OnHandleReady(const Handle& handle) MOJO_OVERRIDE {
+    TestRunLoopHandler::OnHandleReady(handle);
+    EXPECT_EQ(handle.value(), pipe_->handle0.get().value());
+
+    ReadSignal();
+    size_t current_depth = ++depth_;
+    if (current_depth < kDepthLimit) {
+      WriteSignal();
+      run_loop_->Run();
+      if (current_depth == kDepthLimit - 1) {
+        // The topmost loop Quit()-ed, so its parent takes back the
+        // control without exeeding deadline.
+        EXPECT_EQ(error_count(), 0);
+      } else {
+        EXPECT_EQ(error_count(), 1);
+      }
+
+    } else {
+      EXPECT_EQ(current_depth, kDepthLimit);
+      reached_depth_limit_ = true;
+      run_loop_->Quit();
+    }
+    --depth_;
+  }
+
+  void WriteSignal() {
+    char write_byte = kSignalMagic;
+    MojoResult write_result = WriteMessageRaw(
+        pipe_->handle1.get(),
+        &write_byte, 1, NULL, 0, MOJO_WRITE_MESSAGE_FLAG_NONE);
+    EXPECT_EQ(write_result, MOJO_RESULT_OK);
+  }
+
+  void ReadSignal() {
+    char read_byte = 0;
+    uint32_t bytes_read = 1;
+    uint32_t handles_read = 0;
+    MojoResult read_result = ReadMessageRaw(
+        pipe_->handle0.get(),
+        &read_byte, &bytes_read, NULL, &handles_read,
+        MOJO_READ_MESSAGE_FLAG_NONE);
+    EXPECT_EQ(read_result, MOJO_RESULT_OK);
+    EXPECT_EQ(read_byte, kSignalMagic);
+  }
+
+ private:
+  RunLoop* run_loop_;
+  MessagePipe* pipe_;
+  size_t depth_;
+  bool reached_depth_limit_;
+
+  MOJO_DISALLOW_COPY_AND_ASSIGN(NestingRunLoopHandler);
+};
+
+const size_t NestingRunLoopHandler::kDepthLimit = 10;
+const char NestingRunLoopHandler::kSignalMagic = 'X';
+
+TEST_F(RunLoopTest, NestedRun) {
+  NestingRunLoopHandler handler;
+  MessagePipe test_pipe;
+  RunLoop run_loop;
+  handler.set_run_loop(&run_loop);
+  handler.set_pipe(&test_pipe);
+  run_loop.AddHandler(&handler, test_pipe.handle0.get(),
+                      MOJO_HANDLE_SIGNAL_READABLE,
+                      static_cast<MojoDeadline>(10000));
+  handler.WriteSignal();
+  run_loop.Run();
+
+  EXPECT_TRUE(handler.reached_depth_limit());
+  // Got MOJO_RESULT_DEADLINE_EXCEEDED once then removed from the
+  // RunLoop's handler list.
+  EXPECT_EQ(handler.error_count(), 1);
+  EXPECT_EQ(handler.last_error_result(), MOJO_RESULT_DEADLINE_EXCEEDED);
+}
+
+struct Task {
+  Task(int num, std::vector<int>* sequence) : num(num), sequence(sequence) {}
+
+  void Run() const { sequence->push_back(num); }
+
+  int num;
+  std::vector<int>* sequence;
+};
+
+TEST_F(RunLoopTest, DelayedTaskOrder) {
+  std::vector<int> sequence;
+  RunLoop run_loop;
+  run_loop.PostDelayedTask(Closure(Task(1, &sequence)), 0);
+  run_loop.PostDelayedTask(Closure(Task(2, &sequence)), 0);
+  run_loop.PostDelayedTask(Closure(Task(3, &sequence)), 0);
+  run_loop.RunUntilIdle();
+
+  ASSERT_EQ(3u, sequence.size());
+  EXPECT_EQ(1, sequence[0]);
+  EXPECT_EQ(2, sequence[1]);
+  EXPECT_EQ(3, sequence[2]);
+}
 
 }  // namespace
 }  // namespace mojo