/**
* Tests for the benchmark scoring functions.
*/
import { describe, test, expect } from "vitest";
import { normalizePath, pathsMatch, scoreResults } from "../src/bench/score.js";
describe("normalizePath", () => {
test("lowercases path", () => {
expect(normalizePath("Resources/Concepts/Context Engineering.md"))
.toBe("resources/concepts/context engineering.md");
});
test("strips qmd:// prefix", () => {
expect(normalizePath("qmd://collection/docs/readme.md"))
.toBe("docs/readme.md");
});
test("strips leading/trailing slashes", () => {
expect(normalizePath("/docs/readme.md/")).toBe("docs/readme.md");
});
test("handles plain filename", () => {
expect(normalizePath("readme.md")).toBe("readme.md");
});
});
describe("pathsMatch", () => {
test("exact match", () => {
expect(pathsMatch("docs/readme.md", "docs/readme.md")).toBe(true);
});
test("case-insensitive match", () => {
expect(pathsMatch("Docs/README.md", "docs/readme.md")).toBe(true);
});
test("suffix match (result is longer)", () => {
expect(pathsMatch("/full/path/docs/readme.md", "docs/readme.md")).toBe(true);
});
test("suffix match (expected is longer)", () => {
expect(pathsMatch("readme.md", "docs/readme.md")).toBe(true);
});
test("qmd:// prefix handled", () => {
expect(pathsMatch("qmd://col/docs/readme.md", "docs/readme.md")).toBe(true);
});
test("different files don't match", () => {
expect(pathsMatch("docs/readme.md", "docs/other.md")).toBe(false);
});
});
describe("scoreResults", () => {
test("perfect score: all expected in top-k", () => {
const result = scoreResults(
["a.md", "b.md", "c.md"],
["a.md", "b.md"],
2,
);
expect(result.precision_at_k).toBe(1);
expect(result.recall).toBe(1);
expect(result.mrr).toBe(1);
expect(result.f1).toBe(1);
expect(result.hits_at_k).toBe(2);
});
test("zero score: none found", () => {
const result = scoreResults(
["x.md", "y.md", "z.md"],
["a.md", "b.md"],
2,
);
expect(result.precision_at_k).toBe(0);
expect(result.recall).toBe(0);
expect(result.mrr).toBe(0);
expect(result.f1).toBe(0);
expect(result.hits_at_k).toBe(0);
});
test("partial: found outside top-k", () => {
const result = scoreResults(
["x.md", "y.md", "a.md"],
["a.md"],
1,
);
expect(result.precision_at_k).toBe(0); // not in top-1
expect(result.recall).toBe(1); // found somewhere
expect(result.mrr).toBeCloseTo(1 / 3); // rank 3
expect(result.hits_at_k).toBe(0);
});
test("MRR: first relevant at rank 2", () => {
const result = scoreResults(
["x.md", "a.md", "b.md"],
["a.md", "b.md"],
3,
);
expect(result.mrr).toBeCloseTo(0.5); // 1/2
});
test("reports recall@1/3/5 and matched documents", () => {
const result = scoreResults(
["x.md", "qmd://concepts/a.md", "docs/b.md", "docs/c.md", "docs/d.md"],
["concepts/a.md", "b.md", "missing.md"],
3,
);
expect(result.recall_at_1).toBe(0);
expect(result.recall_at_3).toBeCloseTo(2 / 3);
expect(result.recall_at_5).toBeCloseTo(2 / 3);
expect(result.matched_files).toEqual(["concepts/a.md", "b.md"]);
expect(result.unmatched_expected_files).toEqual(["missing.md"]);
});
test("empty results", () => {
const result = scoreResults([], ["a.md"], 1);
expect(result.precision_at_k).toBe(0);
expect(result.recall).toBe(0);
expect(result.mrr).toBe(0);
});
test("empty expected", () => {
const result = scoreResults(["a.md"], [], 1);
expect(result.precision_at_k).toBe(0);
expect(result.recall).toBe(0);
});
});