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

Side by Side Diff: test/unittests/value-serializer-unittest.cc

Issue 2245753002: Blink-compatible serialization of strings. (Closed) Base URL: https://chromium.googlesource.com/v8/v8.git@vs2
Patch Set: explicit cast to actually make it an unsigned comparison Created 4 years, 4 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 | « src/value-serializer.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 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
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
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
OLDNEW
« no previous file with comments | « src/value-serializer.cc ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698