| // 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); |
| } |
| }); |