package main import ( "fmt" "testing" ) func TestPokerModelBotsGetRandomDifficulties(t *testing.T) { m := NewPokerModel(4) if len(m.bots) != 3 { t.Fatalf("ожидалось 3 бота (4 игрока минус человек), получено %d", len(m.bots)) } for seat, bot := range m.bots { if bot.Difficulty < PokerDifficultyEasy || bot.Difficulty > PokerDifficultyHard { t.Errorf("бот на месте %d получил недопустимый уровень сложности %v", seat, bot.Difficulty) } } } func TestPokerModelHumanIsSeatZero(t *testing.T) { m := NewPokerModel(3) if m.humanSeat != 0 { t.Errorf("человек должен всегда занимать место 0, получено %d", m.humanSeat) } if _, isBot := m.bots[m.humanSeat]; isBot { t.Errorf("на месте человека не должно быть бота") } } func TestPokerModelFoldViaKey(t *testing.T) { m := NewPokerModel(3) m.game.CurrentPlayerIdx = m.humanSeat next, _ := m.Update(key("1")) m = next.(PokerModel) if !m.game.Players[m.humanSeat].Folded { t.Errorf("после выбора действия 'сбросить' игрок должен был сбросить карты") } } func TestPokerModelRejectsActionWhenNotHumanTurn(t *testing.T) { m := NewPokerModel(3) m.game.CurrentPlayerIdx = (m.humanSeat + 1) % 3 next, _ := m.Update(key("1")) m = next.(PokerModel) if m.game.Players[m.humanSeat].Folded { t.Errorf("действие не должно было приняться — сейчас не ход человека") } } func TestPokerModelBetAmountSubmode(t *testing.T) { m := NewPokerModel(2) m.game.CurrentPlayerIdx = m.humanSeat actions := m.pokerHumanActions() betIdx := -1 for i, a := range actions { if a == "bet" { betIdx = i } } if betIdx < 0 { t.Fatalf("ожидалось действие 'bet' среди доступных: %v", actions) } next, _ := m.Update(key(fmt.Sprintf("%d", betIdx+1))) m = next.(PokerModel) if !m.choosingBetAmount { t.Fatalf("ожидался переход в подрежим выбора суммы ставки") } before := m.betAmount next, _ = m.Update(key("up")) m = next.(PokerModel) if m.betAmount != before+m.game.BigBlind { t.Errorf("ожидалось увеличение ставки на большой блайнд, было %d, стало %d", before, m.betAmount) } next, _ = m.Update(key("enter")) m = next.(PokerModel) if m.choosingBetAmount { t.Errorf("подрежим должен был закрыться после подтверждения") } human := m.game.Players[m.humanSeat] if human.CurrentBet != before+m.game.BigBlind { t.Errorf("ставка должна была реально примениться, ожидалось %d, получено %d", before+m.game.BigBlind, human.CurrentBet) } } func TestPokerModelBetAmountCancelDoesNotApply(t *testing.T) { m := NewPokerModel(2) m.game.CurrentPlayerIdx = m.humanSeat betBefore := m.game.Players[m.humanSeat].CurrentBet actions := m.pokerHumanActions() betIdx := 0 for i, a := range actions { if a == "bet" { betIdx = i } } next, _ := m.Update(key(fmt.Sprintf("%d", betIdx+1))) m = next.(PokerModel) next, _ = m.Update(key("esc")) m = next.(PokerModel) if m.choosingBetAmount { t.Errorf("esc должен был закрыть подрежим без применения ставки") } if m.game.Players[m.humanSeat].CurrentBet != betBefore { t.Errorf("отменённая ставка не должна была примениться") } } func TestPokerModelBotPlaysWhenNotHumanTurn(t *testing.T) { m := NewPokerModel(3) for m.game.CurrentPlayerIdx == m.humanSeat { m.game.CurrentPlayerIdx = (m.game.CurrentPlayerIdx + 1) % 3 } next, _ := m.Update(botMoveMsg{}) m = next.(PokerModel) if m.isError { t.Errorf("неожиданная ошибка хода бота: %s", m.message) } } func TestPokerModelIgnoresBotMoveMsgOnHumanTurn(t *testing.T) { m := NewPokerModel(3) m.game.CurrentPlayerIdx = m.humanSeat before := *m.game next, _ := m.Update(botMoveMsg{}) m = next.(PokerModel) if m.game.CurrentPlayerIdx != before.CurrentPlayerIdx { t.Errorf("botMoveMsg не должно было ничего менять, пока сейчас ход человека") } } func TestPokerModelQReturnsToMenuNotQuitsApp(t *testing.T) { m := NewPokerModel(3) next, _ := m.Update(key("q")) m = next.(PokerModel) if !m.backToMenu { t.Errorf("ожидался флаг backToMenu после 'q'") } if m.quitting { t.Errorf("'q' не должно завершать приложение целиком") } } func TestPokerModelNextHandViaKey(t *testing.T) { m := NewPokerModel(2) m.game.Players[0].HoleCards = [2]Card{c(Ace, Spades), c(Ace, Hearts)} m.game.Players[1].HoleCards = [2]Card{c(Two, Clubs), c(Seven, Diamonds)} m.game.Board = []Card{c(Ace, Clubs), c(King, Spades), c(Queen, Hearts), c(Four, Diamonds), c(Nine, Clubs)} m.game.Players[0].TotalContributed = 100 m.game.Players[1].TotalContributed = 100 m.game.resolveShowdown() next, _ := m.Update(key("n")) m = next.(PokerModel) if m.game.Phase == PokerPhaseShowdown { t.Errorf("после 'n' должна была начаться новая раздача") } } func TestPokerModelFullTournamentAutoPlaythrough(t *testing.T) { m := NewPokerModel(4) humanBot := PokerBot{Difficulty: PokerDifficultyMedium} steps := 0 for m.game.Phase != PokerPhaseTournamentOver && steps < 50000 { steps++ g := m.game if g.Phase == PokerPhaseShowdown { next, _ := m.Update(key("n")) m = next.(PokerModel) continue } if g.CurrentPlayerIdx != m.humanSeat { next, _ := m.Update(botMoveMsg{}) m = next.(PokerModel) continue } action := humanBot.DecideAction(g, m.humanSeat, m.rng) actions := m.pokerHumanActions() labelToKey := map[string]int{} for i, a := range actions { labelToKey[a] = i + 1 } var keyStr string switch action.Kind { case "fold": keyStr = fmt.Sprintf("%d", labelToKey["fold"]) case "check": if idx, ok := labelToKey["check"]; ok { keyStr = fmt.Sprintf("%d", idx) } else { keyStr = fmt.Sprintf("%d", labelToKey["call"]) } case "call": keyStr = fmt.Sprintf("%d", labelToKey["call"]) case "bet": keyStr = fmt.Sprintf("%d", labelToKey["bet"]) } next, _ := m.Update(key(keyStr)) m = next.(PokerModel) if m.choosingBetAmount { next, _ = m.Update(key("enter")) m = next.(PokerModel) } if m.isError { t.Fatalf("неожиданная ошибка при автопрогоне: %s", m.message) } } if m.game.Phase != PokerPhaseTournamentOver { t.Fatalf("турнир не завершился за %d шагов", steps) } }