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/raw_var_data.h"
6
7 #include "base/logging.h"
8 #include "base/memory/ref_counted.h"
9 #include "base/memory/scoped_ptr.h"
10 #include "base/values.h"
11 #include "ppapi/c/pp_bool.h"
12 #include "ppapi/c/pp_var.h"
13 #include "ppapi/shared_impl/array_var.h"
14 #include "ppapi/shared_impl/dictionary_var.h"
15 #include "ppapi/shared_impl/ppapi_globals.h"
16 #include "ppapi/shared_impl/proxy_lock.h"
17 #include "ppapi/shared_impl/resource_var.h"
18 #include "ppapi/shared_impl/scoped_pp_var.h"
19 #include "ppapi/shared_impl/test_globals.h"
20 #include "ppapi/shared_impl/unittest_utils.h"
21 #include "ppapi/shared_impl/var.h"
22 #include "ppapi/shared_impl/var_tracker.h"
23 #include "testing/gtest/include/gtest/gtest.h"
24
25 namespace ppapi {
26 namespace proxy {
27
28 namespace {
29
DefaultHandleWriter(IPC::Message * m,const SerializedHandle & handle)30 void DefaultHandleWriter(IPC::Message* m, const SerializedHandle& handle) {
31 IPC::ParamTraits<SerializedHandle>::Write(m, handle);
32 }
33
34 class RawVarDataTest : public testing::Test {
35 public:
RawVarDataTest()36 RawVarDataTest() {}
~RawVarDataTest()37 ~RawVarDataTest() {}
38
39 // testing::Test implementation.
SetUp()40 virtual void SetUp() {
41 ProxyLock::EnableLockingOnThreadForTest();
42 ProxyLock::Acquire();
43 }
TearDown()44 virtual void TearDown() {
45 ASSERT_TRUE(PpapiGlobals::Get()->GetVarTracker()->GetLiveVars().empty());
46 ProxyLock::Release();
47 }
48
49 private:
50 TestGlobals globals_;
51 };
52
WriteAndRead(const PP_Var & var,PP_Var * result)53 bool WriteAndRead(const PP_Var& var, PP_Var* result) {
54 PP_Instance dummy_instance = 1234;
55 scoped_ptr<RawVarDataGraph> expected_data(RawVarDataGraph::Create(
56 var, dummy_instance));
57 if (!expected_data)
58 return false;
59 IPC::Message m;
60 expected_data->Write(&m, base::Bind(&DefaultHandleWriter));
61 PickleIterator iter(m);
62 scoped_ptr<RawVarDataGraph> actual_data(RawVarDataGraph::Read(&m, &iter));
63 *result = actual_data->CreatePPVar(dummy_instance);
64 return true;
65 }
66
67 // Assumes a ref for var.
WriteReadAndCompare(const PP_Var & var)68 bool WriteReadAndCompare(const PP_Var& var) {
69 ScopedPPVar expected(ScopedPPVar::PassRef(), var);
70 PP_Var result;
71 bool success = WriteAndRead(expected.get(), &result);
72 if (!success)
73 return false;
74 ScopedPPVar actual(ScopedPPVar::PassRef(), result);
75 return TestEqual(expected.get(), actual.get());
76 }
77
78 } // namespace
79
TEST_F(RawVarDataTest,SimpleTest)80 TEST_F(RawVarDataTest, SimpleTest) {
81 EXPECT_TRUE(WriteReadAndCompare(PP_MakeUndefined()));
82 EXPECT_TRUE(WriteReadAndCompare(PP_MakeNull()));
83 EXPECT_TRUE(WriteReadAndCompare(PP_MakeInt32(100)));
84 EXPECT_TRUE(WriteReadAndCompare(PP_MakeBool(PP_TRUE)));
85 EXPECT_TRUE(WriteReadAndCompare(PP_MakeDouble(53.75)));
86 PP_Var object;
87 object.type = PP_VARTYPE_OBJECT;
88 object.value.as_id = 10;
89 EXPECT_TRUE(WriteReadAndCompare(object));
90 }
91
TEST_F(RawVarDataTest,StringTest)92 TEST_F(RawVarDataTest, StringTest) {
93 EXPECT_TRUE(WriteReadAndCompare(StringVar::StringToPPVar("")));
94 EXPECT_TRUE(WriteReadAndCompare(StringVar::StringToPPVar("hello world!")));
95 }
96
TEST_F(RawVarDataTest,ArrayBufferTest)97 TEST_F(RawVarDataTest, ArrayBufferTest) {
98 std::string data = "hello world!";
99 PP_Var var = PpapiGlobals::Get()->GetVarTracker()->MakeArrayBufferPPVar(
100 data.size(), data.data());
101 EXPECT_TRUE(WriteReadAndCompare(var));
102 var = PpapiGlobals::Get()->GetVarTracker()->MakeArrayBufferPPVar(
103 0, static_cast<void*>(NULL));
104 EXPECT_TRUE(WriteReadAndCompare(var));
105 // TODO(raymes): add tests for shmem type array buffers.
106 }
107
TEST_F(RawVarDataTest,DictionaryArrayTest)108 TEST_F(RawVarDataTest, DictionaryArrayTest) {
109 // Empty array.
110 scoped_refptr<ArrayVar> array(new ArrayVar);
111 ScopedPPVar release_array(ScopedPPVar::PassRef(), array->GetPPVar());
112 EXPECT_TRUE(WriteReadAndCompare(array->GetPPVar()));
113
114 size_t index = 0;
115
116 // Array with primitives.
117 array->Set(index++, PP_MakeUndefined());
118 array->Set(index++, PP_MakeNull());
119 array->Set(index++, PP_MakeInt32(100));
120 array->Set(index++, PP_MakeBool(PP_FALSE));
121 array->Set(index++, PP_MakeDouble(0.123));
122 EXPECT_TRUE(WriteReadAndCompare(array->GetPPVar()));
123
124 // Array with 2 references to the same string.
125 ScopedPPVar release_string(
126 ScopedPPVar::PassRef(), StringVar::StringToPPVar("abc"));
127 array->Set(index++, release_string.get());
128 array->Set(index++, release_string.get());
129 EXPECT_TRUE(WriteReadAndCompare(array->GetPPVar()));
130
131 // Array with nested array that references the same string.
132 scoped_refptr<ArrayVar> array2(new ArrayVar);
133 ScopedPPVar release_array2(ScopedPPVar::PassRef(), array2->GetPPVar());
134 array2->Set(0, release_string.get());
135 array->Set(index++, release_array2.get());
136 EXPECT_TRUE(WriteReadAndCompare(array->GetPPVar()));
137
138 // Empty dictionary.
139 scoped_refptr<DictionaryVar> dictionary(new DictionaryVar);
140 ScopedPPVar release_dictionary(ScopedPPVar::PassRef(),
141 dictionary->GetPPVar());
142 EXPECT_TRUE(WriteReadAndCompare(dictionary->GetPPVar()));
143
144 // Dictionary with primitives.
145 dictionary->SetWithStringKey("1", PP_MakeUndefined());
146 dictionary->SetWithStringKey("2", PP_MakeNull());
147 dictionary->SetWithStringKey("3", PP_MakeInt32(-100));
148 dictionary->SetWithStringKey("4", PP_MakeBool(PP_TRUE));
149 dictionary->SetWithStringKey("5", PP_MakeDouble(-103.52));
150 EXPECT_TRUE(WriteReadAndCompare(dictionary->GetPPVar()));
151
152 // Dictionary with 2 references to the same string.
153 dictionary->SetWithStringKey("6", release_string.get());
154 dictionary->SetWithStringKey("7", release_string.get());
155 EXPECT_TRUE(WriteReadAndCompare(dictionary->GetPPVar()));
156
157 // Dictionary with nested dictionary that references the same string.
158 scoped_refptr<DictionaryVar> dictionary2(new DictionaryVar);
159 ScopedPPVar release_dictionary2(ScopedPPVar::PassRef(),
160 dictionary2->GetPPVar());
161 dictionary2->SetWithStringKey("abc", release_string.get());
162 dictionary->SetWithStringKey("8", release_dictionary2.get());
163 EXPECT_TRUE(WriteReadAndCompare(dictionary->GetPPVar()));
164
165 // Array with dictionary.
166 array->Set(index++, release_dictionary.get());
167 EXPECT_TRUE(WriteReadAndCompare(array->GetPPVar()));
168
169 // Array with dictionary with array.
170 array2->Set(0, PP_MakeInt32(100));
171 dictionary->SetWithStringKey("9", release_array2.get());
172 EXPECT_TRUE(WriteReadAndCompare(array->GetPPVar()));
173
174 // Array <-> dictionary cycle.
175 dictionary->SetWithStringKey("10", release_array.get());
176 PP_Var result;
177 ASSERT_FALSE(WriteAndRead(release_dictionary.get(), &result));
178 // Break the cycle.
179 // TODO(raymes): We need some better machinery for releasing vars with
180 // cycles. Remove the code below once we have that.
181 dictionary->DeleteWithStringKey("10");
182
183 // Array with self references.
184 array->Set(index, release_array.get());
185 ASSERT_FALSE(WriteAndRead(release_array.get(), &result));
186 // Break the self reference.
187 array->Set(index, PP_MakeUndefined());
188 }
189
TEST_F(RawVarDataTest,ResourceTest)190 TEST_F(RawVarDataTest, ResourceTest) {
191 // TODO(mgiuca): This test passes trivially, since GetVarTracker() returns a
192 // TestVarTracker which returns a null PP_Var.
193 ScopedPPVar resource(
194 ScopedPPVar::PassRef(),
195 PpapiGlobals::Get()->GetVarTracker()->MakeResourcePPVar(34));
196 EXPECT_TRUE(WriteReadAndCompare(resource.get()));
197
198 // TODO(mgiuca): Test a host resource with an IPC::Message. It is currently a
199 // checkfail to deserialize such a resource.
200 }
201
202 } // namespace proxy
203 } // namespace ppapi
204