const test = require("node:test");
const assert = require("node:assert/strict");
const Documents = require("../documents.js");
test("safe links only allow web and mail targets", () => {
assert.equal(Documents.safeUrl("https://example.com/a"), "https://example.com/a");
assert.equal(Documents.safeUrl("mailto:[email protected]"), "mailto:[email protected]");
assert.equal(Documents.safeUrl("javascript:alert(1)"), null);
assert.equal(Documents.safeUrl("file:///etc/passwd"), null);
});
test("CSV delimiter detection handles comma, tab, semicolon, and pipe", () => {
assert.equal(Documents.parseCsv("a,b\n1,2").delimiter, ",");
assert.equal(Documents.parseCsv("a\tb\n1\t2").delimiter, "\t");
assert.equal(Documents.parseCsv("a;b\n1;2").delimiter, ";");
assert.equal(Documents.parseCsv("a|b\n1|2").delimiter, "|");
});
test("CSV parsing preserves quoted commas, escaped quotes, and newlines", () => {
const parsed = Documents.parseCsv('name,note\n"Ada, A.","line 1\nline 2"\nBob,"said ""hi"""');
assert.deepEqual(parsed.rows, [
["name", "note"],
["Ada, A.", "line 1\nline 2"],
["Bob", 'said "hi"'],
]);
assert.equal(parsed.cells, 6);
});
test("CSV rows are padded to a stable table width", () => {
const parsed = Documents.parseCsv("a,b,c\n1,2");
assert.deepEqual(parsed.rows[1], ["1", "2", ""]);
});
test("unclosed CSV quotes produce a useful error", () => {
assert.throws(() => Documents.parseCsv('a,"broken'), /unclosed quoted field/);
});
test("UTF-8 decoding strips a BOM and rejects invalid input", () => {
const valid = Uint8Array.from([0xef, 0xbb, 0xbf, 0x68, 0x69]);
assert.equal(Documents.decodeUtf8(valid), "hi");
assert.throws(() => Documents.decodeUtf8(Uint8Array.from([0xc3, 0x28])), /valid UTF-8/);
});