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> | 7 #include <algorithm> |
8 #include <string> | 8 #include <string> |
9 | 9 |
10 #include "include/v8.h" | 10 #include "include/v8.h" |
11 #include "src/api.h" | 11 #include "src/api.h" |
12 #include "src/base/build_config.h" | 12 #include "src/base/build_config.h" |
13 #include "test/unittests/test-utils.h" | 13 #include "test/unittests/test-utils.h" |
| 14 #include "testing/gmock/include/gmock/gmock.h" |
14 #include "testing/gtest/include/gtest/gtest.h" | 15 #include "testing/gtest/include/gtest/gtest.h" |
15 | 16 |
16 namespace v8 { | 17 namespace v8 { |
17 namespace { | 18 namespace { |
18 | 19 |
| 20 using ::testing::_; |
| 21 using ::testing::Invoke; |
| 22 |
19 class ValueSerializerTest : public TestWithIsolate { | 23 class ValueSerializerTest : public TestWithIsolate { |
20 protected: | 24 protected: |
21 ValueSerializerTest() | 25 ValueSerializerTest() |
22 : serialization_context_(Context::New(isolate())), | 26 : serialization_context_(Context::New(isolate())), |
23 deserialization_context_(Context::New(isolate())) {} | 27 deserialization_context_(Context::New(isolate())) { |
| 28 // Create a host object type that can be tested through |
| 29 // serialization/deserialization delegates below. |
| 30 Local<FunctionTemplate> function_template = v8::FunctionTemplate::New( |
| 31 isolate(), [](const FunctionCallbackInfo<Value>& args) { |
| 32 args.Holder()->SetInternalField(0, args[0]); |
| 33 args.Holder()->SetInternalField(1, args[1]); |
| 34 }); |
| 35 function_template->InstanceTemplate()->SetInternalFieldCount(2); |
| 36 function_template->InstanceTemplate()->SetAccessor( |
| 37 StringFromUtf8("value"), |
| 38 [](Local<String> property, const PropertyCallbackInfo<Value>& args) { |
| 39 args.GetReturnValue().Set(args.Holder()->GetInternalField(0)); |
| 40 }); |
| 41 function_template->InstanceTemplate()->SetAccessor( |
| 42 StringFromUtf8("value2"), |
| 43 [](Local<String> property, const PropertyCallbackInfo<Value>& args) { |
| 44 args.GetReturnValue().Set(args.Holder()->GetInternalField(1)); |
| 45 }); |
| 46 for (Local<Context> context : |
| 47 {serialization_context_, deserialization_context_}) { |
| 48 context->Global() |
| 49 ->CreateDataProperty( |
| 50 context, StringFromUtf8("ExampleHostObject"), |
| 51 function_template->GetFunction(context).ToLocalChecked()) |
| 52 .ToChecked(); |
| 53 } |
| 54 host_object_constructor_template_ = function_template; |
| 55 } |
24 | 56 |
25 const Local<Context>& serialization_context() { | 57 const Local<Context>& serialization_context() { |
26 return serialization_context_; | 58 return serialization_context_; |
27 } | 59 } |
28 const Local<Context>& deserialization_context() { | 60 const Local<Context>& deserialization_context() { |
29 return deserialization_context_; | 61 return deserialization_context_; |
30 } | 62 } |
31 | 63 |
32 // Overridden in more specific fixtures. | 64 // Overridden in more specific fixtures. |
| 65 virtual ValueSerializer::Delegate* GetSerializerDelegate() { return nullptr; } |
33 virtual void BeforeEncode(ValueSerializer*) {} | 66 virtual void BeforeEncode(ValueSerializer*) {} |
| 67 virtual ValueDeserializer::Delegate* GetDeserializerDelegate() { |
| 68 return nullptr; |
| 69 } |
34 virtual void BeforeDecode(ValueDeserializer*) {} | 70 virtual void BeforeDecode(ValueDeserializer*) {} |
35 | 71 |
36 template <typename InputFunctor, typename OutputFunctor> | 72 template <typename InputFunctor, typename OutputFunctor> |
37 void RoundTripTest(const InputFunctor& input_functor, | 73 void RoundTripTest(const InputFunctor& input_functor, |
38 const OutputFunctor& output_functor) { | 74 const OutputFunctor& output_functor) { |
39 EncodeTest(input_functor, | 75 EncodeTest(input_functor, |
40 [this, &output_functor](const std::vector<uint8_t>& data) { | 76 [this, &output_functor](const std::vector<uint8_t>& data) { |
41 DecodeTest(data, output_functor); | 77 DecodeTest(data, output_functor); |
42 }); | 78 }); |
43 } | 79 } |
44 | 80 |
45 // Variant for the common case where a script is used to build the original | 81 // Variant for the common case where a script is used to build the original |
46 // value. | 82 // value. |
47 template <typename OutputFunctor> | 83 template <typename OutputFunctor> |
48 void RoundTripTest(const char* source, const OutputFunctor& output_functor) { | 84 void RoundTripTest(const char* source, const OutputFunctor& output_functor) { |
49 RoundTripTest([this, source]() { return EvaluateScriptForInput(source); }, | 85 RoundTripTest([this, source]() { return EvaluateScriptForInput(source); }, |
50 output_functor); | 86 output_functor); |
51 } | 87 } |
52 | 88 |
53 Maybe<std::vector<uint8_t>> DoEncode(Local<Value> value) { | 89 Maybe<std::vector<uint8_t>> DoEncode(Local<Value> value) { |
54 Local<Context> context = serialization_context(); | 90 Local<Context> context = serialization_context(); |
55 ValueSerializer serializer(isolate()); | 91 ValueSerializer serializer(isolate(), GetSerializerDelegate()); |
56 BeforeEncode(&serializer); | 92 BeforeEncode(&serializer); |
57 serializer.WriteHeader(); | 93 serializer.WriteHeader(); |
58 if (!serializer.WriteValue(context, value).FromMaybe(false)) { | 94 if (!serializer.WriteValue(context, value).FromMaybe(false)) { |
59 return Nothing<std::vector<uint8_t>>(); | 95 return Nothing<std::vector<uint8_t>>(); |
60 } | 96 } |
61 return Just(serializer.ReleaseBuffer()); | 97 return Just(serializer.ReleaseBuffer()); |
62 } | 98 } |
63 | 99 |
64 template <typename InputFunctor, typename EncodedDataFunctor> | 100 template <typename InputFunctor, typename EncodedDataFunctor> |
65 void EncodeTest(const InputFunctor& input_functor, | 101 void EncodeTest(const InputFunctor& input_functor, |
(...skipping 20 matching lines...) Expand all Loading... |
86 InvalidEncodeTest(source, [](Local<Message>) {}); | 122 InvalidEncodeTest(source, [](Local<Message>) {}); |
87 } | 123 } |
88 | 124 |
89 template <typename OutputFunctor> | 125 template <typename OutputFunctor> |
90 void DecodeTest(const std::vector<uint8_t>& data, | 126 void DecodeTest(const std::vector<uint8_t>& data, |
91 const OutputFunctor& output_functor) { | 127 const OutputFunctor& output_functor) { |
92 Local<Context> context = deserialization_context(); | 128 Local<Context> context = deserialization_context(); |
93 Context::Scope scope(context); | 129 Context::Scope scope(context); |
94 TryCatch try_catch(isolate()); | 130 TryCatch try_catch(isolate()); |
95 ValueDeserializer deserializer(isolate(), &data[0], | 131 ValueDeserializer deserializer(isolate(), &data[0], |
96 static_cast<int>(data.size())); | 132 static_cast<int>(data.size()), |
| 133 GetDeserializerDelegate()); |
97 deserializer.SetSupportsLegacyWireFormat(true); | 134 deserializer.SetSupportsLegacyWireFormat(true); |
98 BeforeDecode(&deserializer); | 135 BeforeDecode(&deserializer); |
99 ASSERT_TRUE(deserializer.ReadHeader(context).FromMaybe(false)); | 136 ASSERT_TRUE(deserializer.ReadHeader(context).FromMaybe(false)); |
100 Local<Value> result; | 137 Local<Value> result; |
101 ASSERT_TRUE(deserializer.ReadValue(context).ToLocal(&result)); | 138 ASSERT_TRUE(deserializer.ReadValue(context).ToLocal(&result)); |
102 ASSERT_FALSE(result.IsEmpty()); | 139 ASSERT_FALSE(result.IsEmpty()); |
103 ASSERT_FALSE(try_catch.HasCaught()); | 140 ASSERT_FALSE(try_catch.HasCaught()); |
104 ASSERT_TRUE( | 141 ASSERT_TRUE( |
105 context->Global() | 142 context->Global() |
106 ->CreateDataProperty(context, StringFromUtf8("result"), result) | 143 ->CreateDataProperty(context, StringFromUtf8("result"), result) |
107 .FromMaybe(false)); | 144 .FromMaybe(false)); |
108 output_functor(result); | 145 output_functor(result); |
109 ASSERT_FALSE(try_catch.HasCaught()); | 146 ASSERT_FALSE(try_catch.HasCaught()); |
110 } | 147 } |
111 | 148 |
112 template <typename OutputFunctor> | 149 template <typename OutputFunctor> |
113 void DecodeTestForVersion0(const std::vector<uint8_t>& data, | 150 void DecodeTestForVersion0(const std::vector<uint8_t>& data, |
114 const OutputFunctor& output_functor) { | 151 const OutputFunctor& output_functor) { |
115 Local<Context> context = deserialization_context(); | 152 Local<Context> context = deserialization_context(); |
116 Context::Scope scope(context); | 153 Context::Scope scope(context); |
117 TryCatch try_catch(isolate()); | 154 TryCatch try_catch(isolate()); |
118 ValueDeserializer deserializer(isolate(), &data[0], | 155 ValueDeserializer deserializer(isolate(), &data[0], |
119 static_cast<int>(data.size())); | 156 static_cast<int>(data.size()), |
| 157 GetDeserializerDelegate()); |
120 deserializer.SetSupportsLegacyWireFormat(true); | 158 deserializer.SetSupportsLegacyWireFormat(true); |
121 BeforeDecode(&deserializer); | 159 BeforeDecode(&deserializer); |
122 ASSERT_TRUE(deserializer.ReadHeader(context).FromMaybe(false)); | 160 ASSERT_TRUE(deserializer.ReadHeader(context).FromMaybe(false)); |
123 ASSERT_EQ(0, deserializer.GetWireFormatVersion()); | 161 ASSERT_EQ(0, deserializer.GetWireFormatVersion()); |
124 Local<Value> result; | 162 Local<Value> result; |
125 ASSERT_TRUE(deserializer.ReadValue(context).ToLocal(&result)); | 163 ASSERT_TRUE(deserializer.ReadValue(context).ToLocal(&result)); |
126 ASSERT_FALSE(result.IsEmpty()); | 164 ASSERT_FALSE(result.IsEmpty()); |
127 ASSERT_FALSE(try_catch.HasCaught()); | 165 ASSERT_FALSE(try_catch.HasCaught()); |
128 ASSERT_TRUE( | 166 ASSERT_TRUE( |
129 context->Global() | 167 context->Global() |
130 ->CreateDataProperty(context, StringFromUtf8("result"), result) | 168 ->CreateDataProperty(context, StringFromUtf8("result"), result) |
131 .FromMaybe(false)); | 169 .FromMaybe(false)); |
132 output_functor(result); | 170 output_functor(result); |
133 ASSERT_FALSE(try_catch.HasCaught()); | 171 ASSERT_FALSE(try_catch.HasCaught()); |
134 } | 172 } |
135 | 173 |
136 void InvalidDecodeTest(const std::vector<uint8_t>& data) { | 174 void InvalidDecodeTest(const std::vector<uint8_t>& data) { |
137 Local<Context> context = deserialization_context(); | 175 Local<Context> context = deserialization_context(); |
138 Context::Scope scope(context); | 176 Context::Scope scope(context); |
139 TryCatch try_catch(isolate()); | 177 TryCatch try_catch(isolate()); |
140 ValueDeserializer deserializer(isolate(), &data[0], | 178 ValueDeserializer deserializer(isolate(), &data[0], |
141 static_cast<int>(data.size())); | 179 static_cast<int>(data.size()), |
| 180 GetDeserializerDelegate()); |
142 deserializer.SetSupportsLegacyWireFormat(true); | 181 deserializer.SetSupportsLegacyWireFormat(true); |
143 BeforeDecode(&deserializer); | 182 BeforeDecode(&deserializer); |
144 Maybe<bool> header_result = deserializer.ReadHeader(context); | 183 Maybe<bool> header_result = deserializer.ReadHeader(context); |
145 if (header_result.IsNothing()) { | 184 if (header_result.IsNothing()) { |
146 EXPECT_TRUE(try_catch.HasCaught()); | 185 EXPECT_TRUE(try_catch.HasCaught()); |
147 return; | 186 return; |
148 } | 187 } |
149 ASSERT_TRUE(header_result.ToChecked()); | 188 ASSERT_TRUE(header_result.ToChecked()); |
150 ASSERT_TRUE(deserializer.ReadValue(context).IsEmpty()); | 189 ASSERT_TRUE(deserializer.ReadValue(context).IsEmpty()); |
151 EXPECT_TRUE(try_catch.HasCaught()); | 190 EXPECT_TRUE(try_catch.HasCaught()); |
(...skipping 17 matching lines...) Expand all Loading... |
169 Local<String> StringFromUtf8(const char* source) { | 208 Local<String> StringFromUtf8(const char* source) { |
170 return String::NewFromUtf8(isolate(), source, NewStringType::kNormal) | 209 return String::NewFromUtf8(isolate(), source, NewStringType::kNormal) |
171 .ToLocalChecked(); | 210 .ToLocalChecked(); |
172 } | 211 } |
173 | 212 |
174 static std::string Utf8Value(Local<Value> value) { | 213 static std::string Utf8Value(Local<Value> value) { |
175 String::Utf8Value utf8(value); | 214 String::Utf8Value utf8(value); |
176 return std::string(*utf8, utf8.length()); | 215 return std::string(*utf8, utf8.length()); |
177 } | 216 } |
178 | 217 |
| 218 Local<Object> NewHostObject(Local<Context> context, int argc, |
| 219 Local<Value> argv[]) { |
| 220 return host_object_constructor_template_->GetFunction(context) |
| 221 .ToLocalChecked() |
| 222 ->NewInstance(context, argc, argv) |
| 223 .ToLocalChecked(); |
| 224 } |
| 225 |
179 private: | 226 private: |
180 Local<Context> serialization_context_; | 227 Local<Context> serialization_context_; |
181 Local<Context> deserialization_context_; | 228 Local<Context> deserialization_context_; |
| 229 Local<FunctionTemplate> host_object_constructor_template_; |
182 | 230 |
183 DISALLOW_COPY_AND_ASSIGN(ValueSerializerTest); | 231 DISALLOW_COPY_AND_ASSIGN(ValueSerializerTest); |
184 }; | 232 }; |
185 | 233 |
186 TEST_F(ValueSerializerTest, DecodeInvalid) { | 234 TEST_F(ValueSerializerTest, DecodeInvalid) { |
187 // Version tag but no content. | 235 // Version tag but no content. |
188 InvalidDecodeTest({0xff}); | 236 InvalidDecodeTest({0xff}); |
189 // Version too large. | 237 // Version too large. |
190 InvalidDecodeTest({0xff, 0x7f, 0x5f}); | 238 InvalidDecodeTest({0xff, 0x7f, 0x5f}); |
191 // Nonsense tag. | 239 // Nonsense tag. |
(...skipping 1825 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2017 "new Uint8Array(result.a).toString() === '0,1,128,255'")); | 2065 "new Uint8Array(result.a).toString() === '0,1,128,255'")); |
2018 }); | 2066 }); |
2019 } | 2067 } |
2020 | 2068 |
2021 TEST_F(ValueSerializerTestWithSharedArrayBufferTransfer, | 2069 TEST_F(ValueSerializerTestWithSharedArrayBufferTransfer, |
2022 SharedArrayBufferMustBeTransferred) { | 2070 SharedArrayBufferMustBeTransferred) { |
2023 // A SharedArrayBuffer which was not marked for transfer should fail encoding. | 2071 // A SharedArrayBuffer which was not marked for transfer should fail encoding. |
2024 InvalidEncodeTest("new SharedArrayBuffer(32)"); | 2072 InvalidEncodeTest("new SharedArrayBuffer(32)"); |
2025 } | 2073 } |
2026 | 2074 |
| 2075 TEST_F(ValueSerializerTest, UnsupportedHostObject) { |
| 2076 InvalidEncodeTest("new ExampleHostObject()"); |
| 2077 InvalidEncodeTest("({ a: new ExampleHostObject() })"); |
| 2078 } |
| 2079 |
| 2080 class ValueSerializerTestWithHostObject : public ValueSerializerTest { |
| 2081 protected: |
| 2082 ValueSerializerTestWithHostObject() : serializer_delegate_(this) {} |
| 2083 |
| 2084 static const uint8_t kExampleHostObjectTag; |
| 2085 |
| 2086 void WriteExampleHostObjectTag() { |
| 2087 serializer_->WriteRawBytes(&kExampleHostObjectTag, 1); |
| 2088 } |
| 2089 |
| 2090 bool ReadExampleHostObjectTag() { |
| 2091 const void* tag; |
| 2092 return deserializer_->ReadRawBytes(1, &tag) && |
| 2093 *reinterpret_cast<const uint8_t*>(tag) == kExampleHostObjectTag; |
| 2094 } |
| 2095 |
| 2096 // GMock doesn't use the "override" keyword. |
| 2097 #if __clang__ |
| 2098 #pragma clang diagnostic push |
| 2099 #pragma clang diagnostic ignored "-Winconsistent-missing-override" |
| 2100 #endif |
| 2101 |
| 2102 class SerializerDelegate : public ValueSerializer::Delegate { |
| 2103 public: |
| 2104 explicit SerializerDelegate(ValueSerializerTestWithHostObject* test) |
| 2105 : test_(test) {} |
| 2106 MOCK_METHOD1(WriteHostObject, Maybe<bool>(Local<Object> object)); |
| 2107 void ThrowDataCloneError(Local<String> message) override { |
| 2108 test_->isolate()->ThrowException(Exception::Error(message)); |
| 2109 } |
| 2110 |
| 2111 private: |
| 2112 ValueSerializerTestWithHostObject* test_; |
| 2113 }; |
| 2114 |
| 2115 class DeserializerDelegate : public ValueDeserializer::Delegate { |
| 2116 public: |
| 2117 MOCK_METHOD0(ReadHostObject, MaybeLocal<Object>()); |
| 2118 }; |
| 2119 |
| 2120 #if __clang__ |
| 2121 #pragma clang diagnostic pop |
| 2122 #endif |
| 2123 |
| 2124 ValueSerializer::Delegate* GetSerializerDelegate() override { |
| 2125 return &serializer_delegate_; |
| 2126 } |
| 2127 void BeforeEncode(ValueSerializer* serializer) override { |
| 2128 serializer_ = serializer; |
| 2129 } |
| 2130 ValueDeserializer::Delegate* GetDeserializerDelegate() override { |
| 2131 return &deserializer_delegate_; |
| 2132 } |
| 2133 void BeforeDecode(ValueDeserializer* deserializer) override { |
| 2134 deserializer_ = deserializer; |
| 2135 } |
| 2136 |
| 2137 SerializerDelegate serializer_delegate_; |
| 2138 DeserializerDelegate deserializer_delegate_; |
| 2139 ValueSerializer* serializer_; |
| 2140 ValueDeserializer* deserializer_; |
| 2141 |
| 2142 friend class SerializerDelegate; |
| 2143 friend class DeserializerDelegate; |
| 2144 }; |
| 2145 |
| 2146 // This is a tag that's not used in V8. |
| 2147 const uint8_t ValueSerializerTestWithHostObject::kExampleHostObjectTag = '+'; |
| 2148 |
| 2149 TEST_F(ValueSerializerTestWithHostObject, RoundTripUint32) { |
| 2150 // The host can serialize data as uint32_t. |
| 2151 EXPECT_CALL(serializer_delegate_, WriteHostObject(_)) |
| 2152 .WillRepeatedly(Invoke([this](Local<Object> object) { |
| 2153 uint32_t value = 0; |
| 2154 EXPECT_TRUE(object->GetInternalField(0) |
| 2155 ->Uint32Value(serialization_context()) |
| 2156 .To(&value)); |
| 2157 WriteExampleHostObjectTag(); |
| 2158 serializer_->WriteUint32(value); |
| 2159 return Just(true); |
| 2160 })); |
| 2161 EXPECT_CALL(deserializer_delegate_, ReadHostObject()) |
| 2162 .WillRepeatedly(Invoke([this]() { |
| 2163 EXPECT_TRUE(ReadExampleHostObjectTag()); |
| 2164 uint32_t value = 0; |
| 2165 EXPECT_TRUE(deserializer_->ReadUint32(&value)); |
| 2166 Local<Value> argv[] = {Integer::NewFromUnsigned(isolate(), value)}; |
| 2167 return NewHostObject(deserialization_context(), arraysize(argv), argv); |
| 2168 })); |
| 2169 RoundTripTest("new ExampleHostObject(42)", [this](Local<Value> value) { |
| 2170 ASSERT_TRUE(value->IsObject()); |
| 2171 ASSERT_TRUE(Object::Cast(*value)->InternalFieldCount()); |
| 2172 EXPECT_TRUE(EvaluateScriptForResultBool( |
| 2173 "Object.getPrototypeOf(result) === ExampleHostObject.prototype")); |
| 2174 EXPECT_TRUE(EvaluateScriptForResultBool("result.value === 42")); |
| 2175 }); |
| 2176 RoundTripTest( |
| 2177 "new ExampleHostObject(0xCAFECAFE)", [this](Local<Value> value) { |
| 2178 EXPECT_TRUE(EvaluateScriptForResultBool("result.value === 0xCAFECAFE")); |
| 2179 }); |
| 2180 } |
| 2181 |
| 2182 TEST_F(ValueSerializerTestWithHostObject, RoundTripUint64) { |
| 2183 // The host can serialize data as uint64_t. |
| 2184 EXPECT_CALL(serializer_delegate_, WriteHostObject(_)) |
| 2185 .WillRepeatedly(Invoke([this](Local<Object> object) { |
| 2186 uint32_t value = 0, value2 = 0; |
| 2187 EXPECT_TRUE(object->GetInternalField(0) |
| 2188 ->Uint32Value(serialization_context()) |
| 2189 .To(&value)); |
| 2190 EXPECT_TRUE(object->GetInternalField(1) |
| 2191 ->Uint32Value(serialization_context()) |
| 2192 .To(&value2)); |
| 2193 WriteExampleHostObjectTag(); |
| 2194 serializer_->WriteUint64((static_cast<uint64_t>(value) << 32) | value2); |
| 2195 return Just(true); |
| 2196 })); |
| 2197 EXPECT_CALL(deserializer_delegate_, ReadHostObject()) |
| 2198 .WillRepeatedly(Invoke([this]() { |
| 2199 EXPECT_TRUE(ReadExampleHostObjectTag()); |
| 2200 uint64_t value_packed; |
| 2201 EXPECT_TRUE(deserializer_->ReadUint64(&value_packed)); |
| 2202 Local<Value> argv[] = { |
| 2203 Integer::NewFromUnsigned(isolate(), |
| 2204 static_cast<uint32_t>(value_packed >> 32)), |
| 2205 Integer::NewFromUnsigned(isolate(), |
| 2206 static_cast<uint32_t>(value_packed))}; |
| 2207 return NewHostObject(deserialization_context(), arraysize(argv), argv); |
| 2208 })); |
| 2209 RoundTripTest("new ExampleHostObject(42, 0)", [this](Local<Value> value) { |
| 2210 ASSERT_TRUE(value->IsObject()); |
| 2211 ASSERT_TRUE(Object::Cast(*value)->InternalFieldCount()); |
| 2212 EXPECT_TRUE(EvaluateScriptForResultBool( |
| 2213 "Object.getPrototypeOf(result) === ExampleHostObject.prototype")); |
| 2214 EXPECT_TRUE(EvaluateScriptForResultBool("result.value === 42")); |
| 2215 EXPECT_TRUE(EvaluateScriptForResultBool("result.value2 === 0")); |
| 2216 }); |
| 2217 RoundTripTest( |
| 2218 "new ExampleHostObject(0xFFFFFFFF, 0x12345678)", |
| 2219 [this](Local<Value> value) { |
| 2220 EXPECT_TRUE(EvaluateScriptForResultBool("result.value === 0xFFFFFFFF")); |
| 2221 EXPECT_TRUE( |
| 2222 EvaluateScriptForResultBool("result.value2 === 0x12345678")); |
| 2223 }); |
| 2224 } |
| 2225 |
| 2226 TEST_F(ValueSerializerTestWithHostObject, RoundTripRawBytes) { |
| 2227 // The host can serialize arbitrary raw bytes. |
| 2228 const struct { |
| 2229 uint64_t u64; |
| 2230 uint32_t u32; |
| 2231 char str[12]; |
| 2232 } sample_data = {0x1234567812345678, 0x87654321, "Hello world"}; |
| 2233 EXPECT_CALL(serializer_delegate_, WriteHostObject(_)) |
| 2234 .WillRepeatedly(Invoke([this, &sample_data](Local<Object> object) { |
| 2235 WriteExampleHostObjectTag(); |
| 2236 serializer_->WriteRawBytes(&sample_data, sizeof(sample_data)); |
| 2237 return Just(true); |
| 2238 })); |
| 2239 EXPECT_CALL(deserializer_delegate_, ReadHostObject()) |
| 2240 .WillRepeatedly(Invoke([this, &sample_data]() { |
| 2241 EXPECT_TRUE(ReadExampleHostObjectTag()); |
| 2242 const void* copied_data = nullptr; |
| 2243 EXPECT_TRUE( |
| 2244 deserializer_->ReadRawBytes(sizeof(sample_data), &copied_data)); |
| 2245 if (copied_data) { |
| 2246 EXPECT_EQ(0, memcmp(&sample_data, copied_data, sizeof(sample_data))); |
| 2247 } |
| 2248 return NewHostObject(deserialization_context(), 0, nullptr); |
| 2249 })); |
| 2250 RoundTripTest("new ExampleHostObject()", [this](Local<Value> value) { |
| 2251 ASSERT_TRUE(value->IsObject()); |
| 2252 ASSERT_TRUE(Object::Cast(*value)->InternalFieldCount()); |
| 2253 EXPECT_TRUE(EvaluateScriptForResultBool( |
| 2254 "Object.getPrototypeOf(result) === ExampleHostObject.prototype")); |
| 2255 }); |
| 2256 } |
| 2257 |
| 2258 TEST_F(ValueSerializerTestWithHostObject, RoundTripSameObject) { |
| 2259 // If the same object exists in two places, the delegate should be invoked |
| 2260 // only once, and the objects should be the same (by reference equality) on |
| 2261 // the other side. |
| 2262 EXPECT_CALL(serializer_delegate_, WriteHostObject(_)) |
| 2263 .WillOnce(Invoke([this](Local<Object> object) { |
| 2264 WriteExampleHostObjectTag(); |
| 2265 return Just(true); |
| 2266 })); |
| 2267 EXPECT_CALL(deserializer_delegate_, ReadHostObject()) |
| 2268 .WillOnce(Invoke([this]() { |
| 2269 EXPECT_TRUE(ReadExampleHostObjectTag()); |
| 2270 return NewHostObject(deserialization_context(), 0, nullptr); |
| 2271 })); |
| 2272 RoundTripTest( |
| 2273 "({ a: new ExampleHostObject(), get b() { return this.a; }})", |
| 2274 [this](Local<Value> value) { |
| 2275 EXPECT_TRUE(EvaluateScriptForResultBool( |
| 2276 "result.a instanceof ExampleHostObject")); |
| 2277 EXPECT_TRUE(EvaluateScriptForResultBool("result.a === result.b")); |
| 2278 }); |
| 2279 } |
| 2280 |
2027 } // namespace | 2281 } // namespace |
2028 } // namespace v8 | 2282 } // namespace v8 |
OLD | NEW |