OLD | NEW |
---|---|
(Empty) | |
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/scoped_pp_var.h" | |
18 #include "ppapi/shared_impl/test_globals.h" | |
19 #include "ppapi/shared_impl/var.h" | |
20 #include "ppapi/shared_impl/var_tracker.h" | |
21 #include "testing/gtest/include/gtest/gtest.h" | |
22 | |
23 namespace ppapi { | |
24 namespace proxy { | |
25 | |
26 namespace { | |
27 | |
28 class RawVarDataTest : public testing::Test { | |
29 public: | |
30 RawVarDataTest() {} | |
31 ~RawVarDataTest() {} | |
32 | |
33 // testing::Test implementation. | |
34 virtual void SetUp() { | |
35 ProxyLock::Acquire(); | |
36 } | |
37 virtual void TearDown() { | |
38 ASSERT_TRUE(PpapiGlobals::Get()->GetVarTracker()->GetLiveVars().empty()); | |
39 ProxyLock::Release(); | |
40 } | |
41 | |
42 private: | |
43 TestGlobals globals_; | |
44 }; | |
45 | |
46 bool Equals(const PP_Var& expected, | |
47 const PP_Var& actual, | |
48 base::hash_map<int64_t, int64_t>* visited_map) { | |
dmichael (off chromium)
2013/04/16 16:36:53
May be worth a comment... it seems visited_map is
raymes1
2013/04/16 18:27:19
Done.
| |
49 if (expected.type != actual.type) | |
50 return false; | |
51 if (VarTracker::IsVarTypeRefcounted(expected.type)) { | |
52 base::hash_map<int64_t, int64_t>::iterator it = | |
53 visited_map->find(expected.value.as_id); | |
54 if (it != visited_map->end()) | |
55 return it->second == actual.value.as_id; | |
56 else | |
57 (*visited_map)[expected.value.as_id] = actual.value.as_id; | |
58 } | |
59 switch (expected.type) { | |
60 case PP_VARTYPE_UNDEFINED: | |
61 return true; | |
62 case PP_VARTYPE_NULL: | |
63 return true; | |
64 case PP_VARTYPE_BOOL: | |
65 return expected.value.as_bool == actual.value.as_bool; | |
66 case PP_VARTYPE_INT32: | |
67 return expected.value.as_int == actual.value.as_int; | |
68 case PP_VARTYPE_DOUBLE: | |
69 return expected.value.as_double == actual.value.as_double; | |
70 case PP_VARTYPE_OBJECT: | |
71 return expected.value.as_id == actual.value.as_id; | |
dmichael (off chromium)
2013/04/16 16:36:53
This could be a DCHECK instead, right?
raymes1
2013/04/16 18:27:19
Not sure exactly what you mean? In the old code, t
dmichael (off chromium)
2013/04/16 18:41:20
You're right, nevermind. Was confused because we d
| |
72 case PP_VARTYPE_STRING: { | |
73 StringVar* expected_var = StringVar::FromPPVar(expected); | |
74 StringVar* actual_var = StringVar::FromPPVar(actual); | |
75 if (!expected_var || !actual_var) | |
76 return expected_var == actual_var; | |
dmichael (off chromium)
2013/04/16 16:36:53
Since we want to bail for invalid Vars, should thi
raymes1
2013/04/16 18:27:19
Good idea this was a remnant from when I handled t
| |
77 return expected_var->value() == expected_var->value(); | |
78 } | |
79 case PP_VARTYPE_ARRAY_BUFFER: { | |
80 ArrayBufferVar* expected_var = ArrayBufferVar::FromPPVar(expected); | |
81 ArrayBufferVar* actual_var = ArrayBufferVar::FromPPVar(actual); | |
82 if (!expected_var || !actual_var) | |
83 return expected_var == actual_var; | |
84 std::string expected_data(static_cast<const char*>(expected_var->Map()), | |
85 expected_var->ByteLength()); | |
86 std::string actual_data(static_cast<const char*>(actual_var->Map()), | |
87 actual_var->ByteLength()); | |
88 return expected_data == actual_data; | |
dmichael (off chromium)
2013/04/16 16:36:53
Optional: It feels a little odd to copy them just
raymes1
2013/04/16 18:27:19
haha I avoid C memory functions like the plague an
dmichael (off chromium)
2013/04/16 18:41:20
I almost suggested std::equal, but you would have
| |
89 } | |
90 case PP_VARTYPE_ARRAY: { | |
91 ArrayVar* expected_var = ArrayVar::FromPPVar(expected); | |
92 ArrayVar* actual_var = ArrayVar::FromPPVar(actual); | |
93 if (!expected_var || !actual_var) | |
94 return expected_var == actual_var; | |
95 if (expected_var->elements().size() != actual_var->elements().size()) | |
96 return false; | |
97 for (size_t i = 0; i < expected_var->elements().size(); ++i) { | |
98 if (!Equals(expected_var->elements()[i].get(), | |
99 actual_var->elements()[i].get(), | |
100 visited_map)) { | |
101 return false; | |
102 } | |
103 } | |
104 return true; | |
105 } | |
106 case PP_VARTYPE_DICTIONARY: { | |
107 DictionaryVar* expected_var = DictionaryVar::FromPPVar(expected); | |
108 DictionaryVar* actual_var = DictionaryVar::FromPPVar(actual); | |
109 if (!expected_var || !actual_var) | |
110 return expected_var == actual_var; | |
111 if (expected_var->key_value_map().size() != | |
112 actual_var->key_value_map().size()) | |
113 return false; | |
114 DictionaryVar::KeyValueMap::const_iterator expected_iter = | |
115 expected_var->key_value_map().begin(); | |
116 DictionaryVar::KeyValueMap::const_iterator actual_iter = | |
117 actual_var->key_value_map().begin(); | |
118 for ( ; expected_iter != expected_var->key_value_map().end() && | |
119 actual_iter != actual_var->key_value_map().end(); | |
dmichael (off chromium)
2013/04/16 16:36:53
nit/suggestion: you don't really need to bounds ch
raymes1
2013/04/16 18:27:19
Done.
| |
120 ++expected_iter, ++actual_iter) { | |
121 if (expected_iter->first != actual_iter->first) | |
122 return false; | |
123 if (!Equals(expected_iter->second.get(), | |
124 actual_iter->second.get(), | |
125 visited_map)) { | |
126 return false; | |
127 } | |
128 } | |
129 return true; | |
130 } | |
131 } | |
132 NOTREACHED(); | |
133 return false; | |
134 } | |
dmichael (off chromium)
2013/04/16 16:36:53
Optional suggestion: You might want to have loggin
raymes1
2013/04/16 18:27:19
Ok - it's a good suggestion but I just added a TOD
| |
135 | |
136 bool Equals(const PP_Var& expected, | |
137 const PP_Var& actual) { | |
138 base::hash_map<int64_t, int64_t> visited_map; | |
139 return Equals(expected, actual, &visited_map); | |
140 } | |
141 | |
142 PP_Var WriteAndRead(const PP_Var& var) { | |
143 PP_Instance dummy_instance = 1234; | |
144 scoped_ptr<RawVarDataGraph> expected_data(RawVarDataGraph::Create( | |
145 var, dummy_instance)); | |
146 IPC::Message m; | |
147 expected_data->Write(&m); | |
148 PickleIterator iter(m); | |
149 scoped_ptr<RawVarDataGraph> actual_data(RawVarDataGraph::Read(&m, &iter)); | |
150 return actual_data->CreatePPVar(dummy_instance); | |
151 } | |
152 | |
153 // Assumes a ref for var. | |
154 bool WriteReadAndCompare(const PP_Var& var) { | |
155 ScopedPPVar expected(ScopedPPVar::PassRef(), var); | |
156 ScopedPPVar actual(ScopedPPVar::PassRef(), WriteAndRead(expected.get())); | |
157 return Equals(expected.get(), actual.get()); | |
158 } | |
159 | |
160 } // namespace | |
161 | |
162 TEST_F(RawVarDataTest, SimpleTest) { | |
163 EXPECT_TRUE(WriteReadAndCompare(PP_MakeUndefined())); | |
164 EXPECT_TRUE(WriteReadAndCompare(PP_MakeNull())); | |
165 EXPECT_TRUE(WriteReadAndCompare(PP_MakeInt32(100))); | |
166 EXPECT_TRUE(WriteReadAndCompare(PP_MakeBool(PP_TRUE))); | |
167 EXPECT_TRUE(WriteReadAndCompare(PP_MakeDouble(53.75))); | |
168 PP_Var object; | |
169 object.type = PP_VARTYPE_OBJECT; | |
170 object.value.as_id = 10; | |
171 EXPECT_TRUE(WriteReadAndCompare(object)); | |
172 } | |
173 | |
174 TEST_F(RawVarDataTest, StringTest) { | |
175 EXPECT_TRUE(WriteReadAndCompare(StringVar::StringToPPVar(""))); | |
176 EXPECT_TRUE(WriteReadAndCompare(StringVar::StringToPPVar("hello world!"))); | |
177 } | |
178 | |
179 TEST_F(RawVarDataTest, ArrayBufferTest) { | |
180 std::string data = "hello world!"; | |
181 PP_Var var = PpapiGlobals::Get()->GetVarTracker()->MakeArrayBufferPPVar( | |
182 data.size(), data.data()); | |
183 EXPECT_TRUE(WriteReadAndCompare(var)); | |
184 var = PpapiGlobals::Get()->GetVarTracker()->MakeArrayBufferPPVar( | |
185 0, static_cast<void*>(NULL)); | |
186 EXPECT_TRUE(WriteReadAndCompare(var)); | |
187 // TODO(raymes): add tests for shmem type array buffers. | |
188 } | |
189 | |
190 TEST_F(RawVarDataTest, DictionaryArrayTest) { | |
191 // Empty array. | |
192 scoped_refptr<ArrayVar> array(new ArrayVar); | |
193 ScopedPPVar release_array(ScopedPPVar::PassRef(), array->GetPPVar()); | |
194 EXPECT_TRUE(WriteReadAndCompare(array->GetPPVar())); | |
195 | |
196 size_t index = 0; | |
197 | |
198 // Array with primitives. | |
199 array->Set(index++, PP_MakeUndefined()); | |
200 array->Set(index++, PP_MakeNull()); | |
201 array->Set(index++, PP_MakeInt32(100)); | |
202 array->Set(index++, PP_MakeBool(PP_FALSE)); | |
203 array->Set(index++, PP_MakeDouble(0.123)); | |
204 EXPECT_TRUE(WriteReadAndCompare(array->GetPPVar())); | |
205 | |
206 // Empty dictionary. | |
207 scoped_refptr<DictionaryVar> dictionary(new DictionaryVar); | |
208 ScopedPPVar release_dictionary(ScopedPPVar::PassRef(), | |
209 dictionary->GetPPVar()); | |
210 EXPECT_TRUE(WriteReadAndCompare(dictionary->GetPPVar())); | |
211 | |
212 // Dictionary with primitives. | |
213 ScopedPPVar key1(ScopedPPVar::PassRef(), StringVar::StringToPPVar("1")); | |
214 dictionary->Set(key1.get(), PP_MakeUndefined()); | |
215 ScopedPPVar key2(ScopedPPVar::PassRef(), StringVar::StringToPPVar("2")); | |
216 dictionary->Set(key2.get(), PP_MakeNull()); | |
217 ScopedPPVar key3(ScopedPPVar::PassRef(), StringVar::StringToPPVar("3")); | |
218 dictionary->Set(key3.get(), PP_MakeInt32(-100)); | |
219 ScopedPPVar key4(ScopedPPVar::PassRef(), StringVar::StringToPPVar("4")); | |
220 dictionary->Set(key4.get(), PP_MakeBool(PP_TRUE)); | |
221 ScopedPPVar key5(ScopedPPVar::PassRef(), StringVar::StringToPPVar("5")); | |
222 dictionary->Set(key5.get(), PP_MakeDouble(-103.52)); | |
223 EXPECT_TRUE(WriteReadAndCompare(dictionary->GetPPVar())); | |
224 | |
225 // Array with dictionary. | |
226 array->Set(index++, release_dictionary.get()); | |
227 EXPECT_TRUE(WriteReadAndCompare(array->GetPPVar())); | |
228 | |
229 // Array with dictionary with array. | |
230 scoped_refptr<ArrayVar> array2(new ArrayVar); | |
231 ScopedPPVar release_array2(ScopedPPVar::PassRef(), array2->GetPPVar()); | |
232 array2->Set(0, PP_MakeInt32(100)); | |
233 ScopedPPVar key6(ScopedPPVar::PassRef(), StringVar::StringToPPVar("6")); | |
234 dictionary->Set(key6.get(), release_array2.get()); | |
235 EXPECT_TRUE(WriteReadAndCompare(array->GetPPVar())); | |
236 | |
237 // Array <-> dictionary cycle. | |
238 ScopedPPVar key7(ScopedPPVar::PassRef(), StringVar::StringToPPVar("7")); | |
239 dictionary->Set(key7.get(), release_array.get()); | |
240 ScopedPPVar result = ScopedPPVar(ScopedPPVar::PassRef(), | |
241 WriteAndRead(release_dictionary.get())); | |
242 EXPECT_TRUE(Equals(release_dictionary.get(), result.get())); | |
243 // Break the cycle. | |
dmichael (off chromium)
2013/04/16 16:36:53
This is because we'll leak it otherwise?
I feel l
raymes1
2013/04/16 18:27:19
Yes we leak otherwise. I agree. We need to provide
| |
244 dictionary->Delete(key7.get()); | |
245 DictionaryVar* result_dictionary = DictionaryVar::FromPPVar(result.get()); | |
246 result_dictionary->Delete(key7.get()); | |
247 | |
248 // Array with self references. | |
249 array->Set(index, release_array.get()); | |
250 result = ScopedPPVar(ScopedPPVar::PassRef(), | |
251 WriteAndRead(release_array.get())); | |
252 EXPECT_TRUE(Equals(release_array.get(), result.get())); | |
253 // Break the self reference. | |
254 array->Set(index, PP_MakeUndefined()); | |
255 ArrayVar* result_array = ArrayVar::FromPPVar(result.get()); | |
256 result_array->Set(index, PP_MakeUndefined()); | |
257 } | |
dmichael (off chromium)
2013/04/16 16:36:53
How about a test where one direct child references
raymes1
2013/04/16 18:27:19
Good idea. I also forgot to add a test for the sim
| |
258 | |
259 } // namespace proxy | |
260 } // namespace ppapi | |
OLD | NEW |