350 lines
8.3 KiB
Go
350 lines
8.3 KiB
Go
package tui
|
|
|
|
import (
|
|
"testing"
|
|
|
|
"bee/audit/internal/app"
|
|
"bee/audit/internal/platform"
|
|
"bee/audit/internal/runtimeenv"
|
|
|
|
tea "github.com/charmbracelet/bubbletea"
|
|
)
|
|
|
|
func newTestModel() model {
|
|
return newModel(app.New(platform.New()), runtimeenv.ModeLocal)
|
|
}
|
|
|
|
func sendKey(t *testing.T, m model, key tea.KeyType) model {
|
|
t.Helper()
|
|
|
|
next, _ := m.Update(tea.KeyMsg{Type: key})
|
|
return next.(model)
|
|
}
|
|
|
|
func TestUpdateMainMenuCursorNavigation(t *testing.T) {
|
|
t.Parallel()
|
|
|
|
m := newTestModel()
|
|
|
|
m = sendKey(t, m, tea.KeyDown)
|
|
if m.cursor != 1 {
|
|
t.Fatalf("cursor=%d want 1 after down", m.cursor)
|
|
}
|
|
|
|
m = sendKey(t, m, tea.KeyDown)
|
|
if m.cursor != 2 {
|
|
t.Fatalf("cursor=%d want 2 after second down", m.cursor)
|
|
}
|
|
|
|
m = sendKey(t, m, tea.KeyUp)
|
|
if m.cursor != 1 {
|
|
t.Fatalf("cursor=%d want 1 after up", m.cursor)
|
|
}
|
|
}
|
|
|
|
func TestUpdateMainMenuEnterActions(t *testing.T) {
|
|
t.Parallel()
|
|
|
|
tests := []struct {
|
|
name string
|
|
cursor int
|
|
wantScreen screen
|
|
wantBusy bool
|
|
wantCmd bool
|
|
}{
|
|
{name: "network", cursor: 0, wantScreen: screenNetwork},
|
|
{name: "services", cursor: 1, wantScreen: screenMain, wantBusy: true, wantCmd: true},
|
|
{name: "acceptance", cursor: 2, wantScreen: screenAcceptance},
|
|
{name: "run audit", cursor: 3, wantScreen: screenMain, wantBusy: true, wantCmd: true},
|
|
{name: "export", cursor: 4, wantScreen: screenMain, wantBusy: true, wantCmd: true},
|
|
}
|
|
|
|
for _, test := range tests {
|
|
test := test
|
|
t.Run(test.name, func(t *testing.T) {
|
|
t.Parallel()
|
|
|
|
m := newTestModel()
|
|
m.cursor = test.cursor
|
|
|
|
next, cmd := m.Update(tea.KeyMsg{Type: tea.KeyEnter})
|
|
got := next.(model)
|
|
|
|
if got.screen != test.wantScreen {
|
|
t.Fatalf("screen=%q want %q", got.screen, test.wantScreen)
|
|
}
|
|
if got.busy != test.wantBusy {
|
|
t.Fatalf("busy=%v want %v", got.busy, test.wantBusy)
|
|
}
|
|
if (cmd != nil) != test.wantCmd {
|
|
t.Fatalf("cmd present=%v want %v", cmd != nil, test.wantCmd)
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
func TestUpdateConfirmCancelViaKeys(t *testing.T) {
|
|
t.Parallel()
|
|
|
|
m := newTestModel()
|
|
m.screen = screenConfirm
|
|
m.pendingAction = actionRunNvidiaSAT
|
|
|
|
next, _ := m.Update(tea.KeyMsg{Type: tea.KeyRight})
|
|
got := next.(model)
|
|
if got.cursor != 1 {
|
|
t.Fatalf("cursor=%d want 1 after right", got.cursor)
|
|
}
|
|
|
|
next, _ = got.Update(tea.KeyMsg{Type: tea.KeyEnter})
|
|
got = next.(model)
|
|
if got.screen != screenAcceptance {
|
|
t.Fatalf("screen=%q want %q", got.screen, screenAcceptance)
|
|
}
|
|
if got.cursor != 0 {
|
|
t.Fatalf("cursor=%d want 0 after cancel", got.cursor)
|
|
}
|
|
}
|
|
|
|
func TestMainMenuSimpleTransitions(t *testing.T) {
|
|
t.Parallel()
|
|
|
|
tests := []struct {
|
|
name string
|
|
cursor int
|
|
wantScreen screen
|
|
}{
|
|
{name: "network", cursor: 0, wantScreen: screenNetwork},
|
|
{name: "acceptance", cursor: 2, wantScreen: screenAcceptance},
|
|
}
|
|
|
|
for _, test := range tests {
|
|
test := test
|
|
t.Run(test.name, func(t *testing.T) {
|
|
t.Parallel()
|
|
|
|
m := newTestModel()
|
|
m.cursor = test.cursor
|
|
|
|
next, cmd := m.handleMainMenu()
|
|
got := next.(model)
|
|
|
|
if cmd != nil {
|
|
t.Fatalf("expected nil cmd for %s", test.name)
|
|
}
|
|
if got.screen != test.wantScreen {
|
|
t.Fatalf("screen=%q want %q", got.screen, test.wantScreen)
|
|
}
|
|
if got.cursor != 0 {
|
|
t.Fatalf("cursor=%d want 0", got.cursor)
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
func TestMainMenuAsyncActionsSetBusy(t *testing.T) {
|
|
t.Parallel()
|
|
|
|
tests := []struct {
|
|
name string
|
|
cursor int
|
|
}{
|
|
{name: "services", cursor: 1},
|
|
{name: "run audit", cursor: 3},
|
|
{name: "export", cursor: 4},
|
|
{name: "check tools", cursor: 5},
|
|
{name: "log tail", cursor: 6},
|
|
}
|
|
|
|
for _, test := range tests {
|
|
test := test
|
|
t.Run(test.name, func(t *testing.T) {
|
|
t.Parallel()
|
|
|
|
m := newTestModel()
|
|
m.cursor = test.cursor
|
|
|
|
next, cmd := m.handleMainMenu()
|
|
got := next.(model)
|
|
|
|
if !got.busy {
|
|
t.Fatalf("busy=false for %s", test.name)
|
|
}
|
|
if cmd == nil {
|
|
t.Fatalf("expected async cmd for %s", test.name)
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
func TestEscapeNavigation(t *testing.T) {
|
|
t.Parallel()
|
|
|
|
tests := []struct {
|
|
name string
|
|
screen screen
|
|
wantScreen screen
|
|
}{
|
|
{name: "network to main", screen: screenNetwork, wantScreen: screenMain},
|
|
{name: "services to main", screen: screenServices, wantScreen: screenMain},
|
|
{name: "acceptance to main", screen: screenAcceptance, wantScreen: screenMain},
|
|
{name: "service action to services", screen: screenServiceAction, wantScreen: screenServices},
|
|
{name: "export targets to main", screen: screenExportTargets, wantScreen: screenMain},
|
|
{name: "interface pick to network", screen: screenInterfacePick, wantScreen: screenNetwork},
|
|
}
|
|
|
|
for _, test := range tests {
|
|
test := test
|
|
t.Run(test.name, func(t *testing.T) {
|
|
t.Parallel()
|
|
|
|
m := newTestModel()
|
|
m.screen = test.screen
|
|
m.cursor = 3
|
|
|
|
next, _ := m.updateKey(tea.KeyMsg{Type: tea.KeyEsc})
|
|
got := next.(model)
|
|
|
|
if got.screen != test.wantScreen {
|
|
t.Fatalf("screen=%q want %q", got.screen, test.wantScreen)
|
|
}
|
|
if got.cursor != 0 {
|
|
t.Fatalf("cursor=%d want 0", got.cursor)
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
func TestOutputScreenReturnsToPreviousScreen(t *testing.T) {
|
|
t.Parallel()
|
|
|
|
m := newTestModel()
|
|
m.screen = screenOutput
|
|
m.prevScreen = screenNetwork
|
|
m.title = "title"
|
|
m.body = "body"
|
|
|
|
next, _ := m.updateKey(tea.KeyMsg{Type: tea.KeyEnter})
|
|
got := next.(model)
|
|
|
|
if got.screen != screenNetwork {
|
|
t.Fatalf("screen=%q want %q", got.screen, screenNetwork)
|
|
}
|
|
if got.title != "" || got.body != "" {
|
|
t.Fatalf("expected output state cleared, got title=%q body=%q", got.title, got.body)
|
|
}
|
|
}
|
|
|
|
func TestAcceptanceConfirmFlow(t *testing.T) {
|
|
t.Parallel()
|
|
|
|
m := newTestModel()
|
|
m.screen = screenAcceptance
|
|
m.cursor = 0
|
|
|
|
next, cmd := m.handleAcceptanceMenu()
|
|
got := next.(model)
|
|
|
|
if cmd != nil {
|
|
t.Fatal("expected nil cmd")
|
|
}
|
|
if got.screen != screenConfirm {
|
|
t.Fatalf("screen=%q want %q", got.screen, screenConfirm)
|
|
}
|
|
if got.pendingAction != actionRunNvidiaSAT {
|
|
t.Fatalf("pendingAction=%q want %q", got.pendingAction, actionRunNvidiaSAT)
|
|
}
|
|
|
|
next, _ = got.updateConfirm(tea.KeyMsg{Type: tea.KeyEsc})
|
|
got = next.(model)
|
|
if got.screen != screenAcceptance {
|
|
t.Fatalf("screen after esc=%q want %q", got.screen, screenAcceptance)
|
|
}
|
|
}
|
|
|
|
func TestExportTargetSelectionOpensConfirm(t *testing.T) {
|
|
t.Parallel()
|
|
|
|
m := newTestModel()
|
|
m.screen = screenExportTargets
|
|
m.targets = []platform.RemovableTarget{{Device: "/dev/sdb1", FSType: "vfat", Size: "16G"}}
|
|
|
|
next, cmd := m.handleExportTargetsMenu()
|
|
got := next.(model)
|
|
|
|
if cmd != nil {
|
|
t.Fatal("expected nil cmd")
|
|
}
|
|
if got.screen != screenConfirm {
|
|
t.Fatalf("screen=%q want %q", got.screen, screenConfirm)
|
|
}
|
|
if got.pendingAction != actionExportAudit {
|
|
t.Fatalf("pendingAction=%q want %q", got.pendingAction, actionExportAudit)
|
|
}
|
|
if got.selectedTarget == nil || got.selectedTarget.Device != "/dev/sdb1" {
|
|
t.Fatalf("selectedTarget=%+v want /dev/sdb1", got.selectedTarget)
|
|
}
|
|
}
|
|
|
|
func TestInterfacePickStaticIPv4OpensForm(t *testing.T) {
|
|
t.Parallel()
|
|
|
|
m := newTestModel()
|
|
m.pendingAction = actionStaticIPv4
|
|
m.interfaces = []platform.InterfaceInfo{{Name: "eth0"}}
|
|
|
|
next, cmd := m.handleInterfacePickMenu()
|
|
got := next.(model)
|
|
|
|
if cmd != nil {
|
|
t.Fatal("expected nil cmd")
|
|
}
|
|
if got.screen != screenStaticForm {
|
|
t.Fatalf("screen=%q want %q", got.screen, screenStaticForm)
|
|
}
|
|
if got.selectedIface != "eth0" {
|
|
t.Fatalf("selectedIface=%q want eth0", got.selectedIface)
|
|
}
|
|
if len(got.formFields) != 4 {
|
|
t.Fatalf("len(formFields)=%d want 4", len(got.formFields))
|
|
}
|
|
}
|
|
|
|
func TestResultMsgUsesExplicitBackScreen(t *testing.T) {
|
|
t.Parallel()
|
|
|
|
m := newTestModel()
|
|
m.screen = screenConfirm
|
|
|
|
next, _ := m.Update(resultMsg{title: "done", body: "ok", back: screenNetwork})
|
|
got := next.(model)
|
|
|
|
if got.screen != screenOutput {
|
|
t.Fatalf("screen=%q want %q", got.screen, screenOutput)
|
|
}
|
|
if got.prevScreen != screenNetwork {
|
|
t.Fatalf("prevScreen=%q want %q", got.prevScreen, screenNetwork)
|
|
}
|
|
}
|
|
|
|
func TestConfirmCancelTarget(t *testing.T) {
|
|
t.Parallel()
|
|
|
|
m := newTestModel()
|
|
|
|
m.pendingAction = actionExportAudit
|
|
if got := m.confirmCancelTarget(); got != screenExportTargets {
|
|
t.Fatalf("export cancel target=%q want %q", got, screenExportTargets)
|
|
}
|
|
|
|
m.pendingAction = actionRunNvidiaSAT
|
|
if got := m.confirmCancelTarget(); got != screenAcceptance {
|
|
t.Fatalf("sat cancel target=%q want %q", got, screenAcceptance)
|
|
}
|
|
|
|
m.pendingAction = actionNone
|
|
if got := m.confirmCancelTarget(); got != screenMain {
|
|
t.Fatalf("default cancel target=%q want %q", got, screenMain)
|
|
}
|
|
}
|