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

Side by Side Diff: content/child/v8_value_converter_impl_unittest.cc

Issue 1930953002: V8ValueConverter::ToV8Value should not trigger setters (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@2704
Patch Set: Created 4 years, 7 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
« no previous file with comments | « content/child/v8_value_converter_impl.cc ('k') | no next file » | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
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
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
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
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
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
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
OLDNEW
« no previous file with comments | « content/child/v8_value_converter_impl.cc ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698