package tui import ( "os" "path/filepath" "strings" "testing" tea "charm.land/bubbletea/v2" "gitgud.io/mike/mpv-manager/pkg/config" ) func TestReadLogTailSmallFile(t *testing.T) { path := filepath.Join(t.TempDir(), "mpv-manager.log") content := "[2026-08-01 10:00:00] [INFO] one\n[2026-08-01 10:00:01] [INFO] two\n" if err := os.WriteFile(path, []byte(content), 0o644); err != nil { t.Fatal(err) } tail, truncated, err := readLogTail(path, maxLogTailBytes, maxLogTailLines) if err != nil { t.Fatalf("failed to read log tail: %v", err) } if truncated { t.Error("expected no truncation for small file") } if !strings.Contains(tail, "one") || !strings.Contains(tail, "two") { t.Errorf("expected both lines, got %q", tail) } } func TestReadLogTailKeepsLastLines(t *testing.T) { path := filepath.Join(t.TempDir(), "mpv-manager.log") var lines []string for i := 0; i < 10; i++ { lines = append(lines, strings.Repeat("x", 3)+string(rune('0'+i))) } if err := os.WriteFile(path, []byte(strings.Join(lines, "\n")+"\n"), 0o644); err != nil { t.Fatal(err) } tail, truncated, err := readLogTail(path, maxLogTailBytes, 3) if err != nil { t.Fatalf("failed to read log tail: %v", err) } if !truncated { t.Error("expected truncation when exceeding max lines") } got := strings.Split(tail, "\n") if len(got) != 3 { t.Fatalf("expected 3 lines, got %d", len(got)) } if !strings.HasSuffix(got[2], "9") || !strings.HasSuffix(got[0], "7") { t.Errorf("expected last 3 lines, got %v", got) } } func TestReadLogTailByteCapDropsPartialLine(t *testing.T) { path := filepath.Join(t.TempDir(), "mpv-manager.log") content := "partial-line-should-be-dropped\nfull line one\nfull line two\n" if err := os.WriteFile(path, []byte(content), 0o644); err != nil { t.Fatal(err) } // Only the last 25 bytes ("full line one\nfull line two\n") fit. tail, truncated, err := readLogTail(path, 25, maxLogTailLines) if err != nil { t.Fatalf("failed to read log tail: %v", err) } if !truncated { t.Error("expected truncation when exceeding max bytes") } if strings.Contains(tail, "partial") { t.Errorf("expected partial line dropped, got %q", tail) } if !strings.Contains(tail, "full line two") { t.Errorf("expected trailing lines kept, got %q", tail) } } func TestReadLogTailMissingFile(t *testing.T) { if _, _, err := readLogTail(filepath.Join(t.TempDir(), "missing.log"), maxLogTailBytes, maxLogTailLines); err == nil { t.Error("expected error for missing file") } } func TestLogsViewerWithoutLogger(t *testing.T) { sandboxConfigHome(t) m := NewModel() m.setupLogsView() m.state = StateLogsViewer // No logger is initialized in tests, so a status message explains that. if m.logsStatusMsg == "" { t.Error("expected status message when logger is unavailable") } // Esc returns to the main menu. m = pressKey(t, m, tea.KeyPressMsg{Code: tea.KeyEsc}) if m.state != StateMainMenu { t.Fatalf("expected StateMainMenu after Esc, got %v", m.state) } } func TestWebUIToggleShortcutPreference(t *testing.T) { sandboxConfigHome(t) if _, err := config.Reload(); err != nil { t.Fatalf("failed to reload config: %v", err) } m := NewModel() m.setupWebUIList() m.state = StateWebUIMenu if len(m.webUIList.Items()) != 2 { t.Fatalf("expected 2 Web UI menu items, got %d", len(m.webUIList.Items())) } initial := config.GetCreateManagerShortcut() m.webUIList.Select(1) m = pressKey(t, m, tea.KeyPressMsg{Code: tea.KeyEnter}) if got := config.GetCreateManagerShortcut(); got == initial { t.Error("expected shortcut preference toggled") } if !strings.HasPrefix(m.webUIStatusMsg, "✓") { t.Errorf("expected success status, got %q", m.webUIStatusMsg) } // Toggling again restores the initial value. The list was rebuilt by the // first toggle, so re-select the toggle item. m.webUIList.Select(1) m = pressKey(t, m, tea.KeyPressMsg{Code: tea.KeyEnter}) if got := config.GetCreateManagerShortcut(); got != initial { t.Error("expected shortcut preference restored after second toggle") } // Esc clears the status and returns to the main menu. m = pressKey(t, m, tea.KeyPressMsg{Code: tea.KeyEsc}) if m.state != StateMainMenu { t.Fatalf("expected StateMainMenu after Esc, got %v", m.state) } if m.webUIStatusMsg != "" { t.Errorf("expected status cleared after Esc, got %q", m.webUIStatusMsg) } }