Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(219)

Side by Side Diff: webkit/plugins/ppapi/v8_var_converter_unittest.cc

Issue 20165002: Move webkit/plugins/ppapi to content/renderer/pepper. (Closed) Base URL: svn://chrome-svn/chrome/trunk/src/
Patch Set: more more clang fun Created 7 years, 4 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
« no previous file with comments | « webkit/plugins/ppapi/v8_var_converter.cc ('k') | webkit/plugins/webkit_plugins.gypi » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
(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 "webkit/plugins/ppapi/v8_var_converter.h"
6
7 #include <cmath>
8
9 #include "base/logging.h"
10 #include "base/memory/ref_counted.h"
11 #include "base/memory/scoped_ptr.h"
12 #include "base/values.h"
13 #include "ppapi/c/pp_bool.h"
14 #include "ppapi/c/pp_var.h"
15 #include "ppapi/shared_impl/array_var.h"
16 #include "ppapi/shared_impl/dictionary_var.h"
17 #include "ppapi/shared_impl/ppapi_globals.h"
18 #include "ppapi/shared_impl/proxy_lock.h"
19 #include "ppapi/shared_impl/scoped_pp_var.h"
20 #include "ppapi/shared_impl/test_globals.h"
21 #include "ppapi/shared_impl/unittest_utils.h"
22 #include "ppapi/shared_impl/var.h"
23 #include "ppapi/shared_impl/var_tracker.h"
24 #include "testing/gtest/include/gtest/gtest.h"
25 #include "v8/include/v8.h"
26
27 using ppapi::ArrayBufferVar;
28 using ppapi::ArrayVar;
29 using ppapi::DictionaryVar;
30 using ppapi::PpapiGlobals;
31 using ppapi::ProxyLock;
32 using ppapi::ScopedPPVar;
33 using ppapi::StringVar;
34 using ppapi::TestGlobals;
35 using ppapi::TestEqual;
36 using ppapi::VarTracker;
37
38 namespace webkit {
39 namespace ppapi {
40
41 namespace {
42
43 // Maps PP_Var IDs to the V8 value handle they correspond to.
44 typedef base::hash_map<int64_t, v8::Handle<v8::Value> > VarHandleMap;
45
46 bool Equals(const PP_Var& var,
47 v8::Handle<v8::Value> val,
48 VarHandleMap* visited_ids) {
49 if (::ppapi::VarTracker::IsVarTypeRefcounted(var.type)) {
50 VarHandleMap::iterator it = visited_ids->find(var.value.as_id);
51 if (it != visited_ids->end())
52 return it->second == val;
53 (*visited_ids)[var.value.as_id] = val;
54 }
55
56 if (val->IsUndefined()) {
57 return var.type == PP_VARTYPE_UNDEFINED;
58 } else if (val->IsNull()) {
59 return var.type == PP_VARTYPE_NULL;
60 } else if (val->IsBoolean() || val->IsBooleanObject()) {
61 return var.type == PP_VARTYPE_BOOL &&
62 PP_FromBool(val->ToBoolean()->Value()) == var.value.as_bool;
63 } else if (val->IsInt32()) {
64 return var.type == PP_VARTYPE_INT32 &&
65 val->ToInt32()->Value() == var.value.as_int;
66 } else if (val->IsNumber() || val->IsNumberObject()) {
67 return var.type == PP_VARTYPE_DOUBLE &&
68 fabs(val->ToNumber()->Value() - var.value.as_double) <= 1.0e-4;
69 } else if (val->IsString() || val->IsStringObject()) {
70 if (var.type != PP_VARTYPE_STRING)
71 return false;
72 StringVar* string_var = StringVar::FromPPVar(var);
73 DCHECK(string_var);
74 v8::String::Utf8Value utf8(val->ToString());
75 return std::string(*utf8, utf8.length()) == string_var->value();
76 } else if (val->IsArray()) {
77 if (var.type != PP_VARTYPE_ARRAY)
78 return false;
79 ArrayVar* array_var = ArrayVar::FromPPVar(var);
80 DCHECK(array_var);
81 v8::Handle<v8::Array> v8_array = val.As<v8::Array>();
82 if (v8_array->Length() != array_var->elements().size())
83 return false;
84 for (uint32 i = 0; i < v8_array->Length(); ++i) {
85 v8::Handle<v8::Value> child_v8 = v8_array->Get(i);
86 if (!Equals(array_var->elements()[i].get(), child_v8, visited_ids))
87 return false;
88 }
89 return true;
90 } else if (val->IsObject()) {
91 if (var.type == PP_VARTYPE_ARRAY_BUFFER) {
92 // TODO(raymes): Implement this when we have tests for array buffers.
93 NOTIMPLEMENTED();
94 return false;
95 } else {
96 v8::Handle<v8::Object> v8_object = val->ToObject();
97 if (var.type != PP_VARTYPE_DICTIONARY)
98 return false;
99 DictionaryVar* dict_var = DictionaryVar::FromPPVar(var);
100 DCHECK(dict_var);
101 v8::Handle<v8::Array> property_names(v8_object->GetOwnPropertyNames());
102 if (property_names->Length() != dict_var->key_value_map().size())
103 return false;
104 for (uint32 i = 0; i < property_names->Length(); ++i) {
105 v8::Handle<v8::Value> key(property_names->Get(i));
106
107 if (!key->IsString() && !key->IsNumber())
108 return false;
109 v8::Handle<v8::Value> child_v8 = v8_object->Get(key);
110
111 v8::String::Utf8Value name_utf8(key->ToString());
112 ScopedPPVar release_key(ScopedPPVar::PassRef(),
113 StringVar::StringToPPVar(
114 std::string(*name_utf8, name_utf8.length())));
115 if (!dict_var->HasKey(release_key.get()))
116 return false;
117 ScopedPPVar release_value(ScopedPPVar::PassRef(),
118 dict_var->Get(release_key.get()));
119 if (!Equals(release_value.get(), child_v8, visited_ids))
120 return false;
121 }
122 return true;
123 }
124 }
125 return false;
126 }
127
128 bool Equals(const PP_Var& var,
129 v8::Handle<v8::Value> val) {
130 VarHandleMap var_handle_map;
131 return Equals(var, val, &var_handle_map);
132 }
133
134 class V8VarConverterTest : public testing::Test {
135 public:
136 V8VarConverterTest()
137 : isolate_(v8::Isolate::GetCurrent()) {}
138 ~V8VarConverterTest() {}
139
140 // testing::Test implementation.
141 virtual void SetUp() {
142 ProxyLock::Acquire();
143 v8::HandleScope handle_scope(isolate_);
144 v8::Handle<v8::ObjectTemplate> global = v8::ObjectTemplate::New();
145 context_.Reset(isolate_, v8::Context::New(isolate_, NULL, global));
146 }
147 virtual void TearDown() {
148 context_.Dispose();
149 ASSERT_TRUE(PpapiGlobals::Get()->GetVarTracker()->GetLiveVars().empty());
150 ProxyLock::Release();
151 }
152
153 protected:
154 bool RoundTrip(const PP_Var& var, PP_Var* result) {
155 v8::HandleScope handle_scope(isolate_);
156 v8::Context::Scope context_scope(isolate_, context_);
157 v8::Local<v8::Context> context =
158 v8::Local<v8::Context>::New(isolate_, context_);
159 v8::Handle<v8::Value> v8_result;
160 if (!V8VarConverter::ToV8Value(var, context, &v8_result))
161 return false;
162 if (!Equals(var, v8_result))
163 return false;
164 if (!V8VarConverter::FromV8Value(v8_result, context, result))
165 return false;
166 return true;
167 }
168
169 // Assumes a ref for var.
170 bool RoundTripAndCompare(const PP_Var& var) {
171 ScopedPPVar expected(ScopedPPVar::PassRef(), var);
172 PP_Var actual_var;
173 if (!RoundTrip(expected.get(), &actual_var))
174 return false;
175 ScopedPPVar actual(ScopedPPVar::PassRef(), actual_var);
176 return TestEqual(expected.get(), actual.get());
177 }
178
179 v8::Isolate* isolate_;
180
181 // Context for the JavaScript in the test.
182 v8::Persistent<v8::Context> context_;
183
184 private:
185 TestGlobals globals_;
186 };
187
188 } // namespace
189
190 TEST_F(V8VarConverterTest, SimpleRoundTripTest) {
191 EXPECT_TRUE(RoundTripAndCompare(PP_MakeUndefined()));
192 EXPECT_TRUE(RoundTripAndCompare(PP_MakeNull()));
193 EXPECT_TRUE(RoundTripAndCompare(PP_MakeInt32(100)));
194 EXPECT_TRUE(RoundTripAndCompare(PP_MakeBool(PP_TRUE)));
195 EXPECT_TRUE(RoundTripAndCompare(PP_MakeDouble(53.75)));
196 }
197
198 TEST_F(V8VarConverterTest, StringRoundTripTest) {
199 EXPECT_TRUE(RoundTripAndCompare(StringVar::StringToPPVar("")));
200 EXPECT_TRUE(RoundTripAndCompare(StringVar::StringToPPVar("hello world!")));
201 }
202
203 TEST_F(V8VarConverterTest, ArrayBufferRoundTripTest) {
204 // TODO(raymes): Testing this here requires spinning up some of WebKit.
205 // Work out how to do this.
206 }
207
208 TEST_F(V8VarConverterTest, DictionaryArrayRoundTripTest) {
209 // Empty array.
210 scoped_refptr<ArrayVar> array(new ArrayVar);
211 ScopedPPVar release_array(ScopedPPVar::PassRef(), array->GetPPVar());
212 EXPECT_TRUE(RoundTripAndCompare(array->GetPPVar()));
213
214 size_t index = 0;
215
216 // Array with primitives.
217 array->Set(index++, PP_MakeUndefined());
218 array->Set(index++, PP_MakeNull());
219 array->Set(index++, PP_MakeInt32(100));
220 array->Set(index++, PP_MakeBool(PP_FALSE));
221 array->Set(index++, PP_MakeDouble(0.123));
222 EXPECT_TRUE(RoundTripAndCompare(array->GetPPVar()));
223
224 // Array with 2 references to the same string.
225 ScopedPPVar release_string(
226 ScopedPPVar::PassRef(), StringVar::StringToPPVar("abc"));
227 array->Set(index++, release_string.get());
228 array->Set(index++, release_string.get());
229 EXPECT_TRUE(RoundTripAndCompare(array->GetPPVar()));
230
231 // Array with nested array that references the same string.
232 scoped_refptr<ArrayVar> array2(new ArrayVar);
233 ScopedPPVar release_array2(ScopedPPVar::PassRef(), array2->GetPPVar());
234 array2->Set(0, release_string.get());
235 array->Set(index++, release_array2.get());
236 EXPECT_TRUE(RoundTripAndCompare(array->GetPPVar()));
237
238 // Empty dictionary.
239 scoped_refptr<DictionaryVar> dictionary(new DictionaryVar);
240 ScopedPPVar release_dictionary(ScopedPPVar::PassRef(),
241 dictionary->GetPPVar());
242 EXPECT_TRUE(RoundTripAndCompare(dictionary->GetPPVar()));
243
244 // Dictionary with primitives.
245 dictionary->SetWithStringKey("1", PP_MakeUndefined());
246 dictionary->SetWithStringKey("2", PP_MakeNull());
247 dictionary->SetWithStringKey("3", PP_MakeInt32(-100));
248 dictionary->SetWithStringKey("4", PP_MakeBool(PP_TRUE));
249 dictionary->SetWithStringKey("5", PP_MakeDouble(-103.52));
250 EXPECT_TRUE(RoundTripAndCompare(dictionary->GetPPVar()));
251
252 // Dictionary with 2 references to the same string.
253 dictionary->SetWithStringKey("6", release_string.get());
254 dictionary->SetWithStringKey("7", release_string.get());
255 EXPECT_TRUE(RoundTripAndCompare(dictionary->GetPPVar()));
256
257 // Dictionary with nested dictionary that references the same string.
258 scoped_refptr<DictionaryVar> dictionary2(new DictionaryVar);
259 ScopedPPVar release_dictionary2(ScopedPPVar::PassRef(),
260 dictionary2->GetPPVar());
261 dictionary2->SetWithStringKey("abc", release_string.get());
262 dictionary->SetWithStringKey("8", release_dictionary2.get());
263 EXPECT_TRUE(RoundTripAndCompare(dictionary->GetPPVar()));
264
265 // Array with dictionary.
266 array->Set(index++, release_dictionary.get());
267 EXPECT_TRUE(RoundTripAndCompare(array->GetPPVar()));
268
269 // Array with dictionary with array.
270 array2->Set(0, PP_MakeInt32(100));
271 dictionary->SetWithStringKey("9", release_array2.get());
272 EXPECT_TRUE(RoundTripAndCompare(array->GetPPVar()));
273 }
274
275 TEST_F(V8VarConverterTest, Cycles) {
276 // Check that cycles aren't converted.
277 v8::HandleScope handle_scope(isolate_);
278 v8::Context::Scope context_scope(isolate_, context_);
279 v8::Local<v8::Context> context =
280 v8::Local<v8::Context>::New(isolate_, context_);
281
282 // Var->V8 conversion.
283 {
284 scoped_refptr<DictionaryVar> dictionary(new DictionaryVar);
285 ScopedPPVar release_dictionary(ScopedPPVar::PassRef(),
286 dictionary->GetPPVar());
287 scoped_refptr<ArrayVar> array(new ArrayVar);
288 ScopedPPVar release_array(ScopedPPVar::PassRef(), array->GetPPVar());
289
290 dictionary->SetWithStringKey("1", release_array.get());
291 array->Set(0, release_dictionary.get());
292
293 v8::Handle<v8::Value> v8_result;
294
295 // Array <-> dictionary cycle.
296 dictionary->SetWithStringKey("1", release_array.get());
297 ASSERT_FALSE(V8VarConverter::ToV8Value(release_dictionary.get(),
298 context, &v8_result));
299 // Break the cycle.
300 // TODO(raymes): We need some better machinery for releasing vars with
301 // cycles. Remove the code below once we have that.
302 dictionary->DeleteWithStringKey("1");
303
304 // Array with self reference.
305 array->Set(0, release_array.get());
306 ASSERT_FALSE(V8VarConverter::ToV8Value(release_array.get(),
307 context, &v8_result));
308 // Break the self reference.
309 array->Set(0, PP_MakeUndefined());
310 }
311
312 // V8->Var conversion.
313 {
314 v8::Handle<v8::Object> object = v8::Object::New();
315 v8::Handle<v8::Array> array = v8::Array::New();
316
317 PP_Var var_result;
318
319 // Array <-> dictionary cycle.
320 std::string key = "1";
321 object->Set(v8::String::New(key.c_str(), key.length()), array);
322 array->Set(0, object);
323
324 ASSERT_FALSE(V8VarConverter::FromV8Value(object, context, &var_result));
325
326 // Array with self reference.
327 array->Set(0, array);
328 ASSERT_FALSE(V8VarConverter::FromV8Value(array, context, &var_result));
329 }
330 }
331
332 TEST_F(V8VarConverterTest, StrangeDictionaryKeyTest) {
333 {
334 // Test keys with '.'.
335 scoped_refptr<DictionaryVar> dictionary(new DictionaryVar);
336 dictionary->SetWithStringKey(".", PP_MakeUndefined());
337 dictionary->SetWithStringKey("x.y", PP_MakeUndefined());
338 EXPECT_TRUE(RoundTripAndCompare(dictionary->GetPPVar()));
339 }
340
341 {
342 // Test non-string key types. They should be cast to strings.
343 v8::HandleScope handle_scope(isolate_);
344 v8::Context::Scope context_scope(isolate_, context_);
345
346 const char* source = "(function() {"
347 "return {"
348 "1: 'foo',"
349 "'2': 'bar',"
350 "true: 'baz',"
351 "false: 'qux',"
352 "null: 'quux',"
353 "undefined: 'oops'"
354 "};"
355 "})();";
356
357 v8::Handle<v8::Script> script(v8::Script::New(v8::String::New(source)));
358 v8::Handle<v8::Object> object = script->Run().As<v8::Object>();
359 ASSERT_FALSE(object.IsEmpty());
360
361 PP_Var actual;
362 ASSERT_TRUE(V8VarConverter::FromV8Value(object,
363 v8::Local<v8::Context>::New(isolate_, context_), &actual));
364 ScopedPPVar release_actual(ScopedPPVar::PassRef(), actual);
365
366 scoped_refptr<DictionaryVar> expected(new DictionaryVar);
367 ScopedPPVar foo(ScopedPPVar::PassRef(), StringVar::StringToPPVar("foo"));
368 expected->SetWithStringKey("1", foo.get());
369 ScopedPPVar bar(ScopedPPVar::PassRef(), StringVar::StringToPPVar("bar"));
370 expected->SetWithStringKey("2", bar.get());
371 ScopedPPVar baz(ScopedPPVar::PassRef(), StringVar::StringToPPVar("baz"));
372 expected->SetWithStringKey("true", baz.get());
373 ScopedPPVar qux(ScopedPPVar::PassRef(), StringVar::StringToPPVar("qux"));
374 expected->SetWithStringKey("false", qux.get());
375 ScopedPPVar quux(ScopedPPVar::PassRef(), StringVar::StringToPPVar("quux"));
376 expected->SetWithStringKey("null", quux.get());
377 ScopedPPVar oops(ScopedPPVar::PassRef(), StringVar::StringToPPVar("oops"));
378 expected->SetWithStringKey("undefined", oops.get());
379 ScopedPPVar release_expected(
380 ScopedPPVar::PassRef(), expected->GetPPVar());
381
382 ASSERT_TRUE(TestEqual(release_expected.get(), release_actual.get()));
383 }
384 }
385
386 } // namespace ppapi
387 } // namespace webkit
OLDNEW
« no previous file with comments | « webkit/plugins/ppapi/v8_var_converter.cc ('k') | webkit/plugins/webkit_plugins.gypi » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698