// ide-extension-parser-entities.test.mjs — Regression tests for XML numeric // character references in plugin.xml. // // parsePluginXml documents a no-throw contract: "Malformed input returns // { manifest: null, warnings: [...] } rather than throwing." decodeEntities // guarded parseInt with Number.isFinite, which does not bound the value, so // String.fromCodePoint raised RangeError for any code point above 0x10FFFF — // a one-token hostile plugin.xml that aborts the parse instead of being // reported. import { describe, it } from 'node:test'; import assert from 'node:assert/strict'; import { parsePluginXml } from '../../scanners/lib/ide-extension-parser.mjs'; function xmlWithName(name) { return `com.example.p${name}v`; } describe('ide-extension-parser — numeric character references', () => { const outOfRange = [ ['hex, just past the Unicode maximum', '�'], ['decimal, just past the Unicode maximum', '�'], ['hex, far out of range', '�'], ['decimal, far out of range', '�'], ]; for (const [label, ref] of outOfRange) { it(`does not throw on an out-of-range reference (${label})`, () => { assert.doesNotThrow(() => parsePluginXml(xmlWithName(`Bad${ref}Name`))); }); it(`leaves an out-of-range reference literal (${label})`, () => { const { manifest } = parsePluginXml(xmlWithName(`Bad${ref}Name`)); assert.ok(manifest, 'manifest should still parse'); assert.ok( manifest.name.includes(ref), `undecodable reference should be left as-is, got: ${manifest.name}` ); }); } it('still decodes valid numeric references', () => { const { manifest } = parsePluginXml(xmlWithName('AB')); assert.ok(manifest); assert.equal(manifest.name, 'AB'); }); it('still decodes the maximum valid code point', () => { const { manifest } = parsePluginXml(xmlWithName('x􏿿')); assert.ok(manifest); assert.equal(manifest.name, 'x\u{10FFFF}'); }); it('still decodes named entities', () => { const { manifest } = parsePluginXml(xmlWithName('A&B<C')); assert.ok(manifest); assert.equal(manifest.name, 'A&B