| 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 <stddef.h> | 5 #include <stddef.h> |
| 6 #include <stdint.h> | 6 #include <stdint.h> |
| 7 | 7 |
| 8 #include <cmath> | 8 #include <cmath> |
| 9 | 9 |
| 10 #include "base/macros.h" | 10 #include "base/macros.h" |
| (...skipping 85 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 96 std::string GetString(v8::Local<v8::Array> value, uint32_t index) { | 96 std::string GetString(v8::Local<v8::Array> value, uint32_t index) { |
| 97 v8::Local<v8::String> temp = value->Get(index).As<v8::String>(); | 97 v8::Local<v8::String> temp = value->Get(index).As<v8::String>(); |
| 98 if (temp.IsEmpty()) { | 98 if (temp.IsEmpty()) { |
| 99 ADD_FAILURE(); | 99 ADD_FAILURE(); |
| 100 return std::string(); | 100 return std::string(); |
| 101 } | 101 } |
| 102 v8::String::Utf8Value utf8(temp); | 102 v8::String::Utf8Value utf8(temp); |
| 103 return std::string(*utf8, utf8.length()); | 103 return std::string(*utf8, utf8.length()); |
| 104 } | 104 } |
| 105 | 105 |
| 106 int32_t GetInt(v8::Local<v8::Object> value, const std::string& key) { |
| 107 v8::Local<v8::Int32> temp = |
| 108 value->Get(v8::String::NewFromUtf8(isolate_, key.c_str())) |
| 109 .As<v8::Int32>(); |
| 110 if (temp.IsEmpty()) { |
| 111 ADD_FAILURE(); |
| 112 return -1; |
| 113 } |
| 114 return temp->Value(); |
| 115 } |
| 116 |
| 117 int32_t GetInt(v8::Local<v8::Object> value, uint32_t index) { |
| 118 v8::Local<v8::Int32> temp = value->Get(index).As<v8::Int32>(); |
| 119 if (temp.IsEmpty()) { |
| 120 ADD_FAILURE(); |
| 121 return -1; |
| 122 } |
| 123 return temp->Value(); |
| 124 } |
| 125 |
| 106 bool IsNull(base::DictionaryValue* value, const std::string& key) { | 126 bool IsNull(base::DictionaryValue* value, const std::string& key) { |
| 107 base::Value* child = NULL; | 127 base::Value* child = NULL; |
| 108 if (!value->Get(key, &child)) { | 128 if (!value->Get(key, &child)) { |
| 109 ADD_FAILURE(); | 129 ADD_FAILURE(); |
| 110 return false; | 130 return false; |
| 111 } | 131 } |
| 112 return child->GetType() == base::Value::TYPE_NULL; | 132 return child->GetType() == base::Value::TYPE_NULL; |
| 113 } | 133 } |
| 114 | 134 |
| 115 bool IsNull(v8::Local<v8::Object> value, const std::string& key) { | 135 bool IsNull(v8::Local<v8::Object> value, const std::string& key) { |
| (...skipping 192 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 308 scoped_ptr<base::DictionaryValue> converted( | 328 scoped_ptr<base::DictionaryValue> converted( |
| 309 static_cast<base::DictionaryValue*>( | 329 static_cast<base::DictionaryValue*>( |
| 310 converter.FromV8Value(object, context))); | 330 converter.FromV8Value(object, context))); |
| 311 EXPECT_TRUE(converted.get()); | 331 EXPECT_TRUE(converted.get()); |
| 312 // http://code.google.com/p/v8/issues/detail?id=1342 | 332 // http://code.google.com/p/v8/issues/detail?id=1342 |
| 313 // EXPECT_EQ(2u, converted->size()); | 333 // EXPECT_EQ(2u, converted->size()); |
| 314 // EXPECT_TRUE(IsNull(converted.get(), "foo")); | 334 // EXPECT_TRUE(IsNull(converted.get(), "foo")); |
| 315 EXPECT_EQ(1u, converted->size()); | 335 EXPECT_EQ(1u, converted->size()); |
| 316 EXPECT_EQ("bar", GetString(converted.get(), "bar")); | 336 EXPECT_EQ("bar", GetString(converted.get(), "bar")); |
| 317 | 337 |
| 318 // Converting to v8 value should drop the foo property. | 338 // Converting to v8 value should not trigger the setter. |
| 319 converted->SetString("foo", "foo"); | 339 converted->SetString("foo", "foo"); |
| 320 v8::Local<v8::Object> copy = | 340 v8::Local<v8::Object> copy = |
| 321 converter.ToV8Value(converted.get(), context).As<v8::Object>(); | 341 converter.ToV8Value(converted.get(), context).As<v8::Object>(); |
| 322 EXPECT_FALSE(copy.IsEmpty()); | 342 EXPECT_FALSE(copy.IsEmpty()); |
| 323 EXPECT_EQ(2u, copy->GetPropertyNames()->Length()); | 343 EXPECT_EQ(2u, copy->GetPropertyNames()->Length()); |
| 344 EXPECT_EQ("foo", GetString(copy, "foo")); |
| 324 EXPECT_EQ("bar", GetString(copy, "bar")); | 345 EXPECT_EQ("bar", GetString(copy, "bar")); |
| 325 } | 346 } |
| 326 | 347 |
| 327 TEST_F(V8ValueConverterImplTest, ArrayExceptions) { | 348 TEST_F(V8ValueConverterImplTest, ArrayExceptions) { |
| 328 v8::HandleScope handle_scope(isolate_); | 349 v8::HandleScope handle_scope(isolate_); |
| 329 v8::Local<v8::Context> context = | 350 v8::Local<v8::Context> context = |
| 330 v8::Local<v8::Context>::New(isolate_, context_); | 351 v8::Local<v8::Context>::New(isolate_, context_); |
| 331 v8::Context::Scope context_scope(context); | 352 v8::Context::Scope context_scope(context); |
| 332 | 353 |
| 333 const char* source = "(function() {" | 354 const char* source = "(function() {" |
| (...skipping 13 matching lines...) Expand all Loading... |
| 347 | 368 |
| 348 // Converting from v8 value should replace the first item with null. | 369 // Converting from v8 value should replace the first item with null. |
| 349 V8ValueConverterImpl converter; | 370 V8ValueConverterImpl converter; |
| 350 scoped_ptr<base::ListValue> converted(static_cast<base::ListValue*>( | 371 scoped_ptr<base::ListValue> converted(static_cast<base::ListValue*>( |
| 351 converter.FromV8Value(array, context))); | 372 converter.FromV8Value(array, context))); |
| 352 ASSERT_TRUE(converted.get()); | 373 ASSERT_TRUE(converted.get()); |
| 353 // http://code.google.com/p/v8/issues/detail?id=1342 | 374 // http://code.google.com/p/v8/issues/detail?id=1342 |
| 354 EXPECT_EQ(2u, converted->GetSize()); | 375 EXPECT_EQ(2u, converted->GetSize()); |
| 355 EXPECT_TRUE(IsNull(converted.get(), 0)); | 376 EXPECT_TRUE(IsNull(converted.get(), 0)); |
| 356 | 377 |
| 357 // Converting to v8 value should drop the first item and leave a hole. | 378 // Converting to v8 value should not be affected by the getter/setter |
| 379 // because the setters/getters are defined on the array instance, not |
| 380 // on the Array's prototype. |
| 358 converted.reset(static_cast<base::ListValue*>( | 381 converted.reset(static_cast<base::ListValue*>( |
| 359 base::test::ParseJson("[ \"foo\", \"bar\" ]").release())); | 382 base::test::ParseJson("[ \"foo\", \"bar\" ]").release())); |
| 360 v8::Local<v8::Array> copy = | 383 v8::Local<v8::Array> copy = |
| 361 converter.ToV8Value(converted.get(), context).As<v8::Array>(); | 384 converter.ToV8Value(converted.get(), context).As<v8::Array>(); |
| 362 ASSERT_FALSE(copy.IsEmpty()); | 385 ASSERT_FALSE(copy.IsEmpty()); |
| 363 EXPECT_EQ(2u, copy->Length()); | 386 EXPECT_EQ(2u, copy->Length()); |
| 387 EXPECT_EQ("foo", GetString(copy, 0)); |
| 364 EXPECT_EQ("bar", GetString(copy, 1)); | 388 EXPECT_EQ("bar", GetString(copy, 1)); |
| 365 } | 389 } |
| 366 | 390 |
| 367 TEST_F(V8ValueConverterImplTest, WeirdTypes) { | 391 TEST_F(V8ValueConverterImplTest, WeirdTypes) { |
| 368 v8::HandleScope handle_scope(isolate_); | 392 v8::HandleScope handle_scope(isolate_); |
| 369 v8::Local<v8::Context> context = | 393 v8::Local<v8::Context> context = |
| 370 v8::Local<v8::Context>::New(isolate_, context_); | 394 v8::Local<v8::Context>::New(isolate_, context_); |
| 371 v8::Context::Scope context_scope(context); | 395 v8::Context::Scope context_scope(context); |
| 372 | 396 |
| 373 v8::Local<v8::RegExp> regex(v8::RegExp::New( | 397 v8::Local<v8::RegExp> regex(v8::RegExp::New( |
| (...skipping 43 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 scoped_ptr<base::DictionaryValue> result( | 444 scoped_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 | 596 |
| 433 const char* source = "(function() {" | 597 const char* source = "(function() {" |
| 434 "return { foo: undefined, bar: null };" | 598 "return { foo: undefined, bar: null };" |
| 435 "})();"; | 599 "})();"; |
| 436 | 600 |
| (...skipping 433 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 870 EXPECT_TRUE( | 1034 EXPECT_TRUE( |
| 871 base::Value::Equals(reference_number_value.get(), number_value.get())); | 1035 base::Value::Equals(reference_number_value.get(), number_value.get())); |
| 872 | 1036 |
| 873 v8::Local<v8::Primitive> undefined(v8::Undefined(isolate_)); | 1037 v8::Local<v8::Primitive> undefined(v8::Undefined(isolate_)); |
| 874 scoped_ptr<base::Value> undefined_value( | 1038 scoped_ptr<base::Value> undefined_value( |
| 875 converter.FromV8Value(undefined, context)); | 1039 converter.FromV8Value(undefined, context)); |
| 876 EXPECT_FALSE(undefined_value); | 1040 EXPECT_FALSE(undefined_value); |
| 877 } | 1041 } |
| 878 | 1042 |
| 879 } // namespace content | 1043 } // namespace content |
| OLD | NEW |