package casino // Reconfiguration contract regressions: live rules replace only when idle; // occupied games keep their rules (and wagers); deleted rooms evict their // cached games with refunds. import "testing" func TestEnsureMachineReplacesIdleRules(t *testing.T) { m := NewManager(1) first := m.EnsureMachine(1, MachineConfig{ID: "slots", Game: GameSlots, SpinTicks: 2}) if first == nil { t.Fatal("machine not created") } // Same config: same machine. if again := m.EnsureMachine(1, MachineConfig{ID: "slots", Game: GameSlots, SpinTicks: 2}); again != first { t.Fatal("same config returned a different machine") } // Changed config while idle: live rules replaced. changed := m.EnsureMachine(1, MachineConfig{ID: "slots", Game: GameSlots, SpinTicks: 5}) if changed == first { t.Fatal("idle machine did not adopt the new configuration") } if changed.Config.SpinTicks != 5 { t.Fatalf("replacement config spin ticks = %d, want 5", changed.Config.SpinTicks) } } func TestEnsureMachineKeepsOccupiedRules(t *testing.T) { m := NewManager(1) m.EnsureMachine(1, MachineConfig{ID: "slots", Game: GameSlots, SpinTicks: 2}) m.JoinMachine(1, MachineConfig{ID: "slots", Game: GameSlots, SpinTicks: 2}, "alice") // Occupied machine: config changes do NOT replace live rules. kept := m.EnsureMachine(1, MachineConfig{ID: "slots", Game: GameSlots, SpinTicks: 9}) if kept.Config.SpinTicks != 2 { t.Fatalf("occupied machine replaced live rules: spin ticks %d", kept.Config.SpinTicks) } } func TestEnsureTableKeepsOccupiedRules(t *testing.T) { m := NewManager(1) m.Join(1, TableConfig{ID: "bj", Game: GameBlackjack, MinBet: 1, BettingTicks: 50}, "alice") // Occupied table: changed config does not replace live rules. kept := m.EnsureTable(1, TableConfig{ID: "bj", Game: GameBlackjack, MinBet: 1, BettingTicks: 3}) if kept.Config.BettingTicks != 50 { t.Fatalf("occupied table replaced live rules: betting ticks %d", kept.Config.BettingTicks) } } func TestEnsureTableReplacesIdleRules(t *testing.T) { m := NewManager(1) m.Join(1, TableConfig{ID: "bj", Game: GameBlackjack, MinBet: 1, BettingTicks: 50}, "alice") m.Leave(1, "bj", "alice") changed := m.EnsureTable(1, TableConfig{ID: "bj", Game: GameBlackjack, MinBet: 1, BettingTicks: 3}) if changed.Config.BettingTicks != 3 { t.Fatalf("idle table did not adopt new rules: betting ticks %d", changed.Config.BettingTicks) } } func TestEvictRoomRefundsAndRemovesGames(t *testing.T) { m := NewManager(1) w := &testWallet{credits: 100} m.JoinMachine(1, MachineConfig{ID: "slots", Game: GameSlots, MinBet: 1}, "alice") m.SetMachineBet(1, "slots", "alice", 10, w) if w.credits != 90 { t.Fatalf("wallet before evict = %d, want 90", w.credits) } events := m.EvictRoom(1) if w.paid != 10 { t.Fatalf("outstanding wager not refunded on evict: paid %d", w.paid) } if len(events) == 0 { t.Fatal("eviction produced no refund events") } if m.Table(1, "any") != nil { t.Fatal("stale table survived eviction") } // Re-entering the room creates a fresh game. m.JoinMachine(1, MachineConfig{ID: "slots", Game: GameSlots, MinBet: 1}, "alice") }