|
4 | 4 | "strings" |
5 | 5 | "testing" |
6 | 6 | "time" |
| 7 | + |
| 8 | + "github.com/jack-work/figaro/internal/term" |
7 | 9 | ) |
8 | 10 |
|
9 | 11 | // --------------------------------------------------------------------------- |
@@ -42,12 +44,11 @@ func TestStatusViewGoldens(t *testing.T) { |
42 | 44 | want: []string{"✓ · 123abc · test 9.8k/1.0m (1.0%)"}, |
43 | 45 | }, |
44 | 46 | { |
45 | | - // THE NAME IS NOT A VERBOSE EXTRA. The design draws "𝄚 queue", |
46 | | - // always: the glyph alone answers the question only for someone |
47 | | - // who has already memorised the glyphs. |
48 | | - name: "a pit leads with its glyph AND its name", width: 80, |
| 47 | + // THE NAME IS A VERBOSE EXTRA. This bar is read by someone who |
| 48 | + // knows the glyphs; the word is for the reader who does not. |
| 49 | + name: "a pit leads with its glyph alone", width: 80, |
49 | 50 | view: func(v statusView) statusView { v.Drawer = drawerQueue; return v }, |
50 | | - want: []string{"𝄚 queue · ✓ · 123abc · test 9.8k/1.0m (1.0%)"}, |
| 51 | + want: []string{"𝄚 · ✓ · 123abc · test 9.8k/1.0m (1.0%)"}, |
51 | 52 | }, |
52 | 53 | { |
53 | 54 | name: "verbose names the drawer and the state", width: 96, |
@@ -171,3 +172,87 @@ func TestVerboseCarriesTheLastInteraction(t *testing.T) { |
171 | 172 | t.Fatalf("the default bar carries a datetime: %q", row) |
172 | 173 | } |
173 | 174 | } |
| 175 | + |
| 176 | +// TestOnlyTroubleIsRed: a confirmation wears the row's own gray. Painting |
| 177 | +// every alert red made the bar shout "sent" in the colour it keeps for |
| 178 | +// failures, which is how a colour stops meaning anything. |
| 179 | +func TestOnlyTroubleIsRed(t *testing.T) { |
| 180 | + restore := term.SetColorMode(term.ColorAlways) |
| 181 | + defer restore() |
| 182 | + |
| 183 | + v := barFixture() |
| 184 | + v.Alert = "sent" |
| 185 | + info := strings.Join(v.render(100), "") |
| 186 | + if !strings.Contains(info, "sent") { |
| 187 | + t.Fatalf("the confirmation is missing: %q", info) |
| 188 | + } |
| 189 | + if strings.Contains(info, term.NoticeInDim("sent")) { |
| 190 | + t.Fatalf("a confirmation was painted as trouble: %q", info) |
| 191 | + } |
| 192 | + |
| 193 | + v.AlertLevel = alertError |
| 194 | + bad := strings.Join(v.render(100), "") |
| 195 | + if !strings.Contains(bad, term.NoticeInDim("sent")) { |
| 196 | + t.Fatalf("trouble was not painted red: %q", bad) |
| 197 | + } |
| 198 | +} |
| 199 | + |
| 200 | +// TestAlertLevelResetsOnEveryPost: a red error must not tint the confirmation |
| 201 | +// that follows it. setNotice is the confirmation door and clears the level. |
| 202 | +func TestAlertLevelResetsOnEveryPost(t *testing.T) { |
| 203 | + s := newSessionStatus("aria1234", time.Now()) |
| 204 | + s.setNoticeAt("boom", alertError) |
| 205 | + if v := s.viewOf(drawerNothing, false, time.Now()); v.AlertLevel != alertError { |
| 206 | + t.Fatal("the error did not take") |
| 207 | + } |
| 208 | + s.setNotice("sent") |
| 209 | + if v := s.viewOf(drawerNothing, false, time.Now()); v.AlertLevel != alertInfo { |
| 210 | + t.Fatal("a confirmation inherited the previous error's colour") |
| 211 | + } |
| 212 | +} |
| 213 | + |
| 214 | +// TestAlertRetiresOnItsOwn is the test that was missing, and its absence is |
| 215 | +// why an alert sat in the bar forever: setNoticeTTL existed, cli.notice_ttl |
| 216 | +// existed, and NOTHING CALLED EITHER -- so every alert was born with a zero |
| 217 | +// TTL, which means "hold the slot until displaced". |
| 218 | +// |
| 219 | +// It drives the clock rather than sleeping: the expiry is a comparison against |
| 220 | +// a time the caller passes, precisely so this can be tested in microseconds. |
| 221 | +func TestAlertRetiresOnItsOwn(t *testing.T) { |
| 222 | + s := newSessionStatus("aria1234", time.Now()) |
| 223 | + if s.noticeTTL <= 0 { |
| 224 | + t.Fatal("a fresh session has no notice TTL; a default a caller must install is not a default") |
| 225 | + } |
| 226 | + s.setNotice("sent") |
| 227 | + |
| 228 | + now := time.Now() |
| 229 | + if v := s.viewOf(drawerNothing, false, now); v.Alert != "sent" { |
| 230 | + t.Fatalf("the alert did not post: %q", v.Alert) |
| 231 | + } |
| 232 | + // Still there a moment later. |
| 233 | + if v := s.viewOf(drawerNothing, false, now.Add(time.Second)); v.Alert != "sent" { |
| 234 | + t.Fatalf("the alert retired early: %q", v.Alert) |
| 235 | + } |
| 236 | + // And gone once its span is up, WITHOUT a keystroke or a tick: an idle |
| 237 | + // pager animates nothing, so the view build is the backstop. |
| 238 | + if v := s.viewOf(drawerNothing, false, now.Add(defaultNoticeTTL+time.Second)); v.Alert != "" { |
| 239 | + t.Fatalf("the alert outlived its TTL: %q", v.Alert) |
| 240 | + } |
| 241 | +} |
| 242 | + |
| 243 | +// TestNewerAlertDisplacesOlder: the other way an alert leaves. A burst of |
| 244 | +// them -- ten `:send`s in a row -- must show the newest, not a stack. |
| 245 | +func TestNewerAlertDisplacesOlder(t *testing.T) { |
| 246 | + s := newSessionStatus("aria1234", time.Now()) |
| 247 | + for i := 0; i < 10; i++ { |
| 248 | + s.setNotice("sent") |
| 249 | + } |
| 250 | + s.setNotice("showing abc12345") |
| 251 | + v := s.viewOf(drawerNothing, false, time.Now()) |
| 252 | + if v.Alert != "showing abc12345" { |
| 253 | + t.Fatalf("the newest alert did not win: %q", v.Alert) |
| 254 | + } |
| 255 | + if strings.Count(v.Alert, "sent") != 0 { |
| 256 | + t.Fatalf("alerts stacked instead of displacing: %q", v.Alert) |
| 257 | + } |
| 258 | +} |
0 commit comments