go_games_collection/minesweeper_tui_test.go

179 lines
5.4 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 TestMinesweeperModelRevealViaKey(t *testing.T) {
m := NewMinesweeperModel(9, 9, 10)
m.cursor = MinesweeperPos{Row: 4, Col: 4}
next, _ := m.Update(key("enter"))
m = next.(MinesweeperModel)
if m.isError {
t.Fatalf("неожиданная ошибка: %s", m.message)
}
if !m.game.Board[4][4].Revealed {
t.Fatalf("клетка должна была открыться")
}
}
func TestMinesweeperModelFlagViaKey(t *testing.T) {
m := NewMinesweeperModel(9, 9, 10)
m.cursor = MinesweeperPos{Row: 4, Col: 4}
next, _ := m.Update(key("f"))
m = next.(MinesweeperModel)
if m.isError {
t.Fatalf("неожиданная ошибка: %s", m.message)
}
if !m.game.Board[4][4].Flagged {
t.Fatalf("клетка должна была получить флаг")
}
next, _ = m.Update(key("f"))
m = next.(MinesweeperModel)
if m.game.Board[4][4].Flagged {
t.Fatalf("флаг должен был сняться")
}
}
func TestMinesweeperModelCursorMovement(t *testing.T) {
m := NewMinesweeperModel(9, 9, 10)
m.cursor = MinesweeperPos{Row: 4, Col: 4}
next, _ := m.Update(key("up"))
m = next.(MinesweeperModel)
if m.cursor.Row != 3 {
t.Errorf("курсор должен был сдвинуться вверх")
}
next, _ = m.Update(key("right"))
m = next.(MinesweeperModel)
if m.cursor.Col != 5 {
t.Errorf("курсор должен был сдвинуться вправо")
}
}
func TestMinesweeperModelCursorClampsAtEdges(t *testing.T) {
m := NewMinesweeperModel(9, 9, 10)
m.cursor = MinesweeperPos{Row: 0, Col: 0}
next, _ := m.Update(key("up"))
m = next.(MinesweeperModel)
if m.cursor.Row != 0 {
t.Errorf("курсор не должен был уйти за верхний край")
}
next, _ = m.Update(key("left"))
m = next.(MinesweeperModel)
if m.cursor.Col != 0 {
t.Errorf("курсор не должен был уйти за левый край")
}
}
func TestMinesweeperModelCannotRevealFlaggedCell(t *testing.T) {
m := NewMinesweeperModel(9, 9, 10)
m.cursor = MinesweeperPos{Row: 4, Col: 4}
next, _ := m.Update(key("f"))
m = next.(MinesweeperModel)
next, _ = m.Update(key("enter"))
m = next.(MinesweeperModel)
if !m.isError {
t.Fatalf("ожидалась ошибка открытия помеченной клетки")
}
}
func TestMinesweeperModelQReturnsToMenu(t *testing.T) {
m := NewMinesweeperModel(9, 9, 10)
next, _ := m.Update(key("q"))
m = next.(MinesweeperModel)
if !m.backToMenu {
t.Fatalf("ожидался флаг backToMenu после 'q'")
}
if m.quitting {
t.Fatalf("'q' не должен закрывать всё приложение")
}
}
func TestMinesweeperModelNewGameAfterResult(t *testing.T) {
m := NewMinesweeperModel(9, 9, 10)
m.game.Result = &MinesweeperResult{Won: false}
next, _ := m.Update(key("n"))
m = next.(MinesweeperModel)
if m.game.Result != nil {
t.Errorf("новая партия не должна была начаться с результатом")
}
if m.game.Width != 9 || m.game.Height != 9 || m.game.MineCount != 10 {
t.Errorf("новая партия должна была сохранить параметры поля")
}
}
func TestMinesweeperModelSupportsAllPresets(t *testing.T) {
presets := []struct{ w, h, mines int }{
{9, 9, 10},
{16, 16, 40},
{30, 16, 99},
}
for _, p := range presets {
m := NewMinesweeperModel(p.w, p.h, p.mines)
if m.game.Width != p.w || m.game.Height != p.h || m.game.MineCount != p.mines {
t.Errorf("некорректные параметры для пресета %+v: %+v", p, m.game)
}
}
}
func TestMinesweeperModelChordViaKeyOnRevealedCell(t *testing.T) {
m := NewMinesweeperModel(5, 5, 2)
m.game.minesPlaced = true
m.game.Board[0][1].IsMine = true
m.game.Board[1][0].IsMine = true
for r := 0; r < 5; r++ {
for c := 0; c < 5; c++ {
if m.game.Board[r][c].IsMine {
continue
}
n := 0
for _, nb := range msNeighbors(msp(r, c)) {
if m.game.inBounds(nb) && m.game.Board[nb.Row][nb.Col].IsMine {
n++
}
}
m.game.Board[r][c].AdjacentMines = n
}
}
m.game.Board[0][0].Revealed = true
m.game.RevealedCount++
m.game.ToggleFlag(msp(0, 1))
m.game.ToggleFlag(msp(1, 0))
m.cursor = msp(0, 0)
next, _ := m.Update(key("enter"))
m = next.(MinesweeperModel)
if m.isError {
t.Fatalf("неожиданная ошибка хорды через клавишу: %s", m.message)
}
if !m.game.Board[1][1].Revealed {
t.Errorf("хорда через enter на открытой клетке должна была открыть соседа (1,1)")
}
}
// TestMinesweeperModelFullAutoPlaythrough прогоняет TUI-модель через
// последовательность нажатий на всех клетках поля, проверяя, что
// путь через Update не паникует и партия завершается (тем или иным
// исходом).
func TestMinesweeperModelFullAutoPlaythrough(t *testing.T) {
m := NewMinesweeperModel(9, 9, 10)
for r := 0; r < 9 && m.game.Result == nil; r++ {
for c := 0; c < 9 && m.game.Result == nil; c++ {
m.cursor = MinesweeperPos{Row: r, Col: c}
if m.game.Board[r][c].Revealed {
continue
}
next, _ := m.Update(key("enter"))
m = next.(MinesweeperModel)
}
}
if m.game.Result == nil {
t.Fatalf("партия должна была завершиться после перебора всех клеток")
}
}