Fix iOS build for XCode 4.6.
[chromium-blink-merge.git] / ppapi / proxy / plugin_var_tracker_unittest.cc
blob10a7c5021bc2be9cdd27a02418b34699d43e6814
1 // Copyright (c) 2012 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.
5 #include "ipc/ipc_test_sink.h"
6 #include "ppapi/c/dev/ppp_class_deprecated.h"
7 #include "ppapi/proxy/plugin_var_tracker.h"
8 #include "ppapi/proxy/ppapi_messages.h"
9 #include "ppapi/proxy/ppapi_proxy_test.h"
10 #include "ppapi/proxy/proxy_object_var.h"
12 namespace ppapi {
13 namespace proxy {
15 namespace {
17 PP_Var MakeObject(int32 object_id) {
18 PP_Var ret;
19 ret.type = PP_VARTYPE_OBJECT;
20 ret.value.as_id = object_id;
21 return ret;
24 // A Deallocate() function for PPP_Class that just increments the integer
25 // referenced by the pointer so we know how often Deallocate was called.
26 void MarkOnDeallocate(void* object) {
27 (*static_cast<int*>(object))++;
30 // A class that just implements MarkOnDeallocate on destruction.
31 PPP_Class_Deprecated mark_on_deallocate_class = {
32 NULL, // HasProperty,
33 NULL, // HasMethod,
34 NULL, // GetProperty,
35 NULL, // GetAllPropertyNames,
36 NULL, // SetProperty,
37 NULL, // RemoveProperty,
38 NULL, // Call,
39 NULL, // Construct,
40 &MarkOnDeallocate
43 } // namespace
45 class PluginVarTrackerTest : public PluginProxyTest {
46 public:
47 PluginVarTrackerTest() {}
49 protected:
50 // Asserts that there is a unique "release object" IPC message in the test
51 // sink. This will return the var ID from the message or -1 if none found.
52 int32 GetObjectIDForUniqueReleaseObject() {
53 const IPC::Message* release_msg = sink().GetUniqueMessageMatching(
54 PpapiHostMsg_PPBVar_ReleaseObject::ID);
55 if (!release_msg)
56 return -1;
58 Tuple1<int64> id;
59 PpapiHostMsg_PPBVar_ReleaseObject::Read(release_msg, &id);
60 return id.a;
64 TEST_F(PluginVarTrackerTest, GetHostObject) {
65 PP_Var host_object = MakeObject(12345);
67 // Round-trip through the tracker to make sure the host object comes out the
68 // other end.
69 PP_Var plugin_object = var_tracker().ReceiveObjectPassRef(
70 host_object, plugin_dispatcher());
71 PP_Var host_object2 = var_tracker().GetHostObject(plugin_object);
72 EXPECT_EQ(PP_VARTYPE_OBJECT, host_object2.type);
73 EXPECT_EQ(host_object.value.as_id, host_object2.value.as_id);
75 var_tracker().ReleaseVar(plugin_object);
78 TEST_F(PluginVarTrackerTest, ReceiveObjectPassRef) {
79 PP_Var host_object = MakeObject(12345);
81 // Receive the object, we should have one ref and no messages.
82 PP_Var plugin_object = var_tracker().ReceiveObjectPassRef(
83 host_object, plugin_dispatcher());
84 EXPECT_EQ(0u, sink().message_count());
85 EXPECT_EQ(1, var_tracker().GetRefCountForObject(plugin_object));
86 EXPECT_EQ(0,
87 var_tracker().GetTrackedWithNoReferenceCountForObject(plugin_object));
89 // Receive the same object again, we should get the same plugin ID out.
90 PP_Var plugin_object2 = var_tracker().ReceiveObjectPassRef(
91 host_object, plugin_dispatcher());
92 EXPECT_EQ(plugin_object.value.as_id, plugin_object2.value.as_id);
93 EXPECT_EQ(2, var_tracker().GetRefCountForObject(plugin_object));
94 EXPECT_EQ(0,
95 var_tracker().GetTrackedWithNoReferenceCountForObject(plugin_object));
97 // It should have sent one message to decerment the refcount in the host.
98 // This is because it only maintains one host refcount for all references
99 // in the plugin, but the host just sent the second one.
100 EXPECT_EQ(host_object.value.as_id, GetObjectIDForUniqueReleaseObject());
101 sink().ClearMessages();
103 // Release the object, one ref at a time. The second release should free
104 // the tracking data and send a release message to the browser.
105 var_tracker().ReleaseVar(plugin_object);
106 EXPECT_EQ(1, var_tracker().GetRefCountForObject(plugin_object));
107 var_tracker().ReleaseVar(plugin_object);
108 EXPECT_EQ(-1, var_tracker().GetRefCountForObject(plugin_object));
109 EXPECT_EQ(host_object.value.as_id, GetObjectIDForUniqueReleaseObject());
112 // Tests freeing objects that have both refcounts and "tracked with no ref".
113 TEST_F(PluginVarTrackerTest, FreeTrackedAndReferencedObject) {
114 PP_Var host_object = MakeObject(12345);
116 // Phase one: First receive via a "pass ref", then a tracked with no ref.
117 PP_Var plugin_var = var_tracker().ReceiveObjectPassRef(
118 host_object, plugin_dispatcher());
119 PP_Var plugin_var2 = var_tracker().TrackObjectWithNoReference(
120 host_object, plugin_dispatcher());
121 EXPECT_EQ(plugin_var.value.as_id, plugin_var2.value.as_id);
122 EXPECT_EQ(1, var_tracker().GetRefCountForObject(plugin_var));
123 EXPECT_EQ(1,
124 var_tracker().GetTrackedWithNoReferenceCountForObject(plugin_var));
126 // Free via the refcount, this should release the object to the browser but
127 // maintain the tracked object.
128 var_tracker().ReleaseVar(plugin_var);
129 EXPECT_EQ(0, var_tracker().GetRefCountForObject(plugin_var));
130 EXPECT_EQ(1u, sink().message_count());
131 EXPECT_EQ(host_object.value.as_id, GetObjectIDForUniqueReleaseObject());
133 // Now free via the tracked object, this should free it.
134 var_tracker().StopTrackingObjectWithNoReference(plugin_var);
135 EXPECT_EQ(-1, var_tracker().GetRefCountForObject(plugin_var));
137 // Phase two: Receive via a tracked, then get an addref.
138 sink().ClearMessages();
139 plugin_var = var_tracker().TrackObjectWithNoReference(
140 host_object, plugin_dispatcher());
141 plugin_var2 = var_tracker().ReceiveObjectPassRef(
142 host_object, plugin_dispatcher());
143 EXPECT_EQ(plugin_var.value.as_id, plugin_var2.value.as_id);
144 EXPECT_EQ(1, var_tracker().GetRefCountForObject(plugin_var));
145 EXPECT_EQ(1,
146 var_tracker().GetTrackedWithNoReferenceCountForObject(plugin_var));
148 // Free via the tracked object, this should have no effect.
149 var_tracker().StopTrackingObjectWithNoReference(plugin_var);
150 EXPECT_EQ(0,
151 var_tracker().GetTrackedWithNoReferenceCountForObject(plugin_var));
152 EXPECT_EQ(0u, sink().message_count());
154 // Now free via the refcount, this should delete it.
155 var_tracker().ReleaseVar(plugin_var);
156 EXPECT_EQ(-1, var_tracker().GetRefCountForObject(plugin_var));
157 EXPECT_EQ(host_object.value.as_id, GetObjectIDForUniqueReleaseObject());
160 TEST_F(PluginVarTrackerTest, RecursiveTrackWithNoRef) {
161 PP_Var host_object = MakeObject(12345);
163 // Receive a tracked object twice.
164 PP_Var plugin_var = var_tracker().TrackObjectWithNoReference(
165 host_object, plugin_dispatcher());
166 EXPECT_EQ(1,
167 var_tracker().GetTrackedWithNoReferenceCountForObject(plugin_var));
168 PP_Var plugin_var2 = var_tracker().TrackObjectWithNoReference(
169 host_object, plugin_dispatcher());
170 EXPECT_EQ(plugin_var.value.as_id, plugin_var2.value.as_id);
171 EXPECT_EQ(0, var_tracker().GetRefCountForObject(plugin_var));
172 EXPECT_EQ(2,
173 var_tracker().GetTrackedWithNoReferenceCountForObject(plugin_var));
175 // Now release those tracked items, the reference should be freed.
176 var_tracker().StopTrackingObjectWithNoReference(plugin_var);
177 EXPECT_EQ(1,
178 var_tracker().GetTrackedWithNoReferenceCountForObject(plugin_var));
179 var_tracker().StopTrackingObjectWithNoReference(plugin_var);
180 EXPECT_EQ(-1,
181 var_tracker().GetTrackedWithNoReferenceCountForObject(plugin_var));
184 // Tests that objects implemented by the plugin that have no references by
185 // the plugin get their Deallocate function called on destruction.
186 TEST_F(PluginVarTrackerTest, PluginObjectInstanceDeleted) {
187 PP_Var host_object = MakeObject(12345);
188 PP_Instance pp_instance = 0x12345;
190 int deallocate_called = 0;
191 void* user_data = &deallocate_called;
193 // Make a var with one reference.
194 scoped_refptr<ProxyObjectVar> object(
195 new ProxyObjectVar(plugin_dispatcher(), host_object.value.as_id));
196 PP_Var plugin_var = MakeObject(var_tracker().AddVar(object));
197 var_tracker().PluginImplementedObjectCreated(pp_instance,
198 plugin_var,
199 &mark_on_deallocate_class,
200 user_data);
202 // Release the plugin ref to the var. WebKit hasn't called destroy so
203 // we won't get a destroy call.
204 object = NULL;
205 var_tracker().ReleaseVar(plugin_var);
206 EXPECT_EQ(0, deallocate_called);
208 // Synthesize an instance destuction, this should call Deallocate.
209 var_tracker().DidDeleteInstance(pp_instance);
210 EXPECT_EQ(1, deallocate_called);
213 // Tests what happens when a plugin keeps a ref to a plugin-implemented
214 // object var longer than the instance. We should not call the destructor until
215 // the plugin releases its last ref.
216 TEST_F(PluginVarTrackerTest, PluginObjectLeaked) {
217 PP_Var host_object = MakeObject(12345);
218 PP_Instance pp_instance = 0x12345;
220 int deallocate_called = 0;
221 void* user_data = &deallocate_called;
223 // Make a var with one reference.
224 scoped_refptr<ProxyObjectVar> object(
225 new ProxyObjectVar(plugin_dispatcher(), host_object.value.as_id));
226 PP_Var plugin_var = MakeObject(var_tracker().AddVar(object));
227 var_tracker().PluginImplementedObjectCreated(pp_instance,
228 plugin_var,
229 &mark_on_deallocate_class,
230 user_data);
232 // Destroy the instance. This should not call deallocate since the plugin
233 // still has a ref.
234 var_tracker().DidDeleteInstance(pp_instance);
235 EXPECT_EQ(0, deallocate_called);
237 // Release the plugin ref to the var. Since the instance is gone this should
238 // call deallocate.
239 object = NULL;
240 var_tracker().ReleaseVar(plugin_var);
241 EXPECT_EQ(1, deallocate_called);
244 } // namespace proxy
245 } // namespace ppapi