import { describe, expect, it } from "vitest"; import { exceedsImageStorageLimit, exceedsNormalizedImageSize, imageExtensionForFormat, createConcurrencyLimiter, isExpiredImage, isImageFilename, } from "../../../src/backend/images/image-utils.js"; describe("terminal image utilities", () => { it("accepts UUID-based image filenames", () => { expect(isImageFilename("b797234d-eb5d-4b1b-b7f3-17c26f257506.jpeg")).toBe( true, ); }); it("rejects unsafe or unrelated filenames", () => { expect(isImageFilename("../secrets.txt")).toBe(false); expect(isImageFilename("not-an-image.jpeg")).toBe(false); expect(isImageFilename("b797234d-eb5d-4b1b-b7f3-17c26f257506")).toBe(false); }); it("maps decoded raster formats while excluding SVG", () => { expect(imageExtensionForFormat("jpeg")).toBe("jpg"); expect(imageExtensionForFormat("heif")).toBe("heif"); expect(imageExtensionForFormat("tiff")).toBe("tiff"); expect(imageExtensionForFormat("svg")).toBeUndefined(); expect(imageExtensionForFormat(undefined)).toBeUndefined(); }); it("rejects normalized output beyond the byte ceiling", () => { expect(exceedsNormalizedImageSize(10_000_001, 10_000_000)).toBe(true); expect(exceedsNormalizedImageSize(10_000_000, 10_000_000)).toBe(false); }); it("expires files older than the configured TTL", () => { expect(isExpiredImage(1_000, 3_000, 1_000)).toBe(true); expect(isExpiredImage(2_500, 3_000, 1_000)).toBe(false); }); it("treats a zero TTL as retention disabled", () => { expect(isExpiredImage(1_000, 999_999, 0)).toBe(false); }); it("bounds the admission queue", async () => { const limiter = createConcurrencyLimiter(1, 0); const release = await limiter.acquire(); await expect(limiter.acquire()).rejects.toThrow("queue is full"); release(); }); it("rejects uploads that exceed the count or byte limit", () => { expect(exceedsImageStorageLimit(100, 10, 1, 100, 1000)).toBe(true); expect(exceedsImageStorageLimit(1, 900, 101, 100, 1000)).toBe(true); expect(exceedsImageStorageLimit(1, 900, 100, 100, 1000)).toBe(false); }); it("bounds concurrent work", async () => { const limiter = createConcurrencyLimiter(1); let active = 0; let peak = 0; const task = async () => { const release = await limiter.acquire(); active += 1; peak = Math.max(peak, active); await new Promise((resolve) => setTimeout(resolve, 5)); active -= 1; release(); }; await Promise.all([task(), task(), task()]); expect(peak).toBe(1); expect(limiter.active).toBe(0); }); });