using System; using System.Collections.Generic; using System.Numerics; using AcDream.App.UI; namespace AcDream.App.Tests.UI; public class UiChatViewTests { [Fact] public void ClampScroll_PinsToZero_WhenContentFitsView() { // 5 lines of content in a taller view → nothing to scroll, pinned at 0. Assert.Equal(0f, UiChatView.ClampScroll(50f, contentHeight: 80f, viewHeight: 200f)); Assert.Equal(0f, UiChatView.ClampScroll(0f, contentHeight: 80f, viewHeight: 200f)); } [Fact] public void ClampScroll_CapsAtContentMinusView_WhenOverflowing() { // Content 500, view 200 → max scrollback is 300px (oldest line at top). Assert.Equal(300f, UiChatView.ClampScroll(1000f, contentHeight: 500f, viewHeight: 200f)); Assert.Equal(120f, UiChatView.ClampScroll(120f, contentHeight: 500f, viewHeight: 200f)); } [Fact] public void ClampScroll_NeverNegative() { Assert.Equal(0f, UiChatView.ClampScroll(-50f, contentHeight: 500f, viewHeight: 200f)); } // ── Char-index hit-testing (x → col) with a synthetic 10px monospace advance ── private static readonly Func Mono10 = static _ => 10f; [Fact] public void CharIndexAt_ZeroOrNegative_IsColumnZero() { Assert.Equal(0, UiChatView.CharIndexAt("hello", Mono10, 0f)); Assert.Equal(0, UiChatView.CharIndexAt("hello", Mono10, -5f)); } [Fact] public void CharIndexAt_SnapsToGlyphMidpoint() { // glyph[0] spans 0..10 (midpoint 5), glyph[1] 10..20 (midpoint 15), ... Assert.Equal(0, UiChatView.CharIndexAt("hello", Mono10, 4f)); // before mid of glyph 0 Assert.Equal(1, UiChatView.CharIndexAt("hello", Mono10, 6f)); // past mid of glyph 0 Assert.Equal(1, UiChatView.CharIndexAt("hello", Mono10, 14f)); // before mid of glyph 1 Assert.Equal(2, UiChatView.CharIndexAt("hello", Mono10, 16f)); // past mid of glyph 1 } [Fact] public void CharIndexAt_PastEnd_IsLength() { Assert.Equal(5, UiChatView.CharIndexAt("hello", Mono10, 1000f)); } [Fact] public void CharIndexAt_EmptyString_IsZero() { Assert.Equal(0, UiChatView.CharIndexAt("", Mono10, 50f)); } // ── SelectedText assembly ──────────────────────────────────────────── private static IReadOnlyList Lines(params string[] texts) { var list = new List(texts.Length); foreach (var t in texts) list.Add(new UiChatView.Line(t, new Vector4(1, 1, 1, 1))); return list; } [Fact] public void SelectedText_SingleLine_Substring() { var lines = Lines("hello world"); var s = UiChatView.SelectedText(lines, new UiChatView.Pos(0, 6), new UiChatView.Pos(0, 11)); Assert.Equal("world", s); } [Fact] public void SelectedText_SingleLine_ReversedAnchorCaret_IsNormalised() { var lines = Lines("hello world"); // caret BEFORE anchor — Order() must normalise. var s = UiChatView.SelectedText(lines, new UiChatView.Pos(0, 11), new UiChatView.Pos(0, 6)); Assert.Equal("world", s); } [Fact] public void SelectedText_SamePosition_IsEmpty() { var lines = Lines("hello"); Assert.Equal("", UiChatView.SelectedText(lines, new UiChatView.Pos(0, 3), new UiChatView.Pos(0, 3))); } [Fact] public void SelectedText_MultiLine_JoinsWithNewline() { var lines = Lines("first line", "second line", "third line"); // from col 6 of line 0 ("line") through col 5 of line 2 ("third") var s = UiChatView.SelectedText(lines, new UiChatView.Pos(0, 6), new UiChatView.Pos(2, 5)); Assert.Equal("line\nsecond line\nthird", s); } [Fact] public void SelectedText_MultiLine_TwoLines_NoMiddle() { var lines = Lines("alpha", "bravo"); var s = UiChatView.SelectedText(lines, new UiChatView.Pos(0, 2), new UiChatView.Pos(1, 3)); Assert.Equal("pha\nbra", s); } [Fact] public void SelectedText_MultiLine_ReversedAnchorCaret_IsNormalised() { var lines = Lines("alpha", "bravo"); // end before start → Order() swaps them. var s = UiChatView.SelectedText(lines, new UiChatView.Pos(1, 3), new UiChatView.Pos(0, 2)); Assert.Equal("pha\nbra", s); } [Fact] public void SelectedText_EmptyLineList_IsEmpty() { Assert.Equal("", UiChatView.SelectedText(Array.Empty(), new UiChatView.Pos(0, 0), new UiChatView.Pos(0, 0))); } [Fact] public void Order_SortsByLineThenColumn() { var (s1, e1) = UiChatView.Order(new UiChatView.Pos(2, 1), new UiChatView.Pos(0, 5)); Assert.Equal(new UiChatView.Pos(0, 5), s1); Assert.Equal(new UiChatView.Pos(2, 1), e1); var (s2, e2) = UiChatView.Order(new UiChatView.Pos(1, 8), new UiChatView.Pos(1, 2)); Assert.Equal(new UiChatView.Pos(1, 2), s2); Assert.Equal(new UiChatView.Pos(1, 8), e2); } }