mirror of
https://github.com/nodejs/node.git
synced 2026-10-28 10:15:07 +08:00
Signed-off-by: James M Snell <jasnell@gmail.com> Assisted-by: Opencode PR-URL: https://github.com/nodejs/node/pull/65658 Reviewed-By: Trivikram Kamat <trivikr.dev@gmail.com>
179 lines
5.3 KiB
JavaScript
179 lines
5.3 KiB
JavaScript
// Flags: --experimental-stream-iter
|
|
'use strict';
|
|
|
|
const common = require('../common');
|
|
const assert = require('assert');
|
|
const {
|
|
from,
|
|
fromSync,
|
|
text,
|
|
textSync,
|
|
} = require('stream/iter');
|
|
|
|
// =============================================================================
|
|
// textSync / text
|
|
// =============================================================================
|
|
|
|
async function testTextSyncBasic() {
|
|
const data = textSync(fromSync('hello text'));
|
|
assert.strictEqual(data, 'hello text');
|
|
}
|
|
|
|
async function testTextAsync() {
|
|
const data = await text(from('hello async text'));
|
|
assert.strictEqual(data, 'hello async text');
|
|
}
|
|
|
|
async function testTextEncoding() {
|
|
// Default encoding is utf-8
|
|
const data = await text(from('café'));
|
|
assert.strictEqual(data, 'café');
|
|
}
|
|
|
|
// =============================================================================
|
|
// Text encoding tests
|
|
// =============================================================================
|
|
|
|
async function testTextNonUtf8Encoding() {
|
|
// Latin-1 encoding
|
|
const latin1Bytes = new Uint8Array([0xE9, 0xE8, 0xEA]); // é, è, ê in latin1
|
|
const result = await text(from(latin1Bytes), { encoding: 'iso-8859-1' });
|
|
assert.strictEqual(result, 'éèê');
|
|
}
|
|
|
|
async function testTextSyncNonUtf8Encoding() {
|
|
const latin1Bytes = new Uint8Array([0xE9, 0xE8, 0xEA]);
|
|
const result = textSync(fromSync(latin1Bytes), { encoding: 'iso-8859-1' });
|
|
assert.strictEqual(result, 'éèê');
|
|
}
|
|
|
|
async function testTextInvalidUtf8() {
|
|
// Invalid UTF-8 sequence with fatal: true should throw
|
|
const invalid = new Uint8Array([0xFF, 0xFE]);
|
|
await assert.rejects(
|
|
() => text(from(invalid)),
|
|
{ name: 'TypeError' }, // TextDecoder fatal throws TypeError
|
|
);
|
|
}
|
|
|
|
async function testTextWithLimit() {
|
|
// Limit caps total bytes; exceeding throws ERR_OUT_OF_RANGE
|
|
await assert.rejects(
|
|
() => text(from('hello world'), { limit: 5 }),
|
|
{ code: 'ERR_OUT_OF_RANGE' },
|
|
);
|
|
// Within limit should succeed
|
|
const result = await text(from('hello'), { limit: 10 });
|
|
assert.strictEqual(result, 'hello');
|
|
|
|
// Exact boundary: 'hello' is 5 UTF-8 bytes, limit: 5 should succeed
|
|
// (source uses > not >=)
|
|
const exact = await text(from('hello'), { limit: 5 });
|
|
assert.strictEqual(exact, 'hello');
|
|
}
|
|
|
|
async function testTextSyncWithLimit() {
|
|
// Sync version of limit testing
|
|
assert.throws(
|
|
() => textSync(fromSync('hello world'), { limit: 5 }),
|
|
{ code: 'ERR_OUT_OF_RANGE' },
|
|
);
|
|
const result = textSync(fromSync('hello'), { limit: 10 });
|
|
assert.strictEqual(result, 'hello');
|
|
|
|
// Exact boundary
|
|
const exact = textSync(fromSync('hello'), { limit: 5 });
|
|
assert.strictEqual(exact, 'hello');
|
|
}
|
|
|
|
async function testTextEmpty() {
|
|
const result = await text(from(''));
|
|
assert.strictEqual(result, '');
|
|
|
|
const syncResult = textSync(fromSync(''));
|
|
assert.strictEqual(syncResult, '');
|
|
}
|
|
|
|
// text() with abort signal
|
|
async function testTextWithSignal() {
|
|
await assert.rejects(
|
|
() => text(from('data'), { signal: AbortSignal.abort() }),
|
|
{ name: 'AbortError' },
|
|
);
|
|
}
|
|
|
|
// Multi-chunk source with a multi-byte UTF-8 character split across chunks
|
|
async function testTextMultiChunkSplitCodepoint() {
|
|
// '€' is U+20AC, encoded as 3 UTF-8 bytes: 0xE2, 0x82, 0xAC
|
|
// Split these bytes across two chunks to test proper re-assembly
|
|
async function* splitSource() {
|
|
yield [new Uint8Array([0xE2, 0x82])]; // First 2 bytes of '€'
|
|
yield [new Uint8Array([0xAC])]; // Last byte of '€'
|
|
}
|
|
const result = await text(splitSource());
|
|
assert.strictEqual(result, '€');
|
|
}
|
|
|
|
// BOM should be stripped (ignoreBOM defaults to false per spec)
|
|
async function testTextBOMStripped() {
|
|
// UTF-8 BOM: 0xEF, 0xBB, 0xBF followed by 'hi'
|
|
const withBOM = new Uint8Array([0xEF, 0xBB, 0xBF, 0x68, 0x69]);
|
|
const result = await text(from(withBOM));
|
|
assert.strictEqual(result, 'hi');
|
|
}
|
|
|
|
async function testTextSyncBOMStripped() {
|
|
const withBOM = new Uint8Array([0xEF, 0xBB, 0xBF, 0x68, 0x69]);
|
|
const result = textSync(fromSync(withBOM));
|
|
assert.strictEqual(result, 'hi');
|
|
}
|
|
|
|
// Unsupported encoding throws RangeError
|
|
async function testTextUnsupportedEncodingThrowsRangeError() {
|
|
await assert.rejects(
|
|
() => text(from('hello'), { encoding: 'not-a-real-encoding' }),
|
|
{ name: 'RangeError' },
|
|
);
|
|
}
|
|
|
|
function testTextSyncUnsupportedEncodingThrowsRangeError() {
|
|
assert.throws(
|
|
() => textSync(fromSync('hello'), { encoding: 'not-a-real-encoding' }),
|
|
{ name: 'RangeError' },
|
|
);
|
|
}
|
|
|
|
async function testTextConvertedEncodingThrowsRangeError() {
|
|
await assert.rejects(
|
|
() => text(from('hello'), { encoding: 1 }),
|
|
{ code: 'ERR_INVALID_ARG_VALUE' },
|
|
);
|
|
}
|
|
|
|
function testTextSyncConvertedEncodingThrowsRangeError() {
|
|
assert.throws(
|
|
() => textSync(fromSync('hello'), { encoding: 1 }),
|
|
{ code: 'ERR_INVALID_ARG_VALUE' },
|
|
);
|
|
}
|
|
|
|
Promise.all([
|
|
testTextSyncBasic(),
|
|
testTextAsync(),
|
|
testTextEncoding(),
|
|
testTextNonUtf8Encoding(),
|
|
testTextSyncNonUtf8Encoding(),
|
|
testTextInvalidUtf8(),
|
|
testTextWithLimit(),
|
|
testTextSyncWithLimit(),
|
|
testTextEmpty(),
|
|
testTextWithSignal(),
|
|
testTextMultiChunkSplitCodepoint(),
|
|
testTextBOMStripped(),
|
|
testTextSyncBOMStripped(),
|
|
testTextUnsupportedEncodingThrowsRangeError(),
|
|
testTextSyncUnsupportedEncodingThrowsRangeError(),
|
|
testTextConvertedEncodingThrowsRangeError(),
|
|
testTextSyncConvertedEncodingThrowsRangeError(),
|
|
]).then(common.mustCall());
|