- add sources.
[platform/framework/web/crosswalk.git] / src / ppapi / proxy / serialized_var_unittest.cc
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.
4
5 #include "ppapi/proxy/ppapi_proxy_test.h"
6
7 #include "ppapi/proxy/serialized_var.h"
8 #include "ppapi/shared_impl/proxy_lock.h"
9
10 namespace ppapi {
11 namespace proxy {
12
13 namespace {
14
15 PP_Var MakeObjectVar(int64_t object_id) {
16   PP_Var ret;
17   ret.type = PP_VARTYPE_OBJECT;
18   ret.value.as_id = object_id;
19   return ret;
20 }
21
22 class SerializedVarTest : public PluginProxyTest {
23  public:
24   SerializedVarTest() {}
25 };
26
27 }  // namespace
28
29 // Tests output arguments in the plugin. This is when the host calls into the
30 // plugin and the plugin returns something via an out param, like an exception.
31 TEST_F(SerializedVarTest, PluginSerializedVarInOutParam) {
32   ProxyAutoLock lock;
33   PP_Var host_object = MakeObjectVar(0x31337);
34
35   PP_Var plugin_object;
36   {
37     // Receive the object param, we should be tracking it with no refcount, and
38     // no messages sent.
39     SerializedVarTestConstructor input(host_object);
40     SerializedVarReceiveInput receive_input(input);
41     plugin_object = receive_input.Get(plugin_dispatcher());
42     EXPECT_EQ(0, var_tracker().GetRefCountForObject(plugin_object));
43     EXPECT_EQ(0u, sink().message_count());
44
45     SerializedVar sv;
46     {
47       // The "OutParam" does its work in its destructor, it will write the
48       // information to the SerializedVar we passed in the constructor.
49       SerializedVarOutParam out_param(&sv);
50       // An out-param needs to pass a reference to the caller, so it's the
51       // responsibility of the plugin to bump the ref-count on an input
52       // parameter.
53       var_tracker().AddRefVar(plugin_object);
54       EXPECT_EQ(1, var_tracker().GetRefCountForObject(plugin_object));
55       // We should have informed the host that a reference was taken.
56       EXPECT_EQ(1u, sink().message_count());
57       *out_param.OutParam(plugin_dispatcher()) = plugin_object;
58     }
59
60     // The object should have transformed the plugin object back to the host
61     // object ID. Nothing in the var tracker should have changed yet, and no
62     // messages should have been sent.
63     SerializedVarTestReader reader(sv);
64     EXPECT_EQ(host_object.value.as_id, reader.GetVar().value.as_id);
65     EXPECT_EQ(1, var_tracker().GetRefCountForObject(plugin_object));
66     EXPECT_EQ(1u, sink().message_count());
67   }
68
69   // The out param should have done an "end receive caller owned" on the plugin
70   // var serialization rules, which should have released the "track-with-no-
71   // reference" count in the var tracker as well as the 1 reference we passed
72   // back to the host, so the object should no longer be in the tracker. The
73   // reference we added has been removed, so another message should be sent to
74   // the host to tell it we're done with the object.
75   EXPECT_EQ(-1, var_tracker().GetRefCountForObject(plugin_object));
76   EXPECT_EQ(2u, sink().message_count());
77 }
78
79 // Tests output strings in the plugin. This is when the host calls into the
80 // plugin with a string and the plugin returns it via an out param.
81 TEST_F(SerializedVarTest, PluginSerializedStringVarInOutParam) {
82   ProxyAutoLock lock;
83   PP_Var plugin_string;
84   const std::string kTestString("elite");
85   {
86     // Receive the string param. We should track it with 1 refcount.
87     SerializedVarTestConstructor input(kTestString);
88     SerializedVarReceiveInput receive_input(input);
89     plugin_string = receive_input.Get(plugin_dispatcher());
90     EXPECT_EQ(1, var_tracker().GetRefCountForObject(plugin_string));
91     EXPECT_EQ(0u, sink().message_count());
92
93     SerializedVar sv;
94     {
95       // The "OutParam" does its work in its destructor, it will write the
96       // information to the SerializedVar we passed in the constructor.
97       SerializedVarOutParam out_param(&sv);
98       // An out-param needs to pass a reference to the caller, so it's the
99       // responsibility of the plugin to bump the ref-count of an input
100       // parameter.
101       var_tracker().AddRefVar(plugin_string);
102       EXPECT_EQ(2, var_tracker().GetRefCountForObject(plugin_string));
103       EXPECT_EQ(0u, sink().message_count());
104       *out_param.OutParam(plugin_dispatcher()) = plugin_string;
105     }
106
107     // The SerializedVar should have set the string value internally. Nothing in
108     // the var tracker should have changed yet, and no messages should have been
109     // sent.
110     SerializedVarTestReader reader(sv);
111     //EXPECT_EQ(kTestString, *reader.GetTrackerStringPtr());
112     EXPECT_EQ(2, var_tracker().GetRefCountForObject(plugin_string));
113     EXPECT_EQ(0u, sink().message_count());
114   }
115   // The reference the string had initially should be gone, and the reference we
116   // passed to the host should also be gone, so the string should be removed.
117   EXPECT_EQ(-1, var_tracker().GetRefCountForObject(plugin_string));
118   EXPECT_EQ(0u, sink().message_count());
119 }
120
121 // Tests receiving an argument and passing it back to the browser as an output
122 // parameter.
123 TEST_F(SerializedVarTest, PluginSerializedVarOutParam) {
124   ProxyAutoLock lock;
125   PP_Var host_object = MakeObjectVar(0x31337);
126
127   // Start tracking this object in the plugin.
128   PP_Var plugin_object = var_tracker().ReceiveObjectPassRef(
129       host_object, plugin_dispatcher());
130   EXPECT_EQ(1, var_tracker().GetRefCountForObject(plugin_object));
131
132   {
133     SerializedVar sv;
134     {
135       // The "OutParam" does its work in its destructor, it will write the
136       // information to the SerializedVar we passed in the constructor.
137       SerializedVarOutParam out_param(&sv);
138       *out_param.OutParam(plugin_dispatcher()) = plugin_object;
139     }
140
141     // The object should have transformed the plugin object back to the host
142     // object ID. Nothing in the var tracker should have changed yet, and no
143     // messages should have been sent.
144     SerializedVarTestReader reader(sv);
145     EXPECT_EQ(host_object.value.as_id, reader.GetVar().value.as_id);
146     EXPECT_EQ(1, var_tracker().GetRefCountForObject(plugin_object));
147     EXPECT_EQ(0u, sink().message_count());
148   }
149
150   // The out param should have done an "end send pass ref" on the plugin
151   // var serialization rules, which should have in turn released the reference
152   // in the var tracker. Since we only had one reference, this should have sent
153   // a release to the browser.
154   EXPECT_EQ(-1, var_tracker().GetRefCountForObject(plugin_object));
155   EXPECT_EQ(1u, sink().message_count());
156
157   // We don't bother validating that message since it's nontrivial and the
158   // PluginVarTracker test has cases that cover that this message is correct.
159 }
160
161 // Tests the case that the plugin receives the same var twice as an input
162 // parameter (not passing ownership).
163 TEST_F(SerializedVarTest, PluginReceiveInput) {
164   ProxyAutoLock lock;
165   PP_Var host_object = MakeObjectVar(0x31337);
166
167   PP_Var plugin_object;
168   {
169     // Receive the first param, we should be tracking it with no refcount, and
170     // no messages sent.
171     SerializedVarTestConstructor input1(host_object);
172     SerializedVarReceiveInput receive_input(input1);
173     plugin_object = receive_input.Get(plugin_dispatcher());
174     EXPECT_EQ(0, var_tracker().GetRefCountForObject(plugin_object));
175     EXPECT_EQ(0u, sink().message_count());
176
177     // Receive the second param, it should be resolved to the same plugin
178     // object and there should still be no refcount.
179     SerializedVarTestConstructor input2(host_object);
180     SerializedVarReceiveInput receive_input2(input2);
181     PP_Var plugin_object2 = receive_input2.Get(plugin_dispatcher());
182     EXPECT_EQ(plugin_object.value.as_id, plugin_object2.value.as_id);
183     EXPECT_EQ(0, var_tracker().GetRefCountForObject(plugin_object));
184     EXPECT_EQ(0u, sink().message_count());
185
186     // Take a reference to the object, as if the plugin was using it, and then
187     // release it, we should still be tracking the object since the
188     // ReceiveInputs keep the "track_with_no_reference_count" alive until
189     // they're destroyed.
190     var_tracker().AddRefVar(plugin_object);
191     EXPECT_EQ(1, var_tracker().GetRefCountForObject(plugin_object));
192     var_tracker().ReleaseVar(plugin_object);
193     EXPECT_EQ(0, var_tracker().GetRefCountForObject(plugin_object));
194     EXPECT_EQ(2u, sink().message_count());
195   }
196
197   // Since we didn't keep any refs to the objects, it should have freed the
198   // object.
199   EXPECT_EQ(-1, var_tracker().GetRefCountForObject(plugin_object));
200 }
201
202 // Tests the case that the plugin receives the same vars twice as an input
203 // parameter (not passing ownership) within a vector.
204 TEST_F(SerializedVarTest, PluginVectorReceiveInput) {
205   ProxyAutoLock lock;
206   PP_Var host_object = MakeObjectVar(0x31337);
207
208   std::vector<PP_Var> plugin_objects;
209   std::vector<PP_Var> plugin_objects2;
210   {
211     // Receive the params. The object should be tracked with no refcount and
212     // no messages sent. The string should is plugin-side only and should have
213     // a reference-count of 1.
214     std::vector<SerializedVar> input1;
215     input1.push_back(SerializedVarTestConstructor(host_object));
216     input1.push_back(SerializedVarTestConstructor("elite"));
217     SerializedVarVectorReceiveInput receive_input(input1);
218     uint32_t array_size = 0;
219     PP_Var* plugin_objects_array =
220         receive_input.Get(plugin_dispatcher(), &array_size);
221     plugin_objects.insert(plugin_objects.begin(), plugin_objects_array,
222                           plugin_objects_array + array_size);
223     ASSERT_EQ(2u, array_size);
224     EXPECT_EQ(0, var_tracker().GetRefCountForObject(plugin_objects[0]));
225     EXPECT_EQ(1, var_tracker().GetRefCountForObject(plugin_objects[1]));
226     EXPECT_EQ(0u, sink().message_count());
227
228     // Receive the second param, it should be resolved to the same plugin
229     // object and there should still be no refcount.
230     std::vector<SerializedVar> input2;
231     input2.push_back(SerializedVarTestConstructor(host_object));
232     input2.push_back(SerializedVarTestConstructor("elite"));
233     SerializedVarVectorReceiveInput receive_input2(input2);
234     uint32_t array_size2 = 0;
235     PP_Var* plugin_objects_array2 =
236         receive_input2.Get(plugin_dispatcher(), &array_size2);
237     plugin_objects2.insert(plugin_objects2.begin(), plugin_objects_array2,
238                            plugin_objects_array2 + array_size2);
239     ASSERT_EQ(2u, array_size2);
240     EXPECT_EQ(plugin_objects[0].value.as_id, plugin_objects2[0].value.as_id);
241     EXPECT_EQ(0, var_tracker().GetRefCountForObject(plugin_objects[0]));
242     // Strings get re-created with a new ID. We don't try to reuse strings in
243     // the tracker, so the string should get a new ID.
244     EXPECT_NE(plugin_objects[1].value.as_id, plugin_objects2[1].value.as_id);
245     EXPECT_EQ(1, var_tracker().GetRefCountForObject(plugin_objects2[1]));
246     EXPECT_EQ(0u, sink().message_count());
247
248     // Take a reference to the object, as if the plugin was using it, and then
249     // release it, we should still be tracking the object since the
250     // ReceiveInputs keep the "track_with_no_reference_count" alive until
251     // they're destroyed.
252     var_tracker().AddRefVar(plugin_objects[0]);
253     EXPECT_EQ(1, var_tracker().GetRefCountForObject(plugin_objects[0]));
254     var_tracker().ReleaseVar(plugin_objects[0]);
255     EXPECT_EQ(0, var_tracker().GetRefCountForObject(plugin_objects[0]));
256     EXPECT_EQ(2u, sink().message_count());
257
258     // Take a reference to a string and then release it. Make sure no messages
259     // are sent.
260     uint32_t old_message_count = sink().message_count();
261     var_tracker().AddRefVar(plugin_objects[1]);
262     EXPECT_EQ(2, var_tracker().GetRefCountForObject(plugin_objects[1]));
263     var_tracker().ReleaseVar(plugin_objects[1]);
264     EXPECT_EQ(1, var_tracker().GetRefCountForObject(plugin_objects[1]));
265     EXPECT_EQ(old_message_count, sink().message_count());
266   }
267
268   // Since we didn't keep any refs to the objects or strings, so they should
269   // have been freed.
270   EXPECT_EQ(-1, var_tracker().GetRefCountForObject(plugin_objects[0]));
271   EXPECT_EQ(-1, var_tracker().GetRefCountForObject(plugin_objects[1]));
272   EXPECT_EQ(-1, var_tracker().GetRefCountForObject(plugin_objects2[1]));
273 }
274
275 // Tests the plugin receiving a var as a return value from the browser
276 // two different times (passing ownership).
277 TEST_F(SerializedVarTest, PluginReceiveReturn) {
278   ProxyAutoLock lock;
279   PP_Var host_object = MakeObjectVar(0x31337);
280
281   PP_Var plugin_object;
282   {
283     // Receive the first param, we should be tracking it with a refcount of 1.
284     SerializedVarTestConstructor input1(host_object);
285     ReceiveSerializedVarReturnValue receive_input(input1);
286     plugin_object = receive_input.Return(plugin_dispatcher());
287     EXPECT_EQ(1, var_tracker().GetRefCountForObject(plugin_object));
288     EXPECT_EQ(0u, sink().message_count());
289
290     // Receive the second param, it should be resolved to the same plugin
291     // object and there should be a plugin refcount of 2. There should have
292     // been an IPC message sent that released the duplicated ref in the browser
293     // (so both of our refs are represented by one in the browser).
294     SerializedVarTestConstructor input2(host_object);
295     ReceiveSerializedVarReturnValue receive_input2(input2);
296     PP_Var plugin_object2 = receive_input2.Return(plugin_dispatcher());
297     EXPECT_EQ(plugin_object.value.as_id, plugin_object2.value.as_id);
298     EXPECT_EQ(2, var_tracker().GetRefCountForObject(plugin_object));
299     EXPECT_EQ(1u, sink().message_count());
300   }
301
302   // The ReceiveSerializedVarReturnValue destructor shouldn't have affected
303   // the refcount or sent any messages.
304   EXPECT_EQ(2, var_tracker().GetRefCountForObject(plugin_object));
305   EXPECT_EQ(1u, sink().message_count());
306
307   // Manually release one refcount, it shouldn't have sent any more messages.
308   var_tracker().ReleaseVar(plugin_object);
309   EXPECT_EQ(1, var_tracker().GetRefCountForObject(plugin_object));
310   EXPECT_EQ(1u, sink().message_count());
311
312   // Manually release the last refcount, it should have freed it and sent a
313   // release message to the browser.
314   var_tracker().ReleaseVar(plugin_object);
315   EXPECT_EQ(-1, var_tracker().GetRefCountForObject(plugin_object));
316   EXPECT_EQ(2u, sink().message_count());
317 }
318
319 // Returns a value from the browser to the plugin, then return that one ref
320 // back to the browser.
321 TEST_F(SerializedVarTest, PluginReturnValue) {
322   ProxyAutoLock lock;
323   PP_Var host_object = MakeObjectVar(0x31337);
324
325   PP_Var plugin_object;
326   {
327     // Receive the param in the plugin.
328     SerializedVarTestConstructor input1(host_object);
329     ReceiveSerializedVarReturnValue receive_input(input1);
330     plugin_object = receive_input.Return(plugin_dispatcher());
331     EXPECT_EQ(1, var_tracker().GetRefCountForObject(plugin_object));
332     EXPECT_EQ(0u, sink().message_count());
333   }
334
335   {
336     // Now return to the browser.
337     SerializedVar output;
338     SerializedVarReturnValue return_output(&output);
339     return_output.Return(plugin_dispatcher(), plugin_object);
340
341     // The ref in the plugin should be alive until the ReturnValue goes out of
342     // scope, since the release needs to be after the browser processes the
343     // message.
344     EXPECT_EQ(1, var_tracker().GetRefCountForObject(plugin_object));
345   }
346
347   // When the ReturnValue object goes out of scope, it should have sent a
348   // release message to the browser.
349   EXPECT_EQ(-1, var_tracker().GetRefCountForObject(plugin_object));
350   EXPECT_EQ(1u, sink().message_count());
351 }
352
353 }  // namespace proxy
354 }  // namespace ppapi