Files
node/test/parallel/test-whatwg-encoding-singlebyte.mjs
2025-12-30 18:56:47 +00:00

85 lines
3.4 KiB
JavaScript

// Test that single-byte encodings mappings are correct and match spec
// Works without Intl
// From: https://github.com/ExodusOSS/bytes/blob/master/tests/single-byte.test.js
// Copyright Exodus Movement. Licensed under MIT License.
import '../common/index.mjs';
import { readFileSync } from 'node:fs';
import { join } from 'node:path';
import { test, describe } from 'node:test';
import raw from '../fixtures/encoding/encodings.json' with { type: 'json' };
const groups = new Map(raw.map((x) => [x.heading, x.encodings.map((x) => x.name.toLowerCase())]));
const encodings = groups.get('Legacy single-byte encodings');
describe('single-byte encodings are supersets of ascii', () => {
for (const encoding of encodings) {
test(encoding, (t) => {
const loose = new TextDecoder(encoding);
const fatal = new TextDecoder(encoding, { fatal: true });
for (let i = 0; i < 128; i++) {
const str = String.fromCodePoint(i);
t.assert.strictEqual(loose.decode(Uint8Array.of(i)), str, i);
t.assert.strictEqual(fatal.decode(Uint8Array.of(i)), str, i);
}
});
}
});
describe('single-byte encodings index', () => {
for (const encoding of encodings) {
test(encoding, (t) => {
const loose = new TextDecoder(encoding);
const fatal = new TextDecoder(encoding, { fatal: true });
const file = encoding === 'iso-8859-8-i' ? `index-iso-8859-8.txt` : `index-${encoding}.txt`;
const text = readFileSync(join(import.meta.dirname, '../fixtures/encoding/single-byte', file), 'utf8');
const rows = text
.split('\n')
.map((x) => x.trim())
.filter((x) => x && x[0] !== '#')
.map((x) => x.split('\t'))
.map(([istr, codeHex, description]) => {
const i = Number(istr);
t.assert.ok(i < 128);
const code = parseInt(codeHex.slice(2), 16);
t.assert.strictEqual(`${i}`, istr);
t.assert.strictEqual('0x' + code.toString(16).padStart(4, '0').toUpperCase(), codeHex);
t.assert.ok(code && code !== 0xff_fd && code <= 0xff_ff); // Can't be a replacement char, has to be <= 16-bit
t.assert.ok(code < 0xd8_00 || code >= 0xe0_00); // not a surrogate
return [i, { i, code, description }];
});
t.assert.ok(rows.length <= 128);
const known = new Map(rows);
t.assert.strictEqual(rows.length, known.size); // all unique
for (let i = 0; i < 128; i++) {
const row = known.get(i);
const byte = i + 128;
if (row) {
t.assert.strictEqual(i, row.i);
const str = String.fromCodePoint(row.code);
t.assert.strictEqual(fatal.decode(Uint8Array.of(byte)), str, row.description);
t.assert.strictEqual(loose.decode(Uint8Array.of(byte)), str, row.description);
} else {
t.assert.throws(() => fatal.decode(Uint8Array.of(byte)), TypeError);
t.assert.strictEqual(loose.decode(Uint8Array.of(byte)), '\uFFFD');
}
}
});
}
});
// https://encoding.spec.whatwg.org/#x-user-defined-decoder
test('x-user-defined', (t) => {
const encoding = 'x-user-defined';
const loose = new TextDecoder(encoding);
const fatal = new TextDecoder(encoding, { fatal: true });
for (let byte = 0; byte < 256; byte++) {
const str = String.fromCodePoint(byte >= 0x80 ? 0xF780 + byte - 0x80 : byte);
t.assert.strictEqual(fatal.decode(Uint8Array.of(byte)), str, byte);
t.assert.strictEqual(loose.decode(Uint8Array.of(byte)), str, byte);
}
});