2026-08-02 22:10:19 +12:00
|
|
|
package api
|
|
|
|
|
|
|
|
|
|
import (
|
|
|
|
|
"encoding/json"
|
|
|
|
|
"testing"
|
|
|
|
|
"time"
|
|
|
|
|
|
|
|
|
|
"github.com/ponzischeme89/memby/server/internal/radarr"
|
|
|
|
|
)
|
|
|
|
|
|
2026-08-17 19:09:17 +12:00
|
|
|
func TestBuildRadarrRowUsesDigitalReleasesAndEstimatedCinemaFallbackInMonthWindow(t *testing.T) {
|
2026-08-02 22:10:19 +12:00
|
|
|
location := time.FixedZone("NZST", 12*60*60)
|
|
|
|
|
now := time.Date(2026, 7, 30, 9, 0, 0, 0, location)
|
2026-08-17 19:09:17 +12:00
|
|
|
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)
|
2026-08-02 22:10:19 +12:00
|
|
|
|
|
|
|
|
row, err := buildRadarrRow([]radarr.Movie{
|
|
|
|
|
{ID: 1, Title: "Today", DigitalRelease: &digitalToday, Monitored: true},
|
|
|
|
|
{ID: 2, Title: "Sunday", DigitalRelease: &digitalSunday, Monitored: true},
|
2026-08-17 19:09:17 +12:00
|
|
|
{ID: 3, Title: "Three Weeks Out", DigitalRelease: &digitalLater, Monitored: true},
|
2026-08-02 22:10:19 +12:00
|
|
|
{ID: 4, Title: "Cinema Only", InCinemas: &theatricalOnly, Monitored: true},
|
|
|
|
|
{ID: 5, Title: "Old Digital Release", Year: 1993, DigitalRelease: &oldDigital, InCinemas: &modernRerelease, Monitored: true},
|
2026-08-17 19:09:17 +12:00
|
|
|
{ID: 6, Title: "Beyond Window", DigitalRelease: &beyondWindow, Monitored: true},
|
2026-08-02 22:10:19 +12:00
|
|
|
}, now, location)
|
|
|
|
|
if err != nil {
|
|
|
|
|
t.Fatal(err)
|
|
|
|
|
}
|
|
|
|
|
if row.ID != "radarr-upcoming-movies" || row.Kind != "movie-schedule" ||
|
2026-08-17 19:09:17 +12:00
|
|
|
row.Title != "Upcoming Movie releases" || len(row.Items) != 4 {
|
2026-08-02 22:10:19 +12:00
|
|
|
t.Fatalf("unexpected row: %+v", row)
|
|
|
|
|
}
|
2026-08-17 19:09:17 +12:00
|
|
|
|
|
|
|
|
items := make([]radarrScheduleItem, len(row.Items))
|
|
|
|
|
for i, raw := range row.Items {
|
|
|
|
|
if err := json.Unmarshal(raw, &items[i]); err != nil {
|
|
|
|
|
t.Fatal(err)
|
|
|
|
|
}
|
2026-08-02 22:10:19 +12:00
|
|
|
}
|
2026-08-17 19:09:17 +12:00
|
|
|
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"},
|
2026-08-02 22:10:19 +12:00
|
|
|
}
|
2026-08-17 19:09:17 +12:00
|
|
|
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)
|
|
|
|
|
}
|
2026-08-02 22:10:19 +12:00
|
|
|
}
|
2026-08-17 19:09:17 +12:00
|
|
|
if items[1].MembyAvailabilityText != "Estimated digital release" {
|
|
|
|
|
t.Fatalf("unexpected estimated availability: %+v", items[1])
|
2026-08-02 22:10:19 +12:00
|
|
|
}
|
2026-08-17 19:09:17 +12:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 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"},
|
2026-08-02 22:10:19 +12:00
|
|
|
}
|
2026-08-17 19:09:17 +12:00
|
|
|
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)
|
|
|
|
|
}
|
2026-08-02 22:10:19 +12:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
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)
|
|
|
|
|
}
|
|
|
|
|
}
|