// Copyright (c) 2012 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 "ppapi/tests/test_flash_message_loop.h" #include "ppapi/c/pp_macros.h" #include "ppapi/c/ppb_var.h" #include "ppapi/cpp/core.h" #include "ppapi/cpp/dev/scriptable_object_deprecated.h" #include "ppapi/cpp/logging.h" #include "ppapi/cpp/module.h" #include "ppapi/cpp/private/flash_message_loop.h" #include "ppapi/tests/testing_instance.h" namespace { const char kDidRunScriptCallback[] = "DidRunScriptCallback"; } // namespace class TestFlashMessageLoop::InstanceSO : public pp::deprecated::ScriptableObject { public: explicit InstanceSO(TestFlashMessageLoop* owner) : owner_(owner) {} ~InstanceSO() override { if (owner_) owner_->clear_instance_so(); } // pp::deprecated::ScriptableObject overrides. bool HasMethod(const pp::Var& name, pp::Var* exception) override { if (!name.is_string()) return false; return name.AsString() == kDidRunScriptCallback; } pp::Var Call(const pp::Var& method_name, const std::vector& args, pp::Var* exception) override { if (!method_name.is_string()) return false; std::string name = method_name.AsString(); if (name == kDidRunScriptCallback) { if (args.size() != 0) { *exception = pp::Var("Bad argument to DidRunScriptCallback()"); } else if (owner_) { owner_->DidRunScriptCallback(); } } else { *exception = pp::Var("Bad function call"); } return pp::Var(); } void clear_owner() { owner_ = nullptr; } private: TestFlashMessageLoop* owner_; }; REGISTER_TEST_CASE(FlashMessageLoop); TestFlashMessageLoop::TestFlashMessageLoop(TestingInstance* instance) : TestCase(instance), message_loop_(nullptr), instance_so_(nullptr), suspend_script_callback_result_(false), callback_factory_(this) {} TestFlashMessageLoop::~TestFlashMessageLoop() { PP_DCHECK(!message_loop_); ResetTestObject(); if (instance_so_) instance_so_->clear_owner(); } void TestFlashMessageLoop::RunTests(const std::string& filter) { RUN_TEST(Basics, filter); RUN_TEST(RunWithoutQuit, filter); RUN_TEST(SuspendScriptCallbackWhileRunning, filter); } void TestFlashMessageLoop::DidRunScriptCallback() { // Script callbacks are not supposed to run while the Flash message loop is // running. if (message_loop_) suspend_script_callback_result_ = false; } pp::deprecated::ScriptableObject* TestFlashMessageLoop::CreateTestObject() { if (!instance_so_) instance_so_ = new InstanceSO(this); return instance_so_; } std::string TestFlashMessageLoop::TestBasics() { message_loop_ = new pp::flash::MessageLoop(instance_); pp::CompletionCallback callback = callback_factory_.NewCallback( &TestFlashMessageLoop::QuitMessageLoopTask); pp::Module::Get()->core()->CallOnMainThread(0, callback); int32_t result = message_loop_->Run(); ASSERT_TRUE(message_loop_); delete message_loop_; message_loop_ = nullptr; ASSERT_EQ(PP_OK, result); PASS(); } std::string TestFlashMessageLoop::TestRunWithoutQuit() { message_loop_ = new pp::flash::MessageLoop(instance_); pp::CompletionCallback callback = callback_factory_.NewCallback( &TestFlashMessageLoop::DestroyMessageLoopResourceTask); pp::Module::Get()->core()->CallOnMainThread(0, callback); int32_t result = message_loop_->Run(); if (message_loop_) { delete message_loop_; message_loop_ = nullptr; ASSERT_TRUE(false); } ASSERT_EQ(PP_ERROR_ABORTED, result); PASS(); } std::string TestFlashMessageLoop::TestSuspendScriptCallbackWhileRunning() { suspend_script_callback_result_ = true; message_loop_ = new pp::flash::MessageLoop(instance_); pp::CompletionCallback callback = callback_factory_.NewCallback( &TestFlashMessageLoop::TestSuspendScriptCallbackTask); pp::Module::Get()->core()->CallOnMainThread(0, callback); message_loop_->Run(); ASSERT_TRUE(message_loop_); delete message_loop_; message_loop_ = nullptr; ASSERT_TRUE(suspend_script_callback_result_); PASS(); } void TestFlashMessageLoop::TestSuspendScriptCallbackTask(int32_t unused) { pp::Var exception; pp::Var rev = instance_->ExecuteScript( "(function() {" " function delayedHandler() {" " document.getElementById('plugin').DidRunScriptCallback();" " }" " setTimeout(delayedHandler, 1);" "})()", &exception); if (!exception.is_undefined()) suspend_script_callback_result_ = false; pp::CompletionCallback callback = callback_factory_.NewCallback(&TestFlashMessageLoop::QuitMessageLoopTask); pp::Module::Get()->core()->CallOnMainThread(500, callback); } void TestFlashMessageLoop::QuitMessageLoopTask(int32_t unused) { if (message_loop_) message_loop_->Quit(); else PP_NOTREACHED(); } void TestFlashMessageLoop::DestroyMessageLoopResourceTask(int32_t unused) { if (message_loop_) { delete message_loop_; message_loop_ = nullptr; } else { PP_NOTREACHED(); } }