diff options
| author | historia <[not public]> | 2026-10-10 04:08:09 -0400 |
|---|---|---|
| committer | historia <[not public]> | 2026-10-10 04:08:09 -0400 |
| commit | 9fb1f9010526100e12dd1ab1b0ca98401bb6ed75 (patch) | |
| tree | 4a128211bfb0dd429bbb559a591d6c4be25c7757 /internal/game/crazy_time_test.go | |
| parent | ced77d7c89129da6ba4001ab8e3dad265aa41396 (diff) | |
| download | thehouseoficarus-main.tar.gz | |
Diffstat (limited to 'internal/game/crazy_time_test.go')
| -rw-r--r-- | internal/game/crazy_time_test.go | 193 |
1 files changed, 193 insertions, 0 deletions
diff --git a/internal/game/crazy_time_test.go b/internal/game/crazy_time_test.go new file mode 100644 index 0000000..2c07862 --- /dev/null +++ b/internal/game/crazy_time_test.go @@ -0,0 +1,193 @@ +package game + +import ( + "strings" + "testing" + + "thehouseoficarus/internal/casino" +) + +func crazyTimeRoom() string { + return "name: Crazy Time Coliseum\ncasino_tables:\n - id: crazy_time\n game: crazy_time\n min_bet: 1\n max_bet: 1000\n" +} + +func TestCrazyTimePlayAliasAndMenu(t *testing.T) { + g, s, conn := casinoCrapsGame(t, crazyTimeRoom()) + s.Player.Options = map[string]any{"color": "none", "casino_hints": "on"} + g.executePlay(s, []string{"crazy", "time"}, "play crazy time") + table, ok := g.Casino.Participation(s.Player.Name) + if !ok || table == nil || table.Config.Game != casino.GameCrazyTime { + t.Fatal("Crazy Time alias did not seat the player") + } + text := stripANSI(string(conn.data)) + if !strings.Contains(text, "CRAZY TIME") { + t.Fatalf("join output missing the game: %q", text) + } + if !strings.Contains(text, "bet N on BET") { + t.Fatalf("join output missing the bet hint: %q", text) + } + if !strings.Contains(text, "98") { + t.Fatalf("join output missing the RTP: %q", text) + } + conn.data = nil + g.executeRules(s, nil, "rules") + if help := stripANSI(string(conn.data)); !strings.Contains(help, "CRAZY TIME") || !strings.Contains(help, "TOP SLOT") { + t.Fatalf("rules did not open the Crazy Time page: %q", help) + } +} + +func TestCrazyTimeListCommand(t *testing.T) { + g, s, conn := casinoCrapsGame(t, crazyTimeRoom()) + s.Player.Options = map[string]any{"color": "none"} + g.executePlay(s, []string{"crazy time"}, "play crazy time") + conn.data = nil + g.executeList(s, nil, "list") + text := stripANSI(string(conn.data)) + for _, want := range []string{"COIN FLIP", "CASH HUNT", "PACHINKO", "CRAZY TIME", "ALL"} { + if !strings.Contains(text, want) { + t.Fatalf("list missing %s: %q", want, text) + } + } +} + +func TestCrazyTimePlayAndSpin(t *testing.T) { + g, s, conn := casinoCrapsGame(t, crazyTimeRoom()) + s.Player.Options = map[string]any{"color": "none", "casino_hints": "on"} + g.executePlay(s, []string{"crazy time"}, "play crazy time") + conn.data = nil + g.executeBet(s, []string{"5", "on", "cash", "hunt"}, "bet 5 on cash hunt") + if len(s.Player.PendingWagers) != 1 { + t.Fatalf("bet not committed: %+v", s.Player.PendingWagers) + } + if !strings.Contains(stripANSI(string(conn.data)), "CASH HUNT") { + t.Fatalf("bet confirmation missing the target: %q", conn.data) + } + // Spin and drive the whole round (main wheel plus any bonus) to a receipt. + conn.data = nil + g.executeTableAction(s, "spin") + for i := 0; i < 2000 && len(s.Player.PendingWagers) > 0; i++ { + g.CasinoTick() + } + if len(s.Player.PendingWagers) != 0 { + t.Fatalf("round never settled: %+v", s.Player.PendingWagers) + } +} + +func TestCrazyTimeRendering(t *testing.T) { + for _, mode := range []string{"none", "ansi", "xterm256"} { + for _, unicode := range []bool{false, true} { + wheel := &casino.CrazyTimeSnapshot{ + Phase: "result", + Pockets: []string{"1", "2", "5", "10", "COIN FLIP", "CASH HUNT", "PACHINKO", "CRAZY TIME", "1", "2", "5"}, + TopSymbol: "CASH HUNT", + TopMult: 5, + } + rendered := renderCrazyTime(wheel, mode, unicode, false, 0) + if mode == "none" && strings.Contains(rendered, "\x1b") { + t.Fatalf("plain wheel has ANSI escapes: %q", rendered) + } + plain := stripANSI(rendered) + if !strings.Contains(plain, "CASH") || !strings.Contains(plain, "x5") { + t.Fatalf("wheel missing symbol/top multiplier: %q", plain) + } + + bonus := &casino.CrazyTimeSnapshot{ + Phase: "bonus", + Bonus: &casino.CrazyTimeBonusView{ + Kind: casino.CrazyTimeBonusPachinko, + Phase: "result", + PachoPockets: []int{10, 20, -1, 5, 50, 100, 25, 15, 7, 10, 20, 5, 50, 100, 25, 15}, + PachoRow: 16, + PachoLane: 4, + }, + } + rendered = renderCrazyTime(bonus, mode, unicode, false, 0) + if plain := stripANSI(rendered); !strings.Contains(plain, "DBL") || !strings.Contains(plain, "100") { + t.Fatalf("pachinko bonus missing prizes: %q", plain) + } + + coin := &casino.CrazyTimeSnapshot{ + Phase: "bonus", + Bonus: &casino.CrazyTimeBonusView{Kind: casino.CrazyTimeBonusCoinFlip, Phase: "result", CoinLow: 3, CoinHigh: 25, CoinSide: "blue", CoinValue: 25, CoinResult: true}, + } + if plain := stripANSI(renderCrazyTime(coin, mode, unicode, false, 0)); !strings.Contains(plain, "25x") { + t.Fatalf("coin flip bonus missing value: %q", plain) + } + + hunt := &casino.CrazyTimeSnapshot{ + Phase: "bonus", + Bonus: &casino.CrazyTimeBonusView{Kind: casino.CrazyTimeBonusCashHunt, Phase: "result", HuntFinal: []int{2, 5, 10, 25, 50, 100, 500, 15, 20, 2, 5, 10}, HuntPick: 3}, + } + if plain := stripANSI(renderCrazyTime(hunt, mode, unicode, false, 0)); !strings.Contains(plain, "TILE 4") { + t.Fatalf("cash hunt bonus missing the pick: %q", plain) + } + + ct := &casino.CrazyTimeSnapshot{ + Phase: "bonus", + Bonus: &casino.CrazyTimeBonusView{ + Kind: casino.CrazyTimeBonusWheel, + Phase: "result", + CTWheel: []int{10, 15, 20, 25, 50, 100, -1, 10, 15, 20, 25, 50, 100, 10, 15}, + CTOffset: 0, + CTPick: 1, + CTResult: true, + CTValue: 25, + }, + } + if plain := stripANSI(renderCrazyTime(ct, mode, unicode, false, 0)); !strings.Contains(plain, "POINTER") { + t.Fatalf("crazy wheel bonus missing the result: %q", plain) + } + } + } +} + +func TestCrazyTimeBlockedVerbsDoNotLeak(t *testing.T) { + g, s, _ := casinoCrapsGame(t, crazyTimeRoom()) + s.Player.Options = map[string]any{"color": "none"} + g.executePlay(s, []string{"crazy time"}, "play crazy time") + // "sp" must abbreviate to spin, not split (blackjack) or an unknown verb. + got, ok := g.casinoAbbreviation(s, "sp") + if !ok || got != "spin" { + t.Fatalf("sp resolved to %q,%v; want spin", got, ok) + } +} + +func TestCrazyTimeBetOmitsBalanceAndResultShowsItOnce(t *testing.T) { + g, s, conn := casinoCrapsGame(t, crazyTimeRoom()) + s.Player.Options = map[string]any{"color": "none", "casino_hints": "on"} + g.executePlay(s, []string{"crazy time"}, "play crazy time") + conn.data = nil + g.executeBet(s, []string{"5", "on", "all"}, "bet 5 on all") + out := stripANSI(string(conn.data)) + if strings.Contains(out, "Available") { + t.Fatalf("bet printed the wallet: %q", out) + } + if !strings.Contains(out, "all four minigames") { + t.Fatalf("ALL bet not confirmed: %q", out) + } + conn.data = nil + g.executeTableAction(s, "spin") + for i := 0; i < 3000 && len(s.Player.PendingWagers) > 0; i++ { + g.CasinoTick() + } + if len(s.Player.PendingWagers) != 0 { + t.Fatal("round never settled") + } + out = stripANSI(string(conn.data)) + if got := strings.Count(out, "Available "); got != 1 { + t.Fatalf("result printed the wallet %d times, want 1: %q", got, out) + } +} + +func TestCrazyTimeTopSlotOnlyOnResult(t *testing.T) { + pockets := []string{"1", "2", "5", "10", "COIN FLIP", "CASH HUNT", "PACHINKO", "CRAZY TIME", "1", "2", "5"} + spin := &casino.CrazyTimeSnapshot{Phase: "spinning", Pockets: pockets, TopSymbol: "CASH HUNT", TopMult: 5} + if plain := stripANSI(renderCrazyTime(spin, "none", false, false, 0)); strings.Contains(plain, "TOP SLOT") { + t.Fatalf("spinning wheel printed TOP SLOT: %q", plain) + } + result := &casino.CrazyTimeSnapshot{Phase: "result", Pockets: pockets, TopSymbol: "CASH HUNT", TopMult: 5} + plain := stripANSI(renderCrazyTime(result, "none", false, false, 0)) + if !strings.Contains(plain, "TOP SLOT") || !strings.Contains(plain, "x5") { + t.Fatalf("result wheel omitted the Top Slot: %q", plain) + } +} |
