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 |