aboutsummaryrefslogtreecommitdiff
path: root/internal/ui/table_test.go
diff options
context:
space:
mode:
Diffstat (limited to 'internal/ui/table_test.go')
-rw-r--r--internal/ui/table_test.go91
1 files changed, 91 insertions, 0 deletions
diff --git a/internal/ui/table_test.go b/internal/ui/table_test.go
new file mode 100644
index 0000000..68b6d32
--- /dev/null
+++ b/internal/ui/table_test.go
@@ -0,0 +1,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])
+ }
+}