feat(D.2b): VitalsController — bind live vitals data by element id
Mirrors retail gmVitalsUI::PostInit: grab Health/Stamina/Mana meters from the imported layout by their dat element ids (0x100000E6 / EC / EE) and wire Func<float> fill + Func<string> label providers. Missing ids are silently skipped (no throw). Slice sprites + dat font already set by the factory — this is pure data wiring, not graphics. 3 TDD tests: single-meter fill+label, all-three distinct providers, missing-id no-throw. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
parent
9a55a688ca
commit
9d2527d9c8
2 changed files with 166 additions and 0 deletions
102
tests/AcDream.App.Tests/UI/Layout/VitalsBindingTests.cs
Normal file
102
tests/AcDream.App.Tests/UI/Layout/VitalsBindingTests.cs
Normal file
|
|
@ -0,0 +1,102 @@
|
|||
using AcDream.App.UI;
|
||||
using AcDream.App.UI.Layout;
|
||||
|
||||
namespace AcDream.App.Tests.UI.Layout;
|
||||
|
||||
/// <summary>
|
||||
/// Unit tests for <see cref="VitalsController.Bind"/>: verifies that the controller
|
||||
/// correctly maps element ids to UiMeter instances and wires the Fill / Label providers.
|
||||
/// No dats, no GL — pure data-wiring tests.
|
||||
/// </summary>
|
||||
public class VitalsBindingTests
|
||||
{
|
||||
// ── Test 1: Health meter Fill + Label providers are bound ─────────────────
|
||||
|
||||
[Fact]
|
||||
public void Bind_SetsHealthMeterFillFromProvider()
|
||||
{
|
||||
var health = new UiMeter();
|
||||
var layout = FakeLayout(("0x100000E6", health));
|
||||
float hp = 0.42f;
|
||||
|
||||
VitalsController.Bind(layout,
|
||||
healthPct: () => hp,
|
||||
staminaPct: () => 1f,
|
||||
manaPct: () => 1f,
|
||||
healthText: () => "42/100",
|
||||
staminaText: () => "",
|
||||
manaText: () => "");
|
||||
|
||||
Assert.Equal(0.42f, health.Fill()!.Value);
|
||||
Assert.Equal("42/100", health.Label());
|
||||
}
|
||||
|
||||
// ── Test 2: All three meters wired to distinct providers ──────────────────
|
||||
|
||||
[Fact]
|
||||
public void Bind_AllThreeMeters_EachBoundToOwnProvider()
|
||||
{
|
||||
var health = new UiMeter();
|
||||
var stamina = new UiMeter();
|
||||
var mana = new UiMeter();
|
||||
var layout = FakeLayout(
|
||||
("0x100000E6", health),
|
||||
("0x100000EC", stamina),
|
||||
("0x100000EE", mana));
|
||||
|
||||
VitalsController.Bind(layout,
|
||||
healthPct: () => 0.25f,
|
||||
staminaPct: () => 0.50f,
|
||||
manaPct: () => 0.75f,
|
||||
healthText: () => "25/100",
|
||||
staminaText: () => "50/100",
|
||||
manaText: () => "75/100");
|
||||
|
||||
// Each meter should reflect its own provider, not another's.
|
||||
Assert.Equal(0.25f, health.Fill()!.Value);
|
||||
Assert.Equal("25/100", health.Label());
|
||||
|
||||
Assert.Equal(0.50f, stamina.Fill()!.Value);
|
||||
Assert.Equal("50/100", stamina.Label());
|
||||
|
||||
Assert.Equal(0.75f, mana.Fill()!.Value);
|
||||
Assert.Equal("75/100", mana.Label());
|
||||
}
|
||||
|
||||
// ── Test 3: Missing meter ids are silently skipped (no throw) ─────────────
|
||||
|
||||
[Fact]
|
||||
public void Bind_MissingMeterIds_DoesNotThrow()
|
||||
{
|
||||
// Only Health is present; Stamina and Mana are absent from the layout.
|
||||
var health = new UiMeter();
|
||||
var layout = FakeLayout(("0x100000E6", health));
|
||||
|
||||
// Should not throw even though Stamina/Mana are missing.
|
||||
VitalsController.Bind(layout,
|
||||
healthPct: () => 1f,
|
||||
staminaPct: () => 1f,
|
||||
manaPct: () => 1f,
|
||||
healthText: () => "100/100",
|
||||
staminaText: () => "100/100",
|
||||
manaText: () => "100/100");
|
||||
|
||||
// Health was present — it should be wired.
|
||||
Assert.Equal(1f, health.Fill()!.Value);
|
||||
}
|
||||
|
||||
// ── Helpers ───────────────────────────────────────────────────────────────
|
||||
|
||||
private static ImportedLayout FakeLayout(params (string idHex, UiElement e)[] items)
|
||||
{
|
||||
var dict = new Dictionary<uint, UiElement>();
|
||||
var root = new UiPanel();
|
||||
foreach (var (idHex, e) in items)
|
||||
{
|
||||
uint id = Convert.ToUInt32(idHex, 16);
|
||||
root.AddChild(e);
|
||||
dict[id] = e;
|
||||
}
|
||||
return new ImportedLayout(root, dict);
|
||||
}
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue