import { describe, expect, test } from "bun:test" import { RoomManager, type BlindtestTrack } from "../../../rooms" import type { RoundContext } from "../../round" import { BlindtestRound } from "./blindtest-round" import { prepareBlindtestForRoom } from "./pool" import { fuzzyMatch, normalize } from "../../match" function track(submittedBy: string): BlindtestTrack { return { id: "t1", youtubeId: "abc12345678", url: "https://youtu.be/abc12345678", title: "The Legend of Zelda Main Theme", artist: "Koji Kondo", submittedBy, } } function ctxFor( room: ReturnType["room"], t: BlindtestTrack, mode: "title_artist" | "who_added" | "mixed" ): RoundContext { room.settings.blindtestMode = mode return { room, djId: null, votes: new Map(), startedAt: 0, endsAt: 10_000, data: { track: t }, } } describe("match", () => { test("normalize retire accents/ponctuation/casse", () => { expect(normalize("Pokémon: Rouge & Bleu!")).toBe("pokemon rouge bleu") }) test("fuzzyMatch tolère fautes et réponses partielles", () => { expect(fuzzyMatch("zelda", "The Legend of Zelda")).toBe(true) expect(fuzzyMatch("koji kondo", "Koji Kondo")).toBe(true) expect(fuzzyMatch("mario", "The Legend of Zelda")).toBe(false) }) }) describe("BlindtestRound", () => { test("start : le DJ est un humain connecté (le contributeur peut tomber DJ)", () => { const rooms = new RoomManager() const { room, player: a } = rooms.create("Alice", "sa") const { player: b } = rooms.join(room.code, "Bob", "sb") room.blindtestTracks = [track(a.id)] prepareBlindtestForRoom(room) const round = new BlindtestRound() const start = round.start(room) // N'importe quel humain (Alice incluse), jamais un bot ni null. expect([a.id, b.id]).toContain(start.djId!) expect(start.payload).toEqual({ trackId: "t1", youtubeId: "abc12345678" }) }) test("start : un bot n'est jamais DJ", () => { const rooms = new RoomManager() const { room, player: a } = rooms.create("Alice", "sa") rooms.addBot(room) rooms.addBot(room) room.blindtestTracks = [track(a.id)] prepareBlindtestForRoom(room) const round = new BlindtestRound() // Alice est la seule humaine → DJ forcément Alice (les bots sont exclus). expect(round.start(room).djId).toBe(a.id) }) test("who_added : le contributeur gagne par tromperie (mauvaises devinettes)", () => { const rooms = new RoomManager() const { room, player: a } = rooms.create("Alice", "sa") const { player: b } = rooms.join(room.code, "Bob", "sb") const { player: c } = rooms.join(room.code, "Carol", "sc") const t = track(a.id) // Alice = contributrice/DJ const round = new BlindtestRound() const ctx = ctxFor(room, t, "who_added") round.submitAnswer(ctx, b.id, { guessedPlayerId: c.id }) // faux round.submitAnswer(ctx, c.id, { guessedPlayerId: a.id }) // juste round.submitAnswer(ctx, a.id, { guessedPlayerId: b.id }) // contributrice : non scorée const deltas = round.score(ctx) // Carol devine juste → 100 ; Alice trompe Bob (1 mauvaise devinette) → 50 expect(deltas).toContainEqual({ playerId: c.id, delta: 100 }) expect(deltas).toContainEqual({ playerId: a.id, delta: 50 }) expect(deltas.find((d) => d.playerId === b.id)).toBeUndefined() }) test("who_added : points si on devine le bon contributeur", () => { const rooms = new RoomManager() const { room, player: a } = rooms.create("Alice", "sa") const { player: b } = rooms.join(room.code, "Bob", "sb") const t = track(a.id) const round = new BlindtestRound() const ctx = ctxFor(room, t, "who_added") round.submitAnswer(ctx, b.id, { guessedPlayerId: a.id }) // juste const deltas = round.score(ctx) expect(deltas).toEqual([{ playerId: b.id, delta: 100 }]) }) test("title_artist : 60 titre + 40 artiste, fuzzy", () => { const rooms = new RoomManager() const { room, player: a } = rooms.create("Alice", "sa") const { player: b } = rooms.join(room.code, "Bob", "sb") const t = track(a.id) const round = new BlindtestRound() const ctx = ctxFor(room, t, "title_artist") round.submitAnswer(ctx, b.id, { title: "zelda", artist: "koji kondo" }) const { perPlayerResult } = round.reveal(ctx) expect(perPlayerResult[b.id]).toMatchObject({ titleCorrect: true, artistCorrect: true, points: 100, }) expect(round.score(ctx)).toEqual([{ playerId: b.id, delta: 100 }]) }) test("le contributeur ne marque pas sur son propre titre", () => { const rooms = new RoomManager() const { room, player: a } = rooms.create("Alice", "sa") const t = track(a.id) const round = new BlindtestRound() const ctx = ctxFor(room, t, "who_added") round.submitAnswer(ctx, a.id, { guessedPlayerId: a.id }) expect(round.score(ctx)).toEqual([]) }) test("reveal expose le titre, l'artiste et le contributeur", () => { const rooms = new RoomManager() const { room, player: a } = rooms.create("Alice", "sa") const t = track(a.id) const round = new BlindtestRound() const ctx = ctxFor(room, t, "title_artist") const { truth } = round.reveal(ctx) expect(truth.submittedBy).toBe(a.id) expect(truth.submittedByName).toBe("Alice") expect(truth.title).toBe("The Legend of Zelda Main Theme") }) })