package casino import "testing" // TestBaccaratSideBetsRideWithMain pins the multi-wager contract: a side bet // is committed before the main wager, both settle in the same round, and only // the main wager deals the cards. func TestBaccaratSideBetsRideWithMain(t *testing.T) { cfg := TableConfig{ID: "baccarat", Game: GameBaccarat, Baccarat: BaccaratConfig{PairBets: true}} table := newBaccaratTestTable(cfg) table.join("alice") forceShoe(table, baccaratCards("5 5 5 5 5 5")...) w := &testWallet{credits: 1000} if events := table.bet("alice", "player_pair", 10, w); hasMessage(events, "New baccarat hand!") { t.Fatal("side bet alone dealt a round") } if table.players.get("alice").HasBet { t.Fatal("side bet counted as the round's main wager") } events := table.bet("alice", "player", 10, w) if !hasMessage(events, "New baccarat hand!") { t.Fatalf("main wager did not deal: %+v", events) } // Player and banker tie at 5; the player main pushes and the player pair wins 11:1. if w.paid != 130 { t.Fatalf("paid=%d, want 130", w.paid) } var labels []string for _, e := range events { for _, line := range e.Settlement { labels = append(labels, line.Label) } } if len(labels) != 2 || labels[0] != "player" || labels[1] != "player_pair" { t.Fatalf("settlement labels=%v, want [player player_pair]", labels) } // The snapshot carries both bets for the table view. var snapshot *BaccaratSnapshot for _, e := range events { if s, ok := e.Snapshot.(*BaccaratSnapshot); ok && len(s.Bets) > 0 { snapshot = s } } if snapshot == nil || len(snapshot.Bets) != 2 || snapshot.Bets[0].Spot != "player" || snapshot.Bets[0].Amount != 10 || snapshot.Bets[1].Spot != "player_pair" || snapshot.Bets[1].Amount != 10 { t.Fatalf("snapshot bets=%+v", snapshot) } } // A side wager may not follow the main wager: the main is the deal trigger. func TestBaccaratSideBetAfterMainRefused(t *testing.T) { table := newBaccaratTestTable(TableConfig{ID: "baccarat", Game: GameBaccarat, Baccarat: BaccaratConfig{PairBets: true}, MaxPlayers: 2}) table.join("alice") table.join("bob") w := &testWallet{credits: 1000} table.bet("alice", "player", 10, w) if events := table.bet("alice", "player_pair", 10, w); !hasMessage(events, "before your main wager") { t.Fatalf("side bet after main accepted: %+v", events) } } // A bare "bet" repeats the remembered side bets and the main wager together. func TestBaccaratRebetAll(t *testing.T) { cfg := TableConfig{ID: "baccarat", Game: GameBaccarat, Baccarat: BaccaratConfig{PairBets: true}} table := newBaccaratTestTable(cfg) table.join("alice") forceShoe(table, baccaratCards("5 5 5 5 5 5")...) table.bet("alice", "player_pair", 10, &testWallet{credits: 1000}) table.bet("alice", "player", 10, &testWallet{credits: 1000}) forceShoe(table, baccaratCards("5 5 5 5 5 5")...) w := &testWallet{credits: 1000} events := table.rebetAll("alice", w) if !hasMessage(events, "New baccarat hand!") || w.paid != 130 { t.Fatalf("rebet all did not replay both wagers: paid=%d events=%+v", w.paid, events) } } // unbet returns the main wager and every side bet in one step. func TestBaccaratUnbetReturnsAllWagers(t *testing.T) { table := newBaccaratTestTable(TableConfig{ID: "baccarat", Game: GameBaccarat, Baccarat: BaccaratConfig{PairBets: true}}) table.join("alice") w := &testWallet{credits: 1000} table.bet("alice", "player_pair", 10, w) table.bet("alice", "banker_pair", 15, w) if events := table.unbetAllLocked("alice"); !hasMessage(events, "take back 25") { t.Fatalf("unbet did not return both side stakes: %+v", events) } if w.paid != 25 || len(w.open) != 0 { t.Fatalf("paid=%d open=%d, want 25/0", w.paid, len(w.open)) } } // A side-only seat is not part of the round: the timer returns the side stake // and the other seat's main wager still deals. func TestBaccaratSideOnlySeatRefundedOnTimeout(t *testing.T) { cfg := TableConfig{ID: "baccarat", Game: GameBaccarat, Baccarat: BaccaratConfig{PairBets: true}, MaxPlayers: 2, BettingTicks: 2} table := newBaccaratTestTable(cfg) table.join("alice") table.join("bob") wa, wb := &testWallet{credits: 1000}, &testWallet{credits: 1000} table.bet("alice", "player_pair", 10, wa) table.bet("bob", "player", 10, wb) forceShoe(table, baccaratCards("5 5 5 5 5 5")...) var events []Event for i := 0; i < 4 && !hasMessage(events, "New baccarat hand!"); i++ { events = append(events, table.tick()...) } if !hasMessage(events, "New baccarat hand!") { t.Fatalf("side-only seat held the round open: %+v", events) } if wa.paid != 10 { t.Fatalf("alice side stake not returned: paid=%d", wa.paid) } if !hasMessage(events, "side bets is returned") { t.Fatalf("missing side-bet refund notice: %+v", events) } }