Files
node/test/parallel/test-stream-iter-transform-output.js
T
Ethan Arrowood c3189d436e test: replace discard loops with dump()
Replaces the `for await (const _ of source) {}` discard idiom with
dump(), which says what it does and does not need an eslint-disable
for the unused loop variable. The eslint-disable directives and
comments that become redundant are removed with it.

Only files that already declare --experimental-stream-iter are
converted, so no test gains an experimental flag it did not already
opt into. Files still using the old idiom are left as they are;
converting them would change what those tests run under and belongs
in a separate discussion.

Loops that break early are left alone: those cancel the source rather
than reading it to completion, which is not what dump() does.

Assisted-by: Claude Opus 5
Signed-off-by: Ethan Arrowood <ethan@arrowood.dev>
PR-URL: https://github.com/nodejs/node/pull/65598
Reviewed-By: James M Snell <jasnell@gmail.com>
Reviewed-By: Benjamin Gruenbaum <benjamingr@gmail.com>
Reviewed-By: Matteo Collina <matteo.collina@gmail.com>
Reviewed-By: Tim Perry <pimterry@gmail.com>
2026-10-07 20:01:31 +00:00

282 lines
8.3 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 {
bytes,
bytesSync,
dump,
from,
fromSync,
pull,
pullSync,
} = 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);
}
// Consecutive stateless transforms normalize intermediate output (async)
async function testConsecutiveTransformsNormalizeIntermediateOutput() {
const first = (chunks) => {
return chunks === null ? null : new Uint8Array([65]);
};
let receivedBatch = false;
const second = (chunks) => {
if (chunks !== null) receivedBatch = Array.isArray(chunks);
return chunks;
};
const data = await bytes(pull(from('x'), first, second));
assert.ok(receivedBatch);
assert.deepStrictEqual(data, new Uint8Array([65]));
}
// Consecutive stateless transforms normalize intermediate output (sync)
async function testConsecutiveSyncTransformsNormalizeIntermediateOutput() {
const first = (chunks) => {
return chunks === null ? null : new Uint8Array([65]);
};
let receivedBatch = false;
const second = (chunks) => {
if (chunks !== null) receivedBatch = Array.isArray(chunks);
return chunks;
};
const data = bytesSync(pullSync(fromSync('x'), first, second));
assert.ok(receivedBatch);
assert.deepStrictEqual(data, new Uint8Array([65]));
}
// 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'));
}
// Stateful async transform yields null (no output)
async function testStatefulTransformYieldsNull() {
const tx = {
async *transform() {
yield null;
},
};
const data = await bytes(pull(from('x'), tx));
assert.deepStrictEqual(data, new Uint8Array());
}
// Stateful sync transform yields null (no output)
async function testStatefulSyncTransformYieldsNull() {
const tx = {
*transform() {
yield null;
},
};
const data = bytesSync(pullSync(fromSync('x'), tx));
assert.deepStrictEqual(data, new Uint8Array());
}
// 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 () => {
await dump(pull(from('x'), tx));
},
{ 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(),
testConsecutiveTransformsNormalizeIntermediateOutput(),
testConsecutiveSyncTransformsNormalizeIntermediateOutput(),
testTransformReturnsGenerator(),
testSyncTransformReturnsGenerator(),
testTransformReturnsAsyncGenerator(),
testStatefulTransformYieldsString(),
testStatefulTransformYieldsArrayBuffer(),
testStatefulSyncTransformYieldsString(),
testStatefulTransformYieldsNull(),
testStatefulSyncTransformYieldsNull(),
testFlushReturnsSingleUint8Array(),
testFlushReturnsString(),
testSyncFlushReturnsSingleUint8Array(),
testTransformReturnsInvalidType(),
testSyncTransformReturnsInvalidType(),
]).then(common.mustCall());