aboutsummaryrefslogtreecommitdiff
path: root/internal/game/quit_casino_test.go
diff options
context:
space:
mode:
Diffstat (limited to 'internal/game/quit_casino_test.go')
-rw-r--r--internal/game/quit_casino_test.go112
1 files changed, 112 insertions, 0 deletions
diff --git a/internal/game/quit_casino_test.go b/internal/game/quit_casino_test.go
index a62e9cf..f055e07 100644
--- a/internal/game/quit_casino_test.go
+++ b/internal/game/quit_casino_test.go
@@ -150,6 +150,118 @@ func TestStopCancelsQuit(t *testing.T) {
}
}
+// Plain quit mid-round points the player at "quit now" and its forfeit.
+func TestQuitMidRoundMentionsQuitNow(t *testing.T) {
+ g, sess := quitTestGame(t)
+ cfg := casino.TableConfig{ID: "blackjack", Game: casino.GameBlackjack, MinBet: 1, MaxBet: 100}
+ g.Casino.Join(1, cfg, "alice")
+ g.Casino.Join(1, cfg, "bob")
+ g.Casino.Bet(1, "blackjack", "alice", "", 10, casinoWallet{g: g, p: sess.Player})
+ conn := sess.Conn.(*casinoTestConn)
+
+ conn.data = nil
+ g.doQuit(sess)
+
+ if !strings.Contains(string(conn.data), `"quit now"`) || !strings.Contains(string(conn.data), "forfeit") {
+ t.Fatalf("expected a quit-now reminder with the forfeit warning, got %q", string(conn.data))
+ }
+}
+
+// "quit now" starts the logout countdown while the player keeps their seat
+// and wager; the stake is forfeited and the seat freed only on the final
+// tick, immediately before the disconnect.
+func TestQuitNowForfeitsOnlyAtLogout(t *testing.T) {
+ g, sess := quitTestGame(t)
+ sess.Account = &player.Account{Name: "alice"}
+ cfg := casino.TableConfig{ID: "blackjack", Game: casino.GameBlackjack, MinBet: 1, MaxBet: 100}
+ g.Casino.Join(1, cfg, "alice")
+ g.Casino.Join(1, cfg, "bob")
+ g.Casino.Bet(1, "blackjack", "alice", "", 10, casinoWallet{g: g, p: sess.Player})
+ wallet := sess.Player
+
+ g.doQuitNow(sess)
+
+ // Still seated, still committed, countdown running.
+ if _, playing := g.Casino.Participation("alice"); !playing {
+ t.Fatal("quit now freed the seat before the logout tick")
+ }
+ if !g.quitResting("alice") {
+ t.Fatal("quit now did not start the rest countdown")
+ }
+
+ // Drive the countdown to its final tick (fires on the 11th engine tick).
+ for i := 0; i < 15 && sess.Player != nil; i++ {
+ g.Ticks.Tick()
+ }
+ if _, playing := g.Casino.Participation("alice"); playing {
+ t.Fatal("quit now did not free the seat at the logout tick")
+ }
+ // Alice's stake was debited when she bet and never refunded or paid: the
+ // forfeit. Bob remains seated with his round untouched.
+ if wallet.Credits != 990 {
+ t.Fatalf("alice's credits were disturbed by the forfeit: %d", wallet.Credits)
+ }
+ if _, playing := g.Casino.Participation("bob"); !playing {
+ t.Fatal("quit now removed the wrong player")
+ }
+ if sess.Player != nil || sess.State != net.StateMenu {
+ t.Fatal("quit now did not log the player out")
+ }
+ if _, stillLoggedIn := g.loggedInChars["alice"]; stillLoggedIn {
+ t.Fatal("quit now did not remove the session from the logged-in map")
+ }
+ if g.quitResting("alice") {
+ t.Fatal("countdown timer was not cleared after logout")
+ }
+}
+
+// Until the logout tick, "stop" cancels a pending quit-now and leaves the
+// wager intact: the player keeps their seat mid-round.
+func TestQuitNowCancelledByStopMidRound(t *testing.T) {
+ g, sess := quitTestGame(t)
+ cfg := casino.TableConfig{ID: "blackjack", Game: casino.GameBlackjack, MinBet: 1, MaxBet: 100}
+ g.Casino.Join(1, cfg, "alice")
+ g.Casino.Join(1, cfg, "bob")
+ g.Casino.Bet(1, "blackjack", "alice", "", 10, casinoWallet{g: g, p: sess.Player})
+
+ g.doQuitNow(sess)
+ g.executeStop(sess, nil, "stop")
+
+ if g.quitResting("alice") {
+ t.Fatal("stop did not cancel the pending quit-now countdown")
+ }
+ if _, playing := g.Casino.Participation("alice"); !playing {
+ t.Fatal("cancelled quit-now still freed the seat")
+ }
+ // The wager is still committed after the cancellation.
+ if events := g.Casino.Leave(1, "blackjack", "alice"); len(events) == 0 || !strings.Contains(events[0].Message, "middle of a blackjack round") {
+ t.Fatalf("wager was not still committed after the cancelled quit-now: %+v", events)
+ }
+}
+
+// A quit-now at a machine also holds the machine until the logout tick.
+func TestQuitNowAtMachineHoldsUntilLogout(t *testing.T) {
+ g, sess := quitTestGame(t)
+ sess.Account = &player.Account{Name: "alice"}
+ cfg := casino.MachineConfig{ID: "slots", Game: casino.GameSlots, MinBet: 1, MaxBet: 100}
+ g.Casino.JoinMachine(1, cfg, "alice")
+
+ g.doQuitNow(sess)
+
+ if _, playing := g.Casino.Participation("alice"); !playing {
+ t.Fatal("quit now freed the machine before the logout tick")
+ }
+ for i := 0; i < 15 && sess.Player != nil; i++ {
+ g.Ticks.Tick()
+ }
+ if _, playing := g.Casino.Participation("alice"); playing {
+ t.Fatal("quit now did not free the machine at the logout tick")
+ }
+ if sess.Player != nil || sess.State != net.StateMenu {
+ t.Fatal("quit now did not log the player out")
+ }
+}
+
// Stop and quit share one departure path: both refuse mid-round and both
// leave gracefully between rounds.
func TestStopMatchesQuitCasinoPolicy(t *testing.T) {