"""Shared fixtures for v2 ``.alfred`` integration tests. The fixtures here build realistic ``SeriesRelease`` / ``MovieRelease`` aggregates — populated tracks, multi-episode files, both PACK and EPISODIC modes — so every test starts from a known-rich state. The point is to make round-trip tests genuinely lossless-checking (if a field is unused in the fixture, the round-trip can't prove much about it). """ from __future__ import annotations from datetime import UTC, datetime import pytest from alfred.domain.releases.entities import ( EpisodeRelease, MovieRelease, SeasonRelease, SeriesRelease, TrackProfile, ) from alfred.domain.releases.value_objects import EpisodeRange, ReleaseMode from alfred.domain.shared.media import AudioTrack, SubtitleTrack from alfred.domain.shared.value_objects import FilePath, ImdbId, TmdbId from alfred.domain.tv_shows.value_objects import EpisodeNumber, SeasonNumber from alfred.infrastructure.api.tmdb.dto import TmdbSeasonInfo, TmdbShowInfo def _audio(lang: str = "eng", *, index: int = 0) -> AudioTrack: # ``index`` defaults to 0 to match what the bridge reconstructs on # read (sidecars don't persist ffprobe stream indices — see the # bridge module's track-conversion notes). Pass explicit indices # only when a fixture has multiple tracks of the same kind. return AudioTrack( index=index, codec="eac3", channels=6, channel_layout="5.1", language=lang, ) def _sub( lang: str = "eng", *, index: int = 0, forced: bool = False, sdh: bool = False, ) -> SubtitleTrack: return SubtitleTrack( index=index, codec="subrip", language=lang, is_default=False, is_forced=forced, is_sdh=sdh, ) @pytest.fixture def foundation_release() -> SeriesRelease: """Foundation S01 (PACK, 3 files) + S02 (EPISODIC, one multi-episode file).""" s01 = SeasonRelease( season_number=SeasonNumber(1), folder="Foundation.S01.1080p.WEBRip.x265-RARBG", mode=ReleaseMode.PACK, episodes=( EpisodeRelease( episodes=EpisodeRange(EpisodeNumber(1), EpisodeNumber(1)), file_path=FilePath( "Foundation.S01.1080p.WEBRip.x265-RARBG/" "Foundation.S01E01.1080p.WEBRip.x265-RARBG.mkv" ), tracks=TrackProfile( audio_tracks=(_audio("eng"),), subtitle_tracks=( _sub("eng", index=0), _sub("eng", index=1, sdh=True), ), ), ), EpisodeRelease( episodes=EpisodeRange(EpisodeNumber(2), EpisodeNumber(2)), file_path=FilePath( "Foundation.S01.1080p.WEBRip.x265-RARBG/" "Foundation.S01E02.1080p.WEBRip.x265-RARBG.mkv" ), tracks=TrackProfile(audio_tracks=(_audio("eng"),)), ), EpisodeRelease( episodes=EpisodeRange(EpisodeNumber(3), EpisodeNumber(3)), file_path=FilePath( "Foundation.S01.1080p.WEBRip.x265-RARBG/" "Foundation.S01E03.1080p.WEBRip.x265-RARBG.mkv" ), tracks=TrackProfile(audio_tracks=(_audio("eng"),)), ), ), ) s02 = SeasonRelease( season_number=SeasonNumber(2), folder="Foundation.S02", mode=ReleaseMode.EPISODIC, episodes=( EpisodeRelease( episodes=EpisodeRange(EpisodeNumber(1), EpisodeNumber(1)), file_path=FilePath( "Foundation.S02/Foundation.S02E01.1080p.x265-ELiTE/" "Foundation.S02E01.1080p.x265-ELiTE.mkv" ), tracks=TrackProfile(audio_tracks=(_audio("eng"),)), ), # Multi-episode file (E02 + E03 in one .mkv). EpisodeRelease( episodes=EpisodeRange(EpisodeNumber(2), EpisodeNumber(3)), file_path=FilePath( "Foundation.S02/Foundation.S02E02-E03.2160p.WEB.x265-CtrlHD/" "Foundation.S02E02-E03.2160p.WEB.x265-CtrlHD.mkv" ), tracks=TrackProfile( audio_tracks=(_audio("eng"),), subtitle_tracks=(_sub("eng", forced=True),), ), ), ), ) return SeriesRelease( tmdb_id=TmdbId(84958), imdb_id=ImdbId("tt0804484"), seasons=(s01, s02), ) @pytest.fixture def inception_release() -> MovieRelease: """Inception (2010) — single-file movie with rich tracks.""" return MovieRelease( tmdb_id=TmdbId(27205), imdb_id=ImdbId("tt1375666"), folder="Inception.2010.1080p.BluRay.x264-GROUP", file_path=FilePath("Inception.2010.1080p.BluRay.x264-GROUP.mkv"), tracks=TrackProfile( audio_tracks=( AudioTrack( index=0, codec="dts", channels=8, channel_layout="7.1", language="eng", ), ), subtitle_tracks=( _sub("eng", index=0), _sub("fre", index=1, forced=True), ), ), ) @pytest.fixture def foundation_tmdb_info() -> TmdbShowInfo: """Foundation TMDB cache snapshot — 3 seasons, S03 not yet aired.""" return TmdbShowInfo( tmdb_id=84958, imdb_id="tt0804484", name="Foundation", status="Returning Series", seasons=( TmdbSeasonInfo(number=1, episode_count=10, aired=True), TmdbSeasonInfo(number=2, episode_count=10, aired=True), TmdbSeasonInfo(number=3, episode_count=10, aired=False), ), ) @pytest.fixture def now_utc() -> datetime: """Stable UTC reference for deterministic fetched_at fields.""" return datetime(2026, 5, 25, 8, 30, 0, tzinfo=UTC) @pytest.fixture def tv_library(tmp_path): """Empty ``tv_shows/`` directory pre-populated with show folders.""" root = tmp_path / "tv_shows" root.mkdir() (root / "Foundation").mkdir() (root / "Fallout").mkdir() return root @pytest.fixture def movie_library(tmp_path): """Empty ``movies/`` directory pre-populated with one movie folder.""" root = tmp_path / "movies" root.mkdir() (root / "Inception.2010.1080p.BluRay.x264-GROUP").mkdir() return root