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(); 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(); 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(); 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().Phase.Should().Be(GamePhase.Betting); world.Commands.Enqueue(new PlaceBetCommand { Amount = -5 }); group.RunLogical(); world.ReadSingleton().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(world).Should().NotBe(Entity.Null); TestHelpers.FindEntity(world).Should().NotBe(Entity.Null); TestHelpers.FindEntity(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(world); var dealerHand = TestHelpers.FindEntity(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(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(); 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(); 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().Phase == GamePhase.PlayerTurn) { world.Commands.Enqueue(new HitCommand()); group.RunLogical(); } var state = world.ReadSingleton(); 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(); state.Chips.Should().Be(90); state.CurrentBet.Should().Be(10); state.RoundNumber.Should().Be(1); } }