package main import ( "fmt" "testing" ) func TestSenetModelRollViaKey(t *testing.T) { m := NewSenetModel(SenetDifficultyEasy) 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) 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) 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) 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) 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) 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) 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) 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) } }