83 lines
3.0 KiB
JavaScript
83 lines
3.0 KiB
JavaScript
import test from "node:test";
|
|||
|
|
import assert from "node:assert/strict";
|
||
|
|
import {
|
||
|
|
timestampLabel,
|
||
|
|
seekSeconds,
|
||
|
|
sourceLabel,
|
||
|
|
matchLabel,
|
||
|
|
PreviewRevision,
|
||
|
|
} from "../src/media-display.ts";
|
||
|
|
import { LatestLane } from "../src/search-state.ts";
|
||
|
|
const settle = () => new Promise((resolve) => setImmediate(resolve));
|
||
|
|
|
||
|
|
test("millisecond seeks preserve fractions and readable minute labels", () => {
|
||
|
|
assert.equal(timestampLabel(125450), "2:05");
|
||
|
|
assert.equal(timestampLabel(3600000), "60:00");
|
||
|
|
assert.equal(seekSeconds({ kind: "timestamp_ms", number: 125450 }), 125.45);
|
||
|
|
assert.equal(seekSeconds({ kind: "page", number: 4 }), undefined);
|
||
|
|
assert.equal(seekSeconds({ kind: "timestamp_ms", number: -1 }), undefined);
|
||
|
|
assert.equal(timestampLabel(Infinity), "Unknown time");
|
||
|
|
assert.equal(sourceLabel({ kind: "image", number: 0 }), "Image");
|
||
|
|
assert.equal(matchLabel("semantic_audio"), "Audio meaning");
|
||
|
|
assert.equal(matchLabel("semantic_video"), "Video frame meaning");
|
||
|
|
});
|
||
|
|
|
||
|
|
test("another timestamp in the same movie invalidates older preparations", () => {
|
||
|
|
const gate = new PreviewRevision();
|
||
|
|
const first = gate.select("movie:1000");
|
||
|
|
assert.equal(gate.select("movie:1000").changed, false);
|
||
|
|
const second = gate.select("movie:3000");
|
||
|
|
assert.equal(gate.accepts(first.revision), false);
|
||
|
|
assert.equal(gate.accepts(second.revision), true);
|
||
|
|
gate.clear();
|
||
|
|
assert.equal(gate.accepts(second.revision), false);
|
||
|
|
});
|
||
|
|
|
||
|
|
test("one active preview and only latest pending reject stale output", async () => {
|
||
|
|
const gate = new PreviewRevision();
|
||
|
|
const executed = [];
|
||
|
|
const accepted = [];
|
||
|
|
let release;
|
||
|
|
const lane = new LatestLane(
|
||
|
|
async (request) => {
|
||
|
|
executed.push(request.path);
|
||
|
|
if (request.path === "first")
|
||
|
|
await new Promise((resolve) => {
|
||
|
|
release = resolve;
|
||
|
|
});
|
||
|
|
if (gate.accepts(request.revision)) accepted.push(request.path);
|
||
|
|
},
|
||
|
|
(request) => gate.accepts(request.revision),
|
||
|
|
() => assert.fail("Unexpected preview failure"),
|
||
|
|
);
|
||
|
|
lane.submit({ path: "first", revision: gate.select("first").revision });
|
||
|
|
lane.submit({ path: "middle", revision: gate.select("middle").revision });
|
||
|
|
lane.submit({ path: "latest", revision: gate.select("latest").revision });
|
||
|
|
release();
|
||
|
|
await settle();
|
||
|
|
assert.deepEqual(executed, ["first", "latest"]);
|
||
|
|
assert.deepEqual(accepted, ["latest"]);
|
||
|
|
});
|
||
|
|
|
||
|
|
test("Escape clears queued preparation and rejects active output", async () => {
|
||
|
|
const gate = new PreviewRevision();
|
||
|
|
let release;
|
||
|
|
const accepted = [];
|
||
|
|
const lane = new LatestLane(
|
||
|
|
async (request) => {
|
||
|
|
await new Promise((resolve) => {
|
||
|
|
release = resolve;
|
||
|
|
});
|
||
|
|
if (gate.accepts(request.revision)) accepted.push(request.path);
|
||
|
|
},
|
||
|
|
(request) => gate.accepts(request.revision),
|
||
|
|
() => assert.fail("Unexpected preview failure"),
|
||
|
|
);
|
||
|
|
lane.submit({ path: "one", revision: gate.select("one").revision });
|
||
|
|
lane.submit({ path: "two", revision: gate.select("two").revision });
|
||
|
|
gate.clear();
|
||
|
|
lane.clear();
|
||
|
|
release();
|
||
|
|
await settle();
|
||
|
|
assert.deepEqual(accepted, []);
|
||
|
|
});
|