| @@ -27,26 +27,26 @@ func TestTablePlainIsTabs(t *testing.T) { |
| 27 | func TestTableTerminalFits(t *testing.T) { |
27 | func TestTableTerminalFits(t *testing.T) { |
| 28 | var b bytes.Buffer |
28 | var b bytes.Buffer |
| 29 | fixtureTable(&Ctx{Term: Term{Cols: 40}}, &b) |
29 | fixtureTable(&Ctx{Term: Term{Cols: 40}}, &b) |
| 30 | want := "# STATE TITLE AUTHOR\n" + |
30 | want := "#252 open Dependency up… gitbay-bot\n" + |
| 31 | "#252 open Dependency up… gitbay-bot\n" + |
| |
| 32 | "#12 closed Android app cmc\n" |
31 | "#12 closed Android app cmc\n" |
| 33 | if b.String() != want { |
32 | if b.String() != want { |
| 34 | t.Errorf("terminal:\n%s\nwant\n%s", b.String(), want) |
33 | t.Errorf("terminal:\n%s\nwant\n%s", b.String(), want) |
| 35 | } |
34 | } |
| 36 | } |
35 | } |
| 37 | |
36 | |
| 38 | // A column shrunk below its header's width clips the header too. |
37 | // A column shrunk below its header's width clips the header too. The |
| |
38 | // number column is what keeps the header. |
| 39 | func TestTableClipsHeaderToColumn(t *testing.T) { |
39 | func TestTableClipsHeaderToColumn(t *testing.T) { |
| 40 | var b bytes.Buffer |
40 | var b bytes.Buffer |
| 41 | tb := (&Ctx{Term: Term{Cols: 16}}).table(&b, "FINGERPRINT", "SCOPE") |
41 | tb := (&Ctx{Term: Term{Cols: 12}}).table(&b, "FINGERPRINTS", "N") |
| 42 | tb.row(cFlex("SHA256:abcdefghijklmnopqrstuvwxyz"), cState("full")) |
42 | tb.row(cFlex("SHA256:abcdefghijklmnopqrstuvwxyz"), cNum(1)) |
| 43 | tb.flush() |
43 | tb.flush() |
| 44 | for _, line := range strings.Split(strings.TrimSuffix(b.String(), "\n"), "\n") { |
44 | for _, line := range strings.Split(strings.TrimSuffix(b.String(), "\n"), "\n") { |
| 45 | if cells(line) > 16 { |
45 | if cells(line) > 12 { |
| 46 | t.Errorf("line of %d cells at 16 columns: %q", cells(line), line) |
46 | t.Errorf("line of %d cells at 12 columns: %q", cells(line), line) |
| 47 | } |
47 | } |
| 48 | } |
48 | } |
| 49 | if !strings.HasPrefix(b.String(), "FINGERPR… SCOPE\n") { |
49 | if !strings.HasPrefix(b.String(), "FINGERPR… N\n") { |
| 50 | t.Errorf("header:\n%s", b.String()) |
50 | t.Errorf("header:\n%s", b.String()) |
| 51 | } |
51 | } |
| 52 | } |
52 | } |
| @@ -58,8 +58,8 @@ func TestTableColourOnlyAddsSGR(t *testing.T) { |
| 58 | if !strings.Contains(colour.String(), sgrGreen+"open"+sgrReset) { |
58 | if !strings.Contains(colour.String(), sgrGreen+"open"+sgrReset) { |
| 59 | t.Errorf("open not green: %q", colour.String()) |
59 | t.Errorf("open not green: %q", colour.String()) |
| 60 | } |
60 | } |
| 61 | if !strings.HasPrefix(colour.String(), sgrDim) { |
61 | if !strings.HasPrefix(colour.String(), sgrDim+"#252"+sgrReset) { |
| 62 | t.Errorf("header not dim: %q", colour.String()) |
62 | t.Errorf("ref not dim: %q", colour.String()) |
| 63 | } |
63 | } |
| 64 | if stripSGR(colour.String()) != mono.String() { |
64 | if stripSGR(colour.String()) != mono.String() { |
| 65 | t.Errorf("colour changed the layout:\n%s\nvs\n%s", stripSGR(colour.String()), mono.String()) |
65 | t.Errorf("colour changed the layout:\n%s\nvs\n%s", stripSGR(colour.String()), mono.String()) |
| @@ -81,7 +81,7 @@ func TestTableAgesAndPlainStamps(t *testing.T) { |
| 81 | if plain.String() != "#1\t2026-09-23T10:00:00Z\n" { |
81 | if plain.String() != "#1\t2026-09-23T10:00:00Z\n" { |
| 82 | t.Errorf("plain = %q", plain.String()) |
82 | t.Errorf("plain = %q", plain.String()) |
| 83 | } |
83 | } |
| 84 | if term.String() != "# UPDATED\n#1 2h ago\n" { |
84 | if term.String() != "#1 2h ago\n" { |
| 85 | t.Errorf("term = %q", term.String()) |
85 | t.Errorf("term = %q", term.String()) |
| 86 | } |
86 | } |
| 87 | } |
87 | } |
| @@ -102,18 +102,16 @@ func TestTableKeepsCellsBeyondTheHeader(t *testing.T) { |
| 102 | t.Fatalf("archived marker dropped:\n%s", out) |
102 | t.Fatalf("archived marker dropped:\n%s", out) |
| 103 | } |
103 | } |
| 104 | lines := strings.Split(strings.TrimRight(out, "\n"), "\n") |
104 | lines := strings.Split(strings.TrimRight(out, "\n"), "\n") |
| 105 | if len(lines) != 3 { |
105 | if len(lines) != 2 { |
| 106 | t.Fatalf("want 3 lines, got %d:\n%s", len(lines), out) |
106 | t.Fatalf("want 2 lines, got %d:\n%s", len(lines), out) |
| 107 | } |
107 | } |
| 108 | header, row1, row2 := lines[0], lines[1], lines[2] |
108 | oneAt := strings.Index(lines[0], "one") |
| 109 | descAt := strings.Index(header, "DESCRIPTION") |
109 | twoAt := strings.Index(lines[1], "two") |
| 110 | oneAt := strings.Index(row1, "one") |
110 | if oneAt < 0 || twoAt < 0 { |
| 111 | twoAt := strings.Index(row2, "two") |
| |
| 112 | if descAt < 0 || oneAt < 0 || twoAt < 0 { |
| |
| 113 | t.Fatalf("columns not found:\n%s", out) |
111 | t.Fatalf("columns not found:\n%s", out) |
| 114 | } |
112 | } |
| 115 | if descAt != oneAt || descAt != twoAt { |
113 | if oneAt != twoAt { |
| 116 | t.Errorf("DESCRIPTION column not aligned: header at %d, row1 at %d, row2 at %d\n%s", descAt, oneAt, twoAt, out) |
114 | t.Errorf("description column not aligned: row1 at %d, row2 at %d\n%s", oneAt, twoAt, out) |
| 117 | } |
115 | } |
| 118 | } |
116 | } |
| 119 | |
117 | |
| @@ -149,8 +147,8 @@ func TestTableCapsSparseFlex(t *testing.T) { |
| 149 | tb.row(cRef("v0"), cFlex(strings.Repeat("x", 60)), cText("2")) |
147 | tb.row(cRef("v0"), cFlex(strings.Repeat("x", 60)), cText("2")) |
| 150 | tb.flush() |
148 | tb.flush() |
| 151 | lines := strings.Split(b.String(), "\n") |
149 | lines := strings.Split(b.String(), "\n") |
| 152 | if at := strings.Index(lines[0], "ASSETS"); at != len("TAG ")+30+2 { |
150 | if at := strings.LastIndex(lines[0], "2"); at != len("v3 ")+30+2 { |
| 153 | t.Errorf("ASSETS at %d:\n%s", at, b.String()) |
151 | t.Errorf("assets at %d:\n%s", at, b.String()) |
| 154 | } |
152 | } |
| 155 | } |
153 | } |
| 156 | |
154 | |
| @@ -178,7 +176,7 @@ func TestTableDropsEmptyColumns(t *testing.T) { |
| 178 | tb.row(cRef("#1"), cText(""), cFlex("one")) |
176 | tb.row(cRef("#1"), cText(""), cFlex("one")) |
| 179 | tb.row(cRef("#2"), cText(""), cFlex("two")) |
177 | tb.row(cRef("#2"), cText(""), cFlex("two")) |
| 180 | tb.flush() |
178 | tb.flush() |
| 181 | if b.String() != "# TITLE\n#1 one\n#2 two\n" { |
179 | if b.String() != "#1 one\n#2 two\n" { |
| 182 | t.Errorf("terminal = %q", b.String()) |
180 | t.Errorf("terminal = %q", b.String()) |
| 183 | } |
181 | } |
| 184 | var plain bytes.Buffer |
182 | var plain bytes.Buffer |
| @@ -238,3 +236,35 @@ func TestGlyphAndMetaCells(t *testing.T) { |
| 238 | } |
236 | } |
| 239 | } |
237 | } |
| 240 | } |
238 | } |
| |
239 | |
| |
240 | func TestTableDropsHeaderWithoutNumbers(t *testing.T) { |
| |
241 | var b bytes.Buffer |
| |
242 | tb := (&Ctx{Term: Term{Cols: 80}}).table(&b, "#", "STATE", "TITLE") |
| |
243 | tb.row(cRef("#12"), cState("open"), cFlex("Android app")) |
| |
244 | tb.flush() |
| |
245 | if got, want := b.String(), "#12 open Android app\n"; got != want { |
| |
246 | t.Errorf("got %q, want %q", got, want) |
| |
247 | } |
| |
248 | } |
| |
249 | |
| |
250 | func TestTableKeepsHeaderForNumbers(t *testing.T) { |
| |
251 | var b bytes.Buffer |
| |
252 | tb := (&Ctx{Term: Term{Cols: 80}}).table(&b, "RUNNER", "PENDING") |
| |
253 | tb.row(cText("bay1"), cNum(3)) |
| |
254 | tb.flush() |
| |
255 | if !strings.HasPrefix(b.String(), "RUNNER PENDING\n") { |
| |
256 | t.Errorf("header missing: %q", b.String()) |
| |
257 | } |
| |
258 | } |
| |
259 | |
| |
260 | func TestTableLines(t *testing.T) { |
| |
261 | var b bytes.Buffer |
| |
262 | tb := (&Ctx{Term: Term{Cols: 80}}).table(&b) |
| |
263 | tb.row(cRef("!1"), cFlex("one")) |
| |
264 | tb.row(cRef("!22"), cFlex("two")) |
| |
265 | got := tb.lines() |
| |
266 | want := []string{"!1 one", "!22 two"} |
| |
267 | if strings.Join(got, "\n") != strings.Join(want, "\n") { |
| |
268 | t.Errorf("got %q, want %q", got, want) |
| |
269 | } |
| |
270 | } |