using AcDream.App.Studio; using AcDream.App.UI; using AcDream.App.UI.Layout; namespace AcDream.App.Tests.UI.Layout; /// /// Unit tests for — the Attributes-tab controller that /// binds the REAL importer-mounted header + list elements (no created overlay). Pure data /// wiring against fake layouts; no dats, no GL. /// public class CharacterStatControllerTests { // ── Header labels bind to the sheet ────────────────────────────────────── [Fact] public void Bind_SetsNameLabel() { var name = new UiText(); var layout = Fake((CharacterStatController.NameId, name)); CharacterStatController.Bind(layout, SampleData.SampleCharacter); Assert.Equal("Studio Player", name.LinesProvider()[0].Text); } [Fact] public void Bind_SetsLevelLabel() { var level = new UiText(); var layout = Fake((CharacterStatController.LevelId, level)); CharacterStatController.Bind(layout, SampleData.SampleCharacter); Assert.Equal("126", level.LinesProvider()[0].Text); } [Fact] public void Bind_SetsHeritageAndPkLabels() { var heritage = new UiText(); var pk = new UiText(); var layout = Fake((CharacterStatController.HeritageId, heritage), (CharacterStatController.PkStatusId, pk)); CharacterStatController.Bind(layout, SampleData.SampleCharacter); Assert.Equal("Aluvian Heritage", heritage.LinesProvider()[0].Text); Assert.Equal("Non-Player Killer", pk.LinesProvider()[0].Text); } // ── XP meter fill ──────────────────────────────────────────────────────── [Fact] public void Bind_SetsXpMeterFill() { var meter = new UiMeter(); var layout = Fake((CharacterStatController.XpMeterId, meter)); CharacterStatController.Bind(layout, SampleData.SampleCharacter); var fill = meter.Fill(); Assert.NotNull(fill); Assert.True(System.MathF.Abs(fill!.Value - 0.63f) < 0.001f, $"expected ~0.63, got {fill}"); } // ── Attribute list ─────────────────────────────────────────────────────── [Fact] public void Bind_PopulatesAttributeList() { var list = new UiPanel(); var layout = Fake((CharacterStatController.ListBoxId, list)); CharacterStatController.Bind(layout, SampleData.SampleCharacter); var rows = list.Children.OfType().First(); var text = string.Join("\n", rows.LinesProvider().Select(l => l.Text)); Assert.Contains("Strength", text); Assert.Contains("Endurance", text); Assert.Contains("Coordination", text); Assert.Contains("Quickness", text); Assert.Contains("Focus", text); Assert.Contains("Self", text); Assert.Contains("100", text); } // ── Robustness: a partial layout (missing ids) must not throw ──────────── [Fact] public void Bind_MissingElements_DoesNotThrow() => CharacterStatController.Bind(Fake(), SampleData.SampleCharacter); // ── Helper ───────────────────────────────────────────────────────────── private static ImportedLayout Fake(params (uint id, UiElement e)[] items) { var dict = new Dictionary(); var root = new UiPanel(); foreach (var (id, e) in items) { root.AddChild(e); dict[id] = e; } return new ImportedLayout(root, dict); } }