using System.Numerics; namespace AcDream.UI.Abstractions.Tests; /// /// Tests the shape of the new Phase I.1 widget extensions on /// . Every test dispatches through the /// interface (not the concrete fake) so the test only compiles when /// the interface actually has the method — that's the RED signal for /// TDD when adding new widgets in the future. /// public sealed class IPanelRendererWidgetTests { private static (IPanelRenderer Iface, FakePanelRenderer Fake) New() { var f = new FakePanelRenderer(); return (f, f); } [Fact] public void TextColored_RecordsCallWithColorAndText() { var (r, fake) = New(); var color = new Vector4(0.9f, 0.4f, 0.2f, 1f); r.TextColored(color, "ouch"); var call = Assert.Single(fake.Calls); Assert.Equal("TextColored", call.Method); Assert.Equal(color, call.Args[0]); Assert.Equal("ouch", call.Args[1]); } [Fact] public void CollapsingHeader_RecordsLabelAndDefaultOpen_ReturnsBackingValue() { var (r, fake) = New(); fake.CollapsingHeaderNextReturn = false; bool open = r.CollapsingHeader("Player Info"); Assert.False(open); var call = Assert.Single(fake.Calls); Assert.Equal("CollapsingHeader", call.Method); Assert.Equal("Player Info", call.Args[0]); Assert.Equal(true, call.Args[1]); // default } [Fact] public void CollapsingHeader_PassesDefaultOpenFalse() { var (r, fake) = New(); r.CollapsingHeader("Diagnostics", defaultOpen: false); var call = Assert.Single(fake.Calls); Assert.Equal(false, call.Args[1]); } [Fact] public void TreeNode_AndTreePop_FormPair() { var (r, fake) = New(); fake.TreeNodeNextReturn = true; if (r.TreeNode("Inventory")) { r.Text("sword"); r.TreePop(); } Assert.Equal(3, fake.Calls.Count); Assert.Equal("TreeNode", fake.Calls[0].Method); Assert.Equal("Inventory", fake.Calls[0].Args[0]); Assert.Equal("Text", fake.Calls[1].Method); Assert.Equal("TreePop", fake.Calls[2].Method); } [Fact] public void Checkbox_AppliesNextValueToRefAndRecordsBefore() { var (r, fake) = New(); fake.CheckboxNextReturn = true; fake.CheckboxNextValue = true; bool flag = false; bool changed = r.Checkbox("DumpMotion", ref flag); Assert.True(changed); Assert.True(flag); // fake mutated the ref var call = Assert.Single(fake.Calls); Assert.Equal("Checkbox", call.Method); Assert.Equal("DumpMotion", call.Args[0]); Assert.Equal(false, call.Args[1]); // value-before-the-call captured in trace } [Fact] public void Button_ReturnsBackingValueAndRecordsLabel() { var (r, fake) = New(); fake.ButtonNextReturn = true; bool clicked = r.Button("Cycle Weather"); Assert.True(clicked); var call = Assert.Single(fake.Calls); Assert.Equal("Button", call.Method); Assert.Equal("Cycle Weather", call.Args[0]); } [Fact] public void Combo_AppliesNextSelectedIndex_AndReturnsChanged() { var (r, fake) = New(); fake.ComboNextReturn = true; fake.ComboNextSelectedIndex = 2; int idx = 0; var items = new[] { "Dawn", "Noon", "Dusk", "Night" }; bool changed = r.Combo("Time", ref idx, items); Assert.True(changed); Assert.Equal(2, idx); var call = Assert.Single(fake.Calls); Assert.Equal("Combo", call.Method); Assert.Equal("Time", call.Args[0]); Assert.Equal(0, call.Args[1]); Assert.Same(items, call.Args[2]); } [Fact] public void SliderFloat_AppliesNextValueAndReturnsChanged() { var (r, fake) = New(); fake.SliderFloatNextReturn = true; fake.SliderFloatNextValue = 0.7f; float v = 0.1f; bool changed = r.SliderFloat("Sensitivity", ref v, 0f, 1f); Assert.True(changed); Assert.Equal(0.7f, v); var call = Assert.Single(fake.Calls); Assert.Equal("SliderFloat", call.Method); Assert.Equal("Sensitivity", call.Args[0]); Assert.Equal(0.1f, call.Args[1]); Assert.Equal(0f, call.Args[2]); Assert.Equal(1f, call.Args[3]); } [Fact] public void PlotLines_RecordsAllOptionalArgs() { var (r, fake) = New(); var values = new[] { 16f, 17f, 16.5f, 16.2f }; r.PlotLines( "FrameMs", values, count: values.Length, offset: 1, overlay: "60 fps", min: 0f, max: 33f, size: new Vector2(120, 40)); var call = Assert.Single(fake.Calls); Assert.Equal("PlotLines", call.Method); Assert.Equal("FrameMs", call.Args[0]); Assert.Same(values, call.Args[1]); Assert.Equal(values.Length, call.Args[2]); Assert.Equal(1, call.Args[3]); Assert.Equal("60 fps", call.Args[4]); Assert.Equal(0f, call.Args[5]); Assert.Equal(33f, call.Args[6]); Assert.Equal(new Vector2(120, 40), call.Args[7]); } [Fact] public void PlotLines_DefaultsApplied_WhenOptionalsOmitted() { var (r, fake) = New(); var values = new[] { 1f, 2f, 3f }; r.PlotLines("FPS", values, count: values.Length); var call = Assert.Single(fake.Calls); Assert.Equal(0, call.Args[3]); // offset default Assert.Null(call.Args[4]); // overlay default Assert.Null(call.Args[5]); // min default Assert.Null(call.Args[6]); // max default Assert.Null(call.Args[7]); // size default } [Fact] public void Table_BeginNextColumnEnd_FormSequence() { var (r, fake) = New(); r.BeginTable("Keybinds", 2); r.TableNextColumn(); r.Text("F1"); r.TableNextColumn(); r.Text("Toggle Info"); r.EndTable(); Assert.Equal(6, fake.Calls.Count); Assert.Equal("BeginTable", fake.Calls[0].Method); Assert.Equal("Keybinds", fake.Calls[0].Args[0]); Assert.Equal(2, fake.Calls[0].Args[1]); Assert.Equal("TableNextColumn", fake.Calls[1].Method); Assert.Equal("Text", fake.Calls[2].Method); Assert.Equal("TableNextColumn", fake.Calls[3].Method); Assert.Equal("Text", fake.Calls[4].Method); Assert.Equal("EndTable", fake.Calls[5].Method); } [Fact] public void InputTextSubmit_NoSubmit_ReturnsFalseAndSubmittedNull() { var (r, fake) = New(); // InputTextSubmitNextSubmitted left null → the buffer should be untouched // and the out arg should be null. string buf = "hel"; bool submitted = r.InputTextSubmit("##chat", ref buf, 256, out var output); Assert.False(submitted); Assert.Null(output); Assert.Equal("hel", buf); var call = Assert.Single(fake.Calls); Assert.Equal("InputTextSubmit", call.Method); Assert.Equal("##chat", call.Args[0]); Assert.Equal("hel", call.Args[1]); Assert.Equal(256, call.Args[2]); } [Fact] public void InputTextSubmit_OnSubmit_OutputsTextAndClearsBuffer() { var (r, fake) = New(); fake.InputTextSubmitNextSubmitted = "hello world"; fake.InputTextSubmitNextBufferAfter = string.Empty; string buf = "hello world"; bool submitted = r.InputTextSubmit("##chat", ref buf, 256, out var output); Assert.True(submitted); Assert.Equal("hello world", output); // Contract: on submit the impl clears the buffer for the next frame. Assert.Equal(string.Empty, buf); } [Fact] public void Spacing_RecordsCall() { var (r, fake) = New(); r.Spacing(); var call = Assert.Single(fake.Calls); Assert.Equal("Spacing", call.Method); } [Fact] public void Dummy_RecordsSize() { var (r, fake) = New(); r.Dummy(new Vector2(8, 12)); var call = Assert.Single(fake.Calls); Assert.Equal("Dummy", call.Method); Assert.Equal(new Vector2(8, 12), call.Args[0]); } [Fact] public void TextWrapped_RecordsText() { var (r, fake) = New(); r.TextWrapped("a long description that wraps onto multiple lines"); var call = Assert.Single(fake.Calls); Assert.Equal("TextWrapped", call.Method); Assert.Equal("a long description that wraps onto multiple lines", call.Args[0]); } // -- Sanity: existing widgets still recorded correctly via the fake ------- [Fact] public void BeginEndTextSeparatorProgressBar_StillRecorded() { var (r, fake) = New(); fake.BeginReturns = true; Assert.True(r.Begin("Window")); r.Text("hi"); r.SameLine(); r.Separator(); r.ProgressBar(0.5f, 100f, "50%"); r.End(); Assert.Equal(6, fake.Calls.Count); Assert.Equal("Begin", fake.Calls[0].Method); Assert.Equal("Text", fake.Calls[1].Method); Assert.Equal("SameLine", fake.Calls[2].Method); Assert.Equal("Separator", fake.Calls[3].Method); Assert.Equal("ProgressBar", fake.Calls[4].Method); Assert.Equal("End", fake.Calls[5].Method); } }