Some checks failed
Build and Push Docker Image / build (push) Has been cancelled
102 lines
3.1 KiB
TypeScript
102 lines
3.1 KiB
TypeScript
import { describe, expect, test } from "bun:test";
|
|
import { buildScanItemsWhere, parseScanItemsQuery, parseScanLimit } from "../scan";
|
|
|
|
describe("parseScanLimit", () => {
|
|
test("accepts positive integers and nullish/empty as no-limit", () => {
|
|
expect(parseScanLimit(5)).toEqual({ ok: true, value: 5 });
|
|
expect(parseScanLimit(1)).toEqual({ ok: true, value: 1 });
|
|
expect(parseScanLimit(10_000)).toEqual({ ok: true, value: 10_000 });
|
|
expect(parseScanLimit(null)).toEqual({ ok: true, value: null });
|
|
expect(parseScanLimit(undefined)).toEqual({ ok: true, value: null });
|
|
expect(parseScanLimit("")).toEqual({ ok: true, value: null });
|
|
});
|
|
|
|
test("coerces numeric strings (env var path) but rejects garbage", () => {
|
|
expect(parseScanLimit("7")).toEqual({ ok: true, value: 7 });
|
|
expect(parseScanLimit("abc")).toEqual({ ok: false });
|
|
expect(parseScanLimit("12abc")).toEqual({ ok: false });
|
|
});
|
|
|
|
test("rejects the footguns that would silently disable the cap", () => {
|
|
// NaN: processed >= NaN never trips → cap never fires.
|
|
expect(parseScanLimit(Number.NaN)).toEqual({ ok: false });
|
|
// Negative: off-by-one bugs in Math.min(limit, total).
|
|
expect(parseScanLimit(-1)).toEqual({ ok: false });
|
|
expect(parseScanLimit(0)).toEqual({ ok: false });
|
|
// Float: Math.min is fine but percentage math breaks on non-integers.
|
|
expect(parseScanLimit(1.5)).toEqual({ ok: false });
|
|
// Infinity is technically a number but has no business as a cap.
|
|
expect(parseScanLimit(Number.POSITIVE_INFINITY)).toEqual({ ok: false });
|
|
});
|
|
});
|
|
|
|
describe("parseScanItemsQuery", () => {
|
|
test("normalizes default filters and pagination", () => {
|
|
const q = parseScanItemsQuery({});
|
|
expect(q).toEqual({
|
|
offset: 0,
|
|
limit: 50,
|
|
search: "",
|
|
status: "all",
|
|
type: "all",
|
|
source: "all",
|
|
});
|
|
});
|
|
|
|
test("clamps limit and offset, trims and lowercases values", () => {
|
|
const q = parseScanItemsQuery({
|
|
offset: "-12",
|
|
limit: "5000",
|
|
q: " The Wire ",
|
|
status: "SCANNED",
|
|
type: "EPISODE",
|
|
source: "WEBHOOK",
|
|
});
|
|
expect(q).toEqual({
|
|
offset: 0,
|
|
limit: 200,
|
|
search: "The Wire",
|
|
status: "scanned",
|
|
type: "episode",
|
|
source: "webhook",
|
|
});
|
|
});
|
|
|
|
test("falls back to all for unknown enum values", () => {
|
|
const q = parseScanItemsQuery({ status: "zzz", type: "cartoon", source: "mqtt" });
|
|
expect(q.status).toBe("all");
|
|
expect(q.type).toBe("all");
|
|
expect(q.source).toBe("all");
|
|
});
|
|
});
|
|
|
|
describe("buildScanItemsWhere", () => {
|
|
test("builds combined where clause + args in stable order", () => {
|
|
const where = buildScanItemsWhere({
|
|
offset: 0,
|
|
limit: 50,
|
|
search: "blade",
|
|
status: "scanned",
|
|
type: "movie",
|
|
source: "webhook",
|
|
});
|
|
expect(where.sql).toBe(
|
|
"WHERE scan_status = ? AND lower(type) = ? AND ingest_source = ? AND (lower(name) LIKE ? OR lower(file_path) LIKE ?)",
|
|
);
|
|
expect(where.args).toEqual(["scanned", "movie", "webhook", "%blade%", "%blade%"]);
|
|
});
|
|
|
|
test("returns empty where when all filters are broad", () => {
|
|
const where = buildScanItemsWhere({
|
|
offset: 0,
|
|
limit: 50,
|
|
search: "",
|
|
status: "all",
|
|
type: "all",
|
|
source: "all",
|
|
});
|
|
expect(where.sql).toBe("");
|
|
expect(where.args).toEqual([]);
|
|
});
|
|
});
|