oecs-sharp/Game.TicTacToe.Tests/GameFlowTests.cs

157 lines
4.5 KiB
C#

using FluentAssertions;
using Game.TicTacToe;
using OECS;
using Xunit;
namespace Game.TicTacToe.Tests;
public class GameFlowTests
{
[Fact]
public void NewGame_HasEmptyBoard()
{
var (world, _) = TestHelpers.SetupGame();
var emptyCount = 0;
foreach (var _ in world.Select(new Query<Cell>().Without<Mark>()))
emptyCount++;
emptyCount.Should().Be(9);
}
[Fact]
public void PlaceMark_ClaimsCell()
{
var (world, group) = TestHelpers.SetupGame();
world.Commands.Enqueue(new PlaceMarkCommand { Row = 0, Col = 0 });
group.RunLogical();
var markedCount = 0;
foreach (var it in world.Select<Cell, Mark>())
{
markedCount++;
it.Val1.Row.Should().Be(0);
it.Val1.Col.Should().Be(0);
it.Val2.Player.Should().Be(Player.X);
}
markedCount.Should().Be(1);
}
[Fact]
public void PlaceMark_TogglesPlayer()
{
var (world, group) = TestHelpers.SetupGame();
world.Commands.Enqueue(new PlaceMarkCommand { Row = 0, Col = 0 }); // X
group.RunLogical();
world.ReadSingleton<GameState>().CurrentPlayer.Should().Be(Player.O);
world.Commands.Enqueue(new PlaceMarkCommand { Row = 1, Col = 0 }); // O
group.RunLogical();
world.ReadSingleton<GameState>().CurrentPlayer.Should().Be(Player.X);
}
[Fact]
public void PlaceMark_CannotOverwriteClaimedCell()
{
var (world, group) = TestHelpers.SetupGame();
world.Commands.Enqueue(new PlaceMarkCommand { Row = 0, Col = 0 }); // X
group.RunLogical();
world.Commands.Enqueue(new PlaceMarkCommand { Row = 0, Col = 0 }); // O tries same cell
group.RunLogical();
var marks = new List<(int Row, int Col, Player Player)>();
foreach (var it in world.Select<Cell, Mark>())
marks.Add((it.Val1.Row, it.Val1.Col, it.Val2.Player));
marks.Should().ContainSingle()
.Which.Should().Be((0, 0, Player.X));
}
[Fact]
public void XWins_Row()
{
var (world, group) = TestHelpers.SetupGame();
TestHelpers.PlayMoves(world, group, (0, 0), (1, 0), (0, 1), (1, 1), (0, 2));
world.ReadSingleton<GameState>().Status.Should().Be(GameStatus.XWon);
}
[Fact]
public void OWins_Column()
{
var (world, group) = TestHelpers.SetupGame();
TestHelpers.PlayMoves(world, group, (0, 0), (1, 0), (0, 1), (1, 1), (2, 2), (1, 2));
world.ReadSingleton<GameState>().Status.Should().Be(GameStatus.OWon);
}
[Fact]
public void XWins_Diagonal()
{
var (world, group) = TestHelpers.SetupGame();
TestHelpers.PlayMoves(world, group, (0, 0), (1, 0), (1, 1), (1, 2), (2, 2));
world.ReadSingleton<GameState>().Status.Should().Be(GameStatus.XWon);
}
[Fact]
public void Draw_AllCellsFilled()
{
var (world, group) = TestHelpers.SetupGame();
TestHelpers.PlayMoves(world, group,
(0, 0), (0, 1), (0, 2),
(1, 1), (1, 0), (1, 2),
(2, 1), (2, 0), (2, 2));
world.ReadSingleton<GameState>().Status.Should().Be(GameStatus.Draw);
}
[Fact]
public void MovesAfterGameOver_AreIgnored()
{
var (world, group) = TestHelpers.SetupGame();
TestHelpers.PlayMoves(world, group, (0, 0), (1, 0), (0, 1), (1, 1), (0, 2));
world.ReadSingleton<GameState>().Status.Should().Be(GameStatus.XWon);
var moveCountBefore = world.ReadSingleton<GameState>().MoveCount;
world.Commands.Enqueue(new PlaceMarkCommand { Row = 2, Col = 2 });
group.RunLogical();
world.ReadSingleton<GameState>().MoveCount.Should().Be(moveCountBefore);
}
[Fact]
public void SaveLoad_RoundTrips()
{
var (world, group) = TestHelpers.SetupGame();
TestHelpers.PlayMoves(world, group, (0, 0), (1, 0));
using var stream = new MemoryStream();
WorldSerializer.Save(world, stream);
stream.Position = 0;
var world2 = new World();
WorldSerializer.Load(world2, stream);
var state = world2.ReadSingleton<GameState>();
state.CurrentPlayer.Should().Be(Player.X);
state.MoveCount.Should().Be(2);
var marks = new List<(int Row, int Col, Player Player)>();
foreach (var it in world2.Select<Cell, Mark>())
marks.Add((it.Val1.Row, it.Val1.Col, it.Val2.Player));
marks.Should().BeEquivalentTo([(0, 0, Player.X), (1, 0, Player.O)]);
}
}