summaryrefslogtreecommitdiff
path: root/internal/tui/dashboard/model_test.go
diff options
context:
space:
mode:
authorPaul Buetow <paul@buetow.org>2026-03-06 18:08:19 +0200
committerPaul Buetow <paul@buetow.org>2026-03-06 18:08:19 +0200
commit99a6cf4787fd92a25a53acbc9c0bae8bca87cc96 (patch)
tree0c6f6506e944a0eed0fcefa7b9394681c5f178da /internal/tui/dashboard/model_test.go
parent1561987330cb898f5ff64383a9c78e7e6559f118 (diff)
feat(tui): add dashboard bubble viz and expand help shortcuts
Diffstat (limited to 'internal/tui/dashboard/model_test.go')
-rw-r--r--internal/tui/dashboard/model_test.go148
1 files changed, 148 insertions, 0 deletions
diff --git a/internal/tui/dashboard/model_test.go b/internal/tui/dashboard/model_test.go
index d5b78e0..934577d 100644
--- a/internal/tui/dashboard/model_test.go
+++ b/internal/tui/dashboard/model_test.go
@@ -26,6 +26,21 @@ func (f *fakeSnapshotSource) Snapshot() *statsengine.Snapshot {
return f.snap
}
+type fakeResettableSnapshotSource struct {
+ resetCount int
+ snapCount int
+ snap *statsengine.Snapshot
+}
+
+func (f *fakeResettableSnapshotSource) Reset() {
+ f.resetCount++
+}
+
+func (f *fakeResettableSnapshotSource) Snapshot() *statsengine.Snapshot {
+ f.snapCount++
+ return f.snap
+}
+
func TestKeySwitchingChangesActiveTab(t *testing.T) {
m := NewModelWithConfig(nil, nil, 250, common.DefaultKeyMap())
@@ -327,6 +342,98 @@ func TestDirGroupKeyTogglesOnlyOnFilesTab(t *testing.T) {
}
}
+func TestBubbleVisualizationToggleForSyscallsTab(t *testing.T) {
+ snap := statsengine.NewSnapshot(nil, nil, nil, []statsengine.SyscallSnapshot{
+ {Name: "read", Count: 9, Bytes: 512},
+ {Name: "write", Count: 3, Bytes: 1024},
+ }, nil, nil, statsengine.HistogramSnapshot{}, statsengine.HistogramSnapshot{})
+ m := NewModelWithConfig(nil, nil, 250, common.DefaultKeyMap())
+ m.activeTab = TabSyscalls
+ m.latest = &snap
+
+ next, _ := m.Update(tea.KeyPressMsg{Code: []rune{'v'}[0], Text: string([]rune{'v'})})
+ model := next.(Model)
+ if !model.syscallsBubble {
+ t.Fatalf("expected syscalls bubble mode enabled")
+ }
+
+ next, _ = model.Update(tea.KeyPressMsg{Code: []rune{'v'}[0], Text: string([]rune{'v'})})
+ model = next.(Model)
+ if model.syscallsBubble {
+ t.Fatalf("expected syscalls bubble mode toggled off")
+ }
+}
+
+func TestBubbleMetricToggleForSyscallsTab(t *testing.T) {
+ snap := statsengine.NewSnapshot(nil, nil, nil, []statsengine.SyscallSnapshot{
+ {Name: "read", Count: 9, Bytes: 512},
+ }, nil, nil, statsengine.HistogramSnapshot{}, statsengine.HistogramSnapshot{})
+ m := NewModelWithConfig(nil, nil, 250, common.DefaultKeyMap())
+ m.activeTab = TabSyscalls
+ m.latest = &snap
+
+ next, _ := m.Update(tea.KeyPressMsg{Code: []rune{'b'}[0], Text: string([]rune{'b'})})
+ model := next.(Model)
+ if got := model.syscallsChart.Metric(); got != bubbleMetricBytes {
+ t.Fatalf("expected syscalls bubble metric bytes, got %q", got)
+ }
+}
+
+func TestFilesBubbleRequiresDirectoryMode(t *testing.T) {
+ snap := statsengine.NewSnapshot(nil, nil, nil, nil, []statsengine.FileSnapshot{
+ {Path: "/tmp/a", Accesses: 3},
+ {Path: "/tmp/b", Accesses: 1},
+ }, nil, statsengine.HistogramSnapshot{}, statsengine.HistogramSnapshot{})
+ m := NewModelWithConfig(nil, nil, 250, common.DefaultKeyMap())
+ m.activeTab = TabFiles
+ m.latest = &snap
+
+ next, _ := m.Update(tea.KeyPressMsg{Code: []rune{'v'}[0], Text: string([]rune{'v'})})
+ model := next.(Model)
+ if model.filesBubble {
+ t.Fatalf("expected files bubble mode to stay disabled without directory mode")
+ }
+
+ next, _ = model.Update(tea.KeyPressMsg{Code: []rune{'d'}[0], Text: string([]rune{'d'})})
+ model = next.(Model)
+ if !model.filesDirGrouped {
+ t.Fatalf("expected files dir mode enabled")
+ }
+
+ next, _ = model.Update(tea.KeyPressMsg{Code: []rune{'v'}[0], Text: string([]rune{'v'})})
+ model = next.(Model)
+ if !model.filesBubble {
+ t.Fatalf("expected files bubble mode enabled in directory mode")
+ }
+
+ next, _ = model.Update(tea.KeyPressMsg{Code: []rune{'d'}[0], Text: string([]rune{'d'})})
+ model = next.(Model)
+ if model.filesBubble {
+ t.Fatalf("expected files bubble mode disabled when leaving directory mode")
+ }
+}
+
+func TestBubbleModeUsesJKForSelection(t *testing.T) {
+ snap := statsengine.NewSnapshot(nil, nil, nil, []statsengine.SyscallSnapshot{
+ {Name: "read", Count: 9, Bytes: 512},
+ {Name: "write", Count: 3, Bytes: 1024},
+ }, nil, nil, statsengine.HistogramSnapshot{}, statsengine.HistogramSnapshot{})
+ m := NewModelWithConfig(nil, nil, 250, common.DefaultKeyMap())
+ m.activeTab = TabSyscalls
+ m.latest = &snap
+ m.syscallsBubble = true
+ m.refreshBubbleData()
+ if len(m.syscallsChart.nodes) < 2 {
+ t.Fatalf("expected at least two syscall bubbles")
+ }
+
+ next, _ := m.Update(tea.KeyPressMsg{Code: []rune{'j'}[0], Text: string([]rune{'j'})})
+ model := next.(Model)
+ if model.syscallsChart.selected != 1 {
+ t.Fatalf("expected bubble selection to move to index 1, got %d", model.syscallsChart.selected)
+ }
+}
+
func TestScrollOffsetDoesNotGrowUnbounded(t *testing.T) {
m := NewModelWithConfig(nil, nil, 250, common.DefaultKeyMap())
m.activeTab = TabSyscalls
@@ -362,6 +469,47 @@ func TestRefreshKeyEmitsRefreshTick(t *testing.T) {
}
}
+func TestRefreshKeyResetsBaselineWhenSourceSupportsReset(t *testing.T) {
+ snap := &statsengine.Snapshot{TotalSyscalls: 5}
+ engine := &fakeResettableSnapshotSource{snap: snap}
+ m := NewModelWithConfig(engine, nil, 250, common.DefaultKeyMap())
+ m.activeTab = TabOverview
+
+ next, cmd := m.Update(tea.KeyPressMsg{Code: []rune{'r'}[0], Text: string([]rune{'r'})})
+ _ = next
+ if cmd == nil {
+ t.Fatalf("expected reset baseline command")
+ }
+ if engine.resetCount != 1 {
+ t.Fatalf("expected reset count 1, got %d", engine.resetCount)
+ }
+ msg := cmd()
+ stats, ok := msg.(messages.StatsTickMsg)
+ if !ok {
+ t.Fatalf("expected StatsTickMsg from reset baseline, got %T", msg)
+ }
+ if stats.Snap != snap {
+ t.Fatalf("expected snapshot after reset")
+ }
+}
+
+func TestRefreshKeyResetsLiveTrieOutsideFlameTab(t *testing.T) {
+ liveTrie := coreflamegraph.NewLiveTrie([]string{"comm", "path"}, "count")
+ m := NewModelWithConfig(nil, nil, 250, common.DefaultKeyMap())
+ m.SetLiveTrie(liveTrie)
+ m.activeTab = TabSyscalls
+ before := liveTrie.Version()
+
+ next, cmd := m.Update(tea.KeyPressMsg{Code: []rune{'r'}[0], Text: string([]rune{'r'})})
+ _ = next
+ if cmd == nil {
+ t.Fatalf("expected baseline reset command")
+ }
+ if liveTrie.Version() == before {
+ t.Fatalf("expected live trie version to change after baseline reset")
+ }
+}
+
func TestFlameTabReceivesSlashKey(t *testing.T) {
m := NewModelWithConfig(nil, nil, 250, common.DefaultKeyMap())
m.activeTab = TabFlame