Spaces:
Running on CPU Upgrade
Running on CPU Upgrade
| import { describe, expect, test } from "bun:test"; | |
| import { | |
| BASE_ELO, | |
| ELO_K, | |
| ESTABLISHED_THRESHOLD, | |
| RANK_THRESHOLD, | |
| applyElo, | |
| eloChange, | |
| expectedScore, | |
| isEstablished, | |
| isRanked, | |
| tierFor, | |
| } from "./elo"; | |
| describe("isEstablished", () => { | |
| test("flips at the established threshold", () => { | |
| expect(isEstablished(ESTABLISHED_THRESHOLD - 1)).toBe(false); | |
| expect(isEstablished(ESTABLISHED_THRESHOLD)).toBe(true); | |
| expect(isEstablished(0)).toBe(false); | |
| expect(isEstablished(10_000)).toBe(true); | |
| }); | |
| }); | |
| describe("constants match upstream", () => { | |
| test("base, k-factor, and ranking threshold", () => { | |
| expect(BASE_ELO).toBe(1500); | |
| expect(ELO_K).toBe(2); | |
| expect(RANK_THRESHOLD).toBe(100); | |
| }); | |
| }); | |
| describe("expectedScore", () => { | |
| test("equal ratings expect 0.5", () => { | |
| expect(expectedScore(1500, 1500)).toBeCloseTo(0.5, 10); | |
| }); | |
| test("the two sides sum to 1", () => { | |
| expect(expectedScore(1700, 1300) + expectedScore(1300, 1700)).toBeCloseTo( | |
| 1, | |
| 10, | |
| ); | |
| }); | |
| test("a 400-point gap is ~0.909 favourite", () => { | |
| expect(expectedScore(1900, 1500)).toBeCloseTo(10 / 11, 6); | |
| }); | |
| }); | |
| describe("applyElo", () => { | |
| test("equal ratings: winner +k/2, loser -k/2", () => { | |
| const { winner, loser } = applyElo(1500, 1500); | |
| expect(winner).toBeCloseTo(1500 + ELO_K / 2, 10); | |
| expect(loser).toBeCloseTo(1500 - ELO_K / 2, 10); | |
| }); | |
| test("zero-sum: total rating is conserved", () => { | |
| const { winner, loser } = applyElo(1620, 1480); | |
| expect(winner + loser).toBeCloseTo(1620 + 1480, 6); | |
| }); | |
| test("beating a stronger model gains more than beating a weaker one", () => { | |
| const upset = applyElo(1400, 1600).winner - 1400; | |
| const expected = applyElo(1600, 1400).winner - 1600; | |
| expect(upset).toBeGreaterThan(expected); | |
| }); | |
| test("honors a custom k-factor", () => { | |
| expect(applyElo(1500, 1500, 32).winner).toBeCloseTo(1516, 10); | |
| }); | |
| }); | |
| describe("eloChange", () => { | |
| test("equal ratings give half the k-factor", () => { | |
| expect(eloChange(1500, 1500)).toBeCloseTo(ELO_K / 2, 10); | |
| }); | |
| test("delta stays within (0, k)", () => { | |
| for (const [w, l] of [ | |
| [1500, 1500], | |
| [1000, 2000], | |
| [2000, 1000], | |
| ] as const) { | |
| const d = eloChange(w, l); | |
| expect(d).toBeGreaterThan(0); | |
| expect(d).toBeLessThan(ELO_K); | |
| } | |
| }); | |
| }); | |
| describe("tierFor", () => { | |
| test("maps ranks to S/A/B then null", () => { | |
| expect(tierFor(1)).toBe("S"); | |
| expect(tierFor(2)).toBe("S"); | |
| expect(tierFor(3)).toBe("A"); | |
| expect(tierFor(4)).toBe("A"); | |
| expect(tierFor(5)).toBe("B"); | |
| expect(tierFor(7)).toBe("B"); | |
| expect(tierFor(8)).toBeNull(); | |
| }); | |
| }); | |
| describe("isRanked", () => { | |
| test("at least the threshold", () => { | |
| expect(isRanked(RANK_THRESHOLD)).toBe(true); | |
| expect(isRanked(RANK_THRESHOLD - 1)).toBe(false); | |
| expect(isRanked(0)).toBe(false); | |
| }); | |
| }); | |