import { describe, expect, it } from "vitest"; import { estimateGif, gifEstimateText, GIF_MAX_BYTES, GIF_PREVIEW_MAX_BYTES, gifShownLength, gifVerdict, } from "./gif"; import { formatTimecode } from "./timecode"; const MB = 1024 * 1024; describe("estimateGif", () => { it("gives the measured range for a 16:9 picture", () => { const e = estimateGif(30, 480, 16 / 9); expect(e.lo / MB).toBeCloseTo(12, 5); expect(e.hi / MB).toBeCloseTo(30, 5); }); it("grows with the length and the size", () => { expect(estimateGif(20, 480, 16 / 9).hi).toBeGreaterThan(estimateGif(10, 480, 16 / 9).hi); expect(estimateGif(10, 640, 16 / 9).hi).toBeGreaterThan(estimateGif(10, 480, 16 / 9).hi); }); it("counts the pixels of the shape: a square holds more than 16:9, a tall one as many", () => { const wide = estimateGif(10, 480, 16 / 9).hi; expect(estimateGif(10, 480, 1).hi).toBeCloseTo(wide * (16 / 9), 3); expect(estimateGif(10, 480, 9 / 16).hi).toBeCloseTo(wide, 3); }); it("falls back to 16:9 for a shape it cannot read", () => { expect(estimateGif(10, 480, 0).hi).toBe(estimateGif(10, 480, 16 / 9).hi); expect(estimateGif(10, 480, Number.NaN).hi).toBe(estimateGif(10, 480, 16 / 9).hi); }); }); describe("gifEstimateText", () => { it("says whether both ends read the same, so a panel says one size", () => { expect(gifEstimateText(estimateGif(1, 480, 16 / 9), "en")).toEqual({ lo: "1", hi: "1", single: true, }); expect(gifEstimateText(estimateGif(10, 480, 16 / 9), "en")).toEqual({ lo: "4", hi: "10", single: false, }); }); }); describe("gifVerdict", () => { it("refuses past the length cap, whatever the size", () => { expect(gifVerdict(0, 30.2, { hi: 1 })).toBe("too_long"); expect(gifVerdict(0, 30, { hi: 1 })).toBe("ok"); }); it("judges the length the server judges: whole milliseconds between the ends as sent", () => { // A float difference a hair over 30 s is exactly 30 s once the ends are sent. expect(60.529 - 30.529).toBeGreaterThan(30); expect(gifVerdict(30.529, 60.529, { hi: 1 })).toBe("ok"); expect(gifVerdict(0, 30.001, { hi: 1 })).toBe("too_long"); // Each end is sent rounded on its own: 10.0004–40.0008 goes as 10–40.001, 30001 ms, refused… expect(gifVerdict(10.0004, 40.0008, { hi: 1 })).toBe("too_long"); // …and 10.0006–40.0012 as 10.001–40.001, exactly 30 s, made. expect(gifVerdict(10.0006, 40.0012, { hi: 1 })).toBe("ok"); }); it("warns past the server's cap, then past the link preview's", () => { expect(gifVerdict(0, 10, { hi: GIF_MAX_BYTES + 0.6 * MB })).toBe("may_fail"); expect(gifVerdict(0, 10, { hi: GIF_MAX_BYTES })).toBe("no_preview"); expect(gifVerdict(0, 10, { hi: GIF_PREVIEW_MAX_BYTES + 0.6 * MB })).toBe("no_preview"); expect(gifVerdict(0, 10, { hi: GIF_PREVIEW_MAX_BYTES })).toBe("ok"); }); it("judges the size the reader is shown: a high end shown as 30 MB is not past 30 MB", () => { // 30 s at 480 lands a hair over 30 MiB, and reads "about 12–30 MB". const hi = GIF_MAX_BYTES + 0.4 * MB; expect(gifEstimateText({ lo: 12 * MB, hi }, "en").hi).toBe("30"); expect(gifVerdict(0, 30, { hi })).toBe("no_preview"); expect(gifVerdict(0, 10, { hi: GIF_PREVIEW_MAX_BYTES + 0.4 * MB })).toBe("ok"); }); }); describe("gifShownLength", () => { it("never shows a refused range as one the cap allows", () => { expect(formatTimecode(gifShownLength(0, 30.03))).toBe("0:30.1"); expect(formatTimecode(gifShownLength(0, 30.001))).toBe("0:30.1"); expect(gifShownLength(30.529, 60.529)).toBe(30); expect(gifShownLength(0, 12.34)).toBe(12.34); }); });