import assert from 'node:assert/strict' import test from 'node:test' import { decodeBase64, encodeBase64 } from '../security/base64.js' import { canonicalJson } from '../security/canonical-json.js' test('strict Base64 decoder supports padded, unpadded and URL-safe inputs without atob', () => { assert.deepEqual([...decodeBase64('TQ==')], [77]) assert.deepEqual([...decodeBase64('TWE=')], [77, 97]) assert.deepEqual([...decodeBase64('TWFu')], [77, 97, 110]) assert.deepEqual([...decodeBase64('AQIDBA==')], [1, 2, 3, 4]) assert.deepEqual([...decodeBase64('AQIDBA')], [1, 2, 3, 4]) assert.deepEqual([...decodeBase64('-_8=')], [251, 255]) }) test('strict Base64 decoder rejects invalid alphabets, lengths, padding and trailing bits', () => { for (const value of [ 'A', 'A+_-', 'AA=A', 'AA===', 'AAA==', 'TQ=', 'TWE==', 'TQ===', 'TQ==AA', 'TR==', 'TWF=', 'AA!A', ]) { assert.throws(() => decodeBase64(value), /Base64/) } }) test('pure JS Base64 encoder emits canonical standard and URL-safe forms', () => { assert.equal(encodeBase64(new Uint8Array()), '') assert.equal(encodeBase64(Uint8Array.of(77)), 'TQ==') assert.equal(encodeBase64(Uint8Array.of(77, 97)), 'TWE=') assert.equal(encodeBase64(Uint8Array.of(77, 97, 110)), 'TWFu') assert.equal(encodeBase64(Uint8Array.of(251, 255), { urlSafe: true }), '-_8=') assert.equal(encodeBase64(Uint8Array.of(251, 255), { urlSafe: true, padding: false }), '-_8') assert.throws(() => encodeBase64([1, 2, 3] as unknown as Uint8Array), /Uint8Array/) }) test('Base64 codec round-trips chunk boundaries and matches the Node reference', () => { for (const length of [0, 1, 2, 3, 4, 31, 32, 33, 255, 256, 257]) { const input = Uint8Array.from({ length }, (_, index) => (index * 197 + 31) & 0xff) const standard = encodeBase64(input) const urlSafe = encodeBase64(input, { urlSafe: true, padding: false }) assert.equal(standard, Buffer.from(input).toString('base64')) assert.equal(urlSafe, Buffer.from(input).toString('base64url')) assert.deepEqual(decodeBase64(standard), input) assert.deepEqual(decodeBase64(urlSafe), input) } }) test('canonical JSON rejects values that have no cross-runtime protocol representation', () => { assert.throws(() => canonicalJson(Number.NaN), /finite numbers/) assert.throws(() => canonicalJson(Number.POSITIVE_INFINITY), /finite numbers/) assert.throws(() => canonicalJson(() => undefined), /does not support function/) assert.throws(() => canonicalJson(Symbol('value')), /does not support symbol/) assert.throws(() => canonicalJson([undefined]), /cannot contain holes or undefined/) assert.throws(() => canonicalJson(new Array(1)), /cannot contain holes or undefined/) assert.throws(() => canonicalJson(new Date(0)), /only supports plain objects/) })