Files
arr-tui/internal/ui/format_test.go
T
nilsandClaude Sonnet 5.5 446cbdd6c5 Show Radarr and Sonarr queues in the Downloads view (M5)
Add queue listing and removal/blocklisting to the shared arr client.
The Downloads view now fetches SABnzbd and both arr queues in parallel,
shows status, progress and import problems, flags items needing
attention in the summary, and supports removing or blocklisting items.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-20 18:03:16 +02:00

158 lines
5.1 KiB
Go

package ui
import (
"strings"
"testing"
"time"
"git.stinnesbeck.com/nils/arr-tui/internal/arr"
"git.stinnesbeck.com/nils/arr-tui/internal/radarr"
"git.stinnesbeck.com/nils/arr-tui/internal/sonarr"
)
func TestMovieLabel(t *testing.T) {
if got := movieLabel(radarr.Movie{Title: "Alien", Year: 1979}); got != "Alien (1979)" {
t.Errorf("got %q", got)
}
if got := movieLabel(radarr.Movie{ID: 3, Title: "Alien", Year: 1979}); !strings.Contains(got, "✓") {
t.Errorf("in-library marker missing: %q", got)
}
// tview color tags in titles must be escaped
if got := movieLabel(radarr.Movie{Title: "[red]x"}); strings.Contains(got, "[red]x") {
t.Errorf("title not escaped: %q", got)
}
}
func TestMovieDetails(t *testing.T) {
got := movieDetails(radarr.Movie{
ID: 1, Title: "Alien", Year: 1979, Runtime: 117, Genres: []string{"Horror", "Sci-Fi"},
Overview: "In space...", Ratings: radarr.Ratings{IMDB: &radarr.Rating{Value: 8.5}},
})
for _, want := range []string{"Alien (1979)", "★ 8.5", "1h57m", "Horror, Sci-Fi", "In library, not downloaded", "In space..."} {
if !strings.Contains(got, want) {
t.Errorf("details missing %q:\n%s", want, got)
}
}
}
func TestDefaultIndexes(t *testing.T) {
profiles := []arr.QualityProfile{{Name: "Any"}, {Name: "HD-1080p"}}
if profileIndex(profiles, "hd-1080p") != 1 || profileIndex(profiles, "nope") != 0 {
t.Error("profileIndex")
}
folders := []arr.RootFolder{{Path: "/a"}, {Path: "/movies/"}}
if folderIndex(folders, "/movies") != 1 || folderIndex(folders, "") != 0 {
t.Error("folderIndex")
}
}
func TestSeriesLabelAndDetails(t *testing.T) {
s := sonarr.Series{
Title: "Breaking Bad", Year: 2008, Network: "AMC", Status: "ended", Runtime: 47,
Genres: []string{"Crime"},
Ratings: sonarr.Rating{Value: 9.3},
Seasons: []sonarr.Season{{SeasonNumber: 0}, {SeasonNumber: 1}},
}
if got := seriesLabel(s); got != "Breaking Bad (2008)" {
t.Errorf("label = %q", got)
}
got := seriesDetails(s)
for _, want := range []string{"Breaking Bad (2008)", "★ 9.3", "1 season ·", "47 min", "Network: AMC", "Status: ended"} {
if !strings.Contains(got, want) {
t.Errorf("details missing %q:\n%s", want, got)
}
}
s.ID = 1
s.Statistics = sonarr.Statistics{EpisodeCount: 10, EpisodeFileCount: 4}
if got := seriesDetails(s); !strings.Contains(got, "4/10 episodes") {
t.Errorf("progress missing:\n%s", got)
}
s.Statistics.EpisodeFileCount = 10
if got := seriesDetails(s); !strings.Contains(got, "all episodes downloaded") {
t.Errorf("complete marker missing:\n%s", got)
}
}
func TestResultKeysAndWithID(t *testing.T) {
var r result = movieResult{radarr.Movie{TMDBID: 603, Title: "x"}}
if r.key() != "tmdb:603" || r.inLibrary() {
t.Fatalf("movie key/inLibrary: %q %v", r.key(), r.inLibrary())
}
if added := r.withID(5); !added.inLibrary() || r.inLibrary() {
t.Error("withID must return a flagged copy and leave the original alone")
}
r = seriesResult{sonarr.Series{TVDBID: 81189}}
if r.key() != "tvdb:81189" {
t.Errorf("series key = %q", r.key())
}
}
func TestFormatSpeed(t *testing.T) {
tests := map[float64]string{0: "0 KB/s", 0.4: "0 KB/s", 512: "512 KB/s", 1536: "1.5 MB/s"}
for in, want := range tests {
if got := formatSpeed(in); got != want {
t.Errorf("formatSpeed(%v) = %q, want %q", in, got, want)
}
}
}
func TestProgressBar(t *testing.T) {
if got := progressBar(50, 10); got != "█████░░░░░ 50%" {
t.Errorf("got %q", got)
}
if got := progressBar(150, 4); got != "████ 100%" {
t.Errorf("clamp high: %q", got)
}
if got := progressBar(-5, 4); got != "░░░░ 0%" {
t.Errorf("clamp low: %q", got)
}
}
func TestFormatAge(t *testing.T) {
now := time.Unix(1_000_000, 0)
tests := map[int64]string{
0: "",
now.Unix() - 10: "just now",
now.Unix() - 5*60: "5m ago",
now.Unix() - 3*3600: "3h ago",
now.Unix() - 3*24*3600: "3d ago",
}
for in, want := range tests {
if got := formatAge(in, now); got != want {
t.Errorf("formatAge(%d) = %q, want %q", in, got, want)
}
}
}
func TestTruncate(t *testing.T) {
if got := truncate("short", 10); got != "short" {
t.Errorf("got %q", got)
}
if got := truncate("Aborted, cannot be completed", 10); got != "Aborted, …" {
t.Errorf("got %q", got)
}
if got := truncate("äöüäöü", 4); got != "äöü…" {
t.Errorf("rune handling: %q", got)
}
}
func TestArrStatusText(t *testing.T) {
tests := []struct {
name string
item arr.QueueItem
want string
}{
{"downloading", arr.QueueItem{TrackedDownloadState: "downloading", TrackedDownloadStatus: "ok"}, "Downloading"},
{"blocked", arr.QueueItem{TrackedDownloadState: "importBlocked", TrackedDownloadStatus: "warning"}, "[red]Import blocked[-]"},
{"warning", arr.QueueItem{TrackedDownloadState: "importPending", TrackedDownloadStatus: "warning"}, "[yellow]Import pending[-]"},
{"error", arr.QueueItem{Status: "failed", TrackedDownloadStatus: "error"}, "[red]Failed[-]"},
{"fallback to status", arr.QueueItem{Status: "queued"}, "Queued"},
}
for _, tc := range tests {
if got := arrStatusText(tc.item); got != tc.want {
t.Errorf("%s: got %q, want %q", tc.name, got, tc.want)
}
}
}