Initial Go project built with Bubble Tea and Lip Gloss: - Live preview and management of /etc/update-motd.d scripts - Embedded presets (ubuntu-default, minimal, server-dashboard) - Bundled POSIX sh style scripts (brand header, sysinfo panel, footer) - Snapshot/restore safety around applying changes - CLI subcommands preview, apply, restore, list-presets - Unit tests for detect, sanitize, and apply logic
109 lines
3.5 KiB
Go
109 lines
3.5 KiB
Go
package ui
|
|
|
|
import (
|
|
"strings"
|
|
"testing"
|
|
|
|
tea "github.com/charmbracelet/bubbletea"
|
|
|
|
"motd-assist/internal/motd"
|
|
"motd-assist/internal/preset"
|
|
)
|
|
|
|
func mustUpdate(m Model, msg tea.Msg) Model {
|
|
next, _ := m.Update(msg)
|
|
return next.(Model)
|
|
}
|
|
|
|
func newTestModel(t *testing.T) Model {
|
|
t.Helper()
|
|
m := New(t.TempDir())
|
|
m = mustUpdate(m, tea.WindowSizeMsg{Width: 120, Height: 40})
|
|
return m
|
|
}
|
|
|
|
func TestViewRendersAllPanes(t *testing.T) {
|
|
m := newTestModel(t)
|
|
scripts := []motd.Script{
|
|
{Name: "00-header", Path: "/x/00-header", Enabled: true},
|
|
{Name: "10-sysinfo", Path: "/x/10-sysinfo", Enabled: false},
|
|
}
|
|
m = mustUpdate(m, discoverMsg{scripts: scripts, host: motd.HostInfo{Hostname: "myhost", Distro: "Ubuntu 24.04", PAM: true}})
|
|
m = mustUpdate(m, previewMsg{version: m.previewVersion, text: "Willkommen auf myhost"})
|
|
|
|
view := m.View()
|
|
for _, want := range []string{"Presets", "Scripte", "Live-Vorschau", "00-header", "10-sysinfo", "Willkommen auf myhost", "myhost"} {
|
|
if !strings.Contains(view, want) {
|
|
t.Errorf("View enthält %q nicht", want)
|
|
}
|
|
}
|
|
}
|
|
|
|
func TestToggleAndPlan(t *testing.T) {
|
|
m := newTestModel(t)
|
|
scripts := []motd.Script{
|
|
{Name: "00-header", Path: "/x/00-header", Enabled: true},
|
|
{Name: "10-sysinfo", Path: "/x/10-sysinfo", Enabled: false},
|
|
}
|
|
m = mustUpdate(m, discoverMsg{scripts: scripts})
|
|
|
|
// Fokus auf Scripte wechseln und erstes Script ausschalten.
|
|
m = mustUpdate(m, tea.KeyMsg{Type: tea.KeyTab})
|
|
m = mustUpdate(m, tea.KeyMsg{Type: tea.KeySpace})
|
|
|
|
plan := m.currentPlan()
|
|
if len(plan.Chmod) != 1 || plan.Chmod[0].Name != "00-header" || plan.Chmod[0].Enable {
|
|
t.Errorf("Chmod = %+v, want 00-header aus", plan.Chmod)
|
|
}
|
|
if markers := m.markersByRow(); markers["00-header"] != "aus" {
|
|
t.Errorf("Marker = %q, want aus", markers["00-header"])
|
|
}
|
|
}
|
|
|
|
func TestMoveRowChangesOrder(t *testing.T) {
|
|
m := newTestModel(t)
|
|
scripts := []motd.Script{
|
|
{Name: "00-header", Path: "/x", Enabled: true},
|
|
{Name: "10-sysinfo", Path: "/x", Enabled: true},
|
|
}
|
|
m = mustUpdate(m, discoverMsg{scripts: scripts})
|
|
m = mustUpdate(m, tea.KeyMsg{Type: tea.KeyTab})
|
|
m = mustUpdate(m, tea.KeyMsg{Type: tea.KeyRunes, Runes: []rune("d")}) // nach unten
|
|
|
|
if m.working[0].Name != "10-sysinfo" || m.working[1].Name != "00-header" {
|
|
t.Errorf("Reihenfolge = %v, %v", m.working[0].Name, m.working[1].Name)
|
|
}
|
|
if plan := m.currentPlan(); len(plan.Renames) != 2 {
|
|
t.Errorf("Renames = %+v, want 2", plan.Renames)
|
|
}
|
|
}
|
|
|
|
func TestLoadPresetMarksPending(t *testing.T) {
|
|
m := newTestModel(t)
|
|
scripts := []motd.Script{{Name: "00-header", Path: "/x", Enabled: false}}
|
|
m = mustUpdate(m, discoverMsg{scripts: scripts})
|
|
m = mustUpdate(m, presetsMsg{presets: []preset.Preset{{Name: "p1", Scripts: []preset.Entry{{Name: "00-header", Enabled: true}}}}})
|
|
m = mustUpdate(m, tea.KeyMsg{Type: tea.KeyEnter}) // erstes Preset laden
|
|
|
|
if plan := m.currentPlan(); len(plan.Chmod) != 1 || !plan.Chmod[0].Enable {
|
|
t.Errorf("Plan = %+v, want 00-header an", plan)
|
|
}
|
|
if m.status == "" {
|
|
t.Error("Statusmeldung nach Preset-Laden erwartet")
|
|
}
|
|
}
|
|
|
|
func TestDiscardResetsWorking(t *testing.T) {
|
|
m := newTestModel(t)
|
|
scripts := []motd.Script{{Name: "00-header", Path: "/x", Enabled: true}}
|
|
m = mustUpdate(m, discoverMsg{scripts: scripts})
|
|
m = mustUpdate(m, tea.KeyMsg{Type: tea.KeyTab})
|
|
m = mustUpdate(m, tea.KeyMsg{Type: tea.KeySpace}) // ausschalten
|
|
if m.currentPlan().Empty() {
|
|
t.Fatal("Plan sollte Änderungen haben")
|
|
}
|
|
m = mustUpdate(m, tea.KeyMsg{Type: tea.KeyEsc})
|
|
if !m.currentPlan().Empty() {
|
|
t.Errorf("nach esc sollte der Plan leer sein, ist %+v", m.currentPlan())
|
|
}
|
|
}
|