// Copyright 2013 The Chromium Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. #include "gin/modules/timer.h" #include "base/memory/scoped_ptr.h" #include "base/message_loop/message_loop.h" #include "gin/handle.h" #include "gin/object_template_builder.h" #include "gin/public/isolate_holder.h" #include "gin/shell_runner.h" #include "gin/test/v8_test.h" #include "gin/try_catch.h" #include "gin/wrappable.h" #include "v8/include/v8.h" namespace gin { namespace { class Result : public Wrappable { public: static WrapperInfo kWrapperInfo; static Handle Create(v8::Isolate* isolate) { return CreateHandle(isolate, new Result()); } int count() const { return count_; } void set_count(int count) { count_ = count; } void Quit() { base::MessageLoop::current()->QuitNow(); } private: Result() : count_(0) { } ~Result() override {} ObjectTemplateBuilder GetObjectTemplateBuilder( v8::Isolate* isolate) override { return Wrappable::GetObjectTemplateBuilder(isolate) .SetProperty("count", &Result::count, &Result::set_count) .SetMethod("quit", &Result::Quit); } int count_; }; WrapperInfo Result::kWrapperInfo = { gin::kEmbedderNativeGin }; struct TestHelper { TestHelper(v8::Isolate* isolate) : runner(new ShellRunner(&delegate, isolate)), scope(runner.get()), timer_module(TimerModule::Create(isolate)), result(Result::Create(isolate)) { EXPECT_FALSE(runner->global().IsEmpty()); runner->global()->Set(StringToV8(isolate, "timer"), timer_module->GetWrapper(isolate)); runner->global()->Set(StringToV8(isolate, "result"), result->GetWrapper(isolate)); } void QuitSoon(base::MessageLoop* message_loop) { message_loop->PostDelayedTask(FROM_HERE, base::MessageLoop::QuitWhenIdleClosure(), base::TimeDelta::FromMilliseconds(0)); } ShellRunnerDelegate delegate; scoped_ptr runner; Runner::Scope scope; Handle timer_module; Handle result; }; } // namespace typedef V8Test TimerUnittest; TEST_F(TimerUnittest, OneShot) { TestHelper helper(instance_->isolate()); std::string source = "timer.createOneShot(0, function() {" " result.count++;" "});"; helper.runner->Run(source, "script"); EXPECT_EQ(0, helper.result->count()); helper.QuitSoon(&message_loop_); message_loop_.Run(); EXPECT_EQ(1, helper.result->count()); } TEST_F(TimerUnittest, OneShotCancel) { TestHelper helper(instance_->isolate()); std::string source = "var t = timer.createOneShot(0, function() {" " result.count++;" "});" "t.cancel()"; helper.runner->Run(source, "script"); EXPECT_EQ(0, helper.result->count()); helper.QuitSoon(&message_loop_); message_loop_.Run(); EXPECT_EQ(0, helper.result->count()); } TEST_F(TimerUnittest, Repeating) { TestHelper helper(instance_->isolate()); // TODO(aa): Cannot do: if (++result.count == 3) because of v8 bug. Create // test case and report. std::string source = "timer.createRepeating(0, function() {" " result.count++;" " if (result.count == 3) {" " result.quit();" " }" "});"; helper.runner->Run(source, "script"); EXPECT_EQ(0, helper.result->count()); message_loop_.Run(); EXPECT_EQ(3, helper.result->count()); } TEST_F(TimerUnittest, TimerCallbackToDestroyedRunner) { TestHelper helper(instance_->isolate()); std::string source = "timer.createOneShot(0, function() {" " result.count++;" "});"; helper.runner->Run(source, "script"); EXPECT_EQ(0, helper.result->count()); // Destroy runner, which should destroy the timer object we created. helper.QuitSoon(&message_loop_); helper.runner.reset(NULL); message_loop_.Run(); // Timer should not have run because it was deleted. EXPECT_EQ(0, helper.result->count()); } } // namespace gin