node/test/parallel/test-structuredClone-global.js
Jason Zhang 50b4ada551
lib: convert transfer sequence to array in js
This commit lets `tranfer` passed to `structuredClone` get validated at
JS layer by doing webidl conversion. This avoids the C++ to JS function
call overhead in the native implementaiton of `structuredClone`

PR-URL: https://github.com/nodejs/node/pull/55317
Fixes: https://github.com/nodejs/node/issues/55280
Refs: https://github.com/nodejs/node/pull/50330
Reviewed-By: Joyee Cheung <joyeec9h3@gmail.com>
Reviewed-By: Matteo Collina <matteo.collina@gmail.com>
Reviewed-By: James M Snell <jasnell@gmail.com>
Reviewed-By: Matthew Aitken <maitken033380023@gmail.com>
2024-10-13 18:11:21 +00:00

80 lines
2.9 KiB
JavaScript

'use strict';
require('../common');
const assert = require('assert');
assert.throws(() => structuredClone(), { code: 'ERR_MISSING_ARGS' });
assert.throws(() => structuredClone(undefined, ''), { code: 'ERR_INVALID_ARG_TYPE' });
assert.throws(() => structuredClone(undefined, 1), { code: 'ERR_INVALID_ARG_TYPE' });
assert.throws(() => structuredClone(undefined, { transfer: 1 }), { code: 'ERR_INVALID_ARG_TYPE' });
assert.throws(() => structuredClone(undefined, { transfer: '' }), { code: 'ERR_INVALID_ARG_TYPE' });
assert.throws(() => structuredClone(undefined, { transfer: null }), { code: 'ERR_INVALID_ARG_TYPE' });
// Options can be null or undefined.
assert.strictEqual(structuredClone(undefined), undefined);
assert.strictEqual(structuredClone(undefined, null), undefined);
// Transfer can be null or undefined.
assert.strictEqual(structuredClone(undefined, { }), undefined);
// Transferables or its subclasses should be received with its closest transferable superclass
for (const StreamClass of [ReadableStream, WritableStream, TransformStream]) {
const original = new StreamClass();
const transfer = structuredClone(original, { transfer: [original] });
assert.strictEqual(Object.getPrototypeOf(transfer), StreamClass.prototype);
assert.ok(transfer instanceof StreamClass);
const extended = class extends StreamClass {};
const extendedOriginal = new extended();
const extendedTransfer = structuredClone(extendedOriginal, { transfer: [extendedOriginal] });
assert.strictEqual(Object.getPrototypeOf(extendedTransfer), StreamClass.prototype);
assert.ok(extendedTransfer instanceof StreamClass);
}
for (const Transferrable of [File, Blob]) {
const a2 = Transferrable === File ? '' : {};
const original = new Transferrable([], a2);
const transfer = structuredClone(original);
assert.strictEqual(Object.getPrototypeOf(transfer), Transferrable.prototype);
assert.ok(transfer instanceof Transferrable);
const extendedOriginal = new (class extends Transferrable {})([], a2);
const extendedTransfer = structuredClone(extendedOriginal);
assert.strictEqual(Object.getPrototypeOf(extendedTransfer), Transferrable.prototype);
assert.ok(extendedTransfer instanceof Transferrable);
}
// Transfer can be iterable
{
const value = {
a: new ReadableStream(),
b: new WritableStream(),
};
const cloned = structuredClone(value, {
transfer: {
*[Symbol.iterator]() {
for (const key in value) {
yield value[key];
}
}
}
});
for (const key in value) {
assert.ok(value[key].locked);
assert.ok(!cloned[key].locked);
}
}
{
// See: https://github.com/nodejs/node/issues/49940
const cloned = structuredClone({}, {
transfer: {
*[Symbol.iterator]() {}
}
});
assert.deepStrictEqual(cloned, {});
}
const blob = new Blob();
assert.throws(() => structuredClone(blob, { transfer: [blob] }), { name: 'DataCloneError' });