test(ui): AcDream.UI.Abstractions unit tests (11 tests green)
Covers the pure-logic surface of commit 1:
VitalsVMTests
* HealthPercent reads from CombatState.GetHealthPercent
* safe-default 1.0 when GUID unknown / not yet set / never updated
* SetLocalPlayerGuid reroutes lookup to the new guid (no stale cache)
* StaminaPercent / ManaPercent are null for D.2a scope
* ctor throws ArgumentNullException on null CombatState
PanelContextTests
* record-struct fields round-trip
* value-based equality
NullCommandBusTests
* Publish accepts any record type without throwing
* Instance is a true singleton
csproj template mirrors AcDream.Core.Tests (xUnit 2.9.3, Test.Sdk 17.14.1,
runner 3.1.4, coverlet 6.0.4, implicit Using Xunit). References only
AcDream.UI.Abstractions — no runtime / GL dependency, tests run fast.
This commit is contained in:
parent
8c64ad2eeb
commit
fc03fa377b
5 changed files with 152 additions and 0 deletions
|
|
@ -0,0 +1,25 @@
|
|||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFramework>net10.0</TargetFramework>
|
||||
<ImplicitUsings>enable</ImplicitUsings>
|
||||
<Nullable>enable</Nullable>
|
||||
<IsPackable>false</IsPackable>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="coverlet.collector" Version="6.0.4" />
|
||||
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.14.1" />
|
||||
<PackageReference Include="xunit" Version="2.9.3" />
|
||||
<PackageReference Include="xunit.runner.visualstudio" Version="3.1.4" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<Using Include="Xunit" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\..\src\AcDream.UI.Abstractions\AcDream.UI.Abstractions.csproj" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
22
tests/AcDream.UI.Abstractions.Tests/NullCommandBusTests.cs
Normal file
22
tests/AcDream.UI.Abstractions.Tests/NullCommandBusTests.cs
Normal file
|
|
@ -0,0 +1,22 @@
|
|||
namespace AcDream.UI.Abstractions.Tests;
|
||||
|
||||
public sealed class NullCommandBusTests
|
||||
{
|
||||
private sealed record FakeCmd(int Value);
|
||||
|
||||
[Fact]
|
||||
public void Publish_DoesNotThrow_OnAnyRecordType()
|
||||
{
|
||||
var bus = NullCommandBus.Instance;
|
||||
|
||||
bus.Publish(new FakeCmd(42));
|
||||
bus.Publish("a string command");
|
||||
bus.Publish(12345);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Instance_IsSingleton()
|
||||
{
|
||||
Assert.Same(NullCommandBus.Instance, NullCommandBus.Instance);
|
||||
}
|
||||
}
|
||||
24
tests/AcDream.UI.Abstractions.Tests/PanelContextTests.cs
Normal file
24
tests/AcDream.UI.Abstractions.Tests/PanelContextTests.cs
Normal file
|
|
@ -0,0 +1,24 @@
|
|||
namespace AcDream.UI.Abstractions.Tests;
|
||||
|
||||
public sealed class PanelContextTests
|
||||
{
|
||||
[Fact]
|
||||
public void Fields_RoundTripThroughConstructor()
|
||||
{
|
||||
var ctx = new PanelContext(DeltaSeconds: 0.016f, Commands: NullCommandBus.Instance);
|
||||
|
||||
Assert.Equal(0.016f, ctx.DeltaSeconds);
|
||||
Assert.Same(NullCommandBus.Instance, ctx.Commands);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void RecordEquality_ByValue()
|
||||
{
|
||||
var a = new PanelContext(1f / 60f, NullCommandBus.Instance);
|
||||
var b = new PanelContext(1f / 60f, NullCommandBus.Instance);
|
||||
|
||||
// Record-struct equality is value-based on DeltaSeconds + reference-based
|
||||
// on Commands (since ICommandBus is a reference type, same instance → equal).
|
||||
Assert.Equal(a, b);
|
||||
}
|
||||
}
|
||||
80
tests/AcDream.UI.Abstractions.Tests/VitalsVMTests.cs
Normal file
80
tests/AcDream.UI.Abstractions.Tests/VitalsVMTests.cs
Normal file
|
|
@ -0,0 +1,80 @@
|
|||
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<ArgumentNullException>(() => new VitalsVM(null!));
|
||||
}
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue