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
|
package casino
import "testing"
// A disconnect must only forfeit a hand that is actually in flight. A stake
// placed in the betting window has had no card dealt for it, so refunding it
// reveals nothing; destroying it there would let an ordinary transient TCP
// drop swallow an undelt wager.
// TestBlackjackPreDealDisconnectRefundsStake: alice bets, the betting window
// is open (bob has not bet, no cards dealt), alice's socket drops. Her stake
// comes back, the wager record is resolved, and the round that follows pays
// nothing on top of the refund.
func TestBlackjackPreDealDisconnectRefundsStake(t *testing.T) {
table := newBlackjackTable(1, TableConfig{ID: "blackjack", Game: GameBlackjack, MaxPlayers: 2, BettingTicks: 3}, newTestRand())
table.join("alice")
table.join("bob")
wallet := &testWallet{credits: 100}
table.bet("alice", "", 10, wallet)
if table.phase != blackjackBetting {
t.Fatalf("setup: expected the betting window (phase=%s)", table.phase)
}
if wallet.credits != 90 {
t.Fatalf("setup: stake not committed (credits=%d)", wallet.credits)
}
events := table.markDisconnected("alice")
if !hasMessage(events, "alice stands up") {
t.Fatalf("missing disconnect event: %+v", events)
}
if got := wallet.credits + wallet.paid; got != 100 {
t.Fatalf("pre-deal disconnect returned %d of 100; the undelt stake must be refunded", got)
}
if len(wallet.open) != 0 {
t.Fatalf("refunded stake left outstanding: %+v", wallet.open)
}
// The window resolves with bob sitting out; nothing may pay the
// refunded round afterwards.
for i := 0; i < 10; i++ {
table.tick()
}
if got := wallet.credits + wallet.paid; got != 100 {
t.Fatalf("refunded pre-deal round paid again: balance %d", got)
}
if table.phase != blackjackWaiting {
t.Fatalf("table did not reset after the window expired: phase=%s", table.phase)
}
}
// TestBlackjackMidHandDisconnectForfeitsStake: the documented mid-hand
// forfeit policy is unchanged — cards are face up, so the stake stays with
// the house.
func TestBlackjackMidHandDisconnectForfeitsStake(t *testing.T) {
table := newBlackjackTable(1, TableConfig{ID: "blackjack", Game: GameBlackjack, MaxPlayers: 2}, newTestRand())
table.shoe = tableauShoe(
card{rank: "10"}, card{rank: "7"}, // dealer
card{rank: "10"}, card{rank: "8"}, // alice 18
card{rank: "10"}, card{rank: "6"}, // bob 16
)
wallet := &testWallet{credits: 100}
table.join("alice")
table.join("bob")
table.bet("alice", "", 10, wallet)
table.bet("bob", "", 10, &testWallet{credits: 100})
if table.phase != blackjackPlaying {
t.Fatalf("setup: expected a dealt hand (phase=%s)", table.phase)
}
table.markDisconnected("alice")
if wallet.credits != 90 || wallet.paid != 0 {
t.Fatalf("mid-hand disconnect refunded a dealt hand: credits=%d paid=%d, want 90/0 (forfeit)", wallet.credits, wallet.paid)
}
}
// TestBaccaratBettingWindowDisconnectRefundsStake: baccarat deals
// synchronously once every connected seat has bet, so an outstanding wager
// there has never had a card dealt for it either.
func TestBaccaratBettingWindowDisconnectRefundsStake(t *testing.T) {
table := newBaccaratTable(1, TableConfig{ID: "baccarat", Game: GameBaccarat, MaxPlayers: 2, BettingTicks: 3}, newTestRand())
table.join("alice")
table.join("bob")
wallet := &testWallet{credits: 100}
table.bet("alice", baccaratSpotPlayer, 10, wallet)
if table.phase != baccaratBetting {
t.Fatalf("setup: expected the betting window (phase=%s)", table.phase)
}
table.markDisconnected("alice")
if got := wallet.credits + wallet.paid; got != 100 {
t.Fatalf("pre-deal baccarat disconnect returned %d of 100; want the stake refunded", got)
}
if len(wallet.open) != 0 {
t.Fatalf("refunded baccarat stake left outstanding: %+v", wallet.open)
}
for i := 0; i < 10; i++ {
table.tick()
}
if got := wallet.credits + wallet.paid; got != 100 {
t.Fatalf("refunded pre-deal coup paid again: balance %d", got)
}
}
|