1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
|
package ui
import (
"strings"
"testing"
"thehouseoficarus/internal/color"
)
func renderWidths(t *testing.T, tt *Table, unicode bool, maxWidth int) []string {
t.Helper()
lines := tt.Render(unicode, maxWidth)
for _, l := range lines {
if vl := color.VisibleLen(l); maxWidth > 0 && vl > maxWidth+1 {
t.Errorf("line exceeds maxWidth %d: %d (%q)", maxWidth, vl, l)
}
}
// All border/content lines must be the same visible width so the box
// lines up.
widths := map[int]bool{}
for _, l := range lines {
widths[color.VisibleLen(l)] = true
}
if len(widths) > 1 {
var ws []string
for w := range widths {
ws = append(ws, string(rune('0'+w)))
}
t.Errorf("inconsistent line widths: %v", strings.Join(ws, ","))
}
return lines
}
func TestTableFitsWithinWidth(t *testing.T) {
tt := &Table{
Title: "Commands",
Columns: []string{"Command", "Type", "Description"},
Rows: [][]string{
{"north / south / east / west / ne / nw / se / sw / up / down", "Active", "Move in a direction"},
{"bet", "Active", "Place a casino wager (e.g. bet 100 on banker)"},
{"attack / kill", "Active", "Attack a mob"},
},
}
for _, w := range []int{0, 40, 80, 100} {
lines := renderWidths(t, tt, true, w)
// Description column must never be crushed: with three columns the
// description always keeps at least a fair share of the budget.
if w == 80 {
// lines: border, title, sep, header, sep, rows...
if !strings.Contains(lines[5], "Move i") {
t.Errorf("description column crushed at width 80: %q", lines[5])
}
}
}
}
func TestTableNoMutation(t *testing.T) {
tt := &Table{
Title: "T",
Columns: []string{"A", "B"},
Rows: [][]string{{"very long cell content here", "x"}},
}
before := tt.Columns[0]
_ = tt.Render(true, 20)
if tt.Columns[0] != before {
t.Errorf("Render mutated table columns: %q", tt.Columns[0])
}
}
func TestTableASCIIFallback(t *testing.T) {
tt := &Table{Title: "T", Columns: []string{"A", "B"}, Rows: [][]string{{"1", "2"}}}
lines := renderWidths(t, tt, false, 0)
if !strings.Contains(lines[0], "+") {
t.Errorf("expected ASCII border, got %q", lines[0])
}
}
func TestTableColoredCellWidth(t *testing.T) {
// ANSI-colored cells must be measured and padded by visible length.
red := "\x1b[31m"
reset := "\x1b[0m"
tt := &Table{Columns: []string{"A", "B"}, Rows: [][]string{{red + "hi" + reset, "x"}}}
lines := renderWidths(t, tt, true, 0)
// lines: top border, header, sep, data row, bottom border
if len(lines) < 5 {
t.Fatalf("expected 5 lines, got %d: %q", len(lines), lines)
}
if !strings.Contains(lines[3], "hi") || !strings.Contains(lines[3], "x") {
t.Errorf("unexpected row: %q", lines[3])
}
}
|