1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
|
package pidpicker
import (
"ior/internal/tui/messages"
"strings"
"testing"
tea "github.com/charmbracelet/bubbletea"
)
func TestApplyFilterByPIDCommAndCmdline(t *testing.T) {
m := NewWithKeys(DefaultKeyMap())
m.processes = []ProcessInfo{
{Pid: 100, Comm: "bash", Cmdline: "bash -l"},
{Pid: 200, Comm: "sshd", Cmdline: "/usr/sbin/sshd -D"},
}
m.input.SetValue("200")
m.applyFilter()
if len(m.filtered) != 1 || m.filtered[0].Pid != 200 {
t.Fatalf("expected pid filter to keep only 200, got %+v", m.filtered)
}
m.input.SetValue("BASH")
m.applyFilter()
if len(m.filtered) != 1 || m.filtered[0].Pid != 100 {
t.Fatalf("expected comm filter to keep only 100, got %+v", m.filtered)
}
m.input.SetValue("/usr/sbin")
m.applyFilter()
if len(m.filtered) != 1 || m.filtered[0].Pid != 200 {
t.Fatalf("expected cmdline filter to keep only 200, got %+v", m.filtered)
}
}
func TestEnterEmitsAllPIDsAndSelectedPID(t *testing.T) {
m := NewWithKeys(DefaultKeyMap())
m.processes = []ProcessInfo{{Pid: 7, Comm: "vim"}, {Pid: 9, Comm: "top"}}
m.applyFilter()
modelAny, cmdAny := m.Update(tea.KeyMsg{Type: tea.KeyEnter})
_ = modelAny
msgAny := cmdAny()
pidAny, ok := msgAny.(messages.PidSelectedMsg)
if !ok {
t.Fatalf("expected PidSelectedMsg for all-pids selection, got %T", msgAny)
}
if pidAny.Pid != 0 {
t.Fatalf("expected all-pids to emit pid 0, got %d", pidAny.Pid)
}
m.selectedIndex = 2
modelOne, cmdOne := m.Update(tea.KeyMsg{Type: tea.KeyEnter})
_ = modelOne
msgOne := cmdOne()
pidOne, ok := msgOne.(messages.PidSelectedMsg)
if !ok {
t.Fatalf("expected PidSelectedMsg for concrete selection, got %T", msgOne)
}
if pidOne.Pid != 9 {
t.Fatalf("expected selected pid 9, got %d", pidOne.Pid)
}
}
func TestEscQuitsAndRefreshTriggersScan(t *testing.T) {
m := NewWithKeys(DefaultKeyMap())
_, escCmd := m.Update(tea.KeyMsg{Type: tea.KeyEsc})
if escCmd == nil {
t.Fatalf("expected esc to return quit cmd")
}
if msg := escCmd(); msg != (tea.QuitMsg{}) {
t.Fatalf("expected quit msg from esc, got %T", msg)
}
_, refreshCmd := m.Update(tea.KeyMsg{Type: tea.KeyCtrlR})
if refreshCmd == nil {
t.Fatalf("expected refresh cmd")
}
if _, ok := refreshCmd().(processesLoadedMsg); !ok {
t.Fatalf("expected refresh to emit processesLoadedMsg")
}
}
func TestRuneRDoesNotTriggerRefreshWhileFilterFocused(t *testing.T) {
m := NewWithKeys(DefaultKeyMap())
next, cmd := m.Update(tea.KeyMsg{Type: tea.KeyRunes, Runes: []rune{'r'}})
if cmd == nil {
t.Fatalf("expected textinput update cmd")
}
updated := next.(Model)
if got := updated.input.Value(); got != "r" {
t.Fatalf("expected filter input to contain typed r, got %q", got)
}
}
func TestRenderRowsKeepsSelectionVisible(t *testing.T) {
m := NewWithKeys(DefaultKeyMap())
m.height = 8 // visible rows == 2
m.processes = []ProcessInfo{
{Pid: 1, Comm: "p1"},
{Pid: 2, Comm: "p2"},
{Pid: 3, Comm: "p3"},
{Pid: 4, Comm: "p4"},
}
m.applyFilter()
m.selectedIndex = 4
rows := m.renderRows()
if !strings.Contains(rows, "> 4 p4") {
t.Fatalf("expected selected row to remain visible, got:\n%s", rows)
}
}
|