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) } }