185 lines
7.2 KiB
Python
185 lines
7.2 KiB
Python
"""Tests for the releases domain builders."""
|
|
|
|
import pytest
|
|
|
|
from alfred.domain.releases_TO_CHECK.builders import (
|
|
SeasonReleaseBuilder,
|
|
SeriesReleaseBuilder,
|
|
)
|
|
from alfred.domain.releases_TO_CHECK.entities import EpisodeRelease, TrackProfile
|
|
from alfred.domain.releases_TO_CHECK.value_objects import EpisodeRange, ReleaseMode
|
|
from alfred.domain.shared_TO_CHECK.exceptions import ValidationError
|
|
from alfred.domain.shared_TO_CHECK.value_objects import FilePath, ImdbId, TmdbId
|
|
from alfred.domain.tv_shows.value_objects import EpisodeNumber, SeasonNumber
|
|
|
|
|
|
def _ep(start: int, end: int | None = None, *, file: str | None = None) -> EpisodeRelease:
|
|
end_n = EpisodeNumber(end if end is not None else start)
|
|
label = file or f"S01E{start:02d}.mkv"
|
|
return EpisodeRelease(
|
|
episodes=EpisodeRange(EpisodeNumber(start), end_n),
|
|
file_path=FilePath(label),
|
|
tracks=TrackProfile(),
|
|
)
|
|
|
|
|
|
# ---------------------------------------------------------------------------
|
|
# SeasonReleaseBuilder
|
|
# ---------------------------------------------------------------------------
|
|
|
|
|
|
class TestSeasonReleaseBuilder:
|
|
def test_build_empty(self):
|
|
b = SeasonReleaseBuilder(1, folder="X", mode=ReleaseMode.PACK)
|
|
s = b.build()
|
|
assert s.season_number == SeasonNumber(1)
|
|
assert s.episodes == ()
|
|
assert s.mode == ReleaseMode.PACK
|
|
|
|
def test_int_normalized_to_vo(self):
|
|
b = SeasonReleaseBuilder(3, folder="X", mode=ReleaseMode.EPISODIC)
|
|
assert b.season_number == SeasonNumber(3)
|
|
|
|
def test_add_episode_returns_self(self):
|
|
b = SeasonReleaseBuilder(1, folder="X", mode=ReleaseMode.PACK)
|
|
assert b.add_episode(_ep(1)) is b
|
|
|
|
def test_episodes_sorted_by_start(self):
|
|
b = SeasonReleaseBuilder(1, folder="X", mode=ReleaseMode.PACK)
|
|
b.add_episode(_ep(3)).add_episode(_ep(1)).add_episode(_ep(2))
|
|
s = b.build()
|
|
starts = [ep.episodes.start.value for ep in s.episodes]
|
|
assert starts == [1, 2, 3]
|
|
|
|
def test_overlap_raises(self):
|
|
# E01-E03 + E02 -> E02 overlaps with the first range
|
|
b = SeasonReleaseBuilder(1, folder="X", mode=ReleaseMode.PACK)
|
|
b.add_episode(_ep(1, 3)).add_episode(_ep(2))
|
|
with pytest.raises(ValidationError):
|
|
b.build()
|
|
|
|
def test_adjacent_ranges_dont_overlap(self):
|
|
# E01 + E02-E04 + E05 — all touch but no overlap
|
|
b = SeasonReleaseBuilder(1, folder="X", mode=ReleaseMode.PACK)
|
|
b.add_episode(_ep(1)).add_episode(_ep(2, 4)).add_episode(_ep(5))
|
|
s = b.build()
|
|
assert s.episode_count() == 5
|
|
|
|
def test_set_folder(self):
|
|
b = SeasonReleaseBuilder(1, folder="X", mode=ReleaseMode.PACK)
|
|
b.set_folder("Y")
|
|
assert b.build().folder == "Y"
|
|
|
|
def test_set_mode(self):
|
|
b = SeasonReleaseBuilder(1, folder="X", mode=ReleaseMode.PACK)
|
|
b.set_mode(ReleaseMode.EPISODIC)
|
|
assert b.build().mode == ReleaseMode.EPISODIC
|
|
|
|
def test_from_existing_round_trip(self):
|
|
b = SeasonReleaseBuilder(1, folder="Show.S01", mode=ReleaseMode.PACK)
|
|
b.add_episode(_ep(1)).add_episode(_ep(2))
|
|
original = b.build()
|
|
b2 = SeasonReleaseBuilder.from_existing(original)
|
|
rebuilt = b2.build()
|
|
assert rebuilt == original
|
|
|
|
def test_from_existing_then_mutate(self):
|
|
b = SeasonReleaseBuilder(1, folder="X", mode=ReleaseMode.PACK)
|
|
b.add_episode(_ep(1))
|
|
original = b.build()
|
|
b2 = SeasonReleaseBuilder.from_existing(original).add_episode(_ep(2))
|
|
rebuilt = b2.build()
|
|
assert len(rebuilt.episodes) == 2
|
|
|
|
|
|
# ---------------------------------------------------------------------------
|
|
# SeriesReleaseBuilder
|
|
# ---------------------------------------------------------------------------
|
|
|
|
|
|
class TestSeriesReleaseBuilder:
|
|
def test_build_empty(self):
|
|
b = SeriesReleaseBuilder(tmdb_id=TmdbId(84958))
|
|
r = b.build()
|
|
assert r.tmdb_id == TmdbId(84958)
|
|
assert r.imdb_id is None
|
|
assert r.seasons == ()
|
|
|
|
def test_int_and_str_normalized(self):
|
|
b = SeriesReleaseBuilder(tmdb_id=84958, imdb_id="tt0804484")
|
|
r = b.build()
|
|
assert r.tmdb_id == TmdbId(84958)
|
|
assert r.imdb_id == ImdbId("tt0804484")
|
|
|
|
def test_season_builder_create_requires_folder_and_mode(self):
|
|
b = SeriesReleaseBuilder(tmdb_id=TmdbId(1))
|
|
with pytest.raises(ValidationError):
|
|
b.season_builder(1)
|
|
with pytest.raises(ValidationError):
|
|
b.season_builder(1, folder="X")
|
|
with pytest.raises(ValidationError):
|
|
b.season_builder(1, mode=ReleaseMode.PACK)
|
|
|
|
def test_season_builder_reuses_existing(self):
|
|
b = SeriesReleaseBuilder(tmdb_id=TmdbId(1))
|
|
sb1 = b.season_builder(1, folder="X", mode=ReleaseMode.PACK)
|
|
sb2 = b.season_builder(1) # no folder/mode — reuse
|
|
assert sb1 is sb2
|
|
|
|
def test_season_builder_can_override_folder_and_mode(self):
|
|
b = SeriesReleaseBuilder(tmdb_id=TmdbId(1))
|
|
b.season_builder(1, folder="X", mode=ReleaseMode.PACK)
|
|
b.season_builder(1, folder="Y", mode=ReleaseMode.EPISODIC)
|
|
season = b.build().seasons[0]
|
|
assert season.folder == "Y"
|
|
assert season.mode == ReleaseMode.EPISODIC
|
|
|
|
def test_seasons_sorted_on_build(self):
|
|
b = SeriesReleaseBuilder(tmdb_id=TmdbId(1))
|
|
b.season_builder(2, folder="S02", mode=ReleaseMode.PACK)
|
|
b.season_builder(1, folder="S01", mode=ReleaseMode.PACK)
|
|
r = b.build()
|
|
nums = [s.season_number.value for s in r.seasons]
|
|
assert nums == [1, 2]
|
|
|
|
def test_add_season_replaces(self):
|
|
b = SeriesReleaseBuilder(tmdb_id=TmdbId(1))
|
|
b.season_builder(1, folder="OLD", mode=ReleaseMode.PACK)
|
|
# Build a SeasonRelease via its own builder and attach via add_season:
|
|
replacement = SeasonReleaseBuilder(
|
|
1, folder="NEW", mode=ReleaseMode.EPISODIC
|
|
).build()
|
|
b.add_season(replacement)
|
|
season = b.build().seasons[0]
|
|
assert season.folder == "NEW"
|
|
assert season.mode == ReleaseMode.EPISODIC
|
|
|
|
def test_set_imdb_id_string_normalized(self):
|
|
b = SeriesReleaseBuilder(tmdb_id=TmdbId(1))
|
|
b.set_imdb_id("tt0804484")
|
|
assert b.build().imdb_id == ImdbId("tt0804484")
|
|
|
|
def test_set_imdb_id_none(self):
|
|
b = SeriesReleaseBuilder(tmdb_id=TmdbId(1), imdb_id="tt0804484")
|
|
b.set_imdb_id(None)
|
|
assert b.build().imdb_id is None
|
|
|
|
def test_from_existing_round_trip(self):
|
|
b = SeriesReleaseBuilder(tmdb_id=TmdbId(84958), imdb_id="tt0804484")
|
|
sb = b.season_builder(1, folder="S01", mode=ReleaseMode.PACK)
|
|
sb.add_episode(_ep(1)).add_episode(_ep(2))
|
|
original = b.build()
|
|
b2 = SeriesReleaseBuilder.from_existing(original)
|
|
rebuilt = b2.build()
|
|
assert rebuilt == original
|
|
|
|
def test_from_existing_then_mutate(self):
|
|
b = SeriesReleaseBuilder(tmdb_id=TmdbId(1))
|
|
sb = b.season_builder(1, folder="S01", mode=ReleaseMode.PACK)
|
|
sb.add_episode(_ep(1))
|
|
original = b.build()
|
|
b2 = SeriesReleaseBuilder.from_existing(original)
|
|
b2.season_builder(2, folder="S02", mode=ReleaseMode.PACK).add_episode(_ep(1))
|
|
rebuilt = b2.build()
|
|
assert len(rebuilt.seasons) == 2
|