diff options
| author | Paul Buetow <paul@buetow.org> | 2026-03-05 22:35:56 +0200 |
|---|---|---|
| committer | Paul Buetow <paul@buetow.org> | 2026-03-05 22:35:56 +0200 |
| commit | 3307447e4ae159b11bbe262ad161d6e3c571ee4c (patch) | |
| tree | 69f508b120715e102f8508ca88e4cbc8adf74a23 /internal/tui/flamegraph/model_test.go | |
| parent | 6948ab9b8880b318e43590bba8ecab77552348c3 (diff) | |
task 358: add flamegraph keyboard navigation
Diffstat (limited to 'internal/tui/flamegraph/model_test.go')
| -rw-r--r-- | internal/tui/flamegraph/model_test.go | 83 |
1 files changed, 83 insertions, 0 deletions
diff --git a/internal/tui/flamegraph/model_test.go b/internal/tui/flamegraph/model_test.go index 1e472ae..4569296 100644 --- a/internal/tui/flamegraph/model_test.go +++ b/internal/tui/flamegraph/model_test.go @@ -3,6 +3,8 @@ package flamegraph import ( coreflamegraph "ior/internal/flamegraph" "testing" + + tea "charm.land/bubbletea/v2" ) func TestNewModelDefaults(t *testing.T) { @@ -48,3 +50,84 @@ func TestRefreshFromLiveTrieTracksVersionAndSnapshot(t *testing.T) { t.Fatalf("expected no refresh when version is unchanged") } } + +func TestKeyboardNavigationDeepNarrowTree(t *testing.T) { + m := NewModel(nil) + m.frames = []tuiFrame{ + {Name: "root", Depth: 0, Col: 0, Path: "root"}, + {Name: "child", Depth: 1, Col: 0, Path: "root" + pathSeparator + "child"}, + {Name: "leaf", Depth: 2, Col: 0, Path: "root" + pathSeparator + "child" + pathSeparator + "leaf"}, + } + + m = pressFlameKey(t, m, tea.KeyPressMsg{Code: []rune{'k'}[0], Text: "k"}) + if m.selectedIdx != 1 { + t.Fatalf("expected selection to move deeper to idx 1, got %d", m.selectedIdx) + } + m = pressFlameKey(t, m, tea.KeyPressMsg{Code: []rune{'k'}[0], Text: "k"}) + if m.selectedIdx != 2 { + t.Fatalf("expected selection to move deeper to idx 2, got %d", m.selectedIdx) + } + m = pressFlameKey(t, m, tea.KeyPressMsg{Code: []rune{'j'}[0], Text: "j"}) + if m.selectedIdx != 1 { + t.Fatalf("expected selection to move shallower to idx 1, got %d", m.selectedIdx) + } +} + +func TestKeyboardNavigationShallowWideSiblings(t *testing.T) { + m := NewModel(nil) + m.frames = []tuiFrame{ + {Name: "root", Depth: 0, Col: 0, Path: "root"}, + {Name: "A", Depth: 1, Col: 0, Path: "root" + pathSeparator + "A"}, + {Name: "B", Depth: 1, Col: 30, Path: "root" + pathSeparator + "B"}, + {Name: "C", Depth: 1, Col: 60, Path: "root" + pathSeparator + "C"}, + } + + m = pressFlameKey(t, m, tea.KeyPressMsg{Code: []rune{'k'}[0], Text: "k"}) + if m.selectedIdx != 1 { + t.Fatalf("expected first deeper frame to be A, got idx %d", m.selectedIdx) + } + m = pressFlameKey(t, m, tea.KeyPressMsg{Code: []rune{'l'}[0], Text: "l"}) + if m.selectedIdx != 2 { + t.Fatalf("expected next sibling B, got idx %d", m.selectedIdx) + } + m = pressFlameKey(t, m, tea.KeyPressMsg{Code: []rune{'l'}[0], Text: "l"}) + if m.selectedIdx != 3 { + t.Fatalf("expected next sibling C, got idx %d", m.selectedIdx) + } + m = pressFlameKey(t, m, tea.KeyPressMsg{Code: []rune{'l'}[0], Text: "l"}) + if m.selectedIdx != 3 { + t.Fatalf("expected selection to clamp at last sibling, got idx %d", m.selectedIdx) + } + m = pressFlameKey(t, m, tea.KeyPressMsg{Code: []rune{'h'}[0], Text: "h"}) + if m.selectedIdx != 2 { + t.Fatalf("expected previous sibling B, got idx %d", m.selectedIdx) + } +} + +func TestKeyboardNavigationSingleNodeClamped(t *testing.T) { + m := NewModel(nil) + m.frames = []tuiFrame{{Name: "root", Depth: 0, Col: 0, Path: "root"}} + + keys := []tea.KeyPressMsg{ + {Code: []rune{'j'}[0], Text: "j"}, + {Code: []rune{'k'}[0], Text: "k"}, + {Code: []rune{'h'}[0], Text: "h"}, + {Code: []rune{'l'}[0], Text: "l"}, + {Code: tea.KeyDown}, + {Code: tea.KeyUp}, + {Code: tea.KeyLeft}, + {Code: tea.KeyRight}, + } + for _, keyMsg := range keys { + m = pressFlameKey(t, m, keyMsg) + if m.selectedIdx != 0 { + t.Fatalf("expected single-node selection to stay at idx 0, got %d", m.selectedIdx) + } + } +} + +func pressFlameKey(t *testing.T, m Model, keyMsg tea.KeyPressMsg) Model { + t.Helper() + next, _ := m.Update(keyMsg) + return next.(Model) +} |
