157 lines
4.5 KiB
C#
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)]);
|
|
}
|
|
} |