package app import ( "strings" "testing" ) func TestToastStackPushAndOrder(t *testing.T) { var s toastStack s.push(toastInfo, "one") s.push(toastError, "two") s.push(toastAttention, "three") snap := s.snapshot() if len(snap) != 3 { t.Fatalf("snapshot len = %d, want 3", len(snap)) } if snap[0].text != "one" || snap[1].text != "two" || snap[2].text != "three" { t.Fatalf("snapshot order wrong: %#v", snap) } if snap[0].kind != toastInfo || snap[1].kind != toastError || snap[2].kind != toastAttention { t.Fatalf("snapshot kinds wrong: %#v", snap) } // IDs strictly increase. if !(snap[0].id < snap[1].id && snap[1].id < snap[2].id) { t.Fatalf("ids not increasing: %#v", snap) } } func TestToastStackCapDropsOldest(t *testing.T) { var s toastStack for i := 0; i < toastStackCap+3; i++ { s.push(toastInfo, "msg") } snap := s.snapshot() if len(snap) != toastStackCap { t.Fatalf("len = %d, want %d", len(snap), toastStackCap) } // The earliest IDs should have been dropped, leaving the highest // toastStackCap IDs. for i := 1; i < len(snap); i++ { if snap[i].id <= snap[i-1].id { t.Fatalf("ordering broken after cap: %#v", snap) } } // First retained id should be 4 (1,2,3 dropped; cap=5 leaves 4..8). want := uint64(toastStackCap + 3 - toastStackCap + 1) if snap[0].id != want { t.Fatalf("first retained id = %d, want %d", snap[0].id, want) } } func TestToastStackDismissTop(t *testing.T) { var s toastStack if s.dismissTop() { t.Fatalf("dismissTop on empty stack returned true") } s.push(toastInfo, "a") s.push(toastError, "b") if !s.dismissTop() { t.Fatalf("dismissTop returned false with items present") } snap := s.snapshot() if len(snap) != 1 || snap[0].text != "a" { t.Fatalf("after dismissTop: %#v", snap) } if !s.dismissTop() { t.Fatalf("dismissTop on last item returned false") } if s.length() != 0 { t.Fatalf("length after final dismiss = %d, want 0", s.length()) } } func TestToastStackClear(t *testing.T) { var s toastStack if s.clear() { t.Fatalf("clear on empty returned true") } s.push(toastInfo, "a") s.push(toastError, "b") s.push(toastAttention, "c") if !s.clear() { t.Fatalf("clear returned false with items present") } if s.length() != 0 { t.Fatalf("length after clear = %d, want 0", s.length()) } if snap := s.snapshot(); snap != nil { t.Fatalf("snapshot after clear = %#v, want nil", snap) } } func TestToastStackSnapshotIsCopy(t *testing.T) { var s toastStack s.push(toastInfo, "a") snap := s.snapshot() snap[0].text = "mutated" again := s.snapshot() if again[0].text != "a" { t.Fatalf("snapshot is not an independent copy: %#v", again) } } func TestWrapToastBodyFixedHeight(t *testing.T) { got := wrapToastBody("short", 20) if len(got) != toastContentRows { t.Fatalf("len = %d, want %d", len(got), toastContentRows) } if got[0] != "short" { t.Fatalf("line 0 = %q, want \"short\"", got[0]) } if got[1] != "" || got[2] != "" { t.Fatalf("trailing pads not empty: %#v", got) } } func TestWrapToastBodyWrapsOnWordBoundary(t *testing.T) { got := wrapToastBody("the quick brown fox jumps over", 10) // Expect greedy fill: "the quick" (9), "brown fox" (9), "jumps over" (10). want := []string{"the quick", "brown fox", "jumps over"} for i, w := range want { if got[i] != w { t.Fatalf("line %d = %q, want %q (full=%#v)", i, got[i], w, got) } } } func TestWrapToastBodyEllipsizesOverflow(t *testing.T) { got := wrapToastBody("alpha beta gamma delta epsilon zeta eta theta", 6) if len(got) != toastContentRows { t.Fatalf("len = %d, want %d", len(got), toastContentRows) } last := got[toastContentRows-1] if !strings.HasSuffix(last, "…") { t.Fatalf("overflow should ellipsize last line, got %q (full=%#v)", last, got) } if visibleLen(last) > 6 { t.Fatalf("last line %q exceeds width 6", last) } } func TestWrapToastBodyBreaksOverlongWord(t *testing.T) { got := wrapToastBody("supercalifragilistic", 6) if got[0] != "superc" { t.Fatalf("line 0 = %q, want \"superc\"", got[0]) } if got[1] != "alifra" { t.Fatalf("line 1 = %q, want \"alifra\"", got[1]) } // Third line should hold the rest (possibly ellipsized). if got[2] == "" { t.Fatalf("line 2 unexpectedly empty: %#v", got) } } func TestWrapToastBodyEmptyInput(t *testing.T) { got := wrapToastBody("", 20) for i, l := range got { if l != "" { t.Fatalf("line %d = %q, want \"\"", i, l) } } }