import { describe, it, expect } from "vitest"; import { normalizeRatioToken, greatestCommonDivisor, formatAspectRatio, getQuickSetRatioValue, formatRatioDisplayValue, getRatioDisplayParts, parseRatioToAspectCss, toSupportedImageApiRatio, normalizeRatioForApi, } from "./ratioUtils"; describe("normalizeRatioToken", () => { it("normalizes non-breaking spaces", () => { expect(normalizeRatioToken("800\u00a0\u00a0px")).toBe("800 px"); }); it("replaces plain separators with the normal multiplication sign", () => { expect(normalizeRatioToken("800*800")).toBe("800×800"); }); it("replaces legacy mojibake multiply signs", () => { expect(normalizeRatioToken("800\u8133800")).toBe("800×800"); }); it("replaces fullwidth and legacy mojibake colons", () => { expect(normalizeRatioToken("1:1")).toBe("1:1"); expect(normalizeRatioToken("1\u951b?1")).toBe("1:1"); }); it("collapses whitespace and trims", () => { expect(normalizeRatioToken(" 1 : 1 ")).toBe("1 : 1"); }); }); describe("greatestCommonDivisor", () => { it("computes GCD", () => { expect(greatestCommonDivisor(12, 8)).toBe(4); expect(greatestCommonDivisor(1920, 1080)).toBe(120); }); it("handles zero with fallback to 1", () => { expect(greatestCommonDivisor(0, 5)).toBe(5); expect(greatestCommonDivisor(0, 0)).toBe(1); }); it("handles negatives via abs", () => { expect(greatestCommonDivisor(-12, 8)).toBe(4); }); }); describe("formatAspectRatio", () => { it("reduces 1920x1080 to 16:9", () => { expect(formatAspectRatio(1920, 1080)).toBe("16:9"); }); it("reduces 750x1000 to 3:4", () => { expect(formatAspectRatio(750, 1000)).toBe("3:4"); }); it("reduces 800x800 to 1:1", () => { expect(formatAspectRatio(800, 800)).toBe("1:1"); }); }); describe("getQuickSetRatioValue", () => { it("passes through a canonical quick-set value", () => { expect(getQuickSetRatioValue("1:1")).toBe("1:1"); }); it("derives from a WxH size string", () => { expect(getQuickSetRatioValue("1920×1080px")).toBe("16:9"); expect(getQuickSetRatioValue("750×1000px")).toBe("3:4"); }); it("derives from a raw ratio string", () => { expect(getQuickSetRatioValue("9:16")).toBe("9:16"); }); it("falls back to 1:1 for unparseable input", () => { expect(getQuickSetRatioValue("unknown")).toBe("1:1"); }); }); describe("formatRatioDisplayValue", () => { it("formats a WxHpx string with aspect suffix", () => { expect(formatRatioDisplayValue("1000×1000px 1:1")).toBe("1000×1000px\u00a0\u00a0\u00a01:1"); }); it("reformats 800x800px without explicit aspect", () => { expect(formatRatioDisplayValue("800x800px")).toBe("800×800px\u00a0\u00a0\u00a01:1"); }); it("replaces legacy mojibake product image labels", () => { expect(formatRatioDisplayValue("\u935f\u55d7\u6427\u9365?")).toBe("商品图"); }); }); describe("getRatioDisplayParts", () => { it("splits size and aspect", () => { expect(getRatioDisplayParts("1000×1000px 1:1")).toEqual({ size: "1000×1000px", aspect: "1:1", }); }); it("uses 自适应 when no aspect present", () => { const parts = getRatioDisplayParts("原图"); expect(parts.aspect).toBe("自适应"); }); }); describe("parseRatioToAspectCss", () => { it("extracts CSS aspect-ratio", () => { expect(parseRatioToAspectCss("1000×1000px 1:1")).toBe("1000 / 1000"); }); it("falls back to 1 / 1", () => { expect(parseRatioToAspectCss("no numbers")).toBe("1 / 1"); }); }); describe("toSupportedImageApiRatio", () => { it("snaps square to 1:1", () => { expect(toSupportedImageApiRatio(800, 800)).toBe("1:1"); }); it("snaps 750x1000 to 3:4", () => { expect(toSupportedImageApiRatio(750, 1000)).toBe("3:4"); }); it("snaps 1920x1080 to 16:9", () => { expect(toSupportedImageApiRatio(1920, 1080)).toBe("16:9"); }); it("snaps 1080x1920 to 9:16", () => { expect(toSupportedImageApiRatio(1080, 1920)).toBe("9:16"); }); it("snaps 800x600 to 4:3", () => { expect(toSupportedImageApiRatio(800, 600)).toBe("4:3"); }); it("returns 1:1 for non-finite or non-positive", () => { expect(toSupportedImageApiRatio(NaN, 100)).toBe("1:1"); expect(toSupportedImageApiRatio(0, 100)).toBe("1:1"); expect(toSupportedImageApiRatio(-1, 100)).toBe("1:1"); }); }); describe("normalizeRatioForApi", () => { it("extracts the explicit ratio from a display string", () => { expect(normalizeRatioForApi("1000×1000px 1:1")).toBe("1:1"); expect(normalizeRatioForApi("750×1000px 3:4")).toBe("3:4"); }); it("derives ratio from a bare size string", () => { expect(normalizeRatioForApi("1920×1080px")).toBe("16:9"); }); it("returns 1:1 for unparseable input", () => { expect(normalizeRatioForApi("")).toBe("1:1"); expect(normalizeRatioForApi("无尺寸信息")).toBe("1:1"); }); it("uses the last explicit ratio when multiple present", () => { expect(normalizeRatioForApi("4:3 16:9")).toBe("16:9"); }); });