Chromium Code Reviews| 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 <cmath> | 5 #include <cmath> |
| 6 | 6 |
| 7 #include "base/memory/scoped_ptr.h" | 7 #include "base/memory/scoped_ptr.h" |
| 8 #include "base/values.h" | 8 #include "base/values.h" |
| 9 #include "content/renderer/v8_value_converter_impl.h" | 9 #include "content/renderer/v8_value_converter_impl.h" |
| 10 #include "testing/gtest/include/gtest/gtest.h" | 10 #include "testing/gtest/include/gtest/gtest.h" |
| 11 #include "v8/include/v8.h" | 11 #include "v8/include/v8.h" |
| 12 | 12 |
| 13 using content::V8ValueConverter; | |
| 14 | |
| 13 namespace { | 15 namespace { |
| 14 | 16 |
| 15 // A dumb getter for an object's named callback. | 17 // A dumb getter for an object's named callback. |
| 16 v8::Handle<v8::Value> NamedCallbackGetter(v8::Local<v8::String> name, | 18 v8::Handle<v8::Value> NamedCallbackGetter(v8::Local<v8::String> name, |
| 17 const v8::AccessorInfo& info) { | 19 const v8::AccessorInfo& info) { |
| 18 return v8::String::New("bar"); | 20 return v8::String::New("bar"); |
| 19 } | 21 } |
| 20 | 22 |
| 21 } // namespace | 23 } // namespace |
| 22 | 24 |
| (...skipping 82 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 105 return false; | 107 return false; |
| 106 } | 108 } |
| 107 return child->IsNull(); | 109 return child->IsNull(); |
| 108 } | 110 } |
| 109 | 111 |
| 110 void TestWeirdType(const V8ValueConverterImpl& converter, | 112 void TestWeirdType(const V8ValueConverterImpl& converter, |
| 111 v8::Handle<v8::Value> val, | 113 v8::Handle<v8::Value> val, |
| 112 base::Value::Type expected_type, | 114 base::Value::Type expected_type, |
| 113 scoped_ptr<Value> expected_value) { | 115 scoped_ptr<Value> expected_value) { |
| 114 scoped_ptr<Value> raw(converter.FromV8Value(val, context_)); | 116 scoped_ptr<Value> raw(converter.FromV8Value(val, context_)); |
| 115 ASSERT_TRUE(raw.get()); | 117 |
| 116 EXPECT_EQ(expected_type, raw->GetType()); | 118 if (expected_value.get()) { |
| 117 if (expected_value.get()) | 119 ASSERT_TRUE(raw.get()); |
| 118 EXPECT_TRUE(expected_value->Equals(raw.get())); | 120 EXPECT_TRUE(expected_value->Equals(raw.get())); |
| 121 EXPECT_EQ(expected_type, raw->GetType()); | |
| 122 } else { | |
| 123 EXPECT_FALSE(raw.get()); | |
| 124 } | |
| 119 | 125 |
| 120 v8::Handle<v8::Object> object(v8::Object::New()); | 126 v8::Handle<v8::Object> object(v8::Object::New()); |
| 121 object->Set(v8::String::New("test"), val); | 127 object->Set(v8::String::New("test"), val); |
| 122 scoped_ptr<DictionaryValue> dictionary( | 128 scoped_ptr<DictionaryValue> dictionary( |
| 123 static_cast<DictionaryValue*>( | 129 static_cast<DictionaryValue*>( |
| 124 converter.FromV8Value(object, context_))); | 130 converter.FromV8Value(object, context_))); |
| 125 ASSERT_TRUE(dictionary.get()); | 131 ASSERT_TRUE(dictionary.get()); |
| 126 | 132 |
| 127 Value* temp = NULL; | 133 if (expected_value.get()) { |
| 128 ASSERT_TRUE(dictionary->Get("test", &temp)); | 134 Value* temp = NULL; |
| 129 EXPECT_EQ(expected_type, temp->GetType()); | 135 ASSERT_TRUE(dictionary->Get("test", &temp)); |
| 130 if (expected_value.get()) | 136 EXPECT_EQ(expected_type, temp->GetType()); |
| 131 EXPECT_TRUE(expected_value->Equals(temp)); | 137 EXPECT_TRUE(expected_value->Equals(temp)); |
| 138 } else { | |
| 139 EXPECT_FALSE(dictionary->HasKey("test")); | |
| 140 } | |
| 132 | 141 |
| 133 v8::Handle<v8::Array> array(v8::Array::New()); | 142 v8::Handle<v8::Array> array(v8::Array::New()); |
| 134 array->Set(0, val); | 143 array->Set(0, val); |
| 135 scoped_ptr<ListValue> list( | 144 scoped_ptr<ListValue> list( |
| 136 static_cast<ListValue*>( | 145 static_cast<ListValue*>( |
| 137 converter.FromV8Value(array, context_))); | 146 converter.FromV8Value(array, context_))); |
| 138 ASSERT_TRUE(list.get()); | 147 ASSERT_TRUE(list.get()); |
| 139 ASSERT_TRUE(list->Get(0, &temp)); | 148 if (expected_value.get()) { |
| 140 EXPECT_EQ(expected_type, temp->GetType()); | 149 Value* temp = NULL; |
| 141 if (expected_value.get()) | 150 ASSERT_TRUE(list->Get(0, &temp)); |
| 151 EXPECT_EQ(expected_type, temp->GetType()); | |
| 142 EXPECT_TRUE(expected_value->Equals(temp)); | 152 EXPECT_TRUE(expected_value->Equals(temp)); |
| 153 } else { | |
| 154 // Arrays should preserve their length, and convert unconvertible | |
| 155 // types into null. | |
| 156 Value* temp = NULL; | |
| 157 ASSERT_TRUE(list->Get(0, &temp)); | |
| 158 EXPECT_EQ(Value::TYPE_NULL, temp->GetType()); | |
| 159 } | |
| 143 } | 160 } |
| 144 | 161 |
| 145 // Context for the JavaScript in the test. | 162 // Context for the JavaScript in the test. |
| 146 v8::Persistent<v8::Context> context_; | 163 v8::Persistent<v8::Context> context_; |
| 147 }; | 164 }; |
| 148 | 165 |
| 149 TEST_F(V8ValueConverterImplTest, BasicRoundTrip) { | 166 TEST_F(V8ValueConverterImplTest, BasicRoundTrip) { |
| 150 DictionaryValue original_root; | 167 DictionaryValue original_root; |
| 151 original_root.Set("null", Value::CreateNullValue()); | 168 original_root.Set("null", Value::CreateNullValue()); |
| 152 original_root.Set("true", Value::CreateBooleanValue(true)); | 169 original_root.Set("true", Value::CreateBooleanValue(true)); |
| (...skipping 140 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 293 } | 310 } |
| 294 | 311 |
| 295 TEST_F(V8ValueConverterImplTest, WeirdTypes) { | 312 TEST_F(V8ValueConverterImplTest, WeirdTypes) { |
| 296 v8::Context::Scope context_scope(context_); | 313 v8::Context::Scope context_scope(context_); |
| 297 v8::HandleScope handle_scope; | 314 v8::HandleScope handle_scope; |
| 298 | 315 |
| 299 v8::Handle<v8::RegExp> regex( | 316 v8::Handle<v8::RegExp> regex( |
| 300 v8::RegExp::New(v8::String::New("."), v8::RegExp::kNone)); | 317 v8::RegExp::New(v8::String::New("."), v8::RegExp::kNone)); |
| 301 | 318 |
| 302 V8ValueConverterImpl converter; | 319 V8ValueConverterImpl converter; |
| 303 TestWeirdType(converter, v8::Undefined(), Value::TYPE_NULL, | 320 TestWeirdType(converter, |
| 321 v8::Undefined(), | |
| 322 Value::TYPE_NULL, // Arbitrary type, result is NULL. | |
| 304 scoped_ptr<Value>(NULL)); | 323 scoped_ptr<Value>(NULL)); |
| 305 TestWeirdType(converter, v8::Date::New(1000), Value::TYPE_DICTIONARY, | 324 TestWeirdType(converter, |
| 306 scoped_ptr<Value>(NULL)); | 325 v8::Date::New(1000), |
| 307 TestWeirdType(converter, regex, Value::TYPE_DICTIONARY, | 326 Value::TYPE_DICTIONARY, |
| 308 scoped_ptr<Value>(NULL)); | 327 scoped_ptr<Value>(new DictionaryValue())); |
| 328 TestWeirdType(converter, | |
| 329 regex, | |
| 330 Value::TYPE_DICTIONARY, | |
| 331 scoped_ptr<Value>(new DictionaryValue())); | |
| 309 | 332 |
| 310 converter.SetUndefinedAllowed(true); | 333 converter.SetUndefinedValueBehavior(V8ValueConverter::CONVERT_TO_NULL); |
| 311 TestWeirdType(converter, v8::Undefined(), Value::TYPE_NULL, | 334 TestWeirdType(converter, |
| 312 scoped_ptr<Value>(NULL)); | 335 v8::Undefined(), |
| 336 Value::TYPE_NULL, | |
| 337 scoped_ptr<Value>(Value::CreateNullValue())); | |
| 313 | 338 |
| 314 converter.SetDateAllowed(true); | 339 converter.SetDateAllowed(true); |
| 315 TestWeirdType(converter, v8::Date::New(1000), Value::TYPE_DOUBLE, | 340 TestWeirdType(converter, |
| 341 v8::Date::New(1000), | |
| 342 Value::TYPE_DOUBLE, | |
| 316 scoped_ptr<Value>(Value::CreateDoubleValue(1))); | 343 scoped_ptr<Value>(Value::CreateDoubleValue(1))); |
| 317 | 344 |
| 318 converter.SetRegexpAllowed(true); | 345 converter.SetRegexpAllowed(true); |
| 319 TestWeirdType(converter, regex, Value::TYPE_STRING, | 346 TestWeirdType(converter, |
| 347 regex, | |
| 348 Value::TYPE_STRING, | |
| 320 scoped_ptr<Value>(Value::CreateStringValue("/./"))); | 349 scoped_ptr<Value>(Value::CreateStringValue("/./"))); |
| 321 } | 350 } |
| 322 | 351 |
| 323 TEST_F(V8ValueConverterImplTest, Prototype) { | 352 TEST_F(V8ValueConverterImplTest, Prototype) { |
| 324 v8::Context::Scope context_scope(context_); | 353 v8::Context::Scope context_scope(context_); |
| 325 v8::HandleScope handle_scope; | 354 v8::HandleScope handle_scope; |
| 326 | 355 |
| 327 const char* source = "(function() {" | 356 const char* source = "(function() {" |
| 328 "Object.prototype.foo = 'foo';" | 357 "Object.prototype.foo = 'foo';" |
| 329 "return {};" | 358 "return {};" |
| (...skipping 16 matching lines...) Expand all Loading... | |
| 346 | 375 |
| 347 const char* source = "(function() {" | 376 const char* source = "(function() {" |
| 348 "return { foo: undefined, bar: null };" | 377 "return { foo: undefined, bar: null };" |
| 349 "})();"; | 378 "})();"; |
| 350 | 379 |
| 351 v8::Handle<v8::Script> script(v8::Script::New(v8::String::New(source))); | 380 v8::Handle<v8::Script> script(v8::Script::New(v8::String::New(source))); |
| 352 v8::Handle<v8::Object> object = script->Run().As<v8::Object>(); | 381 v8::Handle<v8::Object> object = script->Run().As<v8::Object>(); |
| 353 ASSERT_FALSE(object.IsEmpty()); | 382 ASSERT_FALSE(object.IsEmpty()); |
| 354 | 383 |
| 355 V8ValueConverterImpl converter; | 384 V8ValueConverterImpl converter; |
| 356 converter.SetUndefinedAllowed(true); | 385 converter.SetUndefinedValueBehavior(V8ValueConverter::CONVERT_TO_NULL); |
| 357 converter.SetStripNullFromObjects(true); | 386 converter.SetStripNullFromObjects(true); |
| 358 | 387 |
| 359 scoped_ptr<DictionaryValue> result( | 388 scoped_ptr<DictionaryValue> result( |
| 360 static_cast<DictionaryValue*>(converter.FromV8Value(object, context_))); | 389 static_cast<DictionaryValue*>(converter.FromV8Value(object, context_))); |
| 361 ASSERT_TRUE(result.get()); | 390 ASSERT_TRUE(result.get()); |
| 362 EXPECT_EQ(0u, result->size()); | 391 EXPECT_EQ(0u, result->size()); |
| 363 } | 392 } |
| 364 | 393 |
| 365 TEST_F(V8ValueConverterImplTest, RecursiveObjects) { | 394 TEST_F(V8ValueConverterImplTest, RecursiveObjects) { |
| 366 v8::Context::Scope context_scope(context_); | 395 v8::Context::Scope context_scope(context_); |
| (...skipping 78 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 445 v8::Handle<v8::Script> script(v8::Script::New(v8::String::New(source))); | 474 v8::Handle<v8::Script> script(v8::Script::New(v8::String::New(source))); |
| 446 v8::Handle<v8::Array> array = script->Run().As<v8::Array>(); | 475 v8::Handle<v8::Array> array = script->Run().As<v8::Array>(); |
| 447 ASSERT_FALSE(array.IsEmpty()); | 476 ASSERT_FALSE(array.IsEmpty()); |
| 448 | 477 |
| 449 V8ValueConverterImpl converter; | 478 V8ValueConverterImpl converter; |
| 450 scoped_ptr<ListValue> result( | 479 scoped_ptr<ListValue> result( |
| 451 static_cast<ListValue*>(converter.FromV8Value(array, context_))); | 480 static_cast<ListValue*>(converter.FromV8Value(array, context_))); |
| 452 ASSERT_TRUE(result.get()); | 481 ASSERT_TRUE(result.get()); |
| 453 EXPECT_EQ(2u, result->GetSize()); | 482 EXPECT_EQ(2u, result->GetSize()); |
| 454 } | 483 } |
| 484 | |
| 485 TEST_F(V8ValueConverterImplTest, UndefinedValueBehavior) { | |
| 486 v8::Context::Scope context_scope(context_); | |
| 487 v8::HandleScope handle_scope; | |
| 488 | |
| 489 v8::Handle<v8::Object> object; | |
| 490 { | |
| 491 const char* source = "(function() {" | |
| 492 "return { foo: undefined, bar: null, baz: function(){} };" | |
| 493 "})();"; | |
| 494 v8::Handle<v8::Script> script(v8::Script::New(v8::String::New(source))); | |
| 495 object = script->Run().As<v8::Object>(); | |
| 496 ASSERT_FALSE(object.IsEmpty()); | |
| 497 } | |
| 498 | |
| 499 v8::Handle<v8::Array> array; | |
| 500 { | |
| 501 const char* source = "(function() {" | |
| 502 "return [ undefined, null, function(){} ];" | |
| 503 "})();"; | |
| 504 v8::Handle<v8::Script> script(v8::Script::New(v8::String::New(source))); | |
| 505 array = script->Run().As<v8::Array>(); | |
| 506 ASSERT_FALSE(array.IsEmpty()); | |
|
koz (OOO until 15th September)
2012/09/12 02:08:28
ASSERT_EQ(3u, array.Size()) ?
| |
| 507 } | |
| 508 | |
| 509 // OMIT. | |
| 510 { | |
| 511 V8ValueConverterImpl converter; | |
| 512 converter.SetUndefinedValueBehavior(V8ValueConverter::OMIT); | |
| 513 | |
| 514 DictionaryValue expected_object; | |
| 515 expected_object.Set("bar", Value::CreateNullValue()); | |
| 516 scoped_ptr<Value> actual_object(converter.FromV8Value(object, context_)); | |
| 517 EXPECT_TRUE(Value::Equals(&expected_object, actual_object.get())); | |
| 518 | |
| 519 ListValue expected_array; | |
| 520 // Everything is null because JSON stringification preserves array length. | |
| 521 expected_array.Append(Value::CreateNullValue()); | |
| 522 expected_array.Append(Value::CreateNullValue()); | |
| 523 expected_array.Append(Value::CreateNullValue()); | |
| 524 scoped_ptr<Value> actual_array(converter.FromV8Value(array, context_)); | |
| 525 EXPECT_TRUE(Value::Equals(&expected_array, actual_array.get())); | |
| 526 } | |
| 527 | |
| 528 // CONVERT_TO_NULL. | |
| 529 { | |
| 530 V8ValueConverterImpl converter; | |
| 531 converter.SetUndefinedValueBehavior(V8ValueConverter::CONVERT_TO_NULL); | |
| 532 | |
| 533 DictionaryValue expected_object; | |
| 534 expected_object.Set("foo", Value::CreateNullValue()); | |
| 535 expected_object.Set("bar", Value::CreateNullValue()); | |
| 536 scoped_ptr<Value> actual_object(converter.FromV8Value(object, context_)); | |
| 537 EXPECT_TRUE(Value::Equals(&expected_object, actual_object.get())); | |
| 538 | |
| 539 ListValue expected_array; | |
| 540 expected_array.Append(Value::CreateNullValue()); | |
| 541 expected_array.Append(Value::CreateNullValue()); | |
| 542 expected_array.Append(Value::CreateNullValue()); | |
| 543 scoped_ptr<Value> actual_array(converter.FromV8Value(array, context_)); | |
| 544 EXPECT_TRUE(Value::Equals(&expected_array, actual_array.get())); | |
| 545 } | |
| 546 } | |
| OLD | NEW |