// Tests for `--cut-to-quote`'s matcher: where inside a reviewed window the // quote actually is. // // Pure, so it needs no cue files and no audio. The quote is prose a human // wrote about speech a machine transcribed, and every case here is one of the // ways those two disagree in the real manifests. // // Run with: pnpm test:scripts import assert from "node:assert/strict"; import test from "node:test"; import { citeForCut, cutToQuote, quoteFragments, normaliseWords } from "./resolve-windows.mjs"; /** A cue list at one second per cue, which makes every expectation exact. */ const cues = [ "Before any of this, a bit of throat clearing.", "So here is the thing I actually said.", "And it carries on into a second sentence.", "Then something else entirely, unrelated.", "A last line, for the tail.", ].map((text, i) => ({ start: i * 4, end: i * 4 + 4, text })); const extent = { start: 0, end: 20 }; test("the cut is the sentences the quote is in, not the whole window", () => { const r = cutToQuote(cues, "here is the thing I actually said", extent); assert.equal(r.ok, true); assert.equal(r.cutStart, 4); assert.equal(r.cutEnd, 8); assert.ok(r.score >= 0.9, `score ${r.score}`); }); test("an ellipsis is two places, and the cut spans both", () => { const r = cutToQuote(cues, "here is the thing … into a second sentence", extent); assert.equal(r.ok, true); assert.equal(r.cutStart, 4); assert.equal(r.cutEnd, 12); }); test("bracketed editorial words are not looked for", () => { // "[He]" is the report's word, not his, and counting it against the match // would push a good quote under the threshold. const r = cutToQuote(cues, "[He said] here is the thing I actually said", extent); assert.equal(r.ok, true); assert.equal(r.cutStart, 4); }); test("a quote that is not in the window is UNMATCHED, not a guess", () => { const r = cutToQuote(cues, "nothing of the sort was ever uttered aloud here", extent); assert.equal(r.ok, false); assert.ok(r.score < 0.6, `score ${r.score}`); }); test("the cut never leaves the extent", () => { const tight = { start: 5, end: 7 }; const r = cutToQuote(cues, "here is the thing I actually said", tight); assert.equal(r.ok, true); assert.ok(r.cutStart >= tight.start); assert.ok(r.cutEnd <= tight.end); }); test("no quote is not a failure to match, it is nothing to match", () => { assert.equal(cutToQuote(cues, "", extent).why, "no quote"); assert.equal(cutToQuote(cues, null, extent).why, "no quote"); }); test("normalisation drops case, punctuation and brackets", () => { assert.equal(normaliseWords("So, [Speaker] HERE -- is it?"), "so here is it"); assert.deepEqual(quoteFragments("one two ... three"), [["one", "two"], ["three"]]); }); // ---- the cite that comes with the cut ------------------------------------ // A cut is a window inside the extent, so the cite that was the floor of // `start` routinely ends up before the first frame that plays -- which is the // "cite N is outside the cut" the build used to print on nearly every clip. const entryOf = (o) => ({ video: "vid1", channel: "chan", start: 100.4, end: 160, ...o }); test("a cite before the cut moves to the first whole second inside it", () => { const r = citeForCut(entryOf({ cite: 100 }), { cutStart: 138.2, cutEnd: 157.9 }); assert.deepEqual(r, { cite: 139 }); }); test("the floor of `start` counts as outside a cut that begins at `start`", () => { // start 100.4 -> cite 100, cutStart 100.4: off by the rounding alone, and the // build flagged it just the same. const r = citeForCut(entryOf({ cite: 100 }), { cutStart: 100.4, cutEnd: 120 }); assert.deepEqual(r, { cite: 101 }); }); test("a cite already inside the cut is left alone", () => { assert.equal(citeForCut(entryOf({ cite: 140 }), { cutStart: 138.2, cutEnd: 157.9 }), null); }); test("no cite at all falls back to `start`, and moves with it", () => { assert.deepEqual(citeForCut(entryOf({}), { cutStart: 138.2, cutEnd: 157.9 }), { cite: 139 }); assert.equal(citeForCut(entryOf({ start: 140 }), { cutStart: 138.2, cutEnd: 157.9 }), null); }); test("a cite after the cut comes back to the last whole second inside it", () => { assert.deepEqual(citeForCut(entryOf({ cite: 159 }), { cutStart: 138.2, cutEnd: 157.9 }), { cite: 157, }); }); test("a cut straddling no whole second moves nothing", () => { assert.equal(citeForCut(entryOf({ cite: 100 }), { cutStart: 138.2, cutEnd: 138.9 }), null); }); test("the derived citeUrl follows the cite", () => { const e = entryOf({ cite: 100, citeUrl: "https://anilyzer.pages.dev/?v=chan%2Fvid1&t=100", }); assert.deepEqual(citeForCut(e, { cutStart: 138.2, cutEnd: 157.9 }), { cite: 139, citeUrl: "https://anilyzer.pages.dev/?v=chan%2Fvid1&t=139", }); }); test("the channel may come from the manifest rather than the entry", () => { const e = { video: "vid1", start: 100.4, end: 160, cite: 100, citeUrl: "https://x/?v=chan%2Fvid1&t=100" }; const r = citeForCut(e, { cutStart: 138.2, cutEnd: 157.9 }, { channelSlug: "chan" }); assert.equal(r.citeUrl, "https://x/?v=chan%2Fvid1&t=139"); }); test("a citeUrl naming ANOTHER recording is not ours to move", () => { // A mirror whose archived transcript reads better is a different clock: the // cite is this recording's second, the URL is a promise about that one. const e = entryOf({ cite: 100, citeUrl: "https://anilyzer.pages.dev/?v=other%2Fvid9&t=100" }); assert.deepEqual(citeForCut(e, { cutStart: 138.2, cutEnd: 157.9 }), { cite: 139 }); });