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