| // 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 <stdint.h> |
| |
| #include "base/bind.h" |
| #include "base/test/test_timeouts.h" |
| #include "base/time/time.h" |
| #include "ppapi/c/dev/ppb_var_deprecated.h" |
| #include "ppapi/c/dev/ppp_class_deprecated.h" |
| #include "ppapi/c/pp_var.h" |
| #include "ppapi/c/ppb_var.h" |
| #include "ppapi/c/ppp_instance.h" |
| #include "ppapi/c/private/ppp_instance_private.h" |
| #include "ppapi/proxy/host_dispatcher.h" |
| #include "ppapi/proxy/interface_list.h" |
| #include "ppapi/proxy/ppapi_proxy_test.h" |
| #include "ppapi/shared_impl/ppapi_permissions.h" |
| #include "ppapi/shared_impl/ppb_var_shared.h" |
| #include "ppapi/shared_impl/var.h" |
| |
| namespace ppapi { |
| |
| // A fake version of V8ObjectVar for testing. |
| class V8ObjectVar : public ppapi::Var { |
| public: |
| V8ObjectVar() {} |
| ~V8ObjectVar() override {} |
| |
| // Var overrides. |
| V8ObjectVar* AsV8ObjectVar() override { return this; } |
| PP_VarType GetType() const override { return PP_VARTYPE_OBJECT; } |
| }; |
| |
| namespace proxy { |
| |
| namespace { |
| const PP_Instance kInstance = 0xdeadbeef; |
| |
| PP_Var GetPPVarNoAddRef(Var* var) { |
| PP_Var var_to_return = var->GetPPVar(); |
| PpapiGlobals::Get()->GetVarTracker()->ReleaseVar(var_to_return); |
| return var_to_return; |
| } |
| |
| PluginDispatcher* plugin_dispatcher = NULL; |
| // Return the plugin-side proxy for PPB_Var_Deprecated. |
| const PPB_Var_Deprecated* plugin_var_deprecated_if() { |
| // The test code must set the plugin dispatcher. |
| CHECK(plugin_dispatcher); |
| // Grab the plugin-side proxy for PPB_Var_Deprecated (for CreateObject). |
| return static_cast<const PPB_Var_Deprecated*>( |
| plugin_dispatcher->GetBrowserInterface( |
| PPB_VAR_DEPRECATED_INTERFACE)); |
| } |
| |
| // Mock PPP_Instance_Private. |
| PP_Var instance_obj; |
| PP_Var GetInstanceObject(PP_Instance /*instance*/) { |
| // The 1 ref we got from CreateObject will be passed to the host. We want to |
| // have a ref of our own. |
| printf("GetInstanceObject called\n"); |
| plugin_var_deprecated_if()->AddRef(instance_obj); |
| return instance_obj; |
| } |
| |
| PPP_Instance_Private ppp_instance_private_mock = { |
| &GetInstanceObject |
| }; |
| |
| // We need to pass in a |PPP_Class_Deprecated| to |
| // |PPB_Var_Deprecated->CreateObject| for a mock |Deallocate| method. |
| void Deallocate(void* object) { |
| } |
| |
| const PPP_Class_Deprecated ppp_class_deprecated_mock = { |
| NULL, // HasProperty |
| NULL, // HasMethod |
| NULL, // GetProperty |
| NULL, // GetAllPropertyNames |
| NULL, // SetProperty |
| NULL, // RemoveProperty |
| NULL, // Call |
| NULL, // Construct |
| &Deallocate |
| }; |
| |
| |
| // We need to mock PPP_Instance, so that we can create and destroy the pretend |
| // instance that PPP_Instance_Private uses. |
| PP_Bool DidCreate(PP_Instance /*instance*/, uint32_t /*argc*/, |
| const char* /*argn*/[], const char* /*argv*/[]) { |
| // Create an object var. This should exercise the typical path for creating |
| // instance objects. |
| instance_obj = |
| plugin_var_deprecated_if()->CreateObject(kInstance, |
| &ppp_class_deprecated_mock, |
| NULL); |
| return PP_TRUE; |
| } |
| |
| void DidDestroy(PP_Instance /*instance*/) { |
| // Decrement the reference count for our instance object. It should be |
| // deleted. |
| plugin_var_deprecated_if()->Release(instance_obj); |
| } |
| |
| PPP_Instance_1_0 ppp_instance_mock = { &DidCreate, &DidDestroy }; |
| |
| // Mock PPB_Var_Deprecated, so that we can emulate creating an Object Var. |
| PP_Var CreateObject(PP_Instance /*instance*/, |
| const PPP_Class_Deprecated* /*ppp_class*/, |
| void* /*ppp_class_data*/) { |
| V8ObjectVar* obj_var = new V8ObjectVar; |
| return obj_var->GetPPVar(); |
| } |
| |
| const PPB_Var_Deprecated ppb_var_deprecated_mock = { |
| PPB_Var_Shared::GetVarInterface1_0()->AddRef, |
| PPB_Var_Shared::GetVarInterface1_0()->Release, |
| PPB_Var_Shared::GetVarInterface1_0()->VarFromUtf8, |
| PPB_Var_Shared::GetVarInterface1_0()->VarToUtf8, |
| NULL, // HasProperty |
| NULL, // HasMethod |
| NULL, // GetProperty |
| NULL, // EnumerateProperties |
| NULL, // SetProperty |
| NULL, // RemoveProperty |
| NULL, // Call |
| NULL, // Construct |
| NULL, // IsInstanceOf |
| &CreateObject |
| }; |
| |
| class PPP_Instance_Private_ProxyTest : public TwoWayTest { |
| public: |
| PPP_Instance_Private_ProxyTest() |
| : TwoWayTest(TwoWayTest::TEST_PPP_INTERFACE) { |
| plugin().RegisterTestInterface(PPP_INSTANCE_PRIVATE_INTERFACE, |
| &ppp_instance_private_mock); |
| plugin().RegisterTestInterface(PPP_INSTANCE_INTERFACE_1_0, |
| &ppp_instance_mock); |
| host().RegisterTestInterface(PPB_VAR_DEPRECATED_INTERFACE, |
| &ppb_var_deprecated_mock); |
| } |
| }; |
| |
| } // namespace |
| |
| TEST_F(PPP_Instance_Private_ProxyTest, PPPInstancePrivate) { |
| // This test controls its own instance; we can't use the one that |
| // PluginProxyTestHarness provides. |
| ASSERT_NE(kInstance, pp_instance()); |
| HostDispatcher::SetForInstance(kInstance, host().host_dispatcher()); |
| |
| // Requires dev interfaces. |
| InterfaceList::SetProcessGlobalPermissions( |
| PpapiPermissions::AllPermissions()); |
| |
| // This file-local global is used by the PPP_Instance mock above in order to |
| // access PPB_Var_Deprecated. |
| plugin_dispatcher = plugin().plugin_dispatcher(); |
| |
| // Grab the host-side proxy for PPP_Instance and PPP_Instance_Private. |
| const PPP_Instance_Private* ppp_instance_private = |
| static_cast<const PPP_Instance_Private*>( |
| host().host_dispatcher()->GetProxiedInterface( |
| PPP_INSTANCE_PRIVATE_INTERFACE)); |
| const PPP_Instance_1_1* ppp_instance = static_cast<const PPP_Instance_1_1*>( |
| host().host_dispatcher()->GetProxiedInterface( |
| PPP_INSTANCE_INTERFACE_1_1)); |
| |
| // Initialize an Instance, so that the plugin-side machinery will work |
| // properly. |
| EXPECT_EQ(PP_TRUE, ppp_instance->DidCreate(kInstance, 0, NULL, NULL)); |
| |
| // Check the plugin-side reference count. |
| EXPECT_EQ(1, plugin().var_tracker().GetRefCountForObject(instance_obj)); |
| // Check the host-side var exists with the expected id and has 1 refcount (the |
| // refcount on behalf of the plugin). |
| int32_t expected_host_id = |
| plugin().var_tracker().GetHostObject(instance_obj).value.as_id; |
| Var* host_var = host().var_tracker().GetVar(expected_host_id); |
| ASSERT_TRUE(host_var); |
| EXPECT_EQ( |
| 1, |
| host().var_tracker().GetRefCountForObject(GetPPVarNoAddRef(host_var))); |
| |
| // Call from the browser side to get the instance object. |
| PP_Var host_pp_var = ppp_instance_private->GetInstanceObject(kInstance); |
| EXPECT_EQ(instance_obj.type, host_pp_var.type); |
| EXPECT_EQ(host_pp_var.value.as_id, expected_host_id); |
| EXPECT_EQ(1, plugin().var_tracker().GetRefCountForObject(instance_obj)); |
| // A reference is passed to the browser, which we consume here. |
| host().var_tracker().ReleaseVar(host_pp_var); |
| EXPECT_EQ(1, host().var_tracker().GetRefCountForObject(host_pp_var)); |
| |
| // The plugin is going away; generally, so will all references to its instance |
| // object. |
| host().var_tracker().ReleaseVar(host_pp_var); |
| // Destroy the instance. DidDestroy above decrements the reference count for |
| // instance_obj, so it should also be destroyed. |
| ppp_instance->DidDestroy(kInstance); |
| EXPECT_EQ(-1, plugin().var_tracker().GetRefCountForObject(instance_obj)); |
| EXPECT_EQ(-1, host().var_tracker().GetRefCountForObject(host_pp_var)); |
| } |
| |
| } // namespace proxy |
| } // namespace ppapi |
| |