67 lines
2.8 KiB
TypeScript
67 lines
2.8 KiB
TypeScript
/**
|
|||
|
|
* pdf-ops (sources v0) — the pdfjs text layer against a committed fixture
|
||
|
|
* (tests/fixtures/sample-3page.pdf: 3 pages, distinct subjects, "force" on
|
||
|
|
* page 2 only). The render path (headless Chrome) is covered by the
|
||
|
|
* pdf-reader loop tests via the headlessOverride fake.
|
||
|
|
*/
|
||
|
|
import assert from "node:assert/strict";
|
||
|
|
import * as path from "node:path";
|
||
|
|
import { describe, it } from "node:test";
|
||
|
|
import { parsePageSpec, pdfExtract, pdfInfo, pdfProbe, pdfSearch } from "../src/agent/subagents/pdf-ops.ts";
|
||
|
|
|
||
|
|
const FIXTURE = path.join(import.meta.dirname, "fixtures", "sample-3page.pdf");
|
||
|
|
|
||
|
|
describe("pdf-ops — the pdfjs text layer", () => {
|
||
|
|
it("pdfInfo triages every page (count, text lengths, image counts, math density)", async () => {
|
||
|
|
const info = await pdfInfo(FIXTURE);
|
||
|
|
assert.equal(info.page_count, 3);
|
||
|
|
assert.equal(info.pages.length, 3);
|
||
|
|
assert.equal(info.pages[0]!.page, 1);
|
||
|
|
assert.ok(info.pages.every((p) => p.text_length > 0));
|
||
|
|
assert.ok(info.mean_text_length > 0);
|
||
|
|
// fixture has no images
|
||
|
|
assert.ok(info.pages.every((p) => p.image_count === 0));
|
||
|
|
});
|
||
|
|
|
||
|
|
it("pdfExtract heads pages and honors the spec", async () => {
|
||
|
|
const two = await pdfExtract(FIXTURE, "1-2");
|
||
|
|
assert.match(two, /^--- Page 1 ---/);
|
||
|
|
assert.match(two, /--- Page 2 ---/);
|
||
|
|
assert.ok(!two.includes("--- Page 3 ---"), "page 3 not requested");
|
||
|
|
assert.match(two, /Calculus/);
|
||
|
|
const picks = await pdfExtract(FIXTURE, "1,3");
|
||
|
|
assert.match(picks, /--- Page 1 ---/);
|
||
|
|
assert.ok(!picks.includes("--- Page 2 ---"));
|
||
|
|
assert.match(picks, /Chemistry/);
|
||
|
|
});
|
||
|
|
|
||
|
|
it("pdfSearch finds hits with page/line + context, literal and regex", async () => {
|
||
|
|
const lit = await pdfSearch(FIXTURE, "force", { literal: true });
|
||
|
|
assert.equal(lit.hits.length, 1);
|
||
|
|
assert.equal(lit.hits[0]!.page, 2);
|
||
|
|
assert.match(lit.hits[0]!.context, />>> /);
|
||
|
|
// regex with case-insensitivity
|
||
|
|
const re = await pdfSearch(FIXTURE, "H2O|water");
|
||
|
|
assert.equal(re.hits.length, 1);
|
||
|
|
assert.equal(re.hits[0]!.page, 3);
|
||
|
|
// no-hit silence
|
||
|
|
const none = await pdfSearch(FIXTURE, "zymurgy", { literal: true });
|
||
|
|
assert.equal(none.hits.length, 0);
|
||
|
|
// invalid regex throws the skill's error shape
|
||
|
|
await assert.rejects(() => pdfSearch(FIXTURE, "([unclosed"), /Invalid regex/);
|
||
|
|
});
|
||
|
|
|
||
|
|
it("pdfProbe accepts the fixture and rejects garbage", async () => {
|
||
|
|
await pdfProbe(FIXTURE); // resolves
|
||
|
|
const garbage = path.join(import.meta.dirname, "fixtures", "not-a-pdf.txt");
|
||
|
|
await assert.rejects(() => pdfProbe(garbage));
|
||
|
|
});
|
||
|
|
|
||
|
|
it("parsePageSpec: all / ranges / lists / clamping", () => {
|
||
|
|
assert.deepEqual(parsePageSpec("all", 3), [1, 2, 3]);
|
||
|
|
assert.deepEqual(parsePageSpec("1-5", 3), [1, 2, 3]);
|
||
|
|
assert.deepEqual(parsePageSpec("1,3,7", 3), [1, 3]);
|
||
|
|
assert.deepEqual(parsePageSpec("3", 3), [3]);
|
||
|
|
assert.deepEqual(parsePageSpec(" 2 , 1 ", 3), [1, 2]);
|
||
|
|
});
|
||
|
|
});
|