go_games_collection/thousand_tui_test.go
2026-07-04 13:51:04 +03:00

151 lines
4.3 KiB
Go
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

package main
import "testing"
func TestThousandModelDealsThreePlayers(t *testing.T) {
m := NewThousandModel()
if len(m.game.Players) != 3 {
t.Errorf("ожидалось 3 игрока, получено %d", len(m.game.Players))
}
}
func TestThousandModelBidViaKeys(t *testing.T) {
m := NewThousandModel()
m.game.CurrentBidderIdx = m.humanIdx
m.bidAmount = 100
next, _ := m.Update(key("enter"))
m = next.(ThousandModel)
if m.isError {
t.Fatalf("неожиданная ошибка: %s", m.message)
}
if m.game.HighBid != 100 {
t.Fatalf("ожидалась ставка 100, получено %d", m.game.HighBid)
}
}
func TestThousandModelPassRejectedForFirstBidder(t *testing.T) {
m := NewThousandModel()
m.game.CurrentBidderIdx = m.humanIdx
m.game.firstBidderIdx = m.humanIdx
m.game.bidsMade = 0
next, _ := m.Update(key("p"))
m = next.(ThousandModel)
if !m.isError {
t.Fatalf("первый ходящий не может пасовать, ошибка ожидалась")
}
}
func TestThousandModelDiscardViaKeys(t *testing.T) {
m := NewThousandModel()
m.game.CurrentBidderIdx = m.humanIdx
m.bidAmount = 100
next, _ := m.Update(key("enter"))
m = next.(ThousandModel)
if m.isError {
t.Fatalf("неожиданная ошибка ставки: %s", m.message)
}
if err := m.game.Pass(); err != nil {
t.Fatalf("ошибка подготовки: %v", err)
}
if err := m.game.Pass(); err != nil {
t.Fatalf("ошибка подготовки: %v", err)
}
if m.game.Phase != ThousandPhaseDiscard {
t.Fatalf("ожидалась фаза снoса")
}
if m.game.DeclarerIdx != m.humanIdx {
t.Fatalf("человек должен был стать declarer")
}
m.cursor = 0
next, _ = m.Update(key("enter"))
m = next.(ThousandModel)
if m.isError {
t.Fatalf("неожиданная ошибка при первом сносе: %s", m.message)
}
if len(m.game.Players[m.humanIdx].Hand) != 9 {
t.Fatalf("после первого сноса должно остаться 9 карт, получено %d", len(m.game.Players[m.humanIdx].Hand))
}
}
func TestThousandModelQReturnsToMenu(t *testing.T) {
m := NewThousandModel()
next, _ := m.Update(key("q"))
m = next.(ThousandModel)
if !m.backToMenu {
t.Fatalf("ожидался флаг backToMenu после 'q'")
}
if m.quitting {
t.Fatalf("'q' не должен закрывать всё приложение")
}
}
// TestThousandModelFullAutoPlaythrough прогоняет TUI-модель от
// начала до конца нескольких раздач, где "человек" отыгрывает свои
// решения через реальные нажатия клавиш (используя ту же логику,
// что и бот).
func TestThousandModelFullAutoPlaythrough(t *testing.T) {
m := NewThousandModel()
bot := ThousandBot{}
const maxHands = 30
for hand := 0; hand < maxHands; hand++ {
const maxSteps = 3000
steps := 0
for m.game.Phase != ThousandPhaseHandOver && steps < maxSteps {
steps++
if m.actorForPhase() != m.humanIdx {
next, _ := m.Update(botMoveMsg{})
m = next.(ThousandModel)
continue
}
switch m.game.Phase {
case ThousandPhaseBidding:
if amount, ok := bot.DecideBid(m.game); ok {
m.bidAmount = amount
next, _ := m.Update(key("enter"))
m = next.(ThousandModel)
} else {
next, _ := m.Update(key("p"))
m = next.(ThousandModel)
}
case ThousandPhaseDiscard:
discards := bot.DecideDiscards(m.game.Players[m.humanIdx].Hand)
for _, card := range discards {
for i, hc := range m.currentHand() {
if hc == card {
m.cursor = i
break
}
}
next, _ := m.Update(key("enter"))
m = next.(ThousandModel)
}
case ThousandPhaseTrick:
card := bot.DecidePlay(m.game)
for i, hc := range m.currentHand() {
if hc == card {
m.cursor = i
break
}
}
next, _ := m.Update(key("enter"))
m = next.(ThousandModel)
}
}
if steps >= maxSteps {
t.Fatalf("раздача %d: не завершилась через TUI за %d шагов (фаза %v)", hand, maxSteps, m.game.Phase)
}
if m.game.Result == nil {
t.Fatalf("раздача %d: завершилась без результата", hand)
}
if m.game.Result.MatchOver {
return
}
next, _ := m.Update(key("n"))
m = next.(ThousandModel)
}
}