using Microsoft.Extensions.DependencyInjection; using NeonSprawl.Server.Game.Combat; using NeonSprawl.Server.Game.Targeting; using NeonSprawl.Server.Tests; using Xunit; namespace NeonSprawl.Server.Tests.Game.Combat; public sealed class CombatEntityHealthStoreTests { [Fact] public void TryGet_OnFirstAccess_ShouldLazyInitAlphaToFullHp() { // Arrange var store = new InMemoryCombatEntityHealthStore(); // Act var found = store.TryGet(PrototypeTargetRegistry.PrototypeTargetAlphaId, out var snapshot); // Assert Assert.True(found); Assert.Equal(PrototypeTargetRegistry.PrototypeTargetAlphaId, snapshot.TargetId); Assert.Equal(PrototypeCombatConstants.MaxPrototypeTargetHp, snapshot.MaxHp); Assert.Equal(PrototypeCombatConstants.MaxPrototypeTargetHp, snapshot.CurrentHp); Assert.False(snapshot.Defeated); } [Fact] public void TryApplyDamage_ShouldReduceHp_WhenDamageIsApplied() { // Arrange var store = new InMemoryCombatEntityHealthStore(); // Act var applied = store.TryApplyDamage(PrototypeTargetRegistry.PrototypeTargetAlphaId, 25, out var snapshot); // Assert Assert.True(applied); Assert.Equal(75, snapshot.CurrentHp); Assert.False(snapshot.Defeated); } [Fact] public void TryApplyDamage_RepeatedUntilZero_ShouldMarkDefeated() { // Arrange var store = new InMemoryCombatEntityHealthStore(); // Act var first = store.TryApplyDamage(PrototypeTargetRegistry.PrototypeTargetAlphaId, 25, out _); var second = store.TryApplyDamage(PrototypeTargetRegistry.PrototypeTargetAlphaId, 25, out _); var third = store.TryApplyDamage(PrototypeTargetRegistry.PrototypeTargetAlphaId, 25, out _); var fourth = store.TryApplyDamage(PrototypeTargetRegistry.PrototypeTargetAlphaId, 25, out var defeated); // Assert Assert.True(first); Assert.True(second); Assert.True(third); Assert.True(fourth); Assert.Equal(0, defeated.CurrentHp); Assert.True(defeated.Defeated); } [Fact] public void TryApplyDamage_OnDefeatedTarget_ShouldKeepHpAtZeroAndRemainDefeated() { // Arrange var store = new InMemoryCombatEntityHealthStore(); _ = store.TryApplyDamage(PrototypeTargetRegistry.PrototypeTargetAlphaId, 100, out _); // Act var overkill = store.TryApplyDamage(PrototypeTargetRegistry.PrototypeTargetAlphaId, 25, out var snapshot); // Assert Assert.True(overkill); Assert.Equal(0, snapshot.CurrentHp); Assert.True(snapshot.Defeated); } [Fact] public void TryResetToFull_AfterDefeat_ShouldRestoreFullHpAndClearDefeated() { // Arrange var store = new InMemoryCombatEntityHealthStore(); _ = store.TryApplyDamage(PrototypeTargetRegistry.PrototypeTargetAlphaId, 100, out _); // Act var reset = store.TryResetToFull(PrototypeTargetRegistry.PrototypeTargetAlphaId, out var snapshot); // Assert Assert.True(reset); Assert.Equal(PrototypeCombatConstants.MaxPrototypeTargetHp, snapshot.CurrentHp); Assert.False(snapshot.Defeated); } [Fact] public void TryGet_OnBeta_ShouldLazyInitIndependentlyFromAlpha() { // Arrange var store = new InMemoryCombatEntityHealthStore(); _ = store.TryApplyDamage(PrototypeTargetRegistry.PrototypeTargetAlphaId, 40, out _); // Act var found = store.TryGet(PrototypeTargetRegistry.PrototypeTargetBetaId, out var beta); store.TryGet(PrototypeTargetRegistry.PrototypeTargetAlphaId, out var alpha); // Assert Assert.True(found); Assert.Equal(PrototypeCombatConstants.MaxPrototypeTargetHp, beta.CurrentHp); Assert.False(beta.Defeated); Assert.Equal(60, alpha.CurrentHp); } [Fact] public void TryGet_ShouldReturnFalse_WhenTargetIdIsUnknown() { // Arrange var store = new InMemoryCombatEntityHealthStore(); // Act var found = store.TryGet("not_a_prototype_target", out var snapshot); // Assert Assert.False(found); Assert.Equal(default, snapshot); } [Fact] public void TryGet_ShouldReturnFalse_WhenTargetIdIsEmpty() { // Arrange var store = new InMemoryCombatEntityHealthStore(); // Act var found = store.TryGet(" ", out var snapshot); // Assert Assert.False(found); Assert.Equal(default, snapshot); } [Fact] public void TryApplyDamage_ShouldReturnFalse_WhenDamageIsNegative() { // Arrange var store = new InMemoryCombatEntityHealthStore(); // Act var applied = store.TryApplyDamage(PrototypeTargetRegistry.PrototypeTargetAlphaId, -1, out var snapshot); // Assert Assert.False(applied); Assert.Equal(default, snapshot); } [Fact] public async Task Host_ShouldResolveCombatEntityHealthStoreFromDi_WhenStartupSucceeds() { // Arrange await using var factory = new InMemoryWebApplicationFactory(); using var client = factory.CreateClient(); _ = await client.GetAsync("/health"); // Act var store = factory.Services.GetRequiredService(); var found = store.TryGet(PrototypeTargetRegistry.PrototypeTargetAlphaId, out var snapshot); // Assert Assert.True(found); Assert.Equal(PrototypeCombatConstants.MaxPrototypeTargetHp, snapshot.CurrentHp); Assert.False(snapshot.Defeated); } }