45 lines
1.9 KiB
TypeScript
45 lines
1.9 KiB
TypeScript
import { describe, expect, it } from "vitest";
|
|
import { formatReport, runOcrEval } from "./ocrEvalHarness";
|
|
import { ocrEvalCorpus } from "./corpus";
|
|
|
|
// Regression gate: every case in the combined corpus is verified ground truth,
|
|
// so the parser must read every labeled field correctly. A drop here means an
|
|
// OCR/parser change regressed a previously-correct read - look at the printed
|
|
// failures. If a change intentionally alters a correct output, update the corpus
|
|
// label in the same commit (the label is the source of truth, not the code).
|
|
|
|
describe("OCR eval harness", () => {
|
|
const report = runOcrEval(ocrEvalCorpus);
|
|
|
|
it("prints the accuracy report", () => {
|
|
// Surfaced in test output for humans; not an assertion.
|
|
// eslint-disable-next-line no-console
|
|
console.log("\n" + formatReport(report) + "\n");
|
|
expect(report.totalCases).toBe(ocrEvalCorpus.length);
|
|
});
|
|
|
|
it("reads every labeled field on the eval corpus correctly", () => {
|
|
const failureSummary = report.failures
|
|
.map((failure) => {
|
|
const wrong = failure.fields
|
|
.filter((entry) => !entry.correct)
|
|
.map((entry) => `${entry.field}: expected "${entry.expected}" got "${entry.actual}"`)
|
|
.join("; ");
|
|
return `${failure.id} -> ${wrong}`;
|
|
})
|
|
.join("\n");
|
|
|
|
expect(report.fieldAccuracy, `field regressions:\n${failureSummary}`).toBe(1);
|
|
expect(report.criticalFieldAccuracy).toBe(1);
|
|
expect(report.exactRate).toBe(1);
|
|
});
|
|
|
|
it("labels every critical field at least once across the corpus", () => {
|
|
const criticalCoverage = report.perField.filter(
|
|
(entry) => ["name", "slot", "mainStat", "mainValue", "setName"].includes(entry.field) && entry.evaluated > 0,
|
|
);
|
|
// name is derived indirectly on most cases; slot/mainStat/mainValue/setName must be exercised.
|
|
expect(criticalCoverage.length).toBeGreaterThanOrEqual(4);
|
|
});
|
|
});
|