| 🛟 Updated. 28d5985 k33g 6h ago | 1 | package ui |
| 2 | |
| 3 | import ( |
| 4 | "testing" |
| 5 | |
| 6 | "github.com/gdamore/tcell/v2" |
| 7 | ) |
| 8 | |
| 9 | func TestPainterDrawsText(t *testing.T) { |
| 10 | screen, p := newTestScreen(t, 20, 3) |
| 11 | |
| 12 | p.Text(2, 1, "hello", tcell.StyleDefault) |
| 13 | screen.Show() |
| 14 | |
| 15 | if got := screenLines(t, screen)[1]; got != " hello " { |
| 16 | t.Errorf("row 1 = %q", got) |
| 17 | } |
| 18 | } |
| 19 | |
| 20 | func TestPainterClipsToItsRegion(t *testing.T) { |
| 21 | screen, root := newTestScreen(t, 20, 5) |
| 22 | |
| 23 | // A painter for a 5-wide box: the text must be cut off at its edge rather |
| 24 | // than spilling across the rest of the row. |
| 25 | box := root.Sub(Rect{X: 2, Y: 1, W: 5, H: 1}) |
| 26 | box.Text(0, 0, "abcdefghij", tcell.StyleDefault) |
| 27 | screen.Show() |
| 28 | |
| 29 | if got := screenLines(t, screen)[1]; got != " abcde " { |
| 30 | t.Errorf("row 1 = %q, want the text clipped at column 7", got) |
| 31 | } |
| 32 | } |
| 33 | |
| 34 | func TestPainterClipsNegativeCoordinates(t *testing.T) { |
| 35 | screen, root := newTestScreen(t, 10, 3) |
| 36 | box := root.Sub(Rect{X: 2, Y: 1, W: 4, H: 1}) |
| 37 | |
| 38 | box.SetCell(-5, 0, 'X', tcell.StyleDefault) |
| 39 | box.SetCell(0, -1, 'Y', tcell.StyleDefault) |
| 40 | screen.Show() |
| 41 | |
| 42 | lines := screenLines(t, screen) |
| 43 | for _, line := range lines { |
| 44 | for _, r := range line { |
| 45 | if r == 'X' || r == 'Y' { |
| 46 | t.Errorf("a character escaped the painter's region: %v", lines) |
| 47 | } |
| 48 | } |
| 49 | } |
| 50 | } |
| 51 | |
| 52 | func TestSubPainterInheritsItsParentsClip(t *testing.T) { |
| 53 | screen, root := newTestScreen(t, 20, 5) |
| 54 | |
| 55 | outer := root.Sub(Rect{X: 0, Y: 0, W: 6, H: 5}) |
| 56 | // The child asks for a region reaching past the parent, so its drawing |
| 57 | // must still stop at the parent's edge. |
| 58 | inner := outer.Sub(Rect{X: 3, Y: 2, W: 15, H: 1}) |
| 59 | inner.Text(0, 0, "XXXXXXXXXX", tcell.StyleDefault) |
| 60 | screen.Show() |
| 61 | |
| 62 | if got := screenLines(t, screen)[2]; got != " XXX " { |
| 63 | t.Errorf("row 2 = %q, want the child clipped by its parent", got) |
| 64 | } |
| 65 | } |
| 66 | |
| 67 | func TestPainterSizeIsItsOwnRegion(t *testing.T) { |
| 68 | _, root := newTestScreen(t, 40, 12) |
| 69 | |
| 70 | if got := root.Size(); got != (Rect{W: 40, H: 12}) { |
| 71 | t.Errorf("root Size() = %+v", got) |
| 72 | } |
| 73 | if got := root.Sub(Rect{X: 5, Y: 5, W: 7, H: 3}).Size(); got != (Rect{W: 7, H: 3}) { |
| 74 | t.Errorf("sub Size() = %+v, want the region's own size at the origin", got) |
| 75 | } |
| 76 | } |
| 77 | |
| 78 | func TestPainterFillAndClear(t *testing.T) { |
| 79 | screen, root := newTestScreen(t, 8, 3) |
| 80 | |
| 81 | root.Clear(tcell.StyleDefault) |
| 82 | root.Fill(Rect{X: 1, Y: 1, W: 3, H: 1}, '#', tcell.StyleDefault) |
| 83 | screen.Show() |
| 84 | |
| 85 | if got := screenLines(t, screen)[1]; got != " ### " { |
| 86 | t.Errorf("row 1 = %q", got) |
| 87 | } |
| 88 | } |
| 89 | |
| 90 | func TestPainterLines(t *testing.T) { |
| 91 | screen, root := newTestScreen(t, 6, 4) |
| 92 | |
| 93 | root.HLine(1, 0, 4, '-', tcell.StyleDefault) |
| 94 | root.VLine(0, 1, 3, '|', tcell.StyleDefault) |
| 95 | screen.Show() |
| 96 | |
| 97 | lines := screenLines(t, screen) |
| 98 | if lines[0] != " ---- " { |
| 99 | t.Errorf("row 0 = %q", lines[0]) |
| 100 | } |
| 101 | for y := 1; y < 4; y++ { |
| 102 | if lines[y][0] != '|' { |
| 103 | t.Errorf("row %d = %q, want a vertical line at column 0", y, lines[y]) |
| 104 | } |
| 105 | } |
| 106 | } |
| 107 | |
| 108 | func TestTextLimitedAddsAnEllipsis(t *testing.T) { |
| 109 | screen, root := newTestScreen(t, 20, 2) |
| 110 | |
| 111 | root.TextLimited(0, 0, 6, "a-very-long-name.go", tcell.StyleDefault) |
| 112 | root.TextLimited(0, 1, 10, "short.go", tcell.StyleDefault) |
| 113 | screen.Show() |
| 114 | |
| 115 | lines := screenLines(t, screen) |
| 116 | if got := string([]rune(lines[0])[:6]); got != "a-ver…" { |
| 117 | t.Errorf("row 0 = %q, want it cut to six cells with an ellipsis", got) |
| 118 | } |
| 119 | if lines[1][:8] != "short.go" { |
| 120 | t.Errorf("row 1 = %q, want it drawn whole", lines[1]) |
| 121 | } |
| 122 | } |
| 123 | |
| 124 | func TestTextLimitedWithNoRoomDrawsNothing(t *testing.T) { |
| 125 | screen, root := newTestScreen(t, 5, 1) |
| 126 | |
| 127 | if got := root.TextLimited(2, 0, 0, "hello", tcell.StyleDefault); got != 2 { |
| 128 | t.Errorf("TextLimited returned %d, want the column it was given back", got) |
| 129 | } |
| 130 | screen.Show() |
| 131 | if got := screenLines(t, screen)[0]; got != " " { |
| 132 | t.Errorf("row 0 = %q, want nothing drawn", got) |
| 133 | } |
| 134 | } |
| 135 | |
| 136 | func TestShadeKeepsTheCharactersAndChangesTheStyle(t *testing.T) { |
| 137 | screen, root := newTestScreen(t, 6, 2) |
| 138 | shadow := tcell.StyleDefault.Foreground(tcell.ColorGray) |
| 139 | |
| 140 | root.Text(0, 0, "abcdef", tcell.StyleDefault) |
| 141 | root.Shade(Rect{X: 2, Y: 0, W: 2, H: 1}, shadow) |
| 142 | screen.Show() |
| 143 | |
| 144 | if got := screenLines(t, screen)[0]; got != "abcdef" { |
| 145 | t.Errorf("row 0 = %q, want the characters untouched", got) |
| 146 | } |
| 147 | if got := styleAt(t, screen, 2, 0); got != shadow { |
| 148 | t.Error("the shaded cell kept its old style") |
| 149 | } |
| 150 | if got := styleAt(t, screen, 1, 0); got == shadow { |
| 151 | t.Error("a cell outside the shaded rectangle was restyled") |
| 152 | } |
| 153 | } |
| 154 | |
| 155 | func TestCellAtOutsideTheClipIsBlank(t *testing.T) { |
| 156 | _, root := newTestScreen(t, 10, 3) |
| 157 | box := root.Sub(Rect{X: 1, Y: 1, W: 2, H: 1}) |
| 158 | |
| 159 | if r, _ := box.CellAt(9, 9); r != ' ' { |
| 160 | t.Errorf("CellAt outside the clip returned %q, want a space", r) |
| 161 | } |
| 162 | } |
| 163 | |
| 164 | func TestShowCursorHidesItWhenItFallsOutsideTheClip(t *testing.T) { |
| 165 | screen, root := newTestScreen(t, 10, 3) |
| 166 | box := root.Sub(Rect{X: 1, Y: 1, W: 3, H: 1}) |
| 167 | |
| 168 | box.ShowCursor(1, 0) |
| 169 | screen.Show() |
| 170 | if x, y, visible := screen.GetCursor(); !visible || x != 2 || y != 1 { |
| 171 | t.Errorf("cursor at (%d, %d) visible=%v, want (2, 1) visible", x, y, visible) |
| 172 | } |
| 173 | |
| 174 | box.ShowCursor(9, 0) |
| 175 | screen.Show() |
| 176 | if _, _, visible := screen.GetCursor(); visible { |
| 177 | t.Error("the cursor stayed visible although it left the painter's region") |
| 178 | } |
| 179 | } |