patx/makeitpdf

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/);
});