import { clamp01, lerp, remap, smoothstep, damp, seeded } from "./math"; describe("optimization/math — clamp01()", () => { it("clamps to [0,1]", () => { expect(clamp01(-2)).toBe(0); expect(clamp01(0)).toBe(0); expect(clamp01(0.37)).toBe(0.37); expect(clamp01(1)).toBe(1); expect(clamp01(5)).toBe(1); }); }); describe("optimization/math — lerp()", () => { it("interpolates linearly", () => { expect(lerp(0, 10, 0)).toBe(0); expect(lerp(0, 10, 1)).toBe(10); expect(lerp(0, 10, 0.5)).toBe(5); expect(lerp(2, 4, 0.25)).toBe(2.5); }); it("extrapolates past the endpoints", () => { expect(lerp(0, 10, 2)).toBe(20); expect(lerp(0, 10, -1)).toBe(-10); }); }); describe("optimization/math — remap()", () => { it("remaps and clamps to the output range", () => { expect(remap(5, 0, 10, 0, 100)).toBe(50); expect(remap(-5, 0, 10, 0, 100)).toBe(0); expect(remap(15, 0, 10, 0, 100)).toBe(100); }); it("defaults the output range to [0,1]", () => { expect(remap(2.5, 0, 10)).toBeCloseTo(0.25, 10); }); it("guards against a zero-width input range (no NaN)", () => { const v = remap(5, 2, 2, 0, 1); expect(Number.isNaN(v)).toBe(false); }); }); describe("optimization/math — smoothstep()", () => { it("hits 0 and 1 at the edges and 0.5 at the middle", () => { expect(smoothstep(0, 1, 0)).toBe(0); expect(smoothstep(0, 1, 1)).toBe(1); expect(smoothstep(0, 1, 0.5)).toBeCloseTo(0.5, 10); }); it("clamps outside the edges", () => { expect(smoothstep(0, 1, -1)).toBe(0); expect(smoothstep(0, 1, 2)).toBe(1); }); it("is monotonically non-decreasing", () => { let prev = -Infinity; for (let x = -0.2; x <= 1.2; x += 0.1) { const v = smoothstep(0, 1, x); expect(v).toBeGreaterThanOrEqual(prev); prev = v; } }); it("guards against equal edges (no NaN)", () => { expect(Number.isNaN(smoothstep(1, 1, 1))).toBe(false); }); }); describe("optimization/math — damp()", () => { it("does not move when dt is 0", () => { expect(damp(3, 10, 5, 0)).toBe(3); }); it("moves toward the target and converges with large lambda*dt", () => { const once = damp(0, 10, 1, 0.5); expect(once).toBeGreaterThan(0); expect(once).toBeLessThan(10); expect(damp(0, 10, 50, 1)).toBeCloseTo(10, 5); }); }); describe("optimization/math — seeded()", () => { it("is deterministic for a given input", () => { expect(seeded(7)).toBe(seeded(7)); }); it("returns values within [0,1)", () => { for (let i = 0; i < 200; i++) { const v = seeded(i); expect(v).toBeGreaterThanOrEqual(0); expect(v).toBeLessThan(1); } }); it("produces different values for different seeds", () => { expect(seeded(1)).not.toBe(seeded(2)); }); });