aboutsummaryrefslogtreecommitdiff
path: root/internal/game/render_roulette_tracker_test.go
diff options
context:
space:
mode:
Diffstat (limited to 'internal/game/render_roulette_tracker_test.go')
-rw-r--r--internal/game/render_roulette_tracker_test.go120
1 files changed, 120 insertions, 0 deletions
diff --git a/internal/game/render_roulette_tracker_test.go b/internal/game/render_roulette_tracker_test.go
new file mode 100644
index 0000000..3bae930
--- /dev/null
+++ b/internal/game/render_roulette_tracker_test.go
@@ -0,0 +1,120 @@
+package game
+
+import (
+ "strings"
+ "testing"
+
+ "thehouseoficarus/internal/casino"
+ "thehouseoficarus/internal/color"
+ "thehouseoficarus/internal/net"
+ "thehouseoficarus/internal/player"
+)
+
+func TestRouletteTrackerFormats(t *testing.T) {
+ for _, mode := range []string{"none", "ansi", "xterm256"} {
+ for _, unicode := range []bool{false, true} {
+ for _, history := range [][]string{nil, {"0"}, {"1", "2", "00", "1", "36", "00", "36", "36", "2", "0"}} {
+ s := &casino.RouletteSnapshot{DoubleZero: true, History: history}
+ art := renderRouletteTracker(s, mode, unicode)
+ rows := strings.Split(art, "\n")
+ if len(rows) != 5 {
+ t.Fatalf("tracker has %d rows", len(rows))
+ }
+ for _, row := range rows {
+ if color.VisibleLen(row) != 74 {
+ t.Errorf("tracker row width %d: %q", color.VisibleLen(row), plainRoulette(row))
+ }
+ if !unicode {
+ for _, r := range plainRoulette(row) {
+ if r > 127 {
+ t.Errorf("non-ASCII rune %q", r)
+ }
+ }
+ }
+ }
+ if mode == "none" && strings.Contains(art, "\x1b") {
+ t.Fatal("color disabled but ANSI present")
+ }
+ if mode != "none" {
+ for _, bg := range []int{0, 1, 2} {
+ if !strings.Contains(art, color.BgCode(mode, bg)) {
+ t.Errorf("missing color %d", bg)
+ }
+ }
+ }
+ plain := plainRoulette(art)
+ if strings.Contains(plain, "History, not odds") {
+ t.Fatal("tracker should not carry the removed caption")
+ }
+ if len(history) == 0 {
+ for _, want := range []string{"last 0 spins", "awaiting the first spin", "Hot: --", "Cold: --", "Red --", "Black --"} {
+ if !strings.Contains(plain, want) {
+ t.Errorf("missing %q", want)
+ }
+ }
+ }
+ }
+ }
+ }
+}
+
+func TestRouletteTrackerStatistics(t *testing.T) {
+ s := &casino.RouletteSnapshot{DoubleZero: true, History: []string{"1", "2", "00", "1", "36", "00", "36", "36", "2", "0"}}
+ plain := plainRoulette(renderRouletteTracker(s, "none", true))
+ for _, want := range []string{"last 10 spins", "Red 50.0%", "Black 20.0%", "Zero 30.0%", "Hot: 36R (3) 00G (2) 1R (2)", "Cold: 3R (0) 4B (0) 5R (0)"} {
+ if !strings.Contains(strings.Join(strings.Fields(plain), " "), want) {
+ t.Errorf("missing %q:\n%s", want, plain)
+ }
+ }
+ // Only the newest eight, newest on the left, and 00 stays distinct from 0.
+ recent := strings.Split(plain, "\n")[1]
+ hits := racetrackNumbers(recent)
+ if got := strings.Join(hits, ","); got != "0,2,36,36,00,36,1,00" {
+ t.Errorf("recent hits: %s", got)
+ }
+ // Unhit pockets aren't called hot. Cold tie order includes 00 only on
+ // American wheels; it is not silently merged with zero.
+ s.History = []string{"0"}
+ if line := strings.Split(renderRouletteTracker(s, "none", false), "\n")[2]; !strings.Contains(strings.Join(strings.Fields(line), " "), "Hot: 0G (1) | Cold: 00G (0)") {
+ t.Errorf("zero ranking: %s", line)
+ }
+ s.DoubleZero = false
+ if strings.Contains(renderRouletteTracker(s, "none", false), "00G") {
+ t.Fatal("European tracker contains 00")
+ }
+}
+
+func TestRouletteTrackerAboveBettingBoardsOnly(t *testing.T) {
+ for _, racetrack := range []bool{false, true} {
+ s := &casino.RouletteSnapshot{Racetrack: racetrack, Phase: "betting", History: []string{"17"}, Wheel: casino.WheelOrder(false)}
+ art := renderRouletteSnapshot(s, "none", true, 7)
+ tracker := renderRouletteTracker(s, "none", true)
+ if !strings.HasPrefix(art, tracker+"\n") {
+ t.Fatal("tracker not above board")
+ }
+ for _, phase := range []string{"playing", "result"} {
+ s.Phase = phase
+ s.Pockets = [5]string{"25", "17", "34", "6", "27"}
+ if strings.Contains(renderRouletteSnapshot(s, "none", true, 7), "History:") {
+ t.Fatalf("tracker appeared during %s", phase)
+ }
+ }
+ }
+}
+
+func TestRouletteRulesUseLiveHistory(t *testing.T) {
+ g := &Game{Casino: casino.NewManager(7)}
+ p := player.New("alice")
+ p.RoomID, p.Credits = 1, 100
+ p.Options = map[string]any{"color": "none", "unicode": true}
+ sess := &net.Session{Player: p}
+ cfg := casino.TableConfig{ID: "r", Game: casino.GameRoulette, BettingTicks: 1, Roulette: casino.RouletteConfig{SpinTicks: 1}}
+ g.Casino.Join(1, cfg, p.Name)
+ g.Casino.Bet(1, "r", p.Name, "red", 1, casinoWallet{g: g, p: p, saveCharacter: func(*player.Player) error { return nil }})
+ g.Casino.Tick()
+ g.Casino.Tick()
+ art := g.renderCasinoRules(sess, cfg)
+ if !strings.Contains(art, "History: last 1 spin") || strings.Contains(art, "awaiting the first spin") {
+ t.Fatalf("rules did not show live history:\n%s", art)
+ }
+}