using AcDream.App.Studio; using AcDream.App.UI; using AcDream.App.UI.Layout; namespace AcDream.App.Tests.UI.Layout; /// /// Unit tests for and . /// No dats, no GL — pure data-wiring + report-content tests. /// public class CharacterControllerTests { // ── Test 1: Bind finds the main text element and sets LinesProvider ─────── [Fact] public void Bind_SetsLinesProviderOnMainText() { var text = new UiText(); var layout = FakeLayout((CharacterController.MainTextId, text)); CharacterController.Bind(layout, SampleData.SampleCharacter); // LinesProvider must be replaced (default returns empty). var lines = text.LinesProvider(); Assert.True(lines.Count > 0, "Expected non-empty report after Bind"); } // ── Test 2: Report contains all six attribute names (decomp order 1,2,4,3,5,6) ─── [Fact] public void Bind_ReportContainsAllSixAttributes() { var text = new UiText(); var layout = FakeLayout((CharacterController.MainTextId, text)); CharacterController.Bind(layout, SampleData.SampleCharacter); var allText = string.Join("\n", text.LinesProvider().Select(l => l.Text)); Assert.Contains("Strength", allText); Assert.Contains("Endurance", allText); Assert.Contains("Quickness", allText); Assert.Contains("Coordination", allText); Assert.Contains("Focus", allText); Assert.Contains("Self", allText); } // ── Test 3: Report contains vitals section ──────────────────────────────── [Fact] public void Bind_ReportContainsVitals() { var text = new UiText(); var layout = FakeLayout((CharacterController.MainTextId, text)); CharacterController.Bind(layout, SampleData.SampleCharacter); var allText = string.Join("\n", text.LinesProvider().Select(l => l.Text)); Assert.Contains("Health", allText); Assert.Contains("Stamina", allText); Assert.Contains("Mana", allText); } // ── Test 4: Report contains encumbrance / burden section ───────────────── [Fact] public void Bind_ReportContainsBurden() { var text = new UiText(); var layout = FakeLayout((CharacterController.MainTextId, text)); CharacterController.Bind(layout, SampleData.SampleCharacter); var allText = string.Join("\n", text.LinesProvider().Select(l => l.Text)); Assert.Contains("Burden", allText); Assert.Contains("Capacity", allText); } // ── Test 5: Report contains the sample character's name ────────────────── [Fact] public void Bind_ReportContainsSampleName() { var text = new UiText(); var layout = FakeLayout((CharacterController.MainTextId, text)); CharacterController.Bind(layout, SampleData.SampleCharacter); var allText = string.Join("\n", text.LinesProvider().Select(l => l.Text)); // SampleData.SampleCharacter().Name == "Studio Player" Assert.Contains("Studio Player", allText); } // ── Test 6: Missing element id is a no-op (no throw) ───────────────────── [Fact] public void Bind_MissingElement_DoesNotThrow() { // Layout does not contain MainTextId — Bind must silently skip. var layout = FakeLayout(); // empty layout // Must not throw. CharacterController.Bind(layout, SampleData.SampleCharacter); } // ── Test 7: Element that is NOT a UiText is silently skipped ───────────── [Fact] public void Bind_WrongElementType_DoesNotThrow() { // Place a UiMeter at the MainTextId — Bind must skip (not crash on wrong type). var meter = new UiMeter(); var layout = FakeLayout((CharacterController.MainTextId, meter)); CharacterController.Bind(layout, SampleData.SampleCharacter); // No exception; meter is unchanged. } // ── Test 8: SampleCharacter fixture has non-zero attribute values ───────── [Fact] public void SampleCharacter_AttributesAreNonZero() { var s = SampleData.SampleCharacter(); Assert.True(s.Strength > 0, "Strength must be > 0"); Assert.True(s.Endurance > 0, "Endurance must be > 0"); Assert.True(s.Quickness > 0, "Quickness must be > 0"); Assert.True(s.Coordination > 0, "Coordination must be > 0"); Assert.True(s.Focus > 0, "Focus must be > 0"); Assert.True(s.Self > 0, "Self must be > 0"); } // ── Test 9: SampleCharacter fixture has coherent vitals ────────────────── [Fact] public void SampleCharacter_VitalsAreCoherent() { var s = SampleData.SampleCharacter(); Assert.True(s.HealthCurrent > 0 && s.HealthCurrent <= s.HealthMax, "Health cur must be in [1, max]"); Assert.True(s.StaminaCurrent > 0 && s.StaminaCurrent <= s.StaminaMax, "Stamina cur must be in [1, max]"); Assert.True(s.ManaCurrent > 0 && s.ManaCurrent <= s.ManaMax, "Mana cur must be in [1, max]"); } // ── Test 10: Report contains attribute VALUES from the fixture ──────────── [Fact] public void Bind_ReportContainsSampleAttributeValues() { var text = new UiText(); var layout = FakeLayout((CharacterController.MainTextId, text)); var sheet = SampleData.SampleCharacter(); CharacterController.Bind(layout, () => sheet); var allText = string.Join("\n", text.LinesProvider().Select(l => l.Text)); // All six attribute values should appear as strings in the report. Assert.Contains(sheet.Strength.ToString(), allText); Assert.Contains(sheet.Endurance.ToString(), allText); Assert.Contains(sheet.Quickness.ToString(), allText); Assert.Contains(sheet.Coordination.ToString(), allText); Assert.Contains(sheet.Focus.ToString(), allText); Assert.Contains(sheet.Self.ToString(), allText); } // ── Helpers ─────────────────────────────────────────────────────────────── private static ImportedLayout FakeLayout(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); } }