package api import ( "encoding/json" "testing" "time" "github.com/ponzischeme89/memby/server/internal/radarr" ) func TestBuildRadarrRowUsesDigitalReleasesAndEstimatedCinemaFallbackInMonthWindow(t *testing.T) { location := time.FixedZone("NZST", 12*60*60) now := time.Date(2026, 7, 30, 9, 0, 0, 0, location) day := func(y int, m time.Month, d int) time.Time { return time.Date(y, m, d, 0, 0, 0, 0, location).UTC() } digitalToday := day(2026, 7, 30) digitalSunday := day(2026, 8, 2) // Three weeks out: inside the month window, past the point a weekday still names a day. digitalLater := day(2026, 8, 20) // The day the window closes, which is exclusive. beyondWindow := day(2026, 8, 29) theatricalOnly := day(2026, 7, 1) oldDigital := day(1993, 4, 9) modernRerelease := day(2026, 7, 2) row, err := buildRadarrRow([]radarr.Movie{ {ID: 1, Title: "Today", DigitalRelease: &digitalToday, Monitored: true}, {ID: 2, Title: "Sunday", DigitalRelease: &digitalSunday, Monitored: true}, {ID: 3, Title: "Three Weeks Out", DigitalRelease: &digitalLater, Monitored: true}, {ID: 4, Title: "Cinema Only", InCinemas: &theatricalOnly, Monitored: true}, {ID: 5, Title: "Old Digital Release", Year: 1993, DigitalRelease: &oldDigital, InCinemas: &modernRerelease, Monitored: true}, {ID: 6, Title: "Beyond Window", DigitalRelease: &beyondWindow, Monitored: true}, }, now, location) if err != nil { t.Fatal(err) } if row.ID != "radarr-upcoming-movies" || row.Kind != "movie-schedule" || row.Title != "Upcoming Movie releases" || len(row.Items) != 4 { t.Fatalf("unexpected row: %+v", row) } items := make([]radarrScheduleItem, len(row.Items)) for i, raw := range row.Items { if err := json.Unmarshal(raw, &items[i]); err != nil { t.Fatal(err) } } want := []struct { id, airLabel, dayLabel string }{ {"radarr:1", "Digital release today", "Today"}, {"radarr:4", "Estimated digital release tomorrow", "Tomorrow"}, {"radarr:2", "Digital release Sunday", "Sunday"}, {"radarr:3", "Digital release 20 August", "20 Aug"}, } for i, expect := range want { got := items[i] if got.ID != expect.id || got.MembyAirLabel != expect.airLabel || got.MembyAirDayLabel != expect.dayLabel { t.Fatalf("item %d: got id=%s air=%q day=%q, want id=%s air=%q day=%q", i, got.ID, got.MembyAirLabel, got.MembyAirDayLabel, expect.id, expect.airLabel, expect.dayLabel) } } if items[1].MembyAvailabilityText != "Estimated digital release" { t.Fatalf("unexpected estimated availability: %+v", items[1]) } } // A weekday only names an unambiguous day inside the coming week. The month-long window // routinely holds dates past that, where "Friday" would read as this Friday. func TestRadarrReleaseLabelsCarryADateBeyondTheComingWeek(t *testing.T) { location := time.FixedZone("NZST", 12*60*60) now := time.Date(2026, 7, 30, 9, 0, 0, 0, location) cases := []struct { offset int dayLabel string airLabel string }{ {0, "Today", "Digital release today"}, {1, "Tomorrow", "Digital release tomorrow"}, {2, "Saturday", "Digital release Saturday"}, {radarrWeekdayLabelDays, "Wednesday", "Digital release Wednesday"}, {radarrWeekdayLabelDays + 1, "6 Aug", "Digital release 6 August"}, {21, "20 Aug", "Digital release 20 August"}, } for _, tc := range cases { release := now.AddDate(0, 0, tc.offset) if got := radarrReleaseDayLabel(release, now, location); got != tc.dayLabel { t.Errorf("offset %d: day label = %q, want %q", tc.offset, got, tc.dayLabel) } if got := digitalReleaseLabel(release, now, location, false); got != tc.airLabel { t.Errorf("offset %d: air label = %q, want %q", tc.offset, got, tc.airLabel) } } } func TestRadarrScheduleItemIncludesArtworkAndDownloadState(t *testing.T) { location := time.FixedZone("NZST", 12*60*60) release := time.Date(2026, 8, 1, 0, 0, 0, 0, location).UTC() added := time.Date(2026, 7, 31, 22, 15, 0, 0, time.UTC) movie := radarr.Movie{ ID: 9, Title: "Arrival", DigitalRelease: &release, HasFile: true, Monitored: true, MovieFile: &radarr.MovieFile{DateAdded: &added}, Images: []radarr.Image{{CoverType: "poster"}, {CoverType: "fanart"}}, } effective, ok := effectiveRadarrRelease(movie) if !ok { t.Fatal("expected a release date") } item := toRadarrScheduleItem(movie, effective, time.Date(2026, 7, 30, 9, 0, 0, 0, location), location) if item.MembySource != "radarr" || item.MembyPlayable || item.ImageTags["Primary"] == "" || len(item.BackdropImageTags) != 1 { t.Fatalf("unexpected synthetic item: %+v", item) } if item.MembyAvailability != "available" || item.MembyAvailabilityText != "Added at 10:15 AM" { t.Fatalf("unexpected availability: %+v", item) } }