225 lines
7.5 KiB
C#
225 lines
7.5 KiB
C#
using NeonSprawl.Server.Game.Combat;
|
|
|
|
namespace NeonSprawl.Server.Tests.Game.Combat;
|
|
|
|
public sealed class CombatEntityHealthStoreTests
|
|
{
|
|
[Fact]
|
|
public void TryGet_OnFirstAccess_ShouldLazyInitMeleeToCatalogMaxHp()
|
|
{
|
|
// Arrange
|
|
var store = PrototypeNpcTestFixtures.CreateHealthStore();
|
|
// Act
|
|
var found = store.TryGet(PrototypeNpcRegistry.PrototypeNpcMeleeId, out var snapshot);
|
|
// Assert
|
|
Assert.True(found);
|
|
Assert.Equal(PrototypeNpcRegistry.PrototypeNpcMeleeId, snapshot.TargetId);
|
|
Assert.Equal(100, snapshot.MaxHp);
|
|
Assert.Equal(100, snapshot.CurrentHp);
|
|
Assert.False(snapshot.Defeated);
|
|
}
|
|
|
|
[Fact]
|
|
public void TryApplyDamage_ShouldReduceHp_WhenDamageIsApplied()
|
|
{
|
|
// Arrange
|
|
var store = PrototypeNpcTestFixtures.CreateHealthStore();
|
|
// Act
|
|
var applied = store.TryApplyDamage(PrototypeNpcRegistry.PrototypeNpcMeleeId, 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 = PrototypeNpcTestFixtures.CreateHealthStore();
|
|
// Act
|
|
var first = store.TryApplyDamage(PrototypeNpcRegistry.PrototypeNpcMeleeId, 25, out _);
|
|
var second = store.TryApplyDamage(PrototypeNpcRegistry.PrototypeNpcMeleeId, 25, out _);
|
|
var third = store.TryApplyDamage(PrototypeNpcRegistry.PrototypeNpcMeleeId, 25, out _);
|
|
var fourth = store.TryApplyDamage(PrototypeNpcRegistry.PrototypeNpcMeleeId, 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 = PrototypeNpcTestFixtures.CreateHealthStore();
|
|
_ = store.TryApplyDamage(PrototypeNpcRegistry.PrototypeNpcMeleeId, 100, out _);
|
|
// Act
|
|
var overkill = store.TryApplyDamage(PrototypeNpcRegistry.PrototypeNpcMeleeId, 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 = PrototypeNpcTestFixtures.CreateHealthStore();
|
|
_ = store.TryApplyDamage(PrototypeNpcRegistry.PrototypeNpcMeleeId, 100, out _);
|
|
// Act
|
|
var reset = store.TryResetToFull(PrototypeNpcRegistry.PrototypeNpcMeleeId, out var snapshot);
|
|
// Assert
|
|
Assert.True(reset);
|
|
Assert.Equal(100, snapshot.CurrentHp);
|
|
Assert.False(snapshot.Defeated);
|
|
}
|
|
|
|
[Fact]
|
|
public void TryGet_OnRanged_ShouldLazyInitIndependentlyFromMelee()
|
|
{
|
|
// Arrange
|
|
var store = PrototypeNpcTestFixtures.CreateHealthStore();
|
|
_ = store.TryApplyDamage(PrototypeNpcRegistry.PrototypeNpcMeleeId, 40, out var meleeAfterDamage);
|
|
// Act
|
|
var found = store.TryGet(PrototypeNpcRegistry.PrototypeNpcRangedId, out var ranged);
|
|
// Assert
|
|
Assert.True(found);
|
|
Assert.Equal(80, ranged.MaxHp);
|
|
Assert.Equal(80, ranged.CurrentHp);
|
|
Assert.False(ranged.Defeated);
|
|
Assert.Equal(60, meleeAfterDamage.CurrentHp);
|
|
}
|
|
|
|
[Fact]
|
|
public void TryGet_OnElite_ShouldLazyInitToTwoHundredMaxHp()
|
|
{
|
|
// Arrange
|
|
var store = PrototypeNpcTestFixtures.CreateHealthStore();
|
|
// Act
|
|
var found = store.TryGet(PrototypeNpcRegistry.PrototypeNpcEliteId, out var elite);
|
|
// Assert
|
|
Assert.True(found);
|
|
Assert.Equal(200, elite.MaxHp);
|
|
Assert.Equal(200, elite.CurrentHp);
|
|
Assert.False(elite.Defeated);
|
|
}
|
|
|
|
[Fact]
|
|
public void TryGet_ShouldReturnFalse_WhenTargetIdIsUnknown()
|
|
{
|
|
// Arrange
|
|
var store = PrototypeNpcTestFixtures.CreateHealthStore();
|
|
// 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 = PrototypeNpcTestFixtures.CreateHealthStore();
|
|
// 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 = PrototypeNpcTestFixtures.CreateHealthStore();
|
|
// Act
|
|
var applied = store.TryApplyDamage(PrototypeNpcRegistry.PrototypeNpcMeleeId, -1, out var snapshot);
|
|
// Assert
|
|
Assert.False(applied);
|
|
Assert.Equal(default, snapshot);
|
|
}
|
|
|
|
[Fact]
|
|
public void TryApplyDamage_ShouldReturnFalse_WhenTargetIdIsUnknown()
|
|
{
|
|
// Arrange
|
|
var store = PrototypeNpcTestFixtures.CreateHealthStore();
|
|
// 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 = PrototypeNpcTestFixtures.CreateHealthStore();
|
|
// 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 = PrototypeNpcTestFixtures.CreateHealthStore();
|
|
// Act
|
|
var found = store.TryGet(" Prototype_Npc_Melee ", out var snapshot);
|
|
// Assert
|
|
Assert.True(found);
|
|
Assert.Equal(PrototypeNpcRegistry.PrototypeNpcMeleeId, snapshot.TargetId);
|
|
Assert.Equal(100, snapshot.CurrentHp);
|
|
}
|
|
|
|
[Fact]
|
|
public void TryGet_ShouldReturnFalse_ForLegacyAlphaDummyId()
|
|
{
|
|
// Arrange
|
|
var store = PrototypeNpcTestFixtures.CreateHealthStore();
|
|
// Act
|
|
var found = store.TryGet("prototype_target_alpha", out var snapshot);
|
|
// Assert
|
|
Assert.False(found);
|
|
Assert.Equal(default, snapshot);
|
|
}
|
|
|
|
[Fact]
|
|
public void TryResetToFull_ShouldReturnFalse_WhenTargetIdIsUnknown()
|
|
{
|
|
// Arrange
|
|
var store = PrototypeNpcTestFixtures.CreateHealthStore();
|
|
// 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(PrototypeNpcRegistry.PrototypeNpcMeleeId, out var snapshot);
|
|
// Assert
|
|
Assert.True(found);
|
|
Assert.Equal(100, snapshot.CurrentHp);
|
|
Assert.False(snapshot.Defeated);
|
|
}
|
|
}
|