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

195 lines
5.7 KiB
C#
Raw Normal View History

using FluentAssertions;
using Game.Blackjack;
using OECS;
using Xunit;
namespace Game.Blackjack.Tests;
public class GameFlowTests
{
[Fact]
public void NewGame_StartsInBettingPhase()
{
var (world, _) = TestHelpers.SetupGame();
var state = world.ReadSingleton<GameState>();
state.Phase.Should().Be(GamePhase.Betting);
state.Chips.Should().Be(100);
state.RoundNumber.Should().Be(1);
}
[Fact]
public void PlaceBet_AdvancesToDealing()
{
var (world, group) = TestHelpers.SetupGame();
world.Commands.Enqueue(new PlaceBetCommand { Amount = 10 });
group.RunLogical();
var state = world.ReadSingleton<GameState>();
state.Phase.Should().Be(GamePhase.PlayerTurn);
state.CurrentBet.Should().Be(10);
state.Chips.Should().Be(90);
}
[Fact]
public void PlaceBet_RejectsInsufficientChips()
{
var (world, group) = TestHelpers.SetupGame();
world.Commands.Enqueue(new PlaceBetCommand { Amount = 200 });
group.RunLogical();
var state = world.ReadSingleton<GameState>();
state.Phase.Should().Be(GamePhase.Betting);
state.Chips.Should().Be(100);
}
[Fact]
public void PlaceBet_RejectsZeroOrNegative()
{
var (world, group) = TestHelpers.SetupGame();
world.Commands.Enqueue(new PlaceBetCommand { Amount = 0 });
group.RunLogical();
world.ReadSingleton<GameState>().Phase.Should().Be(GamePhase.Betting);
world.Commands.Enqueue(new PlaceBetCommand { Amount = -5 });
group.RunLogical();
world.ReadSingleton<GameState>().Phase.Should().Be(GamePhase.Betting);
}
[Fact]
public void Dealing_CreatesDeckAndHands()
{
var (world, group) = TestHelpers.SetupGame();
world.Commands.Enqueue(new PlaceBetCommand { Amount = 10 });
group.RunLogical();
TestHelpers.FindEntity<Deck>(world).Should().NotBe(Entity.Null);
TestHelpers.FindEntity<PlayerHand>(world).Should().NotBe(Entity.Null);
TestHelpers.FindEntity<DealerHand>(world).Should().NotBe(Entity.Null);
}
[Fact]
public void Dealing_DealsTwoCardsToEach()
{
var (world, group) = TestHelpers.SetupGame();
world.Commands.Enqueue(new PlaceBetCommand { Amount = 10 });
group.RunLogical();
var playerHand = TestHelpers.FindEntity<PlayerHand>(world);
var dealerHand = TestHelpers.FindEntity<DealerHand>(world);
TestHelpers.CountCardsInHand(world, playerHand).Should().Be(2);
TestHelpers.CountCardsInHand(world, dealerHand).Should().Be(2);
}
[Fact]
public void Hit_DrawsOneCard()
{
var (world, group) = TestHelpers.SetupGame();
world.Commands.Enqueue(new PlaceBetCommand { Amount = 10 });
group.RunLogical();
var playerHand = TestHelpers.FindEntity<PlayerHand>(world);
var before = TestHelpers.CountCardsInHand(world, playerHand);
world.Commands.Enqueue(new HitCommand());
group.RunLogical();
var after = TestHelpers.CountCardsInHand(world, playerHand);
after.Should().Be(before + 1);
}
[Fact]
public void Stand_AdvancesToDealerTurn()
{
var (world, group) = TestHelpers.SetupGame();
world.Commands.Enqueue(new PlaceBetCommand { Amount = 10 });
group.RunLogical();
world.Commands.Enqueue(new StandCommand());
group.RunLogical();
var state = world.ReadSingleton<GameState>();
state.Phase.Should().Be(GamePhase.RoundOver);
}
[Fact]
public void NewRound_ResetsPhase()
{
var (world, group) = TestHelpers.SetupGame();
world.Commands.Enqueue(new PlaceBetCommand { Amount = 10 });
group.RunLogical();
world.Commands.Enqueue(new StandCommand());
group.RunLogical();
world.Commands.Enqueue(new NewRoundCommand());
group.RunLogical();
var state = world.ReadSingleton<GameState>();
state.Phase.Should().Be(GamePhase.Betting);
state.Result.Should().Be(RoundResult.None);
}
[Fact]
public void DeterministicSeed_ProducesSameDeal()
{
var (world1, group1) = TestHelpers.SetupGame(seed: 42);
world1.Commands.Enqueue(new PlaceBetCommand { Amount = 10 });
group1.RunLogical();
var cards1 = TestHelpers.GetAllCards(world1);
var (world2, group2) = TestHelpers.SetupGame(seed: 42);
world2.Commands.Enqueue(new PlaceBetCommand { Amount = 10 });
group2.RunLogical();
var cards2 = TestHelpers.GetAllCards(world2);
cards1.Should().Equal(cards2);
}
[Fact]
public void PlayerBust_LosesBet()
{
var (world, group) = TestHelpers.SetupGame(seed: 12345);
world.Commands.Enqueue(new PlaceBetCommand { Amount = 10 });
group.RunLogical();
while (world.ReadSingleton<GameState>().Phase == GamePhase.PlayerTurn)
{
world.Commands.Enqueue(new HitCommand());
group.RunLogical();
}
var state = world.ReadSingleton<GameState>();
state.Phase.Should().Be(GamePhase.RoundOver);
}
[Fact]
public void Serialization_RoundTrips()
{
var (world, group) = TestHelpers.SetupGame(seed: 42);
world.Commands.Enqueue(new PlaceBetCommand { Amount = 10 });
group.RunLogical();
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.Chips.Should().Be(90);
state.CurrentBet.Should().Be(10);
state.RoundNumber.Should().Be(1);
}
}