11cb0ef41Sopenharmony_ci// Flags: --expose-internals 21cb0ef41Sopenharmony_ci 31cb0ef41Sopenharmony_ci'use strict'; 41cb0ef41Sopenharmony_ci 51cb0ef41Sopenharmony_ciconst common = require('../common'); 61cb0ef41Sopenharmony_ciconst { internalBinding } = require('internal/test/binding'); 71cb0ef41Sopenharmony_ciconst assert = require('assert'); 81cb0ef41Sopenharmony_ciconst v8 = require('v8'); 91cb0ef41Sopenharmony_ciconst os = require('os'); 101cb0ef41Sopenharmony_ci 111cb0ef41Sopenharmony_ciconst circular = {}; 121cb0ef41Sopenharmony_cicircular.circular = circular; 131cb0ef41Sopenharmony_ci 141cb0ef41Sopenharmony_ciconst objects = [ 151cb0ef41Sopenharmony_ci { foo: 'bar' }, 161cb0ef41Sopenharmony_ci { bar: 'baz' }, 171cb0ef41Sopenharmony_ci new Int8Array([1, 2, 3, 4]), 181cb0ef41Sopenharmony_ci new Uint8Array([1, 2, 3, 4]), 191cb0ef41Sopenharmony_ci new Int16Array([1, 2, 3, 4]), 201cb0ef41Sopenharmony_ci new Uint16Array([1, 2, 3, 4]), 211cb0ef41Sopenharmony_ci new Int32Array([1, 2, 3, 4]), 221cb0ef41Sopenharmony_ci new Uint32Array([1, 2, 3, 4]), 231cb0ef41Sopenharmony_ci new Float32Array([1, 2, 3, 4]), 241cb0ef41Sopenharmony_ci new Float64Array([1, 2, 3, 4]), 251cb0ef41Sopenharmony_ci new DataView(new ArrayBuffer(42)), 261cb0ef41Sopenharmony_ci Buffer.from([1, 2, 3, 4]), 271cb0ef41Sopenharmony_ci new BigInt64Array([42n]), 281cb0ef41Sopenharmony_ci new BigUint64Array([42n]), 291cb0ef41Sopenharmony_ci undefined, 301cb0ef41Sopenharmony_ci null, 311cb0ef41Sopenharmony_ci 42, 321cb0ef41Sopenharmony_ci circular, 331cb0ef41Sopenharmony_ci]; 341cb0ef41Sopenharmony_ci 351cb0ef41Sopenharmony_ciconst hostObject = new (internalBinding('js_stream').JSStream)(); 361cb0ef41Sopenharmony_ci 371cb0ef41Sopenharmony_ci{ 381cb0ef41Sopenharmony_ci const ser = new v8.DefaultSerializer(); 391cb0ef41Sopenharmony_ci ser.writeHeader(); 401cb0ef41Sopenharmony_ci for (const obj of objects) { 411cb0ef41Sopenharmony_ci ser.writeValue(obj); 421cb0ef41Sopenharmony_ci } 431cb0ef41Sopenharmony_ci 441cb0ef41Sopenharmony_ci const des = new v8.DefaultDeserializer(ser.releaseBuffer()); 451cb0ef41Sopenharmony_ci des.readHeader(); 461cb0ef41Sopenharmony_ci 471cb0ef41Sopenharmony_ci for (const obj of objects) { 481cb0ef41Sopenharmony_ci assert.deepStrictEqual(des.readValue(), obj); 491cb0ef41Sopenharmony_ci } 501cb0ef41Sopenharmony_ci} 511cb0ef41Sopenharmony_ci 521cb0ef41Sopenharmony_ci{ 531cb0ef41Sopenharmony_ci for (const obj of objects) { 541cb0ef41Sopenharmony_ci assert.deepStrictEqual(v8.deserialize(v8.serialize(obj)), obj); 551cb0ef41Sopenharmony_ci } 561cb0ef41Sopenharmony_ci} 571cb0ef41Sopenharmony_ci 581cb0ef41Sopenharmony_ci{ 591cb0ef41Sopenharmony_ci const ser = new v8.DefaultSerializer(); 601cb0ef41Sopenharmony_ci ser._getDataCloneError = common.mustCall((message) => { 611cb0ef41Sopenharmony_ci assert.strictEqual(message, '#<Object> could not be cloned.'); 621cb0ef41Sopenharmony_ci return new Error('foobar'); 631cb0ef41Sopenharmony_ci }); 641cb0ef41Sopenharmony_ci 651cb0ef41Sopenharmony_ci ser.writeHeader(); 661cb0ef41Sopenharmony_ci 671cb0ef41Sopenharmony_ci assert.throws(() => { 681cb0ef41Sopenharmony_ci ser.writeValue(new Proxy({}, {})); 691cb0ef41Sopenharmony_ci }, /foobar/); 701cb0ef41Sopenharmony_ci} 711cb0ef41Sopenharmony_ci 721cb0ef41Sopenharmony_ci{ 731cb0ef41Sopenharmony_ci const ser = new v8.DefaultSerializer(); 741cb0ef41Sopenharmony_ci ser._writeHostObject = common.mustCall((object) => { 751cb0ef41Sopenharmony_ci assert.strictEqual(object, hostObject); 761cb0ef41Sopenharmony_ci const buf = Buffer.from('hostObjectTag'); 771cb0ef41Sopenharmony_ci 781cb0ef41Sopenharmony_ci ser.writeUint32(buf.length); 791cb0ef41Sopenharmony_ci ser.writeRawBytes(buf); 801cb0ef41Sopenharmony_ci 811cb0ef41Sopenharmony_ci ser.writeUint64(1, 2); 821cb0ef41Sopenharmony_ci ser.writeDouble(-0.25); 831cb0ef41Sopenharmony_ci }); 841cb0ef41Sopenharmony_ci 851cb0ef41Sopenharmony_ci ser.writeHeader(); 861cb0ef41Sopenharmony_ci ser.writeValue({ val: hostObject }); 871cb0ef41Sopenharmony_ci 881cb0ef41Sopenharmony_ci const des = new v8.DefaultDeserializer(ser.releaseBuffer()); 891cb0ef41Sopenharmony_ci des._readHostObject = common.mustCall(() => { 901cb0ef41Sopenharmony_ci const length = des.readUint32(); 911cb0ef41Sopenharmony_ci const buf = des.readRawBytes(length); 921cb0ef41Sopenharmony_ci 931cb0ef41Sopenharmony_ci assert.strictEqual(buf.toString(), 'hostObjectTag'); 941cb0ef41Sopenharmony_ci 951cb0ef41Sopenharmony_ci assert.deepStrictEqual(des.readUint64(), [1, 2]); 961cb0ef41Sopenharmony_ci assert.strictEqual(des.readDouble(), -0.25); 971cb0ef41Sopenharmony_ci return hostObject; 981cb0ef41Sopenharmony_ci }); 991cb0ef41Sopenharmony_ci 1001cb0ef41Sopenharmony_ci des.readHeader(); 1011cb0ef41Sopenharmony_ci 1021cb0ef41Sopenharmony_ci assert.strictEqual(des.readValue().val, hostObject); 1031cb0ef41Sopenharmony_ci} 1041cb0ef41Sopenharmony_ci 1051cb0ef41Sopenharmony_ci// This test ensures that `v8.Serializer.writeRawBytes()` support 1061cb0ef41Sopenharmony_ci// `TypedArray` and `DataView`. 1071cb0ef41Sopenharmony_ci{ 1081cb0ef41Sopenharmony_ci const text = 'hostObjectTag'; 1091cb0ef41Sopenharmony_ci const data = Buffer.from(text); 1101cb0ef41Sopenharmony_ci const arrayBufferViews = common.getArrayBufferViews(data); 1111cb0ef41Sopenharmony_ci 1121cb0ef41Sopenharmony_ci // `buf` is one of `TypedArray` or `DataView`. 1131cb0ef41Sopenharmony_ci function testWriteRawBytes(buf) { 1141cb0ef41Sopenharmony_ci let writeHostObjectCalled = false; 1151cb0ef41Sopenharmony_ci const ser = new v8.DefaultSerializer(); 1161cb0ef41Sopenharmony_ci 1171cb0ef41Sopenharmony_ci ser._writeHostObject = common.mustCall((object) => { 1181cb0ef41Sopenharmony_ci writeHostObjectCalled = true; 1191cb0ef41Sopenharmony_ci ser.writeUint32(buf.byteLength); 1201cb0ef41Sopenharmony_ci ser.writeRawBytes(buf); 1211cb0ef41Sopenharmony_ci }); 1221cb0ef41Sopenharmony_ci 1231cb0ef41Sopenharmony_ci ser.writeHeader(); 1241cb0ef41Sopenharmony_ci ser.writeValue({ val: hostObject }); 1251cb0ef41Sopenharmony_ci 1261cb0ef41Sopenharmony_ci const des = new v8.DefaultDeserializer(ser.releaseBuffer()); 1271cb0ef41Sopenharmony_ci des._readHostObject = common.mustCall(() => { 1281cb0ef41Sopenharmony_ci assert.strictEqual(writeHostObjectCalled, true); 1291cb0ef41Sopenharmony_ci const length = des.readUint32(); 1301cb0ef41Sopenharmony_ci const buf = des.readRawBytes(length); 1311cb0ef41Sopenharmony_ci assert.strictEqual(buf.toString(), text); 1321cb0ef41Sopenharmony_ci 1331cb0ef41Sopenharmony_ci return hostObject; 1341cb0ef41Sopenharmony_ci }); 1351cb0ef41Sopenharmony_ci 1361cb0ef41Sopenharmony_ci des.readHeader(); 1371cb0ef41Sopenharmony_ci 1381cb0ef41Sopenharmony_ci assert.strictEqual(des.readValue().val, hostObject); 1391cb0ef41Sopenharmony_ci } 1401cb0ef41Sopenharmony_ci 1411cb0ef41Sopenharmony_ci arrayBufferViews.forEach((buf) => { 1421cb0ef41Sopenharmony_ci testWriteRawBytes(buf); 1431cb0ef41Sopenharmony_ci }); 1441cb0ef41Sopenharmony_ci} 1451cb0ef41Sopenharmony_ci 1461cb0ef41Sopenharmony_ci{ 1471cb0ef41Sopenharmony_ci const ser = new v8.DefaultSerializer(); 1481cb0ef41Sopenharmony_ci ser._writeHostObject = common.mustCall((object) => { 1491cb0ef41Sopenharmony_ci throw new Error('foobar'); 1501cb0ef41Sopenharmony_ci }); 1511cb0ef41Sopenharmony_ci 1521cb0ef41Sopenharmony_ci ser.writeHeader(); 1531cb0ef41Sopenharmony_ci assert.throws(() => { 1541cb0ef41Sopenharmony_ci ser.writeValue({ val: hostObject }); 1551cb0ef41Sopenharmony_ci }, /foobar/); 1561cb0ef41Sopenharmony_ci} 1571cb0ef41Sopenharmony_ci 1581cb0ef41Sopenharmony_ci{ 1591cb0ef41Sopenharmony_ci assert.throws(() => v8.serialize(hostObject), { 1601cb0ef41Sopenharmony_ci constructor: Error, 1611cb0ef41Sopenharmony_ci message: 'Unserializable host object: JSStream {}' 1621cb0ef41Sopenharmony_ci }); 1631cb0ef41Sopenharmony_ci} 1641cb0ef41Sopenharmony_ci 1651cb0ef41Sopenharmony_ci{ 1661cb0ef41Sopenharmony_ci // Test that an old serialized value can still be deserialized. 1671cb0ef41Sopenharmony_ci const buf = Buffer.from('ff0d6f2203666f6f5e007b01', 'hex'); 1681cb0ef41Sopenharmony_ci 1691cb0ef41Sopenharmony_ci const des = new v8.DefaultDeserializer(buf); 1701cb0ef41Sopenharmony_ci des.readHeader(); 1711cb0ef41Sopenharmony_ci assert.strictEqual(des.getWireFormatVersion(), 0x0d); 1721cb0ef41Sopenharmony_ci 1731cb0ef41Sopenharmony_ci const value = des.readValue(); 1741cb0ef41Sopenharmony_ci assert.strictEqual(value, value.foo); 1751cb0ef41Sopenharmony_ci} 1761cb0ef41Sopenharmony_ci 1771cb0ef41Sopenharmony_ci{ 1781cb0ef41Sopenharmony_ci const message = `New serialization format. 1791cb0ef41Sopenharmony_ci 1801cb0ef41Sopenharmony_ci This test is expected to fail when V8 changes its serialization format. 1811cb0ef41Sopenharmony_ci When that happens, the "desStr" variable must be updated to the new value 1821cb0ef41Sopenharmony_ci and the change should be mentioned in the release notes, as it is semver-major. 1831cb0ef41Sopenharmony_ci 1841cb0ef41Sopenharmony_ci Consider opening an issue as a heads up at https://github.com/nodejs/node/issues/new 1851cb0ef41Sopenharmony_ci `; 1861cb0ef41Sopenharmony_ci 1871cb0ef41Sopenharmony_ci const desStr = 'ff0f6f2203666f6f5e007b01'; 1881cb0ef41Sopenharmony_ci 1891cb0ef41Sopenharmony_ci const desBuf = Buffer.from(desStr, 'hex'); 1901cb0ef41Sopenharmony_ci const des = new v8.DefaultDeserializer(desBuf); 1911cb0ef41Sopenharmony_ci des.readHeader(); 1921cb0ef41Sopenharmony_ci const value = des.readValue(); 1931cb0ef41Sopenharmony_ci 1941cb0ef41Sopenharmony_ci const ser = new v8.DefaultSerializer(); 1951cb0ef41Sopenharmony_ci ser.writeHeader(); 1961cb0ef41Sopenharmony_ci ser.writeValue(value); 1971cb0ef41Sopenharmony_ci 1981cb0ef41Sopenharmony_ci const serBuf = ser.releaseBuffer(); 1991cb0ef41Sopenharmony_ci const serStr = serBuf.toString('hex'); 2001cb0ef41Sopenharmony_ci assert.deepStrictEqual(serStr, desStr, message); 2011cb0ef41Sopenharmony_ci} 2021cb0ef41Sopenharmony_ci 2031cb0ef41Sopenharmony_ci{ 2041cb0ef41Sopenharmony_ci // Unaligned Uint16Array read, with padding in the underlying array buffer. 2051cb0ef41Sopenharmony_ci let buf = Buffer.alloc(32 + 9); 2061cb0ef41Sopenharmony_ci buf.write('ff0d5c0404addeefbe', 32, 'hex'); 2071cb0ef41Sopenharmony_ci buf = buf.slice(32); 2081cb0ef41Sopenharmony_ci 2091cb0ef41Sopenharmony_ci const expectedResult = os.endianness() === 'LE' ? 2101cb0ef41Sopenharmony_ci new Uint16Array([0xdead, 0xbeef]) : new Uint16Array([0xadde, 0xefbe]); 2111cb0ef41Sopenharmony_ci 2121cb0ef41Sopenharmony_ci assert.deepStrictEqual(v8.deserialize(buf), expectedResult); 2131cb0ef41Sopenharmony_ci} 2141cb0ef41Sopenharmony_ci 2151cb0ef41Sopenharmony_ci{ 2161cb0ef41Sopenharmony_ci assert.throws(() => v8.Serializer(), { 2171cb0ef41Sopenharmony_ci constructor: TypeError, 2181cb0ef41Sopenharmony_ci message: "Class constructor Serializer cannot be invoked without 'new'", 2191cb0ef41Sopenharmony_ci code: 'ERR_CONSTRUCT_CALL_REQUIRED' 2201cb0ef41Sopenharmony_ci }); 2211cb0ef41Sopenharmony_ci assert.throws(() => v8.Deserializer(), { 2221cb0ef41Sopenharmony_ci constructor: TypeError, 2231cb0ef41Sopenharmony_ci message: "Class constructor Deserializer cannot be invoked without 'new'", 2241cb0ef41Sopenharmony_ci code: 'ERR_CONSTRUCT_CALL_REQUIRED' 2251cb0ef41Sopenharmony_ci }); 2261cb0ef41Sopenharmony_ci} 2271cb0ef41Sopenharmony_ci 2281cb0ef41Sopenharmony_ci 2291cb0ef41Sopenharmony_ci// `v8.deserialize()` and `new v8.Deserializer()` should support both 2301cb0ef41Sopenharmony_ci// `TypedArray` and `DataView`. 2311cb0ef41Sopenharmony_ci{ 2321cb0ef41Sopenharmony_ci for (const obj of objects) { 2331cb0ef41Sopenharmony_ci const buf = v8.serialize(obj); 2341cb0ef41Sopenharmony_ci 2351cb0ef41Sopenharmony_ci for (const arrayBufferView of common.getArrayBufferViews(buf)) { 2361cb0ef41Sopenharmony_ci assert.deepStrictEqual(v8.deserialize(arrayBufferView), obj); 2371cb0ef41Sopenharmony_ci } 2381cb0ef41Sopenharmony_ci 2391cb0ef41Sopenharmony_ci for (const arrayBufferView of common.getArrayBufferViews(buf)) { 2401cb0ef41Sopenharmony_ci const deserializer = new v8.DefaultDeserializer(arrayBufferView); 2411cb0ef41Sopenharmony_ci deserializer.readHeader(); 2421cb0ef41Sopenharmony_ci const value = deserializer.readValue(); 2431cb0ef41Sopenharmony_ci assert.deepStrictEqual(value, obj); 2441cb0ef41Sopenharmony_ci 2451cb0ef41Sopenharmony_ci const serializer = new v8.DefaultSerializer(); 2461cb0ef41Sopenharmony_ci serializer.writeHeader(); 2471cb0ef41Sopenharmony_ci serializer.writeValue(value); 2481cb0ef41Sopenharmony_ci assert.deepStrictEqual(buf, serializer.releaseBuffer()); 2491cb0ef41Sopenharmony_ci } 2501cb0ef41Sopenharmony_ci } 2511cb0ef41Sopenharmony_ci} 2521cb0ef41Sopenharmony_ci 2531cb0ef41Sopenharmony_ci{ 2541cb0ef41Sopenharmony_ci const INVALID_SOURCE = 'INVALID_SOURCE_TYPE'; 2551cb0ef41Sopenharmony_ci const serializer = new v8.Serializer(); 2561cb0ef41Sopenharmony_ci serializer.writeHeader(); 2571cb0ef41Sopenharmony_ci assert.throws( 2581cb0ef41Sopenharmony_ci () => serializer.writeRawBytes(INVALID_SOURCE), 2591cb0ef41Sopenharmony_ci /^TypeError: source must be a TypedArray or a DataView$/, 2601cb0ef41Sopenharmony_ci ); 2611cb0ef41Sopenharmony_ci assert.throws( 2621cb0ef41Sopenharmony_ci () => v8.deserialize(INVALID_SOURCE), 2631cb0ef41Sopenharmony_ci /^TypeError: buffer must be a TypedArray or a DataView$/, 2641cb0ef41Sopenharmony_ci ); 2651cb0ef41Sopenharmony_ci assert.throws( 2661cb0ef41Sopenharmony_ci () => new v8.Deserializer(INVALID_SOURCE), 2671cb0ef41Sopenharmony_ci /^TypeError: buffer must be a TypedArray or a DataView$/, 2681cb0ef41Sopenharmony_ci ); 2691cb0ef41Sopenharmony_ci} 2701cb0ef41Sopenharmony_ci 2711cb0ef41Sopenharmony_ci{ 2721cb0ef41Sopenharmony_ci // Regression test for https://github.com/nodejs/node/issues/37978 2731cb0ef41Sopenharmony_ci assert.throws(() => { 2741cb0ef41Sopenharmony_ci new v8.Deserializer(new v8.Serializer().releaseBuffer()).readDouble(); 2751cb0ef41Sopenharmony_ci }, /ReadDouble\(\) failed/); 2761cb0ef41Sopenharmony_ci} 277