aboutsummaryrefslogtreecommitdiff
path: root/internal/casino/manager_test.go
blob: 818f3978c9e52ed5c4650a9d7ada590b7b851bc8 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
package casino

import "testing"

type testWallet struct {
	chips, credits, paid int
}

func (w *testWallet) Wager(amount int) (Wager, bool) {
	if w.chips+w.credits < amount {
		return Wager{}, false
	}
	chips := amount
	if chips > w.chips {
		chips = w.chips
	}
	w.chips -= chips
	credits := amount - chips
	w.credits -= credits
	return Wager{Total: amount, Chips: chips, Credits: credits}, true
}

func (w *testWallet) PayCredits(amount int) {
	w.paid += amount
}

func TestMixedWagerUsesChipsFirst(t *testing.T) {
	w := &testWallet{chips: 7, credits: 50}
	wager, ok := w.Wager(12)
	if !ok || wager.Chips != 7 || wager.Credits != 5 || w.chips != 0 || w.credits != 45 {
		t.Fatalf("unexpected wager: %+v wallet=%+v", wager, w)
	}
}

func TestSoloBetResolvesImmediately(t *testing.T) {
	m := NewManager(1)
	cfg := TableConfig{ID: "slots", Game: GameSlots}
	m.Join(1, cfg, "alice")
	w := &testWallet{credits: 100}
	events := m.Bet(1, "slots", "alice", "", 10, w)
	found := false
	for _, event := range events {
		if event.Type == EventRoundStarted {
			found = true
		}
	}
	if !found {
		t.Fatal("solo bet did not resolve immediately")
	}
}

func TestMultiplePlayersWaitForBets(t *testing.T) {
	m := NewManager(1)
	cfg := TableConfig{ID: "slots", Game: GameSlots, BettingTicks: 2}
	m.Join(1, cfg, "alice")
	m.Join(1, cfg, "bob")
	wa, wb := &testWallet{credits: 100}, &testWallet{credits: 100}
	events := m.Bet(1, "slots", "alice", "", 10, wa)
	for _, event := range events {
		if event.Type == EventRoundStarted {
			t.Fatal("round started before all players bet or timeout")
		}
	}
	m.Bet(1, "slots", "bob", "", 10, wb)
}

func TestTableBettingIgnoresDisconnected(t *testing.T) {
	m := NewManager(1)
	cfg := TableConfig{ID: "slots", Game: GameSlots, BettingTicks: 20}
	m.Join(1, cfg, "alice")
	m.Join(1, cfg, "bob")
	m.MarkDisconnected("bob")
	w := &testWallet{credits: 100}
	events := m.Bet(1, "slots", "alice", "", 10, w)
	found := false
	for _, event := range events {
		if event.Type == EventRoundStarted {
			found = true
		}
	}
	if !found {
		t.Fatal("disconnected player stalled the table's round")
	}
}

func TestMachineAutobetCountdownAndStop(t *testing.T) {
	m := NewManager(1)
	cfg := MachineConfig{ID: "slots", Game: GameSlots, SpinTicks: 1}
	m.JoinMachine(1, cfg, "alice")
	w := &testWallet{credits: 100}
	if events := m.SetMachineBet(1, "slots", "alice", 10, w); len(events) == 0 {
		t.Fatalf("setting a bet did not start a spin: %+v", events)
	}
	for m.MachineBusy("alice") {
		m.Tick()
	}
	if events := m.EnableMachineAutoBet(1, "slots", "alice", w); len(events) != 0 {
		t.Fatalf("enabling autobet emitted events before countdown: %+v", events)
	}
	for i, want := range []string{"Autobet enabled!", `Type "stop" to stop playing`, "Betting... 10 credits."} {
		events := m.Tick()
		if len(events) == 0 || eventText(events) != want {
			t.Fatalf("tick %d message=%q events=%+v, want %q", i+1, eventText(events), events, want)
		}
	}
	if !m.MachineBusy("alice") {
		t.Fatal("autobet did not start a spin after countdown")
	}
	if events, stopped := m.StopMachineAutoBet(1, "slots", "alice"); !stopped || len(events) != 1 {
		t.Fatalf("stop autobet events=%+v stopped=%v", events, stopped)
	}
	if _, playing := m.MachineFor("alice"); !playing {
		t.Fatal("stopping autobet removed the player from the machine")
	}
}

func eventText(events []Event) string {
	for _, event := range events {
		if event.PrivateMessage != "" {
			return event.PrivateMessage
		}
		if event.Message != "" {
			return event.Message
		}
	}
	return ""
}