go_games_collection/senet_tui_test.go
2026-07-10 09:12:06 +03:00

176 lines
5.3 KiB
Go
Raw Permalink 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 (
"fmt"
"testing"
)
func TestSenetModelRollViaKey(t *testing.T) {
m := NewSenetModel(SenetDifficultyEasy, ColorChoiceA)
m.game = NewSenetGame(SenetPlayerA)
m.humanColor = SenetPlayerA
next, _ := m.Update(key("r"))
m = next.(SenetModel)
if m.game.DiceValue == 0 {
t.Errorf("после броска значение кости не должно оставаться нулевым")
}
}
func TestSenetModelApplyMoveViaDigitKey(t *testing.T) {
m := NewSenetModel(SenetDifficultyEasy, ColorChoiceA)
m.game = NewSenetGame(SenetPlayerA)
m.humanColor = SenetPlayerA
m.game.Roll(2)
if m.game.CurrentPlayer != SenetPlayerA {
t.Fatalf("тест предполагает ход человека")
}
moves := m.game.LegalMoves()
if len(moves) == 0 {
t.Fatalf("ожидался хотя бы один легальный ход")
}
next, _ := m.Update(key("1"))
m = next.(SenetModel)
if m.isError {
t.Fatalf("неожиданная ошибка: %s", m.message)
}
}
func TestSenetModelRejectsMoveKeyBeforeRoll(t *testing.T) {
m := NewSenetModel(SenetDifficultyEasy, ColorChoiceA)
m.game = NewSenetGame(SenetPlayerA)
m.humanColor = SenetPlayerA
next, _ := m.Update(key("1"))
m = next.(SenetModel)
if m.game.BorneOff[SenetPlayerA] != 0 || m.game.Rolled {
t.Errorf("ход не должен был приняться до броска костей")
}
}
func TestSenetModelBotPlaysWhenNotHumanTurn(t *testing.T) {
m := NewSenetModel(SenetDifficultyEasy, ColorChoiceA)
m.game = NewSenetGame(SenetPlayerB)
m.humanColor = SenetPlayerA
next, _ := m.Update(botMoveMsg{})
m = next.(SenetModel)
if m.game.CurrentPlayer != SenetPlayerA && m.game.Result == nil {
t.Errorf("после хода бота (без доп.бросков) очередь должна была перейти к человеку")
}
}
func TestSenetModelIgnoresBotMoveMsgOnHumanTurn(t *testing.T) {
m := NewSenetModel(SenetDifficultyEasy, ColorChoiceA)
m.game = NewSenetGame(SenetPlayerA)
m.humanColor = SenetPlayerA
next, _ := m.Update(botMoveMsg{})
m = next.(SenetModel)
if m.game.Rolled {
t.Errorf("botMoveMsg не должно было ничего менять, пока сейчас ход человека")
}
}
func TestSenetModelQReturnsToMenuNotQuitsApp(t *testing.T) {
m := NewSenetModel(SenetDifficultyEasy, ColorChoiceA)
next, _ := m.Update(key("q"))
m = next.(SenetModel)
if !m.backToMenu {
t.Errorf("ожидался флаг backToMenu после 'q'")
}
if m.quitting {
t.Errorf("'q' не должно завершать приложение целиком")
}
}
func TestSenetModelActionsIgnoredAfterGameOver(t *testing.T) {
m := NewSenetModel(SenetDifficultyEasy, ColorChoiceA)
m.game = NewSenetGame(SenetPlayerA)
m.humanColor = SenetPlayerA
m.game.Result = &SenetResult{Winner: SenetPlayerA}
next, _ := m.Update(key("r"))
m = next.(SenetModel)
if m.game.Rolled {
t.Errorf("действия после завершения партии не должны приниматься")
}
}
func TestSenetModelFullAutoPlaythrough(t *testing.T) {
m := NewSenetModel(SenetDifficultyMedium, ColorChoiceA)
m.game = NewSenetGame(SenetPlayerA)
m.humanColor = SenetPlayerA
humanBot := SenetBot{Difficulty: SenetDifficultyMedium}
steps := 0
for m.game.Result == nil && steps < 30000 {
steps++
if m.game.CurrentPlayer != m.humanColor {
next, _ := m.Update(botMoveMsg{})
m = next.(SenetModel)
continue
}
if !m.game.Rolled {
next, _ := m.Update(key("r"))
m = next.(SenetModel)
continue
}
moves := m.game.LegalMoves()
if len(moves) == 0 {
t.Fatalf("LegalMoves пуст при Rolled=true для хода человека — не должно происходить")
}
if len(moves) > 9 {
t.Fatalf("число легальных ходов превысило 9: %d", len(moves))
}
chosen := humanBot.DecideMove(m.game, m.rng)
idx := -1
for i, mv := range moves {
if mv.From == chosen {
idx = i
break
}
}
if idx < 0 {
idx = 0
}
next, _ := m.Update(key(fmt.Sprintf("%d", idx+1)))
m = next.(SenetModel)
if m.isError {
t.Fatalf("неожиданная ошибка при ходе: %s", m.message)
}
}
if m.game.Result == nil {
t.Fatalf("партия не завершилась за %d шагов", steps)
}
}
func TestNewSenetModelRespectsColorChoiceA(t *testing.T) {
m := NewSenetModel(SenetDifficultyEasy, ColorChoiceA)
if m.humanColor != SenetPlayerA {
t.Errorf("при выборе ColorChoiceA человек должен был играть за SenetPlayerA, получено %v", m.humanColor)
}
}
func TestNewSenetModelRespectsColorChoiceB(t *testing.T) {
m := NewSenetModel(SenetDifficultyEasy, ColorChoiceB)
if m.humanColor != SenetPlayerB {
t.Errorf("при выборе ColorChoiceB человек должен был играть за SenetPlayerB, получено %v", m.humanColor)
}
}
func TestNewSenetModelRandomColorGivesValidColor(t *testing.T) {
seenA, seenB := false, false
for i := 0; i < 50 && !(seenA && seenB); i++ {
m := NewSenetModel(SenetDifficultyEasy, ColorChoiceRandom)
if m.humanColor == SenetPlayerA {
seenA = true
} else {
seenB = true
}
}
if !seenA || !seenB {
t.Errorf("случайный выбор цвета должен был давать оба варианта за 50 попыток: A=%v B=%v", seenA, seenB)
}
}