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