Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 // Copyright 2016 the V8 project authors. All rights reserved. | 1 // Copyright 2016 the V8 project 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 "src/value-serializer.h" | 5 #include "src/value-serializer.h" |
| 6 | 6 |
| 7 #include <algorithm> | 7 #include <algorithm> |
| 8 #include <string> | 8 #include <string> |
| 9 | 9 |
| 10 #include "include/v8.h" | 10 #include "include/v8.h" |
| (...skipping 29 matching lines...) Expand all Loading... | |
| 40 | 40 |
| 41 template <typename InputFunctor, typename EncodedDataFunctor> | 41 template <typename InputFunctor, typename EncodedDataFunctor> |
| 42 void EncodeTest(const InputFunctor& input_functor, | 42 void EncodeTest(const InputFunctor& input_functor, |
| 43 const EncodedDataFunctor& encoded_data_functor) { | 43 const EncodedDataFunctor& encoded_data_functor) { |
| 44 Context::Scope scope(serialization_context()); | 44 Context::Scope scope(serialization_context()); |
| 45 TryCatch try_catch(isolate()); | 45 TryCatch try_catch(isolate()); |
| 46 // TODO(jbroman): Use the public API once it exists. | 46 // TODO(jbroman): Use the public API once it exists. |
| 47 Local<Value> input_value = input_functor(); | 47 Local<Value> input_value = input_functor(); |
| 48 i::Isolate* internal_isolate = reinterpret_cast<i::Isolate*>(isolate()); | 48 i::Isolate* internal_isolate = reinterpret_cast<i::Isolate*>(isolate()); |
| 49 i::HandleScope handle_scope(internal_isolate); | 49 i::HandleScope handle_scope(internal_isolate); |
| 50 i::ValueSerializer serializer; | 50 i::ValueSerializer serializer(internal_isolate); |
| 51 serializer.WriteHeader(); | 51 serializer.WriteHeader(); |
| 52 ASSERT_TRUE(serializer.WriteObject(Utils::OpenHandle(*input_value)) | 52 ASSERT_TRUE(serializer.WriteObject(Utils::OpenHandle(*input_value)) |
| 53 .FromMaybe(false)); | 53 .FromMaybe(false)); |
| 54 ASSERT_FALSE(try_catch.HasCaught()); | 54 ASSERT_FALSE(try_catch.HasCaught()); |
| 55 encoded_data_functor(serializer.ReleaseBuffer()); | 55 encoded_data_functor(serializer.ReleaseBuffer()); |
| 56 } | 56 } |
| 57 | 57 |
| 58 template <typename OutputFunctor> | 58 template <typename OutputFunctor> |
| 59 void DecodeTest(const std::vector<uint8_t>& data, | 59 void DecodeTest(const std::vector<uint8_t>& data, |
| 60 const OutputFunctor& output_functor) { | 60 const OutputFunctor& output_functor) { |
| (...skipping 320 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 381 [](const std::vector<uint8_t>& data) { | 381 [](const std::vector<uint8_t>& data) { |
| 382 // This is a sufficient but not necessary condition to be aligned. | 382 // This is a sufficient but not necessary condition to be aligned. |
| 383 // Note that the third byte (0x00) is padding. | 383 // Note that the third byte (0x00) is padding. |
| 384 const uint8_t expected_prefix[] = {0xff, 0x09, 0x00, 0x63, 0x94, 0x03}; | 384 const uint8_t expected_prefix[] = {0xff, 0x09, 0x00, 0x63, 0x94, 0x03}; |
| 385 ASSERT_GT(data.size(), sizeof(expected_prefix) / sizeof(uint8_t)); | 385 ASSERT_GT(data.size(), sizeof(expected_prefix) / sizeof(uint8_t)); |
| 386 EXPECT_TRUE(std::equal(std::begin(expected_prefix), | 386 EXPECT_TRUE(std::equal(std::begin(expected_prefix), |
| 387 std::end(expected_prefix), data.begin())); | 387 std::end(expected_prefix), data.begin())); |
| 388 }); | 388 }); |
| 389 } | 389 } |
| 390 | 390 |
| 391 TEST_F(ValueSerializerTest, RoundTripDictionaryObject) { | |
| 392 // Empty object. | |
| 393 RoundTripTest([this]() { return EvaluateScriptForInput("({})"); }, | |
| 394 [this](Local<Value> value) { | |
| 395 ASSERT_TRUE(value->IsObject()); | |
| 396 EXPECT_TRUE(EvaluateScriptForResultBool( | |
| 397 "Object.getPrototypeOf(result) === Object.prototype")); | |
| 398 EXPECT_TRUE(EvaluateScriptForResultBool( | |
| 399 "Object.getOwnPropertyNames(result).length === 0")); | |
| 400 }); | |
| 401 // String key. | |
| 402 RoundTripTest( | |
| 403 [this]() { return EvaluateScriptForInput("({ a: 42 })"); }, | |
| 404 [this](Local<Value> value) { | |
| 405 ASSERT_TRUE(value->IsObject()); | |
| 406 EXPECT_TRUE(EvaluateScriptForResultBool("result.hasOwnProperty('a')")); | |
| 407 EXPECT_TRUE(EvaluateScriptForResultBool("result.a === 42")); | |
| 408 EXPECT_TRUE(EvaluateScriptForResultBool( | |
| 409 "Object.getOwnPropertyNames(result).length === 1")); | |
| 410 }); | |
| 411 // Integer key (treated as a string, but may be encoded differently). | |
|
Camillo Bruni
2016/08/16 11:26:57
nit: can you add a copy of this test with the corn
jbroman
2016/08/16 18:16:29
I've incorporated such an example. It took me awhi
| |
| 412 RoundTripTest( | |
| 413 [this]() { return EvaluateScriptForInput("({ 42: 'a' })"); }, | |
| 414 [this](Local<Value> value) { | |
| 415 ASSERT_TRUE(value->IsObject()); | |
| 416 EXPECT_TRUE(EvaluateScriptForResultBool("result.hasOwnProperty('42')")); | |
| 417 EXPECT_TRUE(EvaluateScriptForResultBool("result[42] === 'a'")); | |
| 418 EXPECT_TRUE(EvaluateScriptForResultBool( | |
| 419 "Object.getOwnPropertyNames(result).length === 1")); | |
| 420 }); | |
| 421 // Key order must be preserved. | |
| 422 RoundTripTest( | |
| 423 [this]() { return EvaluateScriptForInput("({ x: 1, y: 2, a: 3 })"); }, | |
| 424 [this](Local<Value> value) { | |
| 425 EXPECT_TRUE(EvaluateScriptForResultBool( | |
| 426 "Object.getOwnPropertyNames(result).toString() === 'x,y,a'")); | |
| 427 }); | |
| 428 // This detects a fairly subtle case: the object itself must be in the map | |
| 429 // before its properties are deserialized, so that references to it can be | |
| 430 // resolved. | |
| 431 RoundTripTest( | |
| 432 [this]() { | |
| 433 return EvaluateScriptForInput( | |
| 434 "(() => { var y = {}; y.self = y; return y; })()"); | |
| 435 }, | |
| 436 [this](Local<Value> value) { | |
| 437 ASSERT_TRUE(value->IsObject()); | |
| 438 EXPECT_TRUE(EvaluateScriptForResultBool("result === result.self")); | |
| 439 }); | |
|
Camillo Bruni
2016/08/16 11:26:57
future-nit: once you can handle accessors and cust
jbroman
2016/08/16 18:16:29
I can handle them now, aside from a bug which you
| |
| 440 } | |
| 441 | |
| 442 TEST_F(ValueSerializerTest, DecodeDictionaryObject) { | |
| 443 // Empty object. | |
| 444 DecodeTest({0xff, 0x09, 0x3f, 0x00, 0x6f, 0x7b, 0x00, 0x00}, | |
| 445 [this](Local<Value> value) { | |
| 446 ASSERT_TRUE(value->IsObject()); | |
| 447 EXPECT_TRUE(EvaluateScriptForResultBool( | |
| 448 "Object.getPrototypeOf(result) === Object.prototype")); | |
| 449 EXPECT_TRUE(EvaluateScriptForResultBool( | |
| 450 "Object.getOwnPropertyNames(result).length === 0")); | |
| 451 }); | |
| 452 // String key. | |
| 453 DecodeTest( | |
| 454 {0xff, 0x09, 0x3f, 0x00, 0x6f, 0x3f, 0x01, 0x53, 0x01, 0x61, 0x3f, 0x01, | |
| 455 0x49, 0x54, 0x7b, 0x01}, | |
| 456 [this](Local<Value> value) { | |
| 457 ASSERT_TRUE(value->IsObject()); | |
| 458 EXPECT_TRUE(EvaluateScriptForResultBool("result.hasOwnProperty('a')")); | |
| 459 EXPECT_TRUE(EvaluateScriptForResultBool("result.a === 42")); | |
| 460 EXPECT_TRUE(EvaluateScriptForResultBool( | |
| 461 "Object.getOwnPropertyNames(result).length === 1")); | |
| 462 }); | |
| 463 // Integer key (treated as a string, but may be encoded differently). | |
| 464 DecodeTest( | |
| 465 {0xff, 0x09, 0x3f, 0x00, 0x6f, 0x3f, 0x01, 0x49, 0x54, 0x3f, 0x01, 0x53, | |
| 466 0x01, 0x61, 0x7b, 0x01}, | |
| 467 [this](Local<Value> value) { | |
| 468 ASSERT_TRUE(value->IsObject()); | |
| 469 EXPECT_TRUE(EvaluateScriptForResultBool("result.hasOwnProperty('42')")); | |
| 470 EXPECT_TRUE(EvaluateScriptForResultBool("result[42] === 'a'")); | |
| 471 EXPECT_TRUE(EvaluateScriptForResultBool( | |
| 472 "Object.getOwnPropertyNames(result).length === 1")); | |
| 473 }); | |
| 474 // Key order must be preserved. | |
| 475 DecodeTest( | |
| 476 {0xff, 0x09, 0x3f, 0x00, 0x6f, 0x3f, 0x01, 0x53, 0x01, 0x78, 0x3f, 0x01, | |
| 477 0x49, 0x02, 0x3f, 0x01, 0x53, 0x01, 0x79, 0x3f, 0x01, 0x49, 0x04, 0x3f, | |
| 478 0x01, 0x53, 0x01, 0x61, 0x3f, 0x01, 0x49, 0x06, 0x7b, 0x03}, | |
| 479 [this](Local<Value> value) { | |
| 480 EXPECT_TRUE(EvaluateScriptForResultBool( | |
| 481 "Object.getOwnPropertyNames(result).toString() === 'x,y,a'")); | |
| 482 }); | |
| 483 // This detects a fairly subtle case: the object itself must be in the map | |
| 484 // before its properties are deserialized, so that references to it can be | |
| 485 // resolved. | |
| 486 DecodeTest( | |
| 487 {0xff, 0x09, 0x3f, 0x00, 0x6f, 0x3f, 0x01, 0x53, 0x04, 0x73, | |
| 488 0x65, 0x6c, 0x66, 0x3f, 0x01, 0x5e, 0x00, 0x7b, 0x01, 0x00}, | |
| 489 [this](Local<Value> value) { | |
| 490 ASSERT_TRUE(value->IsObject()); | |
| 491 EXPECT_TRUE(EvaluateScriptForResultBool("result === result.self")); | |
| 492 }); | |
| 493 } | |
| 494 | |
| 391 } // namespace | 495 } // namespace |
| 392 } // namespace v8 | 496 } // namespace v8 |
| OLD | NEW |