summaryrefslogtreecommitdiff
path: root/internal/tui/flamegraph/model_test.go
diff options
context:
space:
mode:
authorPaul Buetow <paul@buetow.org>2026-03-05 22:42:08 +0200
committerPaul Buetow <paul@buetow.org>2026-03-05 22:42:08 +0200
commit5d6b2cff5fa13700fdfcc30d7e30f5cece2e6d38 (patch)
tree1ba853dc4bd0505d2fbae69662bc9a9ca9ffb404 /internal/tui/flamegraph/model_test.go
parent4e464d082e0c83f33f4b4659859b8a9be58987e1 (diff)
task 360: add flamegraph search and match navigation
Diffstat (limited to 'internal/tui/flamegraph/model_test.go')
-rw-r--r--internal/tui/flamegraph/model_test.go50
1 files changed, 50 insertions, 0 deletions
diff --git a/internal/tui/flamegraph/model_test.go b/internal/tui/flamegraph/model_test.go
index f79b095..413b571 100644
--- a/internal/tui/flamegraph/model_test.go
+++ b/internal/tui/flamegraph/model_test.go
@@ -164,6 +164,56 @@ func TestZoomInUndoResetAndNestedZoom(t *testing.T) {
}
}
+func TestSearchLifecycleAndMatchNavigation(t *testing.T) {
+ m := NewModel(nil)
+ m.frames = []tuiFrame{
+ {Name: "alpha", Path: "root" + pathSeparator + "alpha"},
+ {Name: "beta", Path: "root" + pathSeparator + "beta"},
+ {Name: "alphabet", Path: "root" + pathSeparator + "alphabet"},
+ }
+
+ m = pressFlameKey(t, m, tea.KeyPressMsg{Code: []rune{'/'}[0], Text: "/"})
+ if !m.searchActive {
+ t.Fatalf("expected search mode to activate on '/'")
+ }
+ for _, r := range []rune{'a', 'l', 'p'} {
+ m = pressFlameKey(t, m, tea.KeyPressMsg{Code: r, Text: string(r)})
+ }
+ m = pressFlameKey(t, m, tea.KeyPressMsg{Code: tea.KeyEnter})
+
+ if m.searchActive {
+ t.Fatalf("expected search mode to close on enter")
+ }
+ if got := len(m.matchIndices); got != 2 {
+ t.Fatalf("expected 2 matches for 'alp', got %d", got)
+ }
+ first := m.selectedIdx
+ m = pressFlameKey(t, m, tea.KeyPressMsg{Code: []rune{'n'}[0], Text: "n"})
+ if m.selectedIdx == first {
+ t.Fatalf("expected 'n' to jump to next match")
+ }
+ m = pressFlameKey(t, m, tea.KeyPressMsg{Code: []rune{'N'}[0], Text: "N"})
+ if m.selectedIdx != first {
+ t.Fatalf("expected 'N' to jump back to previous match")
+ }
+}
+
+func TestSearchEscapeClearsState(t *testing.T) {
+ m := NewModel(nil)
+ m.frames = []tuiFrame{{Name: "alpha", Path: "root" + pathSeparator + "alpha"}}
+
+ m = pressFlameKey(t, m, tea.KeyPressMsg{Code: []rune{'/'}[0], Text: "/"})
+ m = pressFlameKey(t, m, tea.KeyPressMsg{Code: []rune{'a'}[0], Text: "a"})
+ m = pressFlameKey(t, m, tea.KeyPressMsg{Code: tea.KeyEsc})
+
+ if m.searchActive {
+ t.Fatalf("expected search mode to close on escape")
+ }
+ if m.searchQuery != "" || len(m.matchIndices) != 0 {
+ t.Fatalf("expected search state to reset on escape, got query=%q matches=%d", m.searchQuery, len(m.matchIndices))
+ }
+}
+
func newZoomModel() Model {
m := NewModel(nil)
m.width = 120