1// Copyright 2013 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 "gin/modules/timer.h"
6
7#include "base/memory/scoped_ptr.h"
8#include "base/message_loop/message_loop.h"
9#include "gin/handle.h"
10#include "gin/object_template_builder.h"
11#include "gin/public/isolate_holder.h"
12#include "gin/shell_runner.h"
13#include "gin/test/v8_test.h"
14#include "gin/try_catch.h"
15#include "gin/wrappable.h"
16#include "v8/include/v8.h"
17
18namespace gin {
19
20namespace {
21
22class Result : public Wrappable<Result> {
23 public:
24  static WrapperInfo kWrapperInfo;
25  static Handle<Result> Create(v8::Isolate* isolate) {
26    return CreateHandle(isolate, new Result());
27  }
28
29  int count() const { return count_; }
30  void set_count(int count) { count_ = count; }
31
32  void Quit() {
33    base::MessageLoop::current()->QuitNow();
34  }
35
36 private:
37  Result() : count_(0) {
38  }
39
40  virtual ~Result() {
41  }
42
43  virtual ObjectTemplateBuilder GetObjectTemplateBuilder(
44      v8::Isolate* isolate) OVERRIDE {
45    return Wrappable<Result>::GetObjectTemplateBuilder(isolate)
46        .SetProperty("count", &Result::count, &Result::set_count)
47        .SetMethod("quit", &Result::Quit);
48  }
49
50  int count_;
51};
52
53WrapperInfo Result::kWrapperInfo = { gin::kEmbedderNativeGin };
54
55struct TestHelper {
56  TestHelper(v8::Isolate* isolate)
57      : runner(new ShellRunner(&delegate, isolate)),
58        scope(runner.get()),
59        timer_module(TimerModule::Create(isolate)),
60        result(Result::Create(isolate)) {
61    EXPECT_FALSE(runner->global().IsEmpty());
62    runner->global()->Set(StringToV8(isolate, "timer"),
63                          timer_module->GetWrapper(isolate));
64    runner->global()->Set(StringToV8(isolate, "result"),
65                          result->GetWrapper(isolate));
66  }
67
68  void QuitSoon() {
69    loop.PostDelayedTask(FROM_HERE, base::MessageLoop::QuitWhenIdleClosure(),
70                         base::TimeDelta::FromMilliseconds(0));
71  }
72
73  ShellRunnerDelegate delegate;
74  scoped_ptr<ShellRunner> runner;
75  Runner::Scope scope;
76  Handle<TimerModule> timer_module;
77  Handle<Result> result;
78  base::MessageLoop loop;
79};
80
81}  // namespace
82
83typedef V8Test TimerUnittest;
84
85TEST_F(TimerUnittest, OneShot) {
86  TestHelper helper(instance_->isolate());
87  std::string source =
88     "timer.createOneShot(0, function() {"
89     "  result.count++;"
90     "});";
91
92  helper.runner->Run(source, "script");
93  EXPECT_EQ(0, helper.result->count());
94
95  helper.QuitSoon();
96  helper.loop.Run();
97  EXPECT_EQ(1, helper.result->count());
98}
99
100TEST_F(TimerUnittest, OneShotCancel) {
101  TestHelper helper(instance_->isolate());
102  std::string source =
103     "var t = timer.createOneShot(0, function() {"
104     "  result.count++;"
105     "});"
106     "t.cancel()";
107
108  helper.runner->Run(source, "script");
109  EXPECT_EQ(0, helper.result->count());
110
111  helper.QuitSoon();
112  helper.loop.Run();
113  EXPECT_EQ(0, helper.result->count());
114}
115
116TEST_F(TimerUnittest, Repeating) {
117  TestHelper helper(instance_->isolate());
118
119  // TODO(aa): Cannot do: if (++result.count == 3) because of v8 bug. Create
120  // test case and report.
121  std::string source =
122     "timer.createRepeating(0, function() {"
123     "  result.count++;"
124     "  if (result.count == 3) {"
125     "    result.quit();"
126     "  }"
127     "});";
128
129  helper.runner->Run(source, "script");
130  EXPECT_EQ(0, helper.result->count());
131
132  helper.loop.Run();
133  EXPECT_EQ(3, helper.result->count());
134}
135
136TEST_F(TimerUnittest, TimerCallbackToDestroyedRunner) {
137  TestHelper helper(instance_->isolate());
138  std::string source =
139     "timer.createOneShot(0, function() {"
140     "  result.count++;"
141     "});";
142
143  helper.runner->Run(source, "script");
144  EXPECT_EQ(0, helper.result->count());
145
146  // Destroy runner, which should destroy the timer object we created.
147  helper.QuitSoon();
148  helper.runner.reset(NULL);
149  helper.loop.Run();
150
151  // Timer should not have run because it was deleted.
152  EXPECT_EQ(0, helper.result->count());
153}
154
155}  // namespace gin
156