using FluentAssertions; using Game.CardWars; using OECS; using Xunit; namespace Game.CardWars.Tests; public class CardEffectTests { private static (World World, SystemGroup Group) Setup() { CardEffectRegistry.ClearForTests(); return GameFactory.Create(playerCount: 2, seed: 42); } [Fact] public void WarriorEffect_AddsHornWhenAnotherWarriorExists() { var (world, group) = Setup(); var state = world.ReadSingleton(); var player = PlayCardCommand.FindPlayerByIndex(world, state.CurrentPlayerIndex); // Play two warriors. var hand = GameUtil.GetHandCards(world, player); var warrior1 = FindCardWithEffect(world, hand, CardEffect.Warrior); var warrior2 = FindSecondCardWithEffect(world, hand, CardEffect.Warrior); if (warrior1 == Entity.Null || warrior2 == Entity.Null) return; // Not enough warriors in deck. var def = world.ReadComponent(warrior1); world.Commands.Enqueue(new PlayCardCommand { CardEntity = warrior1, Rank = def.Ranks[0], FaceDown = false, TargetPlayer = null }); group.RunLogical(); // First warrior: no other warrior, no horn. GameUtil.GetFieldCards(world, player).Should().Contain(warrior1); world.HasComponent(warrior1).Should().BeFalse(because: "no other warrior on field"); // Play second warrior. var def2 = world.ReadComponent(warrior2); world.Commands.Enqueue(new PlayCardCommand { CardEntity = warrior2, Rank = def2.Ranks[0], FaceDown = false, TargetPlayer = null }); group.RunLogical(); // Second warrior has another warrior, should get horn. // But Wait — the effect checks "other" warriors on field. The first warrior // is on field, so the second warrior should get a horn. world.HasComponent(warrior2).Should().BeTrue(because: "another warrior exists on field"); } [Fact] public void MercenaryEffect_SetsPendingChoice() { var (world, group) = Setup(); var state = world.ReadSingleton(); var player = PlayCardCommand.FindPlayerByIndex(world, state.CurrentPlayerIndex); // Play first mercenary (no effect). var hand = GameUtil.GetHandCards(world, player); var merc = FindCardWithEffect(world, hand, CardEffect.Mercenary); if (merc == Entity.Null) return; var def = world.ReadComponent(merc); world.Commands.Enqueue(new PlayCardCommand { CardEntity = merc, Rank = def.Ranks[0], FaceDown = false, TargetPlayer = null }); group.RunLogical(); // Play second mercenary. We need another one from a drawn card. var publicDeck = GameUtil.FindEntity(world); GameUtil.DrawCard(world, publicDeck, player); var newHand = GameUtil.GetHandCards(world, player); var merc2 = FindCardWithEffect(world, newHand, CardEffect.Mercenary); if (merc2 == Entity.Null) return; var def2 = world.ReadComponent(merc2); world.Commands.Enqueue(new PlayCardCommand { CardEntity = merc2, Rank = def2.Ranks[0], FaceDown = false, TargetPlayer = null }); group.RunLogical(); // Should have a pending Mercenary choice. world.HasSingleton().Should().BeTrue(); var pending = world.ReadSingleton(); pending.CardEntity.Should().Be(merc2); // Resolve the choice (pick a target). world.Commands.Enqueue(new ResolveChoiceCommand { Target = merc }); group.RunLogical(); // The pending should be cleared. world.HasSingleton().Should().BeFalse(); } private static Entity FindCardWithEffect(World world, List cards, CardEffect effect) { foreach (var c in cards) { if (world.HasComponent(c) && world.ReadComponent(c).Effect == effect) return c; } return Entity.Null; } private static Entity FindSecondCardWithEffect(World world, List cards, CardEffect effect) { Entity first = Entity.Null; foreach (var c in cards) { if (world.HasComponent(c) && world.ReadComponent(c).Effect == effect) { if (first == Entity.Null) first = c; else return c; } } return Entity.Null; } }