1import { describe, expect, it } from "vitest"
2
3import { LAYOUTS, type LayoutId } from "@/lib/layouts"
4import {
5 ghostSlotFor,
6 hostSlotIndices,
7 relaySlotsFor,
8} from "@/lib/relaySlots"
9
10/* PRD §7.3 (SE-01, SE-04, SE-05, SE-08) dan MILESTONES M8: pembagian slot
11 estafet. Fungsi murni, jadi diuji tanpa kamera maupun basis data. */
12
13describe("pembagian slot estafet", () => {
14 it("pembuat mengisi indeks genap, teman indeks ganjil, di semua layout", () => {
15 function indeks(owner: "host" | "guest", layoutId: LayoutId): number[] {
16 return relaySlotsFor(layoutId)
17 .filter((slot) => slot.owner === owner)
18 .map((slot) => slot.index)
19 }
20
21 expect(hostSlotIndices("strip-4")).toEqual([0, 2])
22 expect(indeks("guest", "strip-4")).toEqual([1, 3])
23
24 expect(hostSlotIndices("strip-3")).toEqual([0, 2])
25 expect(indeks("guest", "strip-3")).toEqual([1])
26
27 expect(hostSlotIndices("grid-2x2")).toEqual([0, 2])
28 expect(indeks("guest", "grid-2x2")).toEqual([1, 3])
29 })
30
31 it("setiap layout terbagi habis tanpa slot yang hilang atau dobel", () => {
32 for (const [id, layout] of Object.entries(LAYOUTS)) {
33 const slots = relaySlotsFor(id as keyof typeof LAYOUTS)
34 expect(slots).toHaveLength(layout.shotCount)
35 expect(slots.map((slot) => slot.index)).toEqual(
36 Array.from({ length: layout.shotCount }, (_, index) => index)
37 )
38 const host = slots.filter((slot) => slot.owner === "host")
39 const guest = slots.filter((slot) => slot.owner === "guest")
40 expect(host.length + guest.length).toBe(layout.shotCount)
41 /* SE-01: tombol estafet baru muncul setelah minimal setengah slot
42 terisi, dan pembuat selalu mengisi tepat setengahnya. */
43 expect(host.length).toBeGreaterThanOrEqual(layout.shotCount / 2)
44 }
45 })
46
47 it("bayangan pose teman selalu slot pembuat tepat sebelumnya", () => {
48 expect(ghostSlotFor(0)).toBeNull()
49 expect(ghostSlotFor(1)).toBe(0)
50 expect(ghostSlotFor(2)).toBe(1)
51 expect(ghostSlotFor(3)).toBe(2)
52 })
53})
54