import { describe, expect, it } from "vitest"; import { contentRect, cropToSourcePx } from "./cropGeometry"; describe("contentRect (display-px letterbox mapping)", () => { it("returns the full box when box aspect matches the video aspect", () => { // 16:9 picture in a 16:9 box → no bars, content == box expect(contentRect(1600, 900, 16 / 9)).toEqual({ left: 0, top: 0, width: 1600, height: 900, }); }); it("pillarboxes (bars left/right) when the box is wider than the picture", () => { // 16:9 picture in a 2:1 box → full height, narrower centered width const r = contentRect(2000, 1000, 16 / 9)!; expect(r.height).toBe(1000); expect(r.width).toBeCloseTo(1000 * (16 / 9), 3); expect(r.top).toBe(0); expect(r.left).toBeCloseTo((2000 - 1000 * (16 / 9)) / 2, 3); }); it("letterboxes (bars top/bottom) when the box is taller than the picture", () => { // 16:9 picture in a 1:1 box → full width, shorter centered height const r = contentRect(1000, 1000, 16 / 9)!; expect(r.width).toBe(1000); expect(r.height).toBeCloseTo(1000 / (16 / 9), 3); expect(r.left).toBe(0); expect(r.top).toBeCloseTo((1000 - 1000 / (16 / 9)) / 2, 3); }); it("returns null for unmeasurable inputs", () => { expect(contentRect(0, 900, 16 / 9)).toBeNull(); expect(contentRect(1600, 0, 16 / 9)).toBeNull(); expect(contentRect(1600, 900, 0)).toBeNull(); expect(contentRect(1600, 900, NaN)).toBeNull(); }); }); describe("cropToSourcePx (fraction-of-content → even source px)", () => { it("scales content fractions straight to source pixels", () => { // A marquee anchored to the content rect: a fraction is a fraction of the real picture. expect(cropToSourcePx({ x: 0.25, y: 0.25, w: 0.5, h: 0.5 }, 1920, 1080)).toEqual({ x: 480, y: 270, w: 960, h: 540, }); }); it("rounds to even dimensions", () => { // 0.1 * 1920 = 192 (even); 0.333 * 1080 = 359.64 → 360 const c = cropToSourcePx({ x: 0.1, y: 0.333, w: 0.2, h: 0.111 }, 1920, 1080)!; expect(c.w % 2).toBe(0); expect(c.h % 2).toBe(0); expect(c.x % 2).toBe(0); expect(c.y % 2).toBe(0); }); it("allows a top-left origin (x/y may be 0)", () => { const c = cropToSourcePx({ x: 0, y: 0, w: 0.5, h: 0.5 }, 1920, 1080)!; expect(c.x).toBe(0); expect(c.y).toBe(0); }); it("clamps the window inside the frame so even-rounding can't overflow", () => { // A full-frame crop must stay exactly at the source size, not round past it. const c = cropToSourcePx({ x: 0, y: 0, w: 1, h: 1 }, 1921, 1081)!; expect(c.w).toBeLessThanOrEqual(1921); expect(c.h).toBeLessThanOrEqual(1081); expect(c.x + c.w).toBeLessThanOrEqual(1921); expect(c.y + c.h).toBeLessThanOrEqual(1081); }); it("keeps x+w within the frame for an off-square region near the right edge", () => { const srcW = 1280; const srcH = 720; const c = cropToSourcePx({ x: 0.7, y: 0.1, w: 0.3, h: 0.8 }, srcW, srcH)!; expect(c.x + c.w).toBeLessThanOrEqual(srcW); expect(c.y + c.h).toBeLessThanOrEqual(srcH); }); it("returns null for an unusable source size", () => { expect(cropToSourcePx({ x: 0, y: 0, w: 1, h: 1 }, 0, 1080)).toBeNull(); expect(cropToSourcePx({ x: 0, y: 0, w: 1, h: 1 }, 1920, 0)).toBeNull(); }); });