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);
}
}