| Index: test/unittests/value-serializer-unittest.cc
|
| diff --git a/test/unittests/value-serializer-unittest.cc b/test/unittests/value-serializer-unittest.cc
|
| new file mode 100644
|
| index 0000000000000000000000000000000000000000..1bacdececd0ad4f53ae0809f448fbec928689316
|
| --- /dev/null
|
| +++ b/test/unittests/value-serializer-unittest.cc
|
| @@ -0,0 +1,167 @@
|
| +// Copyright 2016 the V8 project authors. All rights reserved.
|
| +// Use of this source code is governed by a BSD-style license that can be
|
| +// found in the LICENSE file.
|
| +
|
| +#include "src/value-serializer.h"
|
| +#include "include/v8.h"
|
| +#include "src/api.h"
|
| +#include "test/unittests/test-utils.h"
|
| +#include "testing/gtest/include/gtest/gtest.h"
|
| +
|
| +namespace v8 {
|
| +namespace {
|
| +
|
| +class ValueSerializerTest : public TestWithIsolate {
|
| + protected:
|
| + ValueSerializerTest()
|
| + : serialization_context_(Context::New(isolate())),
|
| + deserialization_context_(Context::New(isolate())) {}
|
| +
|
| + const Local<Context>& serialization_context() {
|
| + return serialization_context_;
|
| + }
|
| + const Local<Context>& deserialization_context() {
|
| + return deserialization_context_;
|
| + }
|
| +
|
| + 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);
|
| + }
|
| +
|
| + template <typename OutputFunctor>
|
| + void DecodeTest(const std::vector<uint8_t>& data,
|
| + const OutputFunctor& output_functor) {
|
| + Context::Scope scope(deserialization_context());
|
| + TryCatch try_catch(isolate());
|
| + // TODO(jbroman): Use the public API once it exists.
|
| + i::Isolate* internal_isolate = reinterpret_cast<i::Isolate*>(isolate());
|
| + i::HandleScope handle_scope(internal_isolate);
|
| + i::ValueDeserializer deserializer(
|
| + internal_isolate,
|
| + i::Vector<const uint8_t>(&data[0], static_cast<int>(data.size())));
|
| + ASSERT_TRUE(deserializer.ReadHeader().FromMaybe(false));
|
| + Local<Value> result;
|
| + ASSERT_TRUE(ToLocal<Value>(deserializer.ReadObject(), &result));
|
| + ASSERT_FALSE(result.IsEmpty());
|
| + ASSERT_FALSE(try_catch.HasCaught());
|
| + ASSERT_TRUE(deserialization_context()
|
| + ->Global()
|
| + ->CreateDataProperty(deserialization_context_,
|
| + StringFromUtf8("result"), result)
|
| + .FromMaybe(false));
|
| + output_functor(result);
|
| + ASSERT_FALSE(try_catch.HasCaught());
|
| + }
|
| +
|
| + void InvalidDecodeTest(const std::vector<uint8_t>& data) {
|
| + Context::Scope scope(deserialization_context());
|
| + TryCatch try_catch(isolate());
|
| + i::Isolate* internal_isolate = reinterpret_cast<i::Isolate*>(isolate());
|
| + i::HandleScope handle_scope(internal_isolate);
|
| + i::ValueDeserializer deserializer(
|
| + internal_isolate,
|
| + i::Vector<const uint8_t>(&data[0], static_cast<int>(data.size())));
|
| + Maybe<bool> header_result = deserializer.ReadHeader();
|
| + if (header_result.IsNothing()) return;
|
| + ASSERT_TRUE(header_result.ToChecked());
|
| + ASSERT_TRUE(deserializer.ReadObject().is_null());
|
| + }
|
| +
|
| + Local<Value> EvaluateScriptForInput(const char* utf8_source) {
|
| + Local<String> source = StringFromUtf8(utf8_source);
|
| + Local<Script> script =
|
| + Script::Compile(serialization_context_, source).ToLocalChecked();
|
| + return script->Run(serialization_context_).ToLocalChecked();
|
| + }
|
| +
|
| + bool EvaluateScriptForResultBool(const char* utf8_source) {
|
| + Local<String> source = StringFromUtf8(utf8_source);
|
| + Local<Script> script =
|
| + Script::Compile(deserialization_context_, source).ToLocalChecked();
|
| + Local<Value> value = script->Run(deserialization_context_).ToLocalChecked();
|
| + return value->BooleanValue(deserialization_context_).FromJust();
|
| + }
|
| +
|
| + Local<String> StringFromUtf8(const char* source) {
|
| + return String::NewFromUtf8(isolate(), source, NewStringType::kNormal)
|
| + .ToLocalChecked();
|
| + }
|
| +
|
| + private:
|
| + Local<Context> serialization_context_;
|
| + Local<Context> deserialization_context_;
|
| +
|
| + DISALLOW_COPY_AND_ASSIGN(ValueSerializerTest);
|
| +};
|
| +
|
| +TEST_F(ValueSerializerTest, DecodeInvalid) {
|
| + // Version tag but no content.
|
| + InvalidDecodeTest({0xff});
|
| + // Version too large.
|
| + InvalidDecodeTest({0xff, 0x7f, 0x5f});
|
| + // Nonsense tag.
|
| + InvalidDecodeTest({0xff, 0x09, 0xdd});
|
| +}
|
| +
|
| +TEST_F(ValueSerializerTest, RoundTripOddball) {
|
| + RoundTripTest([this]() { return Undefined(isolate()); },
|
| + [](Local<Value> value) { EXPECT_TRUE(value->IsUndefined()); });
|
| + RoundTripTest([this]() { return True(isolate()); },
|
| + [](Local<Value> value) { EXPECT_TRUE(value->IsTrue()); });
|
| + RoundTripTest([this]() { return False(isolate()); },
|
| + [](Local<Value> value) { EXPECT_TRUE(value->IsFalse()); });
|
| + RoundTripTest([this]() { return Null(isolate()); },
|
| + [](Local<Value> value) { EXPECT_TRUE(value->IsNull()); });
|
| +}
|
| +
|
| +TEST_F(ValueSerializerTest, DecodeOddball) {
|
| + // What this code is expected to generate.
|
| + DecodeTest({0xff, 0x09, 0x5f},
|
| + [](Local<Value> value) { EXPECT_TRUE(value->IsUndefined()); });
|
| + DecodeTest({0xff, 0x09, 0x54},
|
| + [](Local<Value> value) { EXPECT_TRUE(value->IsTrue()); });
|
| + DecodeTest({0xff, 0x09, 0x46},
|
| + [](Local<Value> value) { EXPECT_TRUE(value->IsFalse()); });
|
| + DecodeTest({0xff, 0x09, 0x30},
|
| + [](Local<Value> value) { EXPECT_TRUE(value->IsNull()); });
|
| +
|
| + // What v9 of the Blink code generates.
|
| + DecodeTest({0xff, 0x09, 0x3f, 0x00, 0x5f, 0x00},
|
| + [](Local<Value> value) { EXPECT_TRUE(value->IsUndefined()); });
|
| + DecodeTest({0xff, 0x09, 0x3f, 0x00, 0x54, 0x00},
|
| + [](Local<Value> value) { EXPECT_TRUE(value->IsTrue()); });
|
| + DecodeTest({0xff, 0x09, 0x3f, 0x00, 0x46, 0x00},
|
| + [](Local<Value> value) { EXPECT_TRUE(value->IsFalse()); });
|
| + DecodeTest({0xff, 0x09, 0x3f, 0x00, 0x30, 0x00},
|
| + [](Local<Value> value) { EXPECT_TRUE(value->IsNull()); });
|
| +
|
| + // v0 (with no explicit version).
|
| + DecodeTest({0x5f, 0x00},
|
| + [](Local<Value> value) { EXPECT_TRUE(value->IsUndefined()); });
|
| + DecodeTest({0x54, 0x00},
|
| + [](Local<Value> value) { EXPECT_TRUE(value->IsTrue()); });
|
| + DecodeTest({0x46, 0x00},
|
| + [](Local<Value> value) { EXPECT_TRUE(value->IsFalse()); });
|
| + DecodeTest({0x30, 0x00},
|
| + [](Local<Value> value) { EXPECT_TRUE(value->IsNull()); });
|
| +}
|
| +
|
| +} // namespace
|
| +} // namespace v8
|
|
|