using NeonSprawl.Server.Game.Combat; namespace NeonSprawl.Server.Tests.Game.Combat; public sealed class PlayerCombatHealthStoreTests { [Fact] public void TryGet_ShouldLazyInitToMaxHp_OnFirstAccess() { // Arrange var store = new InMemoryPlayerCombatHealthStore(); // Act var ok = store.TryGet("dev-local-1", out var snapshot); // Assert Assert.True(ok); Assert.Equal("dev-local-1", snapshot.PlayerId); Assert.Equal(PlayerCombatHealthDefaults.MaxHp, snapshot.MaxHp); Assert.Equal(PlayerCombatHealthDefaults.MaxHp, snapshot.CurrentHp); Assert.False(snapshot.Defeated); } [Fact] public void TryApplyDamage_ShouldDecreaseHp_AndFloorAtZero() { // Arrange var store = new InMemoryPlayerCombatHealthStore(); // Act var ok = store.TryApplyDamage("dev-local-1", 15, out var snapshot); // Assert Assert.True(ok); Assert.Equal(85, snapshot.CurrentHp); Assert.False(snapshot.Defeated); } [Fact] public void TryApplyDamage_ShouldMarkDefeated_WhenHpReachesZero() { // Arrange var store = new InMemoryPlayerCombatHealthStore(); // Act var ok = store.TryApplyDamage("dev-local-1", 100, out var snapshot); // Assert Assert.True(ok); Assert.Equal(0, snapshot.CurrentHp); Assert.True(snapshot.Defeated); } [Fact] public void TryApplyDamage_ShouldKeepHpAtZero_WhenAlreadyDefeated() { // Arrange var store = new InMemoryPlayerCombatHealthStore(); _ = store.TryApplyDamage("dev-local-1", 100, out _); // Act var ok = store.TryApplyDamage("dev-local-1", 25, out var snapshot); // Assert Assert.True(ok); Assert.Equal(0, snapshot.CurrentHp); Assert.True(snapshot.Defeated); } [Fact] public void TryResetToFull_ShouldRestoreMaxHp() { // Arrange var store = new InMemoryPlayerCombatHealthStore(); _ = store.TryApplyDamage("dev-local-1", 40, out _); // Act var ok = store.TryResetToFull("dev-local-1", out var snapshot); // Assert Assert.True(ok); Assert.Equal(PlayerCombatHealthDefaults.MaxHp, snapshot.CurrentHp); Assert.False(snapshot.Defeated); } [Theory] [InlineData(null)] [InlineData("")] [InlineData(" ")] public void TryGet_ShouldReturnFalse_WhenPlayerIdInvalid(string? playerId) { // Arrange var store = new InMemoryPlayerCombatHealthStore(); // Act var ok = store.TryGet(playerId, out var snapshot); // Assert Assert.False(ok); Assert.Equal(default, snapshot); } [Fact] public void TryApplyDamage_ShouldReturnFalse_WhenDamageNegative() { // Arrange var store = new InMemoryPlayerCombatHealthStore(); // Act var ok = store.TryApplyDamage("dev-local-1", -1, out var snapshot); // Assert Assert.False(ok); Assert.Equal(default, snapshot); } [Fact] public async Task Host_ShouldResolvePlayerCombatHealthStoreFromDi_WhenStartupSucceeds() { // Arrange await using var factory = new InMemoryWebApplicationFactory(); // Act var store = factory.Services.GetRequiredService(); // Assert Assert.NotNull(store); Assert.True(store.TryGet("dev-local-1", out var snapshot)); Assert.Equal(PlayerCombatHealthDefaults.MaxHp, snapshot.CurrentHp); } }