Files
mal/internal/episodes/service/policy_merge_extra_test.go

117 lines
3.5 KiB
Go

package service
import (
"testing"
"time"
"mal/integrations/jikan"
"mal/internal/domain"
)
func TestMergeEpisodesFiltersProviderBackedJikanToAvailableNumbers(t *testing.T) {
episodes := mergeEpisodes([]jikan.Episode{
{Episode: "1", Title: "Available"},
{Episode: "2", Title: "Unavailable"},
{Episode: "3", Title: "Dubbed"},
}, domain.EpisodeAvailability{
Sub: []int{1},
Dub: []int{3},
}, 0)
if len(episodes) != 2 {
t.Fatalf("len(episodes) = %d, want 2", len(episodes))
}
assertEpisode(t, episodes[0], 1, "Available", true, false, true, false)
assertEpisode(t, episodes[1], 3, "Dubbed", false, true, false, false)
}
func TestMergeEpisodesHonorsExpectedCountForAvailability(t *testing.T) {
episodes := mergeEpisodes(nil, domain.EpisodeAvailability{
Sub: []int{0, 1, 2, 4},
Dub: []int{-1, 2, 3, 5},
}, 3)
if len(episodes) != 3 {
t.Fatalf("len(episodes) = %d, want 3", len(episodes))
}
assertEpisode(t, episodes[0], 1, "Episode 1", true, false, true, false)
assertEpisode(t, episodes[1], 2, "Episode 2", true, true, false, false)
assertEpisode(t, episodes[2], 3, "Episode 3", false, true, false, false)
}
func TestIsCanonicalEpisodePayloadValidAllowsProviderPayloadWhenNoExpectedCount(t *testing.T) {
payload := domain.CanonicalEpisodeList{
Source: "AllAnime",
Episodes: []domain.CanonicalEpisode{
{Number: 1, HasSub: true},
{Number: 2, HasDub: true},
},
}
if !isCanonicalEpisodePayloadValid(payload, 0) {
t.Fatalf("expected provider-backed payload with availability to be valid")
}
}
func TestIsCanonicalEpisodePayloadValidRejectsOutOfRangeEpisodeNumber(t *testing.T) {
payload := domain.CanonicalEpisodeList{
Episodes: []domain.CanonicalEpisode{
{Number: 0, Title: "Invalid"},
},
}
if isCanonicalEpisodePayloadValid(payload, 12) {
t.Fatalf("expected zero episode number to be invalid")
}
}
func TestNextRefreshAtForFinishedAnimeIsEmpty(t *testing.T) {
now := time.Date(2026, 5, 16, 13, 0, 0, 0, time.UTC)
got := nextRefreshAt(domain.Anime{Anime: jikan.Anime{Airing: false}}, now)
if got.Valid {
t.Fatalf("nextRefreshAt finished anime = %s, want invalid", got.Time)
}
}
func TestNextRefreshAtRetriesSoonAfterRecentBroadcast(t *testing.T) {
anime := domain.Anime{Anime: jikan.Anime{Airing: true}}
anime.Broadcast.Day = "Saturdays"
anime.Broadcast.Time = "12:00"
anime.Broadcast.Timezone = "UTC"
now := time.Date(2026, 5, 16, 13, 0, 0, 0, time.UTC)
got := nextRefreshAt(anime, now)
want := now.Add(retryInterval).UTC()
if !got.Valid || !got.Time.Equal(want) {
t.Fatalf("nextRefreshAt = %#v, want %s", got, want)
}
}
func TestNextRefreshAtFallsBackWhenBroadcastMetadataMissing(t *testing.T) {
anime := domain.Anime{Anime: jikan.Anime{Airing: true}}
now := time.Date(2026, 5, 16, 13, 0, 0, 0, time.UTC)
got := nextRefreshAt(anime, now)
want := now.Add(airingFallbackRefreshInterval).UTC()
if !got.Valid || !got.Time.Equal(want) {
t.Fatalf("nextRefreshAt = %#v, want %s", got, want)
}
}
func TestBroadcastHelpersRejectInvalidValues(t *testing.T) {
if day := weekdayFromJikan("someday"); day != -1 {
t.Fatalf("weekdayFromJikan invalid = %d, want -1", day)
}
if _, _, ok := parseBroadcastTime("25:99"); ok {
t.Fatalf("parseBroadcastTime should reject invalid time")
}
anime := domain.Anime{Anime: jikan.Anime{MalID: 1}}
anime.Broadcast.Day = "Saturdays"
anime.Broadcast.Time = "bad"
if got := nextBroadcastAfter(anime, time.Date(2026, 5, 16, 13, 0, 0, 0, time.UTC)); !got.IsZero() {
t.Fatalf("nextBroadcastAfter invalid time = %s, want zero", got)
}
}