| Index: test/unittests/value-serializer-unittest.cc
|
| diff --git a/test/unittests/value-serializer-unittest.cc b/test/unittests/value-serializer-unittest.cc
|
| index 696f90466a6e383abb3571b23a08ce3ca21a7706..c48961fb6cddbb61ac4c2fa464af29ab925e0062 100644
|
| --- a/test/unittests/value-serializer-unittest.cc
|
| +++ b/test/unittests/value-serializer-unittest.cc
|
| @@ -4,6 +4,9 @@
|
|
|
| #include "src/value-serializer.h"
|
|
|
| +#include <algorithm>
|
| +#include <string>
|
| +
|
| #include "include/v8.h"
|
| #include "src/api.h"
|
| #include "src/base/build_config.h"
|
| @@ -29,22 +32,27 @@ class ValueSerializerTest : public TestWithIsolate {
|
| template <typename InputFunctor, typename OutputFunctor>
|
| void RoundTripTest(const InputFunctor& input_functor,
|
| const OutputFunctor& output_functor) {
|
| - std::vector<uint8_t> data;
|
| - {
|
| - Context::Scope scope(serialization_context());
|
| - TryCatch try_catch(isolate());
|
| - // TODO(jbroman): Use the public API once it exists.
|
| - Local<Value> input_value = input_functor();
|
| - i::Isolate* internal_isolate = reinterpret_cast<i::Isolate*>(isolate());
|
| - i::HandleScope handle_scope(internal_isolate);
|
| - i::ValueSerializer serializer;
|
| - serializer.WriteHeader();
|
| - ASSERT_TRUE(serializer.WriteObject(Utils::OpenHandle(*input_value))
|
| - .FromMaybe(false));
|
| - ASSERT_FALSE(try_catch.HasCaught());
|
| - data = serializer.ReleaseBuffer();
|
| - }
|
| - DecodeTest(data, output_functor);
|
| + EncodeTest(input_functor,
|
| + [this, &output_functor](const std::vector<uint8_t>& data) {
|
| + DecodeTest(data, output_functor);
|
| + });
|
| + }
|
| +
|
| + template <typename InputFunctor, typename EncodedDataFunctor>
|
| + void EncodeTest(const InputFunctor& input_functor,
|
| + const EncodedDataFunctor& encoded_data_functor) {
|
| + Context::Scope scope(serialization_context());
|
| + TryCatch try_catch(isolate());
|
| + // TODO(jbroman): Use the public API once it exists.
|
| + Local<Value> input_value = input_functor();
|
| + i::Isolate* internal_isolate = reinterpret_cast<i::Isolate*>(isolate());
|
| + i::HandleScope handle_scope(internal_isolate);
|
| + i::ValueSerializer serializer;
|
| + serializer.WriteHeader();
|
| + ASSERT_TRUE(serializer.WriteObject(Utils::OpenHandle(*input_value))
|
| + .FromMaybe(false));
|
| + ASSERT_FALSE(try_catch.HasCaught());
|
| + encoded_data_functor(serializer.ReleaseBuffer());
|
| }
|
|
|
| template <typename OutputFunctor>
|
| @@ -106,6 +114,11 @@ class ValueSerializerTest : public TestWithIsolate {
|
| .ToLocalChecked();
|
| }
|
|
|
| + static std::string Utf8Value(Local<Value> value) {
|
| + String::Utf8Value utf8(value);
|
| + return std::string(*utf8, utf8.length());
|
| + }
|
| +
|
| private:
|
| Local<Context> serialization_context_;
|
| Local<Context> deserialization_context_;
|
| @@ -248,5 +261,132 @@ TEST_F(ValueSerializerTest, DecodeNumber) {
|
| // TODO(jbroman): Equivalent test for big-endian machines.
|
| }
|
|
|
| +// String constants (in UTF-8) used for string encoding tests.
|
| +static const char kHelloString[] = "Hello";
|
| +static const char kQuebecString[] = "\x51\x75\xC3\xA9\x62\x65\x63";
|
| +static const char kEmojiString[] = "\xF0\x9F\x91\x8A";
|
| +
|
| +TEST_F(ValueSerializerTest, RoundTripString) {
|
| + RoundTripTest([this]() { return String::Empty(isolate()); },
|
| + [](Local<Value> value) {
|
| + ASSERT_TRUE(value->IsString());
|
| + EXPECT_EQ(0, String::Cast(*value)->Length());
|
| + });
|
| + // Inside ASCII.
|
| + RoundTripTest([this]() { return StringFromUtf8(kHelloString); },
|
| + [](Local<Value> value) {
|
| + ASSERT_TRUE(value->IsString());
|
| + EXPECT_EQ(5, String::Cast(*value)->Length());
|
| + EXPECT_EQ(kHelloString, Utf8Value(value));
|
| + });
|
| + // Inside Latin-1 (i.e. one-byte string), but not ASCII.
|
| + RoundTripTest([this]() { return StringFromUtf8(kQuebecString); },
|
| + [](Local<Value> value) {
|
| + ASSERT_TRUE(value->IsString());
|
| + EXPECT_EQ(6, String::Cast(*value)->Length());
|
| + EXPECT_EQ(kQuebecString, Utf8Value(value));
|
| + });
|
| + // An emoji (decodes to two 16-bit chars).
|
| + RoundTripTest([this]() { return StringFromUtf8(kEmojiString); },
|
| + [](Local<Value> value) {
|
| + ASSERT_TRUE(value->IsString());
|
| + EXPECT_EQ(2, String::Cast(*value)->Length());
|
| + EXPECT_EQ(kEmojiString, Utf8Value(value));
|
| + });
|
| +}
|
| +
|
| +TEST_F(ValueSerializerTest, DecodeString) {
|
| + // Decoding the strings above from UTF-8.
|
| + DecodeTest({0xff, 0x09, 0x53, 0x00},
|
| + [](Local<Value> value) {
|
| + ASSERT_TRUE(value->IsString());
|
| + EXPECT_EQ(0, String::Cast(*value)->Length());
|
| + });
|
| + DecodeTest({0xff, 0x09, 0x53, 0x05, 'H', 'e', 'l', 'l', 'o'},
|
| + [](Local<Value> value) {
|
| + ASSERT_TRUE(value->IsString());
|
| + EXPECT_EQ(5, String::Cast(*value)->Length());
|
| + EXPECT_EQ(kHelloString, Utf8Value(value));
|
| + });
|
| + DecodeTest({0xff, 0x09, 0x53, 0x07, 'Q', 'u', 0xc3, 0xa9, 'b', 'e', 'c'},
|
| + [](Local<Value> value) {
|
| + ASSERT_TRUE(value->IsString());
|
| + EXPECT_EQ(6, String::Cast(*value)->Length());
|
| + EXPECT_EQ(kQuebecString, Utf8Value(value));
|
| + });
|
| + DecodeTest({0xff, 0x09, 0x53, 0x04, 0xf0, 0x9f, 0x91, 0x8a},
|
| + [](Local<Value> value) {
|
| + ASSERT_TRUE(value->IsString());
|
| + EXPECT_EQ(2, String::Cast(*value)->Length());
|
| + EXPECT_EQ(kEmojiString, Utf8Value(value));
|
| + });
|
| +
|
| +// And from two-byte strings (endianness dependent).
|
| +#if defined(V8_TARGET_LITTLE_ENDIAN)
|
| + DecodeTest({0xff, 0x09, 0x63, 0x00},
|
| + [](Local<Value> value) {
|
| + ASSERT_TRUE(value->IsString());
|
| + EXPECT_EQ(0, String::Cast(*value)->Length());
|
| + });
|
| + DecodeTest({0xff, 0x09, 0x63, 0x0a, 'H', '\0', 'e', '\0', 'l', '\0', 'l',
|
| + '\0', 'o', '\0'},
|
| + [](Local<Value> value) {
|
| + ASSERT_TRUE(value->IsString());
|
| + EXPECT_EQ(5, String::Cast(*value)->Length());
|
| + EXPECT_EQ(kHelloString, Utf8Value(value));
|
| + });
|
| + DecodeTest({0xff, 0x09, 0x63, 0x0c, 'Q', '\0', 'u', '\0', 0xe9, '\0', 'b',
|
| + '\0', 'e', '\0', 'c', '\0'},
|
| + [](Local<Value> value) {
|
| + ASSERT_TRUE(value->IsString());
|
| + EXPECT_EQ(6, String::Cast(*value)->Length());
|
| + EXPECT_EQ(kQuebecString, Utf8Value(value));
|
| + });
|
| + DecodeTest({0xff, 0x09, 0x63, 0x04, 0x3d, 0xd8, 0x4a, 0xdc},
|
| + [](Local<Value> value) {
|
| + ASSERT_TRUE(value->IsString());
|
| + EXPECT_EQ(2, String::Cast(*value)->Length());
|
| + EXPECT_EQ(kEmojiString, Utf8Value(value));
|
| + });
|
| +#endif
|
| + // TODO(jbroman): The same for big-endian systems.
|
| +}
|
| +
|
| +TEST_F(ValueSerializerTest, DecodeInvalidString) {
|
| + // UTF-8 string with too few bytes available.
|
| + InvalidDecodeTest({0xff, 0x09, 0x53, 0x10, 'v', '8'});
|
| +#if defined(V8_TARGET_LITTLE_ENDIAN)
|
| + // Two-byte string with too few bytes available.
|
| + InvalidDecodeTest({0xff, 0x09, 0x63, 0x10, 'v', '\0', '8', '\0'});
|
| + // Two-byte string with an odd byte length.
|
| + InvalidDecodeTest({0xff, 0x09, 0x63, 0x03, 'v', '\0', '8'});
|
| +#endif
|
| + // TODO(jbroman): The same for big-endian systems.
|
| +}
|
| +
|
| +TEST_F(ValueSerializerTest, EncodeTwoByteStringUsesPadding) {
|
| + // As long as the output has a version that Blink expects to be able to read,
|
| + // we must respect its alignment requirements. It requires that two-byte
|
| + // characters be aligned.
|
| + EncodeTest(
|
| + [this]() {
|
| + // We need a string whose length will take two bytes to encode, so that
|
| + // a padding byte is needed to keep the characters aligned. The string
|
| + // must also have a two-byte character, so that it gets the two-byte
|
| + // encoding.
|
| + std::string string(200, ' ');
|
| + string += kEmojiString;
|
| + return StringFromUtf8(string.c_str());
|
| + },
|
| + [](const std::vector<uint8_t>& data) {
|
| + // This is a sufficient but not necessary condition to be aligned.
|
| + // Note that the third byte (0x00) is padding.
|
| + const uint8_t expected_prefix[] = {0xff, 0x09, 0x00, 0x63, 0x94, 0x03};
|
| + ASSERT_GT(data.size(), sizeof(expected_prefix) / sizeof(uint8_t));
|
| + EXPECT_TRUE(std::equal(std::begin(expected_prefix),
|
| + std::end(expected_prefix), data.begin()));
|
| + });
|
| +}
|
| +
|
| } // namespace
|
| } // namespace v8
|
|
|