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> |
| 8 #include <string> |
| 9 |
7 #include "include/v8.h" | 10 #include "include/v8.h" |
8 #include "src/api.h" | 11 #include "src/api.h" |
9 #include "src/base/build_config.h" | 12 #include "src/base/build_config.h" |
10 #include "test/unittests/test-utils.h" | 13 #include "test/unittests/test-utils.h" |
11 #include "testing/gtest/include/gtest/gtest.h" | 14 #include "testing/gtest/include/gtest/gtest.h" |
12 | 15 |
13 namespace v8 { | 16 namespace v8 { |
14 namespace { | 17 namespace { |
15 | 18 |
16 class ValueSerializerTest : public TestWithIsolate { | 19 class ValueSerializerTest : public TestWithIsolate { |
17 protected: | 20 protected: |
18 ValueSerializerTest() | 21 ValueSerializerTest() |
19 : serialization_context_(Context::New(isolate())), | 22 : serialization_context_(Context::New(isolate())), |
20 deserialization_context_(Context::New(isolate())) {} | 23 deserialization_context_(Context::New(isolate())) {} |
21 | 24 |
22 const Local<Context>& serialization_context() { | 25 const Local<Context>& serialization_context() { |
23 return serialization_context_; | 26 return serialization_context_; |
24 } | 27 } |
25 const Local<Context>& deserialization_context() { | 28 const Local<Context>& deserialization_context() { |
26 return deserialization_context_; | 29 return deserialization_context_; |
27 } | 30 } |
28 | 31 |
29 template <typename InputFunctor, typename OutputFunctor> | 32 template <typename InputFunctor, typename OutputFunctor> |
30 void RoundTripTest(const InputFunctor& input_functor, | 33 void RoundTripTest(const InputFunctor& input_functor, |
31 const OutputFunctor& output_functor) { | 34 const OutputFunctor& output_functor) { |
32 std::vector<uint8_t> data; | 35 EncodeTest(input_functor, |
33 { | 36 [this, &output_functor](const std::vector<uint8_t>& data) { |
34 Context::Scope scope(serialization_context()); | 37 DecodeTest(data, output_functor); |
35 TryCatch try_catch(isolate()); | 38 }); |
36 // TODO(jbroman): Use the public API once it exists. | 39 } |
37 Local<Value> input_value = input_functor(); | 40 |
38 i::Isolate* internal_isolate = reinterpret_cast<i::Isolate*>(isolate()); | 41 template <typename InputFunctor, typename EncodedDataFunctor> |
39 i::HandleScope handle_scope(internal_isolate); | 42 void EncodeTest(const InputFunctor& input_functor, |
40 i::ValueSerializer serializer; | 43 const EncodedDataFunctor& encoded_data_functor) { |
41 serializer.WriteHeader(); | 44 Context::Scope scope(serialization_context()); |
42 ASSERT_TRUE(serializer.WriteObject(Utils::OpenHandle(*input_value)) | 45 TryCatch try_catch(isolate()); |
43 .FromMaybe(false)); | 46 // TODO(jbroman): Use the public API once it exists. |
44 ASSERT_FALSE(try_catch.HasCaught()); | 47 Local<Value> input_value = input_functor(); |
45 data = serializer.ReleaseBuffer(); | 48 i::Isolate* internal_isolate = reinterpret_cast<i::Isolate*>(isolate()); |
46 } | 49 i::HandleScope handle_scope(internal_isolate); |
47 DecodeTest(data, output_functor); | 50 i::ValueSerializer serializer; |
| 51 serializer.WriteHeader(); |
| 52 ASSERT_TRUE(serializer.WriteObject(Utils::OpenHandle(*input_value)) |
| 53 .FromMaybe(false)); |
| 54 ASSERT_FALSE(try_catch.HasCaught()); |
| 55 encoded_data_functor(serializer.ReleaseBuffer()); |
48 } | 56 } |
49 | 57 |
50 template <typename OutputFunctor> | 58 template <typename OutputFunctor> |
51 void DecodeTest(const std::vector<uint8_t>& data, | 59 void DecodeTest(const std::vector<uint8_t>& data, |
52 const OutputFunctor& output_functor) { | 60 const OutputFunctor& output_functor) { |
53 Context::Scope scope(deserialization_context()); | 61 Context::Scope scope(deserialization_context()); |
54 TryCatch try_catch(isolate()); | 62 TryCatch try_catch(isolate()); |
55 // TODO(jbroman): Use the public API once it exists. | 63 // TODO(jbroman): Use the public API once it exists. |
56 i::Isolate* internal_isolate = reinterpret_cast<i::Isolate*>(isolate()); | 64 i::Isolate* internal_isolate = reinterpret_cast<i::Isolate*>(isolate()); |
57 i::HandleScope handle_scope(internal_isolate); | 65 i::HandleScope handle_scope(internal_isolate); |
(...skipping 41 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
99 Script::Compile(deserialization_context_, source).ToLocalChecked(); | 107 Script::Compile(deserialization_context_, source).ToLocalChecked(); |
100 Local<Value> value = script->Run(deserialization_context_).ToLocalChecked(); | 108 Local<Value> value = script->Run(deserialization_context_).ToLocalChecked(); |
101 return value->BooleanValue(deserialization_context_).FromJust(); | 109 return value->BooleanValue(deserialization_context_).FromJust(); |
102 } | 110 } |
103 | 111 |
104 Local<String> StringFromUtf8(const char* source) { | 112 Local<String> StringFromUtf8(const char* source) { |
105 return String::NewFromUtf8(isolate(), source, NewStringType::kNormal) | 113 return String::NewFromUtf8(isolate(), source, NewStringType::kNormal) |
106 .ToLocalChecked(); | 114 .ToLocalChecked(); |
107 } | 115 } |
108 | 116 |
| 117 static std::string Utf8Value(Local<Value> value) { |
| 118 String::Utf8Value utf8(value); |
| 119 return std::string(*utf8, utf8.length()); |
| 120 } |
| 121 |
109 private: | 122 private: |
110 Local<Context> serialization_context_; | 123 Local<Context> serialization_context_; |
111 Local<Context> deserialization_context_; | 124 Local<Context> deserialization_context_; |
112 | 125 |
113 DISALLOW_COPY_AND_ASSIGN(ValueSerializerTest); | 126 DISALLOW_COPY_AND_ASSIGN(ValueSerializerTest); |
114 }; | 127 }; |
115 | 128 |
116 TEST_F(ValueSerializerTest, DecodeInvalid) { | 129 TEST_F(ValueSerializerTest, DecodeInvalid) { |
117 // Version tag but no content. | 130 // Version tag but no content. |
118 InvalidDecodeTest({0xff}); | 131 InvalidDecodeTest({0xff}); |
(...skipping 122 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
241 // signaling NaN | 254 // signaling NaN |
242 DecodeTest({0xff, 0x09, 0x4e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf4, 0x7f}, | 255 DecodeTest({0xff, 0x09, 0x4e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf4, 0x7f}, |
243 [](Local<Value> value) { | 256 [](Local<Value> value) { |
244 ASSERT_TRUE(value->IsNumber()); | 257 ASSERT_TRUE(value->IsNumber()); |
245 EXPECT_TRUE(std::isnan(Number::Cast(*value)->Value())); | 258 EXPECT_TRUE(std::isnan(Number::Cast(*value)->Value())); |
246 }); | 259 }); |
247 #endif | 260 #endif |
248 // TODO(jbroman): Equivalent test for big-endian machines. | 261 // TODO(jbroman): Equivalent test for big-endian machines. |
249 } | 262 } |
250 | 263 |
| 264 // String constants (in UTF-8) used for string encoding tests. |
| 265 static const char kHelloString[] = "Hello"; |
| 266 static const char kQuebecString[] = "\x51\x75\xC3\xA9\x62\x65\x63"; |
| 267 static const char kEmojiString[] = "\xF0\x9F\x91\x8A"; |
| 268 |
| 269 TEST_F(ValueSerializerTest, RoundTripString) { |
| 270 RoundTripTest([this]() { return String::Empty(isolate()); }, |
| 271 [](Local<Value> value) { |
| 272 ASSERT_TRUE(value->IsString()); |
| 273 EXPECT_EQ(0, String::Cast(*value)->Length()); |
| 274 }); |
| 275 // Inside ASCII. |
| 276 RoundTripTest([this]() { return StringFromUtf8(kHelloString); }, |
| 277 [](Local<Value> value) { |
| 278 ASSERT_TRUE(value->IsString()); |
| 279 EXPECT_EQ(5, String::Cast(*value)->Length()); |
| 280 EXPECT_EQ(kHelloString, Utf8Value(value)); |
| 281 }); |
| 282 // Inside Latin-1 (i.e. one-byte string), but not ASCII. |
| 283 RoundTripTest([this]() { return StringFromUtf8(kQuebecString); }, |
| 284 [](Local<Value> value) { |
| 285 ASSERT_TRUE(value->IsString()); |
| 286 EXPECT_EQ(6, String::Cast(*value)->Length()); |
| 287 EXPECT_EQ(kQuebecString, Utf8Value(value)); |
| 288 }); |
| 289 // An emoji (decodes to two 16-bit chars). |
| 290 RoundTripTest([this]() { return StringFromUtf8(kEmojiString); }, |
| 291 [](Local<Value> value) { |
| 292 ASSERT_TRUE(value->IsString()); |
| 293 EXPECT_EQ(2, String::Cast(*value)->Length()); |
| 294 EXPECT_EQ(kEmojiString, Utf8Value(value)); |
| 295 }); |
| 296 } |
| 297 |
| 298 TEST_F(ValueSerializerTest, DecodeString) { |
| 299 // Decoding the strings above from UTF-8. |
| 300 DecodeTest({0xff, 0x09, 0x53, 0x00}, |
| 301 [](Local<Value> value) { |
| 302 ASSERT_TRUE(value->IsString()); |
| 303 EXPECT_EQ(0, String::Cast(*value)->Length()); |
| 304 }); |
| 305 DecodeTest({0xff, 0x09, 0x53, 0x05, 'H', 'e', 'l', 'l', 'o'}, |
| 306 [](Local<Value> value) { |
| 307 ASSERT_TRUE(value->IsString()); |
| 308 EXPECT_EQ(5, String::Cast(*value)->Length()); |
| 309 EXPECT_EQ(kHelloString, Utf8Value(value)); |
| 310 }); |
| 311 DecodeTest({0xff, 0x09, 0x53, 0x07, 'Q', 'u', 0xc3, 0xa9, 'b', 'e', 'c'}, |
| 312 [](Local<Value> value) { |
| 313 ASSERT_TRUE(value->IsString()); |
| 314 EXPECT_EQ(6, String::Cast(*value)->Length()); |
| 315 EXPECT_EQ(kQuebecString, Utf8Value(value)); |
| 316 }); |
| 317 DecodeTest({0xff, 0x09, 0x53, 0x04, 0xf0, 0x9f, 0x91, 0x8a}, |
| 318 [](Local<Value> value) { |
| 319 ASSERT_TRUE(value->IsString()); |
| 320 EXPECT_EQ(2, String::Cast(*value)->Length()); |
| 321 EXPECT_EQ(kEmojiString, Utf8Value(value)); |
| 322 }); |
| 323 |
| 324 // And from two-byte strings (endianness dependent). |
| 325 #if defined(V8_TARGET_LITTLE_ENDIAN) |
| 326 DecodeTest({0xff, 0x09, 0x63, 0x00}, |
| 327 [](Local<Value> value) { |
| 328 ASSERT_TRUE(value->IsString()); |
| 329 EXPECT_EQ(0, String::Cast(*value)->Length()); |
| 330 }); |
| 331 DecodeTest({0xff, 0x09, 0x63, 0x0a, 'H', '\0', 'e', '\0', 'l', '\0', 'l', |
| 332 '\0', 'o', '\0'}, |
| 333 [](Local<Value> value) { |
| 334 ASSERT_TRUE(value->IsString()); |
| 335 EXPECT_EQ(5, String::Cast(*value)->Length()); |
| 336 EXPECT_EQ(kHelloString, Utf8Value(value)); |
| 337 }); |
| 338 DecodeTest({0xff, 0x09, 0x63, 0x0c, 'Q', '\0', 'u', '\0', 0xe9, '\0', 'b', |
| 339 '\0', 'e', '\0', 'c', '\0'}, |
| 340 [](Local<Value> value) { |
| 341 ASSERT_TRUE(value->IsString()); |
| 342 EXPECT_EQ(6, String::Cast(*value)->Length()); |
| 343 EXPECT_EQ(kQuebecString, Utf8Value(value)); |
| 344 }); |
| 345 DecodeTest({0xff, 0x09, 0x63, 0x04, 0x3d, 0xd8, 0x4a, 0xdc}, |
| 346 [](Local<Value> value) { |
| 347 ASSERT_TRUE(value->IsString()); |
| 348 EXPECT_EQ(2, String::Cast(*value)->Length()); |
| 349 EXPECT_EQ(kEmojiString, Utf8Value(value)); |
| 350 }); |
| 351 #endif |
| 352 // TODO(jbroman): The same for big-endian systems. |
| 353 } |
| 354 |
| 355 TEST_F(ValueSerializerTest, DecodeInvalidString) { |
| 356 // UTF-8 string with too few bytes available. |
| 357 InvalidDecodeTest({0xff, 0x09, 0x53, 0x10, 'v', '8'}); |
| 358 #if defined(V8_TARGET_LITTLE_ENDIAN) |
| 359 // Two-byte string with too few bytes available. |
| 360 InvalidDecodeTest({0xff, 0x09, 0x63, 0x10, 'v', '\0', '8', '\0'}); |
| 361 // Two-byte string with an odd byte length. |
| 362 InvalidDecodeTest({0xff, 0x09, 0x63, 0x03, 'v', '\0', '8'}); |
| 363 #endif |
| 364 // TODO(jbroman): The same for big-endian systems. |
| 365 } |
| 366 |
| 367 TEST_F(ValueSerializerTest, EncodeTwoByteStringUsesPadding) { |
| 368 // As long as the output has a version that Blink expects to be able to read, |
| 369 // we must respect its alignment requirements. It requires that two-byte |
| 370 // characters be aligned. |
| 371 EncodeTest( |
| 372 [this]() { |
| 373 // We need a string whose length will take two bytes to encode, so that |
| 374 // a padding byte is needed to keep the characters aligned. The string |
| 375 // must also have a two-byte character, so that it gets the two-byte |
| 376 // encoding. |
| 377 std::string string(200, ' '); |
| 378 string += kEmojiString; |
| 379 return StringFromUtf8(string.c_str()); |
| 380 }, |
| 381 [](const std::vector<uint8_t>& data) { |
| 382 // This is a sufficient but not necessary condition to be aligned. |
| 383 // Note that the third byte (0x00) is padding. |
| 384 const uint8_t expected_prefix[] = {0xff, 0x09, 0x00, 0x63, 0x94, 0x03}; |
| 385 ASSERT_GT(data.size(), sizeof(expected_prefix) / sizeof(uint8_t)); |
| 386 EXPECT_TRUE(std::equal(std::begin(expected_prefix), |
| 387 std::end(expected_prefix), data.begin())); |
| 388 }); |
| 389 } |
| 390 |
251 } // namespace | 391 } // namespace |
252 } // namespace v8 | 392 } // namespace v8 |
OLD | NEW |