import { expect, it } from "vitest";
import { parseXmlDocument } from "./xmlDocument.js";
it.each([
'😀 � & �',
"",
'\r\n �\rtext',
"�",
']>�',
])("preserves legal Unicode and source-located DOM nodes: %j", (source) => {
const parsed = parseXmlDocument(source, {
doctype: "allow",
lineEndings: "preserve",
});
if (!parsed.ok) throw parsed.error;
expect(parsed.value.documentElement?.tagName).toBe("root");
expect(parsed.value.documentElement?.lineNumber).toBeDefined();
expect(parsed.value.documentElement?.textContent).toContain("�");
});
it.each([
"�",
'',
'',
"�",
"� & unknown",
"� &missing;",
"�\u0000",
"�",
"�\uFFFF",
"�]]>",
"",
"�",
"�",
"]>�",
"�",
])("rejects malformed XML without warning-message matching: %j", (source) => {
const parsed = parseXmlDocument(source, {
doctype: "allow",
lineEndings: "preserve",
});
expect(parsed.ok).toBe(false);
if (parsed.ok) throw new Error("Expected refusal");
expect(parsed.error.reason).toBe("malformed");
expect(parsed.error.cause).toBeDefined();
});
it("keeps literal line endings and character-reference values distinct", () => {
const parsed = parseXmlDocument("\r\n
\r�", {
doctype: "allow",
lineEndings: "preserve",
});
if (!parsed.ok) throw parsed.error;
expect(parsed.value.documentElement?.textContent).toBe("\r\n\r\r�");
});
it("applies the consumer's explicit DTD policy", () => {
const parsed = parseXmlDocument(
']>',
{ doctype: "reject", lineEndings: "preserve" },
);
expect(parsed.ok).toBe(false);
if (parsed.ok) throw new Error("Expected unsupported DTD");
expect(parsed.error.reason).toBe("doctype");
});
it("applies XML line-ending normalization only when the consumer selects it", () => {
const parsed = parseXmlDocument('\r\nx', {
doctype: "allow",
lineEndings: "normalize",
});
if (!parsed.ok) throw parsed.error;
expect(parsed.value.documentElement?.getAttribute("attr")).toBe("a b");
expect(parsed.value.documentElement?.textContent).toBe("\nx");
});
it("preserves Unicode separators under XML 1.0 normalization", () => {
const parsed = parseXmlDocument(
'a\r\u0085b\r\u2028c\r\n
d\u2029',
{ doctype: "allow", lineEndings: "normalize" },
);
if (!parsed.ok) throw parsed.error;
expect(parsed.value.documentElement?.getAttribute("attr")).toBe(
"a\u0085b\u2028c\u2029d",
);
expect(parsed.value.documentElement?.textContent).toBe(
"a\n\u0085b\n\u2028c\n\rd\u2029",
);
});