OLD | NEW |
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 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 | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "content/child/v8_value_converter_impl.h" | 5 #include "content/child/v8_value_converter_impl.h" |
6 | 6 |
7 #include <stddef.h> | 7 #include <stddef.h> |
8 #include <stdint.h> | 8 #include <stdint.h> |
9 | 9 |
10 #include <cmath> | 10 #include <cmath> |
(...skipping 86 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
97 std::string GetString(v8::Local<v8::Array> value, uint32_t index) { | 97 std::string GetString(v8::Local<v8::Array> value, uint32_t index) { |
98 v8::Local<v8::String> temp = value->Get(index).As<v8::String>(); | 98 v8::Local<v8::String> temp = value->Get(index).As<v8::String>(); |
99 if (temp.IsEmpty()) { | 99 if (temp.IsEmpty()) { |
100 ADD_FAILURE(); | 100 ADD_FAILURE(); |
101 return std::string(); | 101 return std::string(); |
102 } | 102 } |
103 v8::String::Utf8Value utf8(temp); | 103 v8::String::Utf8Value utf8(temp); |
104 return std::string(*utf8, utf8.length()); | 104 return std::string(*utf8, utf8.length()); |
105 } | 105 } |
106 | 106 |
| 107 int32_t GetInt(v8::Local<v8::Object> value, const std::string& key) { |
| 108 v8::Local<v8::Int32> temp = |
| 109 value->Get(v8::String::NewFromUtf8(isolate_, key.c_str())) |
| 110 .As<v8::Int32>(); |
| 111 if (temp.IsEmpty()) { |
| 112 ADD_FAILURE(); |
| 113 return -1; |
| 114 } |
| 115 return temp->Value(); |
| 116 } |
| 117 |
| 118 int32_t GetInt(v8::Local<v8::Object> value, uint32_t index) { |
| 119 v8::Local<v8::Int32> temp = value->Get(index).As<v8::Int32>(); |
| 120 if (temp.IsEmpty()) { |
| 121 ADD_FAILURE(); |
| 122 return -1; |
| 123 } |
| 124 return temp->Value(); |
| 125 } |
| 126 |
107 bool IsNull(base::DictionaryValue* value, const std::string& key) { | 127 bool IsNull(base::DictionaryValue* value, const std::string& key) { |
108 base::Value* child = NULL; | 128 base::Value* child = NULL; |
109 if (!value->Get(key, &child)) { | 129 if (!value->Get(key, &child)) { |
110 ADD_FAILURE(); | 130 ADD_FAILURE(); |
111 return false; | 131 return false; |
112 } | 132 } |
113 return child->GetType() == base::Value::TYPE_NULL; | 133 return child->GetType() == base::Value::TYPE_NULL; |
114 } | 134 } |
115 | 135 |
116 bool IsNull(v8::Local<v8::Object> value, const std::string& key) { | 136 bool IsNull(v8::Local<v8::Object> value, const std::string& key) { |
(...skipping 194 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
311 std::unique_ptr<base::DictionaryValue> converted( | 331 std::unique_ptr<base::DictionaryValue> converted( |
312 static_cast<base::DictionaryValue*>( | 332 static_cast<base::DictionaryValue*>( |
313 converter.FromV8Value(object, context))); | 333 converter.FromV8Value(object, context))); |
314 EXPECT_TRUE(converted.get()); | 334 EXPECT_TRUE(converted.get()); |
315 // http://code.google.com/p/v8/issues/detail?id=1342 | 335 // http://code.google.com/p/v8/issues/detail?id=1342 |
316 // EXPECT_EQ(2u, converted->size()); | 336 // EXPECT_EQ(2u, converted->size()); |
317 // EXPECT_TRUE(IsNull(converted.get(), "foo")); | 337 // EXPECT_TRUE(IsNull(converted.get(), "foo")); |
318 EXPECT_EQ(1u, converted->size()); | 338 EXPECT_EQ(1u, converted->size()); |
319 EXPECT_EQ("bar", GetString(converted.get(), "bar")); | 339 EXPECT_EQ("bar", GetString(converted.get(), "bar")); |
320 | 340 |
321 // Converting to v8 value should drop the foo property. | 341 // Converting to v8 value should not trigger the setter. |
322 converted->SetString("foo", "foo"); | 342 converted->SetString("foo", "foo"); |
323 v8::Local<v8::Object> copy = | 343 v8::Local<v8::Object> copy = |
324 converter.ToV8Value(converted.get(), context).As<v8::Object>(); | 344 converter.ToV8Value(converted.get(), context).As<v8::Object>(); |
325 EXPECT_FALSE(copy.IsEmpty()); | 345 EXPECT_FALSE(copy.IsEmpty()); |
326 EXPECT_EQ(2u, copy->GetPropertyNames()->Length()); | 346 EXPECT_EQ(2u, copy->GetPropertyNames()->Length()); |
| 347 EXPECT_EQ("foo", GetString(copy, "foo")); |
327 EXPECT_EQ("bar", GetString(copy, "bar")); | 348 EXPECT_EQ("bar", GetString(copy, "bar")); |
328 } | 349 } |
329 | 350 |
330 TEST_F(V8ValueConverterImplTest, ArrayExceptions) { | 351 TEST_F(V8ValueConverterImplTest, ArrayExceptions) { |
331 v8::HandleScope handle_scope(isolate_); | 352 v8::HandleScope handle_scope(isolate_); |
332 v8::Local<v8::Context> context = | 353 v8::Local<v8::Context> context = |
333 v8::Local<v8::Context>::New(isolate_, context_); | 354 v8::Local<v8::Context>::New(isolate_, context_); |
334 v8::Context::Scope context_scope(context); | 355 v8::Context::Scope context_scope(context); |
335 v8::MicrotasksScope microtasks( | 356 v8::MicrotasksScope microtasks( |
336 isolate_, v8::MicrotasksScope::kDoNotRunMicrotasks); | 357 isolate_, v8::MicrotasksScope::kDoNotRunMicrotasks); |
(...skipping 15 matching lines...) Expand all Loading... |
352 | 373 |
353 // Converting from v8 value should replace the first item with null. | 374 // Converting from v8 value should replace the first item with null. |
354 V8ValueConverterImpl converter; | 375 V8ValueConverterImpl converter; |
355 std::unique_ptr<base::ListValue> converted( | 376 std::unique_ptr<base::ListValue> converted( |
356 static_cast<base::ListValue*>(converter.FromV8Value(array, context))); | 377 static_cast<base::ListValue*>(converter.FromV8Value(array, context))); |
357 ASSERT_TRUE(converted.get()); | 378 ASSERT_TRUE(converted.get()); |
358 // http://code.google.com/p/v8/issues/detail?id=1342 | 379 // http://code.google.com/p/v8/issues/detail?id=1342 |
359 EXPECT_EQ(2u, converted->GetSize()); | 380 EXPECT_EQ(2u, converted->GetSize()); |
360 EXPECT_TRUE(IsNull(converted.get(), 0)); | 381 EXPECT_TRUE(IsNull(converted.get(), 0)); |
361 | 382 |
362 // Converting to v8 value should drop the first item and leave a hole. | 383 // Converting to v8 value should not be affected by the getter/setter |
| 384 // because the setters/getters are defined on the array instance, not |
| 385 // on the Array's prototype. |
363 converted.reset(static_cast<base::ListValue*>( | 386 converted.reset(static_cast<base::ListValue*>( |
364 base::test::ParseJson("[ \"foo\", \"bar\" ]").release())); | 387 base::test::ParseJson("[ \"foo\", \"bar\" ]").release())); |
365 v8::Local<v8::Array> copy = | 388 v8::Local<v8::Array> copy = |
366 converter.ToV8Value(converted.get(), context).As<v8::Array>(); | 389 converter.ToV8Value(converted.get(), context).As<v8::Array>(); |
367 ASSERT_FALSE(copy.IsEmpty()); | 390 ASSERT_FALSE(copy.IsEmpty()); |
368 EXPECT_EQ(2u, copy->Length()); | 391 EXPECT_EQ(2u, copy->Length()); |
| 392 EXPECT_EQ("foo", GetString(copy, 0)); |
369 EXPECT_EQ("bar", GetString(copy, 1)); | 393 EXPECT_EQ("bar", GetString(copy, 1)); |
370 } | 394 } |
371 | 395 |
372 TEST_F(V8ValueConverterImplTest, WeirdTypes) { | 396 TEST_F(V8ValueConverterImplTest, WeirdTypes) { |
373 v8::HandleScope handle_scope(isolate_); | 397 v8::HandleScope handle_scope(isolate_); |
374 v8::Local<v8::Context> context = | 398 v8::Local<v8::Context> context = |
375 v8::Local<v8::Context>::New(isolate_, context_); | 399 v8::Local<v8::Context>::New(isolate_, context_); |
376 v8::Context::Scope context_scope(context); | 400 v8::Context::Scope context_scope(context); |
377 | 401 |
378 v8::Local<v8::RegExp> regex(v8::RegExp::New( | 402 v8::Local<v8::RegExp> regex(v8::RegExp::New( |
(...skipping 38 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
417 ASSERT_FALSE(object.IsEmpty()); | 441 ASSERT_FALSE(object.IsEmpty()); |
418 | 442 |
419 V8ValueConverterImpl converter; | 443 V8ValueConverterImpl converter; |
420 std::unique_ptr<base::DictionaryValue> result( | 444 std::unique_ptr<base::DictionaryValue> result( |
421 static_cast<base::DictionaryValue*>( | 445 static_cast<base::DictionaryValue*>( |
422 converter.FromV8Value(object, context))); | 446 converter.FromV8Value(object, context))); |
423 ASSERT_TRUE(result.get()); | 447 ASSERT_TRUE(result.get()); |
424 EXPECT_EQ(0u, result->size()); | 448 EXPECT_EQ(0u, result->size()); |
425 } | 449 } |
426 | 450 |
| 451 TEST_F(V8ValueConverterImplTest, ObjectPrototypeSetter) { |
| 452 std::unique_ptr<base::Value> original = |
| 453 base::test::ParseJson("{ \"foo\": \"good value\" }"); |
| 454 |
| 455 v8::HandleScope handle_scope(isolate_); |
| 456 v8::Local<v8::Context> context = |
| 457 v8::Local<v8::Context>::New(isolate_, context_); |
| 458 v8::Context::Scope context_scope(context); |
| 459 v8::MicrotasksScope microtasks(isolate_, |
| 460 v8::MicrotasksScope::kDoNotRunMicrotasks); |
| 461 |
| 462 const char* source = |
| 463 "var result = { getters: 0, setters: 0 };" |
| 464 "Object.defineProperty(Object.prototype, 'foo', {" |
| 465 " get() { ++result.getters; return 'bogus'; }," |
| 466 " set() { ++result.setters; }," |
| 467 "});" |
| 468 "result;"; |
| 469 |
| 470 const char* source_sanity = |
| 471 "({}).foo = 'Trigger setter';" |
| 472 "({}).foo;"; |
| 473 |
| 474 v8::Local<v8::Script> script( |
| 475 v8::Script::Compile(v8::String::NewFromUtf8(isolate_, source))); |
| 476 v8::Local<v8::Object> result = script->Run().As<v8::Object>(); |
| 477 ASSERT_FALSE(result.IsEmpty()); |
| 478 |
| 479 // Sanity checks: the getters/setters are normally triggered. |
| 480 v8::Script::Compile(v8::String::NewFromUtf8(isolate_, source_sanity))->Run(); |
| 481 EXPECT_EQ(1, GetInt(result, "getters")); |
| 482 EXPECT_EQ(1, GetInt(result, "setters")); |
| 483 |
| 484 V8ValueConverterImpl converter; |
| 485 v8::Local<v8::Object> converted = |
| 486 converter.ToV8Value(original.get(), context).As<v8::Object>(); |
| 487 EXPECT_FALSE(converted.IsEmpty()); |
| 488 |
| 489 // Getters/setters shouldn't be triggered. |
| 490 EXPECT_EQ(1, GetInt(result, "getters")); |
| 491 EXPECT_EQ(1, GetInt(result, "setters")); |
| 492 |
| 493 EXPECT_EQ(1u, converted->GetPropertyNames()->Length()); |
| 494 EXPECT_EQ("good value", GetString(converted, "foo")); |
| 495 |
| 496 // Getters/setters shouldn't be triggered while accessing existing values. |
| 497 EXPECT_EQ(1, GetInt(result, "getters")); |
| 498 EXPECT_EQ(1, GetInt(result, "setters")); |
| 499 |
| 500 // Repeat the same exercise with a dictionary without the key. |
| 501 base::DictionaryValue missing_key_dict; |
| 502 missing_key_dict.SetString("otherkey", "hello"); |
| 503 v8::Local<v8::Object> converted2 = |
| 504 converter.ToV8Value(&missing_key_dict, context).As<v8::Object>(); |
| 505 EXPECT_FALSE(converted2.IsEmpty()); |
| 506 |
| 507 // Getters/setters shouldn't be triggered. |
| 508 EXPECT_EQ(1, GetInt(result, "getters")); |
| 509 EXPECT_EQ(1, GetInt(result, "setters")); |
| 510 |
| 511 EXPECT_EQ(1u, converted2->GetPropertyNames()->Length()); |
| 512 EXPECT_EQ("hello", GetString(converted2, "otherkey")); |
| 513 |
| 514 // Missing key = should trigger getter upon access. |
| 515 EXPECT_EQ("bogus", GetString(converted2, "foo")); |
| 516 EXPECT_EQ(2, GetInt(result, "getters")); |
| 517 EXPECT_EQ(1, GetInt(result, "setters")); |
| 518 } |
| 519 |
| 520 TEST_F(V8ValueConverterImplTest, ArrayPrototypeSetter) { |
| 521 std::unique_ptr<base::Value> original = |
| 522 base::test::ParseJson("[100, 200, 300]"); |
| 523 |
| 524 v8::HandleScope handle_scope(isolate_); |
| 525 v8::Local<v8::Context> context = |
| 526 v8::Local<v8::Context>::New(isolate_, context_); |
| 527 v8::Context::Scope context_scope(context); |
| 528 v8::MicrotasksScope microtasks(isolate_, |
| 529 v8::MicrotasksScope::kDoNotRunMicrotasks); |
| 530 |
| 531 const char* source = |
| 532 "var result = { getters: 0, setters: 0 };" |
| 533 "Object.defineProperty(Array.prototype, '1', {" |
| 534 " get() { ++result.getters; return 1337; }," |
| 535 " set() { ++result.setters; }," |
| 536 "});" |
| 537 "result;"; |
| 538 |
| 539 const char* source_sanity = |
| 540 "[][1] = 'Trigger setter';" |
| 541 "[][1];"; |
| 542 |
| 543 v8::Local<v8::Script> script( |
| 544 v8::Script::Compile(v8::String::NewFromUtf8(isolate_, source))); |
| 545 v8::Local<v8::Object> result = script->Run().As<v8::Object>(); |
| 546 ASSERT_FALSE(result.IsEmpty()); |
| 547 |
| 548 // Sanity checks: the getters/setters are normally triggered. |
| 549 v8::Script::Compile(v8::String::NewFromUtf8(isolate_, source_sanity))->Run(); |
| 550 EXPECT_EQ(1, GetInt(result, "getters")); |
| 551 EXPECT_EQ(1, GetInt(result, "setters")); |
| 552 |
| 553 V8ValueConverterImpl converter; |
| 554 v8::Local<v8::Array> converted = |
| 555 converter.ToV8Value(original.get(), context).As<v8::Array>(); |
| 556 EXPECT_FALSE(converted.IsEmpty()); |
| 557 |
| 558 // Getters/setters shouldn't be triggered during the conversion. |
| 559 EXPECT_EQ(1, GetInt(result, "getters")); |
| 560 EXPECT_EQ(1, GetInt(result, "setters")); |
| 561 |
| 562 EXPECT_EQ(3u, converted->Length()); |
| 563 EXPECT_EQ(100, GetInt(converted, 0)); |
| 564 EXPECT_EQ(200, GetInt(converted, 1)); |
| 565 EXPECT_EQ(300, GetInt(converted, 2)); |
| 566 |
| 567 // Getters/setters shouldn't be triggered while accessing existing values. |
| 568 EXPECT_EQ(1, GetInt(result, "getters")); |
| 569 EXPECT_EQ(1, GetInt(result, "setters")); |
| 570 |
| 571 // Try again, using an array without the index. |
| 572 base::ListValue one_item_list; |
| 573 one_item_list.Append(new base::FundamentalValue(123456)); |
| 574 v8::Local<v8::Array> converted2 = |
| 575 converter.ToV8Value(&one_item_list, context).As<v8::Array>(); |
| 576 EXPECT_FALSE(converted2.IsEmpty()); |
| 577 |
| 578 // Getters/setters shouldn't be triggered during the conversion. |
| 579 EXPECT_EQ(1, GetInt(result, "getters")); |
| 580 EXPECT_EQ(1, GetInt(result, "setters")); |
| 581 |
| 582 EXPECT_EQ(1u, converted2->Length()); |
| 583 EXPECT_EQ(123456, GetInt(converted2, 0)); |
| 584 |
| 585 // Accessing missing index 1 triggers the getter. |
| 586 EXPECT_EQ(1337, GetInt(converted2, 1)); |
| 587 EXPECT_EQ(2, GetInt(result, "getters")); |
| 588 EXPECT_EQ(1, GetInt(result, "setters")); |
| 589 } |
| 590 |
427 TEST_F(V8ValueConverterImplTest, StripNullFromObjects) { | 591 TEST_F(V8ValueConverterImplTest, StripNullFromObjects) { |
428 v8::HandleScope handle_scope(isolate_); | 592 v8::HandleScope handle_scope(isolate_); |
429 v8::Local<v8::Context> context = | 593 v8::Local<v8::Context> context = |
430 v8::Local<v8::Context>::New(isolate_, context_); | 594 v8::Local<v8::Context>::New(isolate_, context_); |
431 v8::Context::Scope context_scope(context); | 595 v8::Context::Scope context_scope(context); |
432 v8::MicrotasksScope microtasks( | 596 v8::MicrotasksScope microtasks( |
433 isolate_, v8::MicrotasksScope::kDoNotRunMicrotasks); | 597 isolate_, v8::MicrotasksScope::kDoNotRunMicrotasks); |
434 | 598 |
435 const char* source = "(function() {" | 599 const char* source = "(function() {" |
436 "return { foo: undefined, bar: null };" | 600 "return { foo: undefined, bar: null };" |
(...skipping 453 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
890 EXPECT_TRUE( | 1054 EXPECT_TRUE( |
891 base::Value::Equals(reference_number_value.get(), number_value.get())); | 1055 base::Value::Equals(reference_number_value.get(), number_value.get())); |
892 | 1056 |
893 v8::Local<v8::Primitive> undefined(v8::Undefined(isolate_)); | 1057 v8::Local<v8::Primitive> undefined(v8::Undefined(isolate_)); |
894 std::unique_ptr<base::Value> undefined_value( | 1058 std::unique_ptr<base::Value> undefined_value( |
895 converter.FromV8Value(undefined, context)); | 1059 converter.FromV8Value(undefined, context)); |
896 EXPECT_FALSE(undefined_value); | 1060 EXPECT_FALSE(undefined_value); |
897 } | 1061 } |
898 | 1062 |
899 } // namespace content | 1063 } // namespace content |
OLD | NEW |