Files
RMM-Hunter/internal/tui/app_test.go
T
Evan Hosinski 2b6c4eb4cd Implement TUI for managing suspicious artifacts (FilePicker, TypePicker, ListView, and DetailView)
Introduce Bubble Tea-based terminal UI to manage suspicious artifact findings, including file selection, type filtering, list view, and details.
2025-10-10 22:43:47 -04:00

106 lines
2.5 KiB
Go

package tui
import (
"os"
"path/filepath"
"testing"
"time"
tea "github.com/charmbracelet/bubbletea"
)
// writeTestReport creates a minimal JSON report envelope with empty findings
func writeTestReport(t *testing.T, dir, name string, withFindings bool) string {
t.Helper()
path := filepath.Join(dir, name)
var content string
if withFindings {
content = `{
"reportName": "rmm-hunter-report",
"generatedAt": "2025-01-01T00:00:00Z",
"riskRating": {"score":0, "rating":"Low", "summary":""},
"findings": {"processes":[],"services":[],"binaries":[],"autoRuns":[],"scheduledTasks":[],"outboundConnections":[],"directories":[]}
}`
} else {
content = `{}`
}
if err := os.WriteFile(path, []byte(content), 0644); err != nil {
t.Fatalf("failed to write test report: %v", err)
}
return path
}
func TestAppFlow_SelectFile_SelectType_Back_Quit(t *testing.T) {
// Run in a temp dir so file picker sees our .json
tmp := t.TempDir()
if err := os.Chdir(tmp); err != nil {
t.Fatalf("chdir: %v", err)
}
_ = writeTestReport(t, tmp, "test.json", true)
p := tea.NewProgram(NewApp(), tea.WithoutRenderer())
done := make(chan error, 1)
go func() {
_, err := p.Run()
done <- err
}()
// Give init a moment to load files
time.Sleep(100 * time.Millisecond)
// Select file
p.Send(tea.KeyMsg{Type: tea.KeyEnter})
time.Sleep(50 * time.Millisecond)
// Choose type 1 (autoruns)
p.Send(tea.KeyMsg{Type: tea.KeyRunes, Runes: []rune{'1'}})
time.Sleep(50 * time.Millisecond)
// Go back to type picker
p.Send(tea.KeyMsg{Type: tea.KeyLeft})
time.Sleep(50 * time.Millisecond)
// Quit
p.Send(tea.KeyMsg{Type: tea.KeyRunes, Runes: []rune{'q'}})
select {
case err := <-done:
if err != nil {
t.Fatalf("program error: %v", err)
}
case <-time.After(2 * time.Second):
t.Fatal("program did not exit in time")
}
}
func TestApp_ErrorOnBadJSON(t *testing.T) {
tmp := t.TempDir()
if err := os.Chdir(tmp); err != nil {
t.Fatalf("chdir: %v", err)
}
_ = writeTestReport(t, tmp, "bad.json", false)
p := tea.NewProgram(NewApp(), tea.WithoutRenderer())
done := make(chan error, 1)
go func() {
_, err := p.Run()
done <- err
}()
time.Sleep(100 * time.Millisecond)
// Select file -> should error
p.Send(tea.KeyMsg{Type: tea.KeyEnter})
// Any key quits on error screen
time.Sleep(50 * time.Millisecond)
p.Send(tea.KeyMsg{Type: tea.KeyEsc})
select {
case err := <-done:
if err != nil {
t.Fatalf("program error: %v", err)
}
case <-time.After(2 * time.Second):
t.Fatal("program did not exit in time")
}
}