import { test } from 'node:test'; import assert from 'node:assert/strict'; import { runInNewContext } from 'node:vm'; import { compat, patchPdf, workerTarget, marker } from './install-pdf-compat.mjs'; function run(code) { return runInNewContext('delete Math.sumPrecise; delete Map.prototype.getOrInsert; delete Map.prototype.getOrInsertComputed;\n' + compat + '\n' + code); } test('precise summation handles cancellation, rounding, overflow, subnormals and special values', () => { assert.equal(run('Math.sumPrecise([1e20, 1, -1e20])'), 1); assert.equal(run('Math.sumPrecise([Number.MAX_VALUE, Number.MAX_VALUE, -Number.MAX_VALUE])'), Number.MAX_VALUE); assert.equal(run('Math.sumPrecise([Number.MAX_VALUE, Number.MAX_VALUE])'), Infinity); assert.equal(run('Math.sumPrecise([Number.MIN_VALUE, Number.MIN_VALUE])'), 2 * Number.MIN_VALUE); assert.equal(run('Math.sumPrecise([1, 2 ** -53])'), 1); assert.equal(run('Math.sumPrecise([1, 2 ** -53, 2 ** -54])'), 1 + Number.EPSILON); assert.ok(Object.is(run('Math.sumPrecise([])'), -0)); assert.ok(Object.is(run('Math.sumPrecise([-0])'), -0)); assert.ok(Object.is(run('Math.sumPrecise([-1, 1])'), 0)); assert.ok(Number.isNaN(run('Math.sumPrecise([Infinity, -Infinity])'))); assert.throws(() => run('Math.sumPrecise([Infinity, "1"])'), /numbers/); }); test('computed insertion caches undefined and promises without recomputation', () => { assert.equal(run('const m = new Map(); let n = 0; m.getOrInsertComputed("x", () => { n++; }); m.getOrInsertComputed("x", () => { n++; }); n'), 1); assert.equal(run('const m = new Map(); const p = Promise.resolve(1); m.getOrInsertComputed("x", () => p) === m.getOrInsertComputed("x", () => 2)'), true); }); test('callback validation, errors, receiver, key normalization and reentrancy', () => { assert.throws(() => run('new Map([[1, 2]]).getOrInsertComputed(1, null)'), /callable/); assert.throws(() => run('Map.prototype.getOrInsertComputed.call({}, 1, () => 2)'), /incompatible receiver/); assert.equal(run('new Map().getOrInsertComputed(-0, k => Object.is(k, 0))'), true); assert.equal(run('const m = new Map(); m.getOrInsertComputed(1, k => { m.set(k, 2); return 3; }); m.get(1)'), 3); assert.equal(run('const m = new Map(); try { m.getOrInsertComputed(1, () => { throw Error(); }); } catch {} m.size'), 0); assert.equal(run('new Map([[NaN, 4]]).getOrInsertComputed(NaN, () => 5)'), 4); }); test('plain insertion and non-enumerable, repeat-safe methods', () => { assert.equal(run('const m = new Map([[1, undefined]]); m.getOrInsert(1, 2) === undefined && m.getOrInsert(2, 3) === 3'), true); assert.equal(run('Object.getOwnPropertyDescriptor(Map.prototype, "getOrInsertComputed").enumerable'), false); assert.equal(runInNewContext('Map.prototype.getOrInsertComputed = () => 42;\n' + compat + '\nnew Map().getOrInsertComputed()'), 42); }); test('patch guards and worker injection', () => { const source = 'this.#methodPromises.getOrInsertComputed(name, f); ' + workerTarget + ' tail]);'; const patched = patchPdf(source, '0.2.1-rc.2', '0.2.1-rc.2'); assert.ok(patched.startsWith(marker + '\n' + compat)); assert.ok(patched.includes('new Blob([' + JSON.stringify(compat) + ', _dsh_pdf_worker_default,')); assert.throws(() => patchPdf(patched, '0.2.1-rc.2', '0.2.1-rc.2'), /already/); assert.throws(() => patchPdf(source, 'other', '0.2.1-rc.2'), /version/); for (const bad of ['', source + workerTarget]) assert.throws(() => patchPdf(bad, '0.2.1-rc.2', '0.2.1-rc.2'), /unexpected/); });