neon-sprawl/server/NeonSprawl.Server.Tests/Game/Combat/CombatEntityHealthStoreTest...

154 lines
5.6 KiB
C#

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<ICombatEntityHealthStore>();
var found = store.TryGet(PrototypeTargetRegistry.PrototypeTargetAlphaId, out var snapshot);
// Assert
Assert.True(found);
Assert.Equal(PrototypeCombatConstants.MaxPrototypeTargetHp, snapshot.CurrentHp);
Assert.False(snapshot.Defeated);
}
}