202 lines
7.0 KiB
C#
202 lines
7.0 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 var alphaAfterDamage);
|
|
// Act
|
|
var found = store.TryGet(PrototypeTargetRegistry.PrototypeTargetBetaId, out var beta);
|
|
// Assert
|
|
Assert.True(found);
|
|
Assert.Equal(PrototypeCombatConstants.MaxPrototypeTargetHp, beta.CurrentHp);
|
|
Assert.False(beta.Defeated);
|
|
Assert.Equal(60, alphaAfterDamage.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 void TryApplyDamage_ShouldReturnFalse_WhenTargetIdIsUnknown()
|
|
{
|
|
// Arrange
|
|
var store = new InMemoryCombatEntityHealthStore();
|
|
// Act
|
|
var applied = store.TryApplyDamage("not_a_prototype_target", 25, out var snapshot);
|
|
// Assert
|
|
Assert.False(applied);
|
|
Assert.Equal(default, snapshot);
|
|
}
|
|
|
|
[Fact]
|
|
public void TryApplyDamage_ShouldReturnFalse_WhenTargetIdIsEmpty()
|
|
{
|
|
// Arrange
|
|
var store = new InMemoryCombatEntityHealthStore();
|
|
// Act
|
|
var applied = store.TryApplyDamage(" ", 25, out var snapshot);
|
|
// Assert
|
|
Assert.False(applied);
|
|
Assert.Equal(default, snapshot);
|
|
}
|
|
|
|
[Fact]
|
|
public void TryGet_ShouldNormalizeCaseVariantTargetIds()
|
|
{
|
|
// Arrange
|
|
var store = new InMemoryCombatEntityHealthStore();
|
|
// Act
|
|
var found = store.TryGet(" Prototype_Target_Alpha ", out var snapshot);
|
|
// Assert
|
|
Assert.True(found);
|
|
Assert.Equal(PrototypeTargetRegistry.PrototypeTargetAlphaId, snapshot.TargetId);
|
|
Assert.Equal(PrototypeCombatConstants.MaxPrototypeTargetHp, snapshot.CurrentHp);
|
|
}
|
|
|
|
[Fact]
|
|
public void TryResetToFull_ShouldReturnFalse_WhenTargetIdIsUnknown()
|
|
{
|
|
// Arrange
|
|
var store = new InMemoryCombatEntityHealthStore();
|
|
// Act
|
|
var reset = store.TryResetToFull("not_a_prototype_target", out var snapshot);
|
|
// Assert
|
|
Assert.False(reset);
|
|
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);
|
|
}
|
|
}
|