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