1 // Copyright (c) 2011 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 "testing/gtest/include/gtest/gtest.h"
6
7 #include "base/compiler_specific.h"
8 #include "ppapi/shared_impl/proxy_lock.h"
9 #include "ppapi/shared_impl/var.h"
10 #include "ppapi/shared_impl/var_tracker.h"
11 #include "ppapi/shared_impl/test_globals.h"
12
13 namespace ppapi {
14
15 namespace {
16
17 int mock_var_alive_count = 0;
18
19 class MockStringVar : public StringVar {
20 public:
MockStringVar(const std::string & str)21 MockStringVar(const std::string& str) : StringVar(str) {
22 mock_var_alive_count++;
23 }
~MockStringVar()24 virtual ~MockStringVar() { mock_var_alive_count--; }
HasValidVarID()25 bool HasValidVarID() { return GetExistingVarID() != 0; }
26 };
27
28 class MockObjectVar : public Var {
29 public:
MockObjectVar()30 MockObjectVar() : Var() { mock_var_alive_count++; }
~MockObjectVar()31 virtual ~MockObjectVar() { mock_var_alive_count--; }
GetType() const32 virtual PP_VarType GetType() const OVERRIDE { return PP_VARTYPE_OBJECT; }
HasValidVarID()33 bool HasValidVarID() { return GetExistingVarID() != 0; }
34 };
35
36 } // namespace
37
38 class VarTrackerTest : public testing::Test {
39 public:
VarTrackerTest()40 VarTrackerTest() {}
41
42 // Test implementation.
SetUp()43 virtual void SetUp() OVERRIDE {
44 ASSERT_EQ(0, mock_var_alive_count);
45 ProxyLock::EnableLockingOnThreadForTest();
46 }
TearDown()47 virtual void TearDown() OVERRIDE {}
48
var_tracker()49 VarTracker& var_tracker() { return *globals_.GetVarTracker(); }
50
51 private:
52 TestGlobals globals_;
53 };
54
55 // Test that ResetVarID is called when the last PP_Var ref was deleted but the
56 // object lives on.
TEST_F(VarTrackerTest,LastResourceRef)57 TEST_F(VarTrackerTest, LastResourceRef) {
58 ProxyAutoLock lock;
59 scoped_refptr<MockStringVar> var(new MockStringVar(std::string("xyz")));
60 PP_Var pp_var = var->GetPPVar();
61 EXPECT_TRUE(var->HasValidVarID());
62 EXPECT_TRUE(var_tracker().GetVar(var->GetExistingVarID()));
63
64 // Releasing it should keep the object (because we have a ref) but reset the
65 // var_id_.
66 EXPECT_TRUE(var_tracker().ReleaseVar(pp_var));
67 EXPECT_FALSE(var->HasValidVarID());
68 EXPECT_EQ(1, mock_var_alive_count);
69
70 var = NULL;
71 EXPECT_EQ(0, mock_var_alive_count);
72 }
73
TEST_F(VarTrackerTest,GetPluginRefAgain)74 TEST_F(VarTrackerTest, GetPluginRefAgain) {
75 ProxyAutoLock lock;
76 scoped_refptr<MockStringVar> var(new MockStringVar(std::string("xyz")));
77 PP_Var pp_var = var->GetPPVar();
78 EXPECT_TRUE(var_tracker().ReleaseVar(pp_var));
79 EXPECT_FALSE(var->HasValidVarID());
80 EXPECT_EQ(1, mock_var_alive_count);
81
82 // Obtaining PP_Var ref again, and add ref from VarTracker.
83 pp_var = var->GetPPVar();
84 EXPECT_TRUE(var->HasValidVarID());
85 EXPECT_TRUE(var_tracker().GetVar(var->GetExistingVarID()));
86 scoped_refptr<MockStringVar> another_var =
87 static_cast<MockStringVar*>(var_tracker().GetVar(pp_var));
88 EXPECT_EQ(1, mock_var_alive_count);
89
90 // Releasing it again.
91 EXPECT_TRUE(var_tracker().ReleaseVar(pp_var));
92 EXPECT_FALSE(var->HasValidVarID());
93 EXPECT_EQ(1, mock_var_alive_count);
94
95 var = NULL;
96 EXPECT_FALSE(var_tracker().GetVar(pp_var));
97 EXPECT_EQ(1, mock_var_alive_count);
98 another_var = NULL;
99 EXPECT_FALSE(var_tracker().GetVar(pp_var));
100 EXPECT_EQ(0, mock_var_alive_count);
101 }
102
103 // Tests when the plugin is holding a ref to a PP_Var when the instance is
104 // owned only by VarTracker.
TEST_F(VarTrackerTest,PluginRefWithoutVarRef)105 TEST_F(VarTrackerTest, PluginRefWithoutVarRef) {
106 ProxyAutoLock lock;
107 // Make a PP_Var with one ref held by the plugin, and release the reference.
108 scoped_refptr<MockStringVar> var(new MockStringVar(std::string("zzz")));
109 PP_Var pp_var = var->GetPPVar();
110 EXPECT_EQ(1, mock_var_alive_count);
111 var = NULL;
112 EXPECT_EQ(1, mock_var_alive_count);
113
114 // The var is owned only by VarTracker. PP_Var must be still valid.
115 EXPECT_TRUE(var_tracker().GetVar(pp_var));
116
117 var_tracker().ReleaseVar(pp_var);
118 EXPECT_EQ(0, mock_var_alive_count);
119 EXPECT_FALSE(var_tracker().GetVar(pp_var));
120 }
121
122 // Tests on Var having type of PP_VARTYPE_OBJECT.
TEST_F(VarTrackerTest,ObjectRef)123 TEST_F(VarTrackerTest, ObjectRef) {
124 ProxyAutoLock lock;
125 scoped_refptr<MockObjectVar> var(new MockObjectVar());
126 PP_Var pp_var = var->GetPPVar();
127 EXPECT_TRUE(var_tracker().ReleaseVar(pp_var));
128 EXPECT_FALSE(var->HasValidVarID());
129 EXPECT_EQ(1, mock_var_alive_count);
130
131 // Obtaining PP_Var ref again, and add ref from VarTracker.
132 pp_var = var->GetPPVar();
133 EXPECT_TRUE(var->HasValidVarID());
134 EXPECT_TRUE(var_tracker().GetVar(var->GetExistingVarID()));
135 scoped_refptr<MockObjectVar> another_var =
136 static_cast<MockObjectVar*>(var_tracker().GetVar(pp_var));
137 EXPECT_EQ(1, mock_var_alive_count);
138
139 // Releasing all references, then only VarTracker own the instance.
140 var = NULL;
141 EXPECT_TRUE(var_tracker().GetVar(pp_var));
142 EXPECT_EQ(1, mock_var_alive_count);
143 another_var = NULL;
144 EXPECT_TRUE(var_tracker().GetVar(pp_var));
145 EXPECT_EQ(1, mock_var_alive_count);
146
147 // Releasing plugin reference.
148 EXPECT_TRUE(var_tracker().ReleaseVar(pp_var));
149 EXPECT_EQ(0, mock_var_alive_count);
150 }
151
152 } // namespace ppapi
153