Index: ppapi/proxy/serialized_var_unittest.cc |
diff --git a/ppapi/proxy/serialized_var_unittest.cc b/ppapi/proxy/serialized_var_unittest.cc |
index 8ad6c992c9f1101cb9dbdb4f968d45252f7cc257..150f5e796fcbca73ccc385f5063883aea835720d 100644 |
--- a/ppapi/proxy/serialized_var_unittest.cc |
+++ b/ppapi/proxy/serialized_var_unittest.cc |
@@ -11,13 +11,6 @@ namespace proxy { |
namespace { |
-PP_Var MakeStringVar(int64_t string_id) { |
- PP_Var ret; |
- ret.type = PP_VARTYPE_STRING; |
- ret.value.as_id = string_id; |
- return ret; |
-} |
- |
PP_Var MakeObjectVar(int64_t object_id) { |
PP_Var ret; |
ret.type = PP_VARTYPE_OBJECT; |
@@ -34,6 +27,95 @@ class SerializedVarTest : public PluginProxyTest { |
// Tests output arguments in the plugin. This is when the host calls into the |
// plugin and the plugin returns something via an out param, like an exception. |
+TEST_F(SerializedVarTest, PluginSerializedVarInOutParam) { |
+ PP_Var host_object = MakeObjectVar(0x31337); |
+ |
+ PP_Var plugin_object; |
+ { |
+ // Receive the object param, we should be tracking it with no refcount, and |
+ // no messages sent. |
+ SerializedVarTestConstructor input(host_object); |
+ SerializedVarReceiveInput receive_input(input); |
+ plugin_object = receive_input.Get(plugin_dispatcher()); |
+ EXPECT_EQ(0, var_tracker().GetRefCountForObject(plugin_object)); |
+ EXPECT_EQ(0u, sink().message_count()); |
+ |
+ SerializedVar sv; |
+ { |
+ // The "OutParam" does its work in its destructor, it will write the |
+ // information to the SerializedVar we passed in the constructor. |
+ SerializedVarOutParam out_param(&sv); |
+ // An out-param needs to pass a reference to the caller, so it's the |
+ // responsibility of the plugin to bump the ref-count on an input |
+ // parameter. |
+ var_tracker().AddRefVar(plugin_object); |
+ EXPECT_EQ(1, var_tracker().GetRefCountForObject(plugin_object)); |
+ // We should have informed the host that a reference was taken. |
+ EXPECT_EQ(1u, sink().message_count()); |
+ *out_param.OutParam(plugin_dispatcher()) = plugin_object; |
+ } |
+ |
+ // The object should have transformed the plugin object back to the host |
+ // object ID. Nothing in the var tracker should have changed yet, and no |
+ // messages should have been sent. |
+ SerializedVarTestReader reader(sv); |
+ EXPECT_EQ(host_object.value.as_id, reader.GetIncompleteVar().value.as_id); |
+ EXPECT_EQ(1, var_tracker().GetRefCountForObject(plugin_object)); |
+ EXPECT_EQ(1u, sink().message_count()); |
+ } |
+ |
+ // The out param should have done an "end receive caller owned" on the plugin |
+ // var serialization rules, which should have released the "track-with-no- |
+ // reference" count in the var tracker as well as the 1 reference we passed |
+ // back to the host, so the object should no longer be in the tracker. The |
+ // reference we added has been removed, so another message should be sent to |
+ // the host to tell it we're done with the object. |
+ EXPECT_EQ(-1, var_tracker().GetRefCountForObject(plugin_object)); |
+ EXPECT_EQ(2u, sink().message_count()); |
+} |
+ |
+// Tests output strings in the plugin. This is when the host calls into the |
+// plugin with a string and the plugin returns it via an out param. |
+TEST_F(SerializedVarTest, PluginSerializedStringVarInOutParam) { |
+ PP_Var plugin_string; |
+ const std::string kTestString("elite"); |
+ { |
+ // Receive the string param. We should track it with 1 refcount. |
+ SerializedVarTestConstructor input(kTestString); |
+ SerializedVarReceiveInput receive_input(input); |
+ plugin_string = receive_input.Get(plugin_dispatcher()); |
+ EXPECT_EQ(1, var_tracker().GetRefCountForObject(plugin_string)); |
+ EXPECT_EQ(0u, sink().message_count()); |
+ |
+ SerializedVar sv; |
+ { |
+ // The "OutParam" does its work in its destructor, it will write the |
+ // information to the SerializedVar we passed in the constructor. |
+ SerializedVarOutParam out_param(&sv); |
+ // An out-param needs to pass a reference to the caller, so it's the |
+ // responsibility of the plugin to bump the ref-count of an input |
+ // parameter. |
+ var_tracker().AddRefVar(plugin_string); |
+ EXPECT_EQ(2, var_tracker().GetRefCountForObject(plugin_string)); |
+ EXPECT_EQ(0u, sink().message_count()); |
+ *out_param.OutParam(plugin_dispatcher()) = plugin_string; |
+ } |
+ |
+ // The SerializedVar should have set the string value internally. Nothing in |
+ // the var tracker should have changed yet, and no messages should have been |
+ // sent. |
+ SerializedVarTestReader reader(sv); |
+ EXPECT_EQ(kTestString, reader.GetString()); |
+ EXPECT_EQ(2, var_tracker().GetRefCountForObject(plugin_string)); |
+ EXPECT_EQ(0u, sink().message_count()); |
+ } |
+ // The reference the string had initially should be gone, and the reference we |
+ // passed to the host should also be gone, so the string should be removed. |
+ EXPECT_EQ(-1, var_tracker().GetRefCountForObject(plugin_string)); |
+ EXPECT_EQ(0u, sink().message_count()); |
+} |
+ |
+// Tests receiving an argument and passing it back out as an output parameter. |
TEST_F(SerializedVarTest, PluginSerializedVarOutParam) { |
PP_Var host_object = MakeObjectVar(0x31337); |
@@ -111,6 +193,72 @@ TEST_F(SerializedVarTest, PluginReceiveInput) { |
EXPECT_EQ(-1, var_tracker().GetRefCountForObject(plugin_object)); |
} |
+// Tests the case that the plugin receives the same vars twice as an input |
+// parameter (not passing ownership) within a vector. |
+TEST_F(SerializedVarTest, PluginVectorReceiveInput) { |
+ PP_Var host_object = MakeObjectVar(0x31337); |
+ |
+ PP_Var* plugin_objects; |
+ PP_Var* plugin_objects2; |
+ { |
+ // Receive the params. The object should be tracked with no refcount and |
+ // no messages sent. The string should is plugin-side only and should have |
+ // a reference-count of 1. |
+ std::vector<SerializedVar> input1; |
+ input1.push_back(SerializedVarTestConstructor(host_object)); |
+ input1.push_back(SerializedVarTestConstructor("elite")); |
+ SerializedVarVectorReceiveInput receive_input(input1); |
+ uint32_t array_size = 0; |
+ plugin_objects = receive_input.Get(plugin_dispatcher(), &array_size); |
+ ASSERT_EQ(2u, array_size); |
+ EXPECT_EQ(0, var_tracker().GetRefCountForObject(plugin_objects[0])); |
+ EXPECT_EQ(1, var_tracker().GetRefCountForObject(plugin_objects[1])); |
+ EXPECT_EQ(0u, sink().message_count()); |
+ |
+ // Receive the second param, it should be resolved to the same plugin |
+ // object and there should still be no refcount. |
+ std::vector<SerializedVar> input2; |
+ input2.push_back(SerializedVarTestConstructor(host_object)); |
+ input2.push_back(SerializedVarTestConstructor("elite")); |
+ SerializedVarVectorReceiveInput receive_input2(input2); |
+ uint32_t array_size2 = 0; |
+ plugin_objects2 = receive_input2.Get(plugin_dispatcher(), &array_size2); |
+ ASSERT_EQ(2u, array_size2); |
+ EXPECT_EQ(plugin_objects[0].value.as_id, plugin_objects2[0].value.as_id); |
+ EXPECT_EQ(0, var_tracker().GetRefCountForObject(plugin_objects[0])); |
+ // Strings get re-created with a new ID. We don't try to reuse strings in |
+ // the tracker, so the string should get a new ID. |
+ EXPECT_NE(plugin_objects[1].value.as_id, plugin_objects2[1].value.as_id); |
+ EXPECT_EQ(1, var_tracker().GetRefCountForObject(plugin_objects2[1])); |
+ EXPECT_EQ(0u, sink().message_count()); |
+ |
+ // Take a reference to the object, as if the plugin was using it, and then |
+ // release it, we should still be tracking the object since the |
+ // ReceiveInputs keep the "track_with_no_reference_count" alive until |
+ // they're destroyed. |
+ var_tracker().AddRefVar(plugin_objects[0]); |
+ EXPECT_EQ(1, var_tracker().GetRefCountForObject(plugin_objects[0])); |
+ var_tracker().ReleaseVar(plugin_objects[0]); |
+ EXPECT_EQ(0, var_tracker().GetRefCountForObject(plugin_objects[0])); |
+ EXPECT_EQ(2u, sink().message_count()); |
+ |
+ // Take a reference to a string and then release it. Make sure no messages |
+ // are sent. |
+ uint32_t old_message_count = sink().message_count(); |
+ var_tracker().AddRefVar(plugin_objects[1]); |
+ EXPECT_EQ(2, var_tracker().GetRefCountForObject(plugin_objects[1])); |
+ var_tracker().ReleaseVar(plugin_objects[1]); |
+ EXPECT_EQ(1, var_tracker().GetRefCountForObject(plugin_objects[1])); |
+ EXPECT_EQ(old_message_count, sink().message_count()); |
+ } |
+ |
+ // Since we didn't keep any refs to the objects or strings, so they should |
+ // have been freed. |
+ EXPECT_EQ(-1, var_tracker().GetRefCountForObject(plugin_objects[0])); |
+ EXPECT_EQ(-1, var_tracker().GetRefCountForObject(plugin_objects[1])); |
+ EXPECT_EQ(-1, var_tracker().GetRefCountForObject(plugin_objects2[1])); |
+} |
+ |
// Tests the plugin receiving a var as a return value from the browser |
// two different times (passing ownership). |
TEST_F(SerializedVarTest, PluginReceiveReturn) { |