diff options
-rw-r--r-- | ppapi/ppapi.gyp | 20 | ||||
-rw-r--r-- | ppapi/proxy/plugin_var_tracker.h | 1 | ||||
-rw-r--r-- | ppapi/proxy/plugin_var_tracker_unittest.cc | 176 | ||||
-rw-r--r-- | ppapi/proxy/run_all_unittests.cc | 9 |
4 files changed, 206 insertions, 0 deletions
diff --git a/ppapi/ppapi.gyp b/ppapi/ppapi.gyp index ae5b4ed..c2c3237 100644 --- a/ppapi/ppapi.gyp +++ b/ppapi/ppapi.gyp @@ -647,5 +647,25 @@ }] ], }, + { + 'target_name': 'ppapi_unittests', + 'type': 'executable', + 'variables': { + 'chromium_code': 1, + }, + 'msvs_guid': 'C2BD9365-5BD7-44A7-854E-A49E606BE8E4', + 'dependencies': [ + 'ppapi_proxy', + '../base/base.gyp:test_support_base', + '../ipc/ipc.gyp:test_support_ipc', + '../testing/gmock.gyp:gmock', + '../testing/gtest.gyp:gtest', + ], + 'sources': [ + 'proxy/run_all_unittests.cc', + + 'proxy/plugin_var_tracker_unittest.cc', + ], + }, ], } diff --git a/ppapi/proxy/plugin_var_tracker.h b/ppapi/proxy/plugin_var_tracker.h index 4d6c49c..02e83d5 100644 --- a/ppapi/proxy/plugin_var_tracker.h +++ b/ppapi/proxy/plugin_var_tracker.h @@ -83,6 +83,7 @@ class PluginVarTracker { private: friend struct DefaultSingletonTraits<PluginVarTracker>; + friend class PluginVarTrackerTest; // Represents a var as received from the host. struct HostVar { diff --git a/ppapi/proxy/plugin_var_tracker_unittest.cc b/ppapi/proxy/plugin_var_tracker_unittest.cc new file mode 100644 index 0000000..52f7168 --- /dev/null +++ b/ppapi/proxy/plugin_var_tracker_unittest.cc @@ -0,0 +1,176 @@ +// Copyright (c) 2011 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 "ipc/ipc_test_sink.h" +#include "ppapi/proxy/plugin_var_tracker.h" +#include "ppapi/proxy/ppapi_messages.h" +#include "testing/gtest/include/gtest/gtest.h" + +namespace pp { +namespace proxy { + +namespace { + +PP_Var MakeObject(PluginVarTracker::VarID object_id) { + PP_Var ret; + ret.type = PP_VARTYPE_OBJECT; + ret.value.as_id = object_id; + return ret; +} + +// Creates a PP_Var from the given string ID. +PP_Var MakeString(PluginVarTracker::VarID string_id) { + PP_Var ret; + ret.type = PP_VARTYPE_STRING; + ret.value.as_id = string_id; + return ret; +} + +} // namespace + +class PluginVarTrackerTest : public testing::Test { + public: + PluginVarTrackerTest() {} + + protected: + // Asserts that there is a unique "release object" IPC message in the test + // sink. This will return the var ID from the message or -1 if none found. + PluginVarTracker::VarID GetObjectIDForUniqueReleaseObject() { + const IPC::Message* release_msg = sink_.GetUniqueMessageMatching( + PpapiHostMsg_PPBVar_ReleaseObject::ID); + if (!release_msg) + return -1; + + Tuple1<int64> id; + PpapiHostMsg_PPBVar_ReleaseObject::Read(release_msg, &id); + return id.a; + } + + PluginVarTracker tracker_; + + IPC::TestSink sink_; +}; + +TEST_F(PluginVarTrackerTest, Strings) { + std::string str("Hello"); + PluginVarTracker::VarID str_id1 = tracker_.MakeString(str); + EXPECT_NE(0, str_id1); + + PluginVarTracker::VarID str_id2 = tracker_.MakeString( + str.c_str(), static_cast<uint32_t>(str.size())); + EXPECT_NE(0, str_id2); + + // Make sure the strings come out the other end. + std::string result = tracker_.GetString(MakeString(str_id1)); + EXPECT_EQ(str, result); + result = tracker_.GetString(MakeString(str_id2)); + EXPECT_EQ(str, result); +} + +TEST_F(PluginVarTrackerTest, GetHostObject) { + PP_Var host_object = MakeObject(12345); + + // Round-trip through the tracker to make sure the host object comes out the + // other end. + PP_Var plugin_object = tracker_.ReceiveObjectPassRef(host_object, &sink_); + PP_Var host_object2 = tracker_.GetHostObject(plugin_object); + EXPECT_EQ(PP_VARTYPE_OBJECT, host_object2.type); + EXPECT_EQ(host_object.value.as_id, host_object2.value.as_id); + + tracker_.Release(plugin_object); +} + +TEST_F(PluginVarTrackerTest, ReceiveObjectPassRef) { + PP_Var host_object = MakeObject(12345); + + // Receive the object, we should have one ref and no messages. + PP_Var plugin_object = tracker_.ReceiveObjectPassRef(host_object, &sink_); + EXPECT_EQ(0u, sink_.message_count()); + EXPECT_EQ(1, tracker_.GetRefCountForObject(plugin_object)); + EXPECT_EQ(0, + tracker_.GetTrackedWithNoReferenceCountForObject(plugin_object)); + + // Receive the same object again, we should get the same plugin ID out. + PP_Var plugin_object2 = tracker_.ReceiveObjectPassRef(host_object, &sink_); + EXPECT_EQ(plugin_object.value.as_id, plugin_object2.value.as_id); + EXPECT_EQ(2, tracker_.GetRefCountForObject(plugin_object)); + EXPECT_EQ(0, + tracker_.GetTrackedWithNoReferenceCountForObject(plugin_object)); + + // It should have sent one message to decerment the refcount in the host. + // This is because it only maintains one host refcount for all references + // in the plugin, but the host just sent the second one. + EXPECT_EQ(host_object.value.as_id, GetObjectIDForUniqueReleaseObject()); + sink_.ClearMessages(); + + // Release the object, one ref at a time. The second release should free + // the tracking data and send a release message to the browser. + tracker_.Release(plugin_object); + EXPECT_EQ(1, tracker_.GetRefCountForObject(plugin_object)); + tracker_.Release(plugin_object); + EXPECT_EQ(-1, tracker_.GetRefCountForObject(plugin_object)); + EXPECT_EQ(host_object.value.as_id, GetObjectIDForUniqueReleaseObject()); +} + +// Tests freeing objects that have both refcounts and "tracked with no ref". +TEST_F(PluginVarTrackerTest, FreeTrackedAndReferencedObject) { + PP_Var host_object = MakeObject(12345); + + // Phase one: First receive via a "pass ref", then a tracked with no ref. + PP_Var plugin_var = tracker_.ReceiveObjectPassRef(host_object, &sink_); + PP_Var plugin_var2 = tracker_.TrackObjectWithNoReference(host_object, &sink_); + EXPECT_EQ(plugin_var.value.as_id, plugin_var2.value.as_id); + EXPECT_EQ(1, tracker_.GetRefCountForObject(plugin_var)); + EXPECT_EQ(1, tracker_.GetTrackedWithNoReferenceCountForObject(plugin_var)); + + // Free via the refcount, this should release the object to the browser but + // maintain the tracked object. + tracker_.Release(plugin_var); + EXPECT_EQ(0, tracker_.GetRefCountForObject(plugin_var)); + EXPECT_EQ(1u, sink_.message_count()); + EXPECT_EQ(host_object.value.as_id, GetObjectIDForUniqueReleaseObject()); + + // Now free via the tracked object, this should free it. + tracker_.StopTrackingObjectWithNoReference(plugin_var); + EXPECT_EQ(-1, tracker_.GetRefCountForObject(plugin_var)); + + // Phase two: Receive via a tracked, then get an addref. + sink_.ClearMessages(); + plugin_var = tracker_.TrackObjectWithNoReference(host_object, &sink_); + plugin_var2 = tracker_.ReceiveObjectPassRef(host_object, &sink_); + EXPECT_EQ(plugin_var.value.as_id, plugin_var2.value.as_id); + EXPECT_EQ(1, tracker_.GetRefCountForObject(plugin_var)); + EXPECT_EQ(1, tracker_.GetTrackedWithNoReferenceCountForObject(plugin_var)); + + // Free via the tracked object, this should have no effect. + tracker_.StopTrackingObjectWithNoReference(plugin_var); + EXPECT_EQ(0, tracker_.GetTrackedWithNoReferenceCountForObject(plugin_var)); + EXPECT_EQ(0u, sink_.message_count()); + + // Now free via the refcount, this should delete it. + tracker_.Release(plugin_var); + EXPECT_EQ(-1, tracker_.GetRefCountForObject(plugin_var)); + EXPECT_EQ(host_object.value.as_id, GetObjectIDForUniqueReleaseObject()); +} + +TEST_F(PluginVarTrackerTest, RecursiveTrackWithNoRef) { + PP_Var host_object = MakeObject(12345); + + // Receive a tracked object twice. + PP_Var plugin_var = tracker_.TrackObjectWithNoReference(host_object, &sink_); + EXPECT_EQ(1, tracker_.GetTrackedWithNoReferenceCountForObject(plugin_var)); + PP_Var plugin_var2 = tracker_.TrackObjectWithNoReference(host_object, &sink_); + EXPECT_EQ(plugin_var.value.as_id, plugin_var2.value.as_id); + EXPECT_EQ(0, tracker_.GetRefCountForObject(plugin_var)); + EXPECT_EQ(2, tracker_.GetTrackedWithNoReferenceCountForObject(plugin_var)); + + // Now release those tracked items, the reference should be freed. + tracker_.StopTrackingObjectWithNoReference(plugin_var); + EXPECT_EQ(1, tracker_.GetTrackedWithNoReferenceCountForObject(plugin_var)); + tracker_.StopTrackingObjectWithNoReference(plugin_var); + EXPECT_EQ(-1, tracker_.GetTrackedWithNoReferenceCountForObject(plugin_var)); +} + +} // namespace proxy +} // namespace pp diff --git a/ppapi/proxy/run_all_unittests.cc b/ppapi/proxy/run_all_unittests.cc new file mode 100644 index 0000000..7fd6ef2 --- /dev/null +++ b/ppapi/proxy/run_all_unittests.cc @@ -0,0 +1,9 @@ +// Copyright (c) 2011 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 "base/test/test_suite.h" + +int main(int argc, char** argv) { + return base::TestSuite(argc, argv).Run(); +} |