// Unit tests for the torus camera helper in src/map/torus.ts. // // `wrapCameraTorus` is the pure-math primitive the renderer uses to // keep the camera centre inside the central tile of the 3×3 wrap // layout. The helper guarantees three properties: the result lies // inside `[0, W) × [0, H)`, the toroidal point is preserved (the // transform is an additive multiple of `W` / `H`), and the camera // scale is unchanged. import { describe, expect, test } from "vitest"; import { World } from "../src/map/world"; import { wrapCameraTorus } from "../src/map/torus"; const world = new World(1000, 800); describe("wrapCameraTorus", () => { test("leaves a camera inside [0, W) × [0, H) untouched", () => { const c = wrapCameraTorus( { centerX: 500, centerY: 400, scale: 2 }, world, ); expect(c.centerX).toBe(500); expect(c.centerY).toBe(400); expect(c.scale).toBe(2); }); test("wraps a camera one tile past the right edge back to the left", () => { const c = wrapCameraTorus( { centerX: 1500, centerY: 200, scale: 1 }, world, ); expect(c.centerX).toBe(500); expect(c.centerY).toBe(200); }); test("wraps a camera one tile below the top edge back to the bottom", () => { const c = wrapCameraTorus( { centerX: 100, centerY: -300, scale: 1 }, world, ); expect(c.centerX).toBe(100); expect(c.centerY).toBe(500); }); test("wraps a camera many tiles away on both axes", () => { const c = wrapCameraTorus( { centerX: 1000 * 5 + 123, centerY: -800 * 7 - 45, scale: 0.5 }, world, ); expect(c.centerX).toBeCloseTo(123, 6); expect(c.centerY).toBeCloseTo(800 - 45, 6); expect(c.scale).toBe(0.5); }); test("collapses the world boundary to zero (right edge wraps to left)", () => { const c = wrapCameraTorus( { centerX: 1000, centerY: 800, scale: 1 }, world, ); // 1000 mod 1000 === 0; same for 800. The right and bottom // world edges map to the left and top edges. expect(c.centerX).toBe(0); expect(c.centerY).toBe(0); }); test("preserves the toroidal coordinate (delta is a world-multiple)", () => { const before = { centerX: 1000 * 3 + 250.75, centerY: 800 * -2 + 100.25, scale: 1 }; const after = wrapCameraTorus(before, world); const dx = before.centerX - after.centerX; const dy = before.centerY - after.centerY; expect(Math.abs(dx % world.width)).toBeLessThan(1e-6); expect(Math.abs(dy % world.height)).toBeLessThan(1e-6); }); test("never returns negative coordinates", () => { for (const camera of [ { centerX: -1, centerY: -1, scale: 1 }, { centerX: -0.5, centerY: -0.5, scale: 1 }, { centerX: -world.width * 1.25, centerY: -world.height * 1.25, scale: 1 }, ]) { const c = wrapCameraTorus(camera, world); expect(c.centerX).toBeGreaterThanOrEqual(0); expect(c.centerX).toBeLessThan(world.width); expect(c.centerY).toBeGreaterThanOrEqual(0); expect(c.centerY).toBeLessThan(world.height); } }); test("scale field is preserved verbatim", () => { const c = wrapCameraTorus( { centerX: 1234, centerY: -567, scale: 0.123456 }, world, ); expect(c.scale).toBe(0.123456); }); });