diff options
| author | historia <[not public]> | 2026-09-18 05:31:09 -0400 |
|---|---|---|
| committer | historia <[not public]> | 2026-09-18 05:31:09 -0400 |
| commit | 153acb7f644d755c45533b7c5311e3ffa47e8973 (patch) | |
| tree | 7645e6f7b65bc3830b078e3b9336d2e6b199d584 /internal/game/hardening_casino_quit_autobet_test.go | |
| parent | 87d08f0151e643951769e323995f1c5ed89ee200 (diff) | |
| download | thehouseoficarus-153acb7f644d755c45533b7c5311e3ffa47e8973.tar.gz | |
fix: harden engine across casino, economy, concurrency, security, and content
Diffstat (limited to 'internal/game/hardening_casino_quit_autobet_test.go')
| -rw-r--r-- | internal/game/hardening_casino_quit_autobet_test.go | 75 |
1 files changed, 75 insertions, 0 deletions
diff --git a/internal/game/hardening_casino_quit_autobet_test.go b/internal/game/hardening_casino_quit_autobet_test.go new file mode 100644 index 0000000..34f36e7 --- /dev/null +++ b/internal/game/hardening_casino_quit_autobet_test.go @@ -0,0 +1,75 @@ +package game + +import ( + "strings" + "testing" + + "thehouseoficarus/internal/casino" +) + +// Quitting at a slot machine must take one command: a machine between spins +// has no committed stake, so "quit" stops autobet AND frees the seat instead +// of reporting the player as still playing (the old flow needed a second +// quit and warned about a forfeit that could not happen). + +func TestQuitAtMachineStopsAutobetAndLeavesInOneAttempt(t *testing.T) { + g, sess := quitTestGame(t) + cfg := casino.MachineConfig{ID: "slots", Game: casino.GameSlots, MinBet: 1, MaxBet: 100, SpinTicks: 1} + g.Casino.JoinMachine(1, cfg, "alice") + wallet := casinoWallet{g: g, p: sess.Player} + if events := g.Casino.SetMachineBet(1, "slots", "alice", 10, wallet); len(events) == 0 { + t.Fatal("bet produced no events") + } + // Let the bet's spin finish: the machine is now between spins. + for i := 0; i < 30 && g.Casino.MachineBusy("alice"); i++ { + g.Casino.Tick() + } + if events := g.Casino.EnableMachineAutoBet(1, "slots", "alice", wallet); len(events) != 0 { + t.Fatalf("enabling autobet emitted events: %+v", events) + } + + conn := sess.Conn.(*casinoTestConn) + conn.data = nil + g.doQuit(sess) + out := string(conn.data) + + if !g.quitResting() { + t.Fatalf("quit between spins did not start the rest countdown: %q", out) + } + if _, playing := g.Casino.Participation("alice"); playing { + t.Fatalf("quit left the player at the machine, requiring a second quit: %q", out) + } + if !strings.Contains(out, "Autobet stopped") { + t.Fatalf("quit did not stop autobet: %q", out) + } + if strings.Contains(out, "WARNING") || strings.Contains(out, "forfeit") { + t.Fatalf("quit warned about a stake that does not exist: %q", out) + } +} + +// A machine mid-spin really does hold a committed stake, so quit must still +// refuse it (with the forfeit warning) rather than silently discard the spin. +func TestQuitMidSpinStillWarnsAboutTheCommittedStake(t *testing.T) { + g, sess := quitTestGame(t) + cfg := casino.MachineConfig{ID: "slots", Game: casino.GameSlots, MinBet: 1, MaxBet: 100, SpinTicks: 50} + g.Casino.JoinMachine(1, cfg, "alice") + wallet := casinoWallet{g: g, p: sess.Player} + if events := g.Casino.SetMachineBet(1, "slots", "alice", 10, wallet); len(events) == 0 { + t.Fatal("bet produced no events") + } + + conn := sess.Conn.(*casinoTestConn) + conn.data = nil + g.doQuit(sess) + out := string(conn.data) + + if g.quitResting() { + t.Fatal("quit started the countdown with a spin in flight") + } + if _, playing := g.Casino.Participation("alice"); !playing { + t.Fatal("quit freed the machine mid-spin") + } + if !strings.Contains(out, "forfeit") { + t.Fatalf("expected the forfeit warning for a committed stake, got %q", out) + } +} |
