node/test/parallel/test-stream-iter-transform-output.js
James M Snell 2fa9c1bc58 test: add tests for experimental stream/iter implementation
Signed-off-by: James M Snell <jasnell@gmail.com>
Assisted-By: Claude/Opus 4.6
PR-URL: https://github.com/nodejs/node/pull/62066
Reviewed-By: Robert Nagy <ronagy@icloud.com>
Reviewed-By: Benjamin Gruenbaum <benjamingr@gmail.com>
Reviewed-By: Matteo Collina <matteo.collina@gmail.com>
2026-03-27 19:55:17 -07:00

225 lines
6.6 KiB
JavaScript

// Flags: --experimental-stream-iter
'use strict';
// Tests for transform output normalization edge cases:
// ArrayBuffer, ArrayBufferView, iterables, strings, invalid types.
const common = require('../common');
const assert = require('assert');
const {
pull,
pullSync,
bytes,
bytesSync,
from,
fromSync,
} = require('stream/iter');
// Stateless transform returns ArrayBuffer (async)
async function testTransformReturnsArrayBuffer() {
const tx = (chunks) => {
if (chunks === null) return null;
const ab = new ArrayBuffer(chunks[0].length);
new Uint8Array(ab).set(chunks[0]);
return ab;
};
const data = await bytes(pull(from('AB'), tx));
assert.deepStrictEqual(data, new TextEncoder().encode('AB'));
}
// Stateless transform returns ArrayBuffer (sync)
async function testSyncTransformReturnsArrayBuffer() {
const tx = (chunks) => {
if (chunks === null) return null;
const ab = new ArrayBuffer(chunks[0].length);
new Uint8Array(ab).set(chunks[0]);
return ab;
};
const data = bytesSync(pullSync(fromSync('AB'), tx));
assert.deepStrictEqual(data, new TextEncoder().encode('AB'));
}
// Stateless transform returns Float32Array (non-Uint8Array ArrayBufferView)
async function testTransformReturnsFloat32Array() {
const tx = (chunks) => {
if (chunks === null) return null;
return new Float32Array([1.0]);
};
const data = await bytes(pull(from('x'), tx));
assert.strictEqual(data.byteLength, 4); // 1 float32 = 4 bytes
}
// Stateless sync transform returns Float32Array
async function testSyncTransformReturnsFloat32Array() {
const tx = (chunks) => {
if (chunks === null) return null;
return new Float32Array([1.0]);
};
const data = bytesSync(pullSync(fromSync('x'), tx));
assert.strictEqual(data.byteLength, 4);
}
// Stateless transform returns a sync generator (iterable)
async function testTransformReturnsGenerator() {
const tx = (chunks) => {
if (chunks === null) return null;
return (function*() {
yield new Uint8Array([65]);
yield new Uint8Array([66]);
})();
};
const data = await bytes(pull(from('x'), tx));
assert.deepStrictEqual(data, new Uint8Array([65, 66]));
}
// Stateless sync transform returns a generator
async function testSyncTransformReturnsGenerator() {
const tx = (chunks) => {
if (chunks === null) return null;
return (function*() {
yield new Uint8Array([67]);
yield new Uint8Array([68]);
})();
};
const data = bytesSync(pullSync(fromSync('x'), tx));
assert.deepStrictEqual(data, new Uint8Array([67, 68]));
}
// Stateless async transform returns an async generator
async function testTransformReturnsAsyncGenerator() {
const tx = (chunks) => {
if (chunks === null) return null;
return (async function*() {
yield new Uint8Array([69]);
yield new Uint8Array([70]);
})();
};
const data = await bytes(pull(from('x'), tx));
assert.deepStrictEqual(data, new Uint8Array([69, 70]));
}
// Stateful async transform yields string
async function testStatefulTransformYieldsString() {
const tx = {
async *transform(source) {
for await (const chunks of source) {
if (chunks === null) return;
yield 'hello';
}
},
};
const data = await bytes(pull(from('x'), tx));
assert.deepStrictEqual(data, new TextEncoder().encode('hello'));
}
// Stateful async transform yields ArrayBuffer
async function testStatefulTransformYieldsArrayBuffer() {
const tx = {
async *transform(source) {
for await (const chunks of source) {
if (chunks === null) return;
const ab = new ArrayBuffer(2);
new Uint8Array(ab).set([71, 72]);
yield ab;
}
},
};
const data = await bytes(pull(from('x'), tx));
assert.deepStrictEqual(data, new Uint8Array([71, 72]));
}
// Stateful sync transform yields string
async function testStatefulSyncTransformYieldsString() {
const tx = {
*transform(source) {
for (const chunks of source) {
if (chunks === null) return;
yield 'world';
}
},
};
const data = bytesSync(pullSync(fromSync('x'), tx));
assert.deepStrictEqual(data, new TextEncoder().encode('world'));
}
// Flush returns single Uint8Array (not batch)
async function testFlushReturnsSingleUint8Array() {
const tx = (chunks) => {
if (chunks === null) return new Uint8Array([99]); // Flush returns single
return chunks;
};
const data = await bytes(pull(from('x'), tx));
// Should contain both the original data and the flush byte
assert.ok(data.includes(99));
}
// Flush returns string
async function testFlushReturnsString() {
const tx = (chunks) => {
if (chunks === null) return 'trailer';
return chunks;
};
const data = await bytes(pull(from('x'), tx));
const trailer = new TextEncoder().encode('trailer');
// Last bytes should be the trailer
const tail = data.slice(data.length - trailer.length);
assert.deepStrictEqual(tail, trailer);
}
// Sync flush returns single Uint8Array
async function testSyncFlushReturnsSingleUint8Array() {
const tx = (chunks) => {
if (chunks === null) return new Uint8Array([88]);
return chunks;
};
const data = bytesSync(pullSync(fromSync('x'), tx));
assert.ok(data.includes(88));
}
// Transform returns invalid type → ERR_INVALID_ARG_TYPE
async function testTransformReturnsInvalidType() {
const tx = (chunks) => {
if (chunks === null) return null;
return 42; // Invalid
};
await assert.rejects(
async () => {
// eslint-disable-next-line no-unused-vars
for await (const batch of pull(from('x'), tx)) { /* consume */ }
},
{ code: 'ERR_INVALID_ARG_TYPE' },
);
}
// Sync transform returns invalid type → ERR_INVALID_ARG_TYPE
async function testSyncTransformReturnsInvalidType() {
const tx = (chunks) => {
if (chunks === null) return null;
return 42;
};
assert.throws(
() => {
// eslint-disable-next-line no-unused-vars
for (const batch of pullSync(fromSync('x'), tx)) { /* consume */ }
},
{ code: 'ERR_INVALID_ARG_TYPE' },
);
}
Promise.all([
testTransformReturnsArrayBuffer(),
testSyncTransformReturnsArrayBuffer(),
testTransformReturnsFloat32Array(),
testSyncTransformReturnsFloat32Array(),
testTransformReturnsGenerator(),
testSyncTransformReturnsGenerator(),
testTransformReturnsAsyncGenerator(),
testStatefulTransformYieldsString(),
testStatefulTransformYieldsArrayBuffer(),
testStatefulSyncTransformYieldsString(),
testFlushReturnsSingleUint8Array(),
testFlushReturnsString(),
testSyncFlushReturnsSingleUint8Array(),
testTransformReturnsInvalidType(),
testSyncTransformReturnsInvalidType(),
]).then(common.mustCall());