using AcDream.Core.Combat; using AcDream.UI.Abstractions.Panels.Vitals; namespace AcDream.UI.Abstractions.Tests; public sealed class VitalsVMTests { [Fact] public void HealthPercent_ReturnsCombatStateValue_AfterUpdateHealth() { var combat = new CombatState(); uint guid = 0x5000_0042u; combat.OnUpdateHealth(guid, 0.42f); var vm = new VitalsVM(combat); vm.SetLocalPlayerGuid(guid); Assert.Equal(0.42f, vm.HealthPercent, precision: 3); } [Fact] public void HealthPercent_ReturnsOne_WhenGuidUnknown() { var combat = new CombatState(); var vm = new VitalsVM(combat); // No SetLocalPlayerGuid call — defaults to 0 which CombatState has never seen. Assert.Equal(1f, vm.HealthPercent); } [Fact] public void HealthPercent_ReturnsOne_WhenGuidSetButNeverUpdated() { var combat = new CombatState(); var vm = new VitalsVM(combat); vm.SetLocalPlayerGuid(0xDEAD_BEEFu); Assert.Equal(1f, vm.HealthPercent); } [Fact] public void StaminaPercent_IsNull_ForD2aScope() { // D.2a explicitly defers Stamina until LocalPlayerState + PlayerDescription // wiring. When that arrives VitalsVM.StaminaPercent becomes non-null and // VitalsPanel starts drawing the Stam bar automatically. var vm = new VitalsVM(new CombatState()); Assert.Null(vm.StaminaPercent); } [Fact] public void ManaPercent_IsNull_ForD2aScope() { var vm = new VitalsVM(new CombatState()); Assert.Null(vm.ManaPercent); } [Fact] public void SetLocalPlayerGuid_ReroutesHealthLookup_WithoutStaleCache() { // Simulate the realistic GameWindow flow: VM is constructed pre-login // with GUID=0, then SetLocalPlayerGuid is called at EnterWorld. var combat = new CombatState(); uint playerGuid = 0x5003_E219u; combat.OnUpdateHealth(playerGuid, 0.75f); var vm = new VitalsVM(combat); // Before SetLocalPlayerGuid — reads GUID=0 → returns safe 1.0. Assert.Equal(1f, vm.HealthPercent); vm.SetLocalPlayerGuid(playerGuid); Assert.Equal(0.75f, vm.HealthPercent, precision: 3); } [Fact] public void Constructor_ThrowsOnNullCombat() { Assert.Throws(() => new VitalsVM(null!)); } }