175 lines
5.2 KiB
Go
175 lines
5.2 KiB
Go
package main
|
||
|
||
import (
|
||
"fmt"
|
||
"testing"
|
||
)
|
||
|
||
func TestUrModelRollViaKey(t *testing.T) {
|
||
m := NewUrModel(UrDifficultyEasy, ColorChoiceA)
|
||
m.game = NewUrGame(UrPlayerA)
|
||
m.humanColor = UrPlayerA
|
||
|
||
next, _ := m.Update(key("r"))
|
||
m = next.(UrModel)
|
||
if !m.game.Rolled && m.game.CurrentPlayer == UrPlayerA {
|
||
t.Errorf("после броска Rolled должен был выставиться (или очередь смениться, если ходов нет)")
|
||
}
|
||
}
|
||
|
||
func TestUrModelApplyMoveViaDigitKey(t *testing.T) {
|
||
m := NewUrModel(UrDifficultyEasy, ColorChoiceA)
|
||
m.game = NewUrGame(UrPlayerA)
|
||
m.humanColor = UrPlayerA
|
||
m.game.Roll(3)
|
||
if m.game.CurrentPlayer != UrPlayerA {
|
||
t.Fatalf("тест предполагает ход человека")
|
||
}
|
||
|
||
next, _ := m.Update(key("1"))
|
||
m = next.(UrModel)
|
||
if m.isError {
|
||
t.Fatalf("неожиданная ошибка: %s", m.message)
|
||
}
|
||
if m.game.Path[UrPlayerA][0] != 3 {
|
||
t.Errorf("ожидалась позиция 3 после хода, получено %d", m.game.Path[UrPlayerA][0])
|
||
}
|
||
}
|
||
|
||
func TestUrModelRejectsMoveKeyBeforeRoll(t *testing.T) {
|
||
m := NewUrModel(UrDifficultyEasy, ColorChoiceA)
|
||
m.game = NewUrGame(UrPlayerA)
|
||
m.humanColor = UrPlayerA
|
||
|
||
next, _ := m.Update(key("1"))
|
||
m = next.(UrModel)
|
||
if m.game.Path[UrPlayerA][0] != 0 {
|
||
t.Errorf("ход не должен был приняться до броска костей")
|
||
}
|
||
}
|
||
|
||
func TestUrModelBotPlaysWhenNotHumanTurn(t *testing.T) {
|
||
m := NewUrModel(UrDifficultyEasy, ColorChoiceA)
|
||
m.game = NewUrGame(UrPlayerB)
|
||
m.humanColor = UrPlayerA
|
||
|
||
next, _ := m.Update(botMoveMsg{})
|
||
m = next.(UrModel)
|
||
if m.game.CurrentPlayer != UrPlayerA {
|
||
t.Errorf("после полного хода бота (без розеток) очередь должна была перейти к человеку")
|
||
}
|
||
}
|
||
|
||
func TestUrModelIgnoresBotMoveMsgOnHumanTurn(t *testing.T) {
|
||
m := NewUrModel(UrDifficultyEasy, ColorChoiceA)
|
||
m.game = NewUrGame(UrPlayerA)
|
||
m.humanColor = UrPlayerA
|
||
|
||
next, _ := m.Update(botMoveMsg{})
|
||
m = next.(UrModel)
|
||
if m.game.Rolled {
|
||
t.Errorf("botMoveMsg не должно было ничего менять, пока сейчас ход человека")
|
||
}
|
||
}
|
||
|
||
func TestUrModelQReturnsToMenuNotQuitsApp(t *testing.T) {
|
||
m := NewUrModel(UrDifficultyEasy, ColorChoiceA)
|
||
next, _ := m.Update(key("q"))
|
||
m = next.(UrModel)
|
||
if !m.backToMenu {
|
||
t.Errorf("ожидался флаг backToMenu после 'q'")
|
||
}
|
||
if m.quitting {
|
||
t.Errorf("'q' не должно завершать приложение целиком")
|
||
}
|
||
}
|
||
|
||
func TestUrModelActionsIgnoredAfterGameOver(t *testing.T) {
|
||
m := NewUrModel(UrDifficultyEasy, ColorChoiceA)
|
||
m.game = NewUrGame(UrPlayerA)
|
||
m.humanColor = UrPlayerA
|
||
m.game.Result = &UrResult{Winner: UrPlayerA}
|
||
|
||
next, _ := m.Update(key("r"))
|
||
m = next.(UrModel)
|
||
if m.game.Rolled {
|
||
t.Errorf("действия после завершения партии не должны приниматься")
|
||
}
|
||
}
|
||
|
||
func TestUrModelFullAutoPlaythrough(t *testing.T) {
|
||
m := NewUrModel(UrDifficultyMedium, ColorChoiceA)
|
||
m.game = NewUrGame(UrPlayerA)
|
||
m.humanColor = UrPlayerA
|
||
humanBot := UrBot{Difficulty: UrDifficultyMedium}
|
||
|
||
steps := 0
|
||
for m.game.Result == nil && steps < 20000 {
|
||
steps++
|
||
if m.game.CurrentPlayer != m.humanColor {
|
||
next, _ := m.Update(botMoveMsg{})
|
||
m = next.(UrModel)
|
||
continue
|
||
}
|
||
if !m.game.Rolled {
|
||
next, _ := m.Update(key("r"))
|
||
m = next.(UrModel)
|
||
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.PieceIdx == chosen {
|
||
idx = i
|
||
break
|
||
}
|
||
}
|
||
if idx < 0 {
|
||
idx = 0
|
||
}
|
||
next, _ := m.Update(key(fmt.Sprintf("%d", idx+1)))
|
||
m = next.(UrModel)
|
||
if m.isError {
|
||
t.Fatalf("неожиданная ошибка при ходе: %s", m.message)
|
||
}
|
||
}
|
||
if m.game.Result == nil {
|
||
t.Fatalf("партия не завершилась за %d шагов", steps)
|
||
}
|
||
}
|
||
|
||
func TestNewUrModelRespectsColorChoiceA(t *testing.T) {
|
||
m := NewUrModel(UrDifficultyEasy, ColorChoiceA)
|
||
if m.humanColor != UrPlayerA {
|
||
t.Errorf("при выборе ColorChoiceA человек должен был играть за UrPlayerA, получено %v", m.humanColor)
|
||
}
|
||
}
|
||
|
||
func TestNewUrModelRespectsColorChoiceB(t *testing.T) {
|
||
m := NewUrModel(UrDifficultyEasy, ColorChoiceB)
|
||
if m.humanColor != UrPlayerB {
|
||
t.Errorf("при выборе ColorChoiceB человек должен был играть за UrPlayerB, получено %v", m.humanColor)
|
||
}
|
||
}
|
||
|
||
func TestNewUrModelRandomColorGivesValidColor(t *testing.T) {
|
||
seenA, seenB := false, false
|
||
for i := 0; i < 50 && !(seenA && seenB); i++ {
|
||
m := NewUrModel(UrDifficultyEasy, ColorChoiceRandom)
|
||
if m.humanColor == UrPlayerA {
|
||
seenA = true
|
||
} else {
|
||
seenB = true
|
||
}
|
||
}
|
||
if !seenA || !seenB {
|
||
t.Errorf("случайный выбор цвета должен был давать оба варианта за 50 попыток: A=%v B=%v", seenA, seenB)
|
||
}
|
||
}
|