mirror of
https://github.com/unshackle-dl/unshackle.git
synced 2026-11-13 12:35:05 +00:00
Renames 314 defs and 41 module/class-level constants. Keeps 11 names underscored where the stripped form collides in scope, plus 5.5.0 shims for the three symbols external service repos call.
152 lines
5.1 KiB
Python
152 lines
5.1 KiB
Python
"""Tests for date-based ("daily"/sports) episode naming via Episode.air_date."""
|
|
|
|
from __future__ import annotations
|
|
|
|
from datetime import date, datetime
|
|
|
|
import pytest
|
|
|
|
from unshackle.core.config import config
|
|
from unshackle.core.titles.episode import Episode
|
|
|
|
|
|
class DummyService:
|
|
pass
|
|
|
|
|
|
class StubMediaInfo:
|
|
"""Minimal MediaInfo stand-in: the template context only reads track lists."""
|
|
|
|
video_tracks: list = []
|
|
audio_tracks: list = []
|
|
|
|
|
|
def make_episode(**overrides) -> Episode:
|
|
kwargs = dict(
|
|
id_="ep-0001",
|
|
service=DummyService,
|
|
title="The Show",
|
|
season=2024,
|
|
number=181,
|
|
name="The Big Race",
|
|
year=2024,
|
|
)
|
|
kwargs.update(overrides)
|
|
return Episode(**kwargs)
|
|
|
|
|
|
@pytest.fixture
|
|
def reset_template():
|
|
saved = (config.output_template, config.folder_templates, config.folder_template)
|
|
config.output_template = {"series": "{title}.{year?}.{season_episode}.{quality}-{tag}"}
|
|
config.folder_templates = {}
|
|
config.folder_template = ""
|
|
yield config
|
|
config.output_template, config.folder_templates, config.folder_template = saved
|
|
|
|
|
|
def test_air_date_replaces_season_episode_dotted(reset_template):
|
|
ep = make_episode(air_date=date(2024, 6, 30))
|
|
ctx = ep.build_template_context(StubMediaInfo())
|
|
assert ctx["season_episode"] == "2024.06.30"
|
|
assert ctx["season"] == "2024.06.30"
|
|
assert ctx["episode"] == ""
|
|
assert ctx["year"] == "" # date carries the year
|
|
assert ctx["date"] == "2024-06-30" # ISO regardless of separator
|
|
|
|
|
|
def test_air_date_uses_space_separator(reset_template):
|
|
reset_template.output_template = {"series": "{title} {season_episode} {quality}-{tag}"}
|
|
ep = make_episode(air_date=date(2024, 6, 30))
|
|
assert ep.build_template_context(StubMediaInfo())["season_episode"] == "2024 06 30"
|
|
|
|
|
|
def test_iso_string_air_date_coerced(reset_template):
|
|
ep = make_episode(air_date="2024-06-30")
|
|
assert isinstance(ep.air_date, date)
|
|
assert ep.build_template_context(StubMediaInfo())["season_episode"] == "2024.06.30"
|
|
|
|
|
|
def test_year_always_dropped_in_file_when_dated(reset_template):
|
|
"""The air date is the sole date in the filename; a distinct year is dropped too (deterministic)."""
|
|
ep = make_episode(year=2010, air_date=date(2013, 10, 30))
|
|
ctx = ep.build_template_context(StubMediaInfo())
|
|
assert ctx["year"] == ""
|
|
assert ctx["season_episode"] == "2013.10.30"
|
|
|
|
|
|
def test_yearless_title_takes_year_from_date(reset_template):
|
|
"""A title with no year still names cleanly; the date supplies the year."""
|
|
ep = make_episode(year=None, air_date=date(2026, 6, 28))
|
|
ctx = ep.build_template_context(StubMediaInfo())
|
|
assert ctx["year"] == ""
|
|
assert ctx["season_episode"] == "2026.06.28"
|
|
|
|
|
|
def test_datetime_normalized_to_date(reset_template):
|
|
"""A datetime (subclass of date) must not leak its time into the {date} token."""
|
|
ep = make_episode(air_date=datetime(2024, 6, 30, 13, 0, 0))
|
|
assert type(ep.air_date) is date
|
|
assert ep.build_template_context(StubMediaInfo())["date"] == "2024-06-30"
|
|
|
|
|
|
def test_no_air_date_is_unchanged(reset_template):
|
|
"""Regression: without air_date, naming is exactly as before (presentation-only field)."""
|
|
ep = make_episode()
|
|
ctx = ep.build_template_context(StubMediaInfo())
|
|
assert ctx["season_episode"] == "S2024E181"
|
|
assert ctx["season"] == "S2024"
|
|
assert ctx["episode"] == "E181"
|
|
assert ctx["year"] == 2024
|
|
assert ctx["date"] == ""
|
|
|
|
|
|
def test_dated_folder_groups_by_year(reset_template):
|
|
reset_template.folder_templates = {}
|
|
reset_template.folder_template = ""
|
|
folder = make_episode(air_date=date(2024, 6, 30)).get_filename(StubMediaInfo(), folder=True)
|
|
assert "2024" in folder
|
|
assert "S2024" not in folder # season folder is the year, not the faked season
|
|
|
|
|
|
# --- selection by date ------------------------------------------------------
|
|
|
|
|
|
def test_a_dated_episode_matches_its_iso_date_key():
|
|
assert make_episode(air_date=date(2024, 6, 30)).matches_wanted({"2024-06-30"})
|
|
|
|
|
|
def test_a_dated_episode_still_matches_its_season_episode_key():
|
|
assert make_episode(air_date=date(2024, 6, 30)).matches_wanted({"2024x181"})
|
|
|
|
|
|
def test_a_date_key_does_not_match_another_day():
|
|
assert not make_episode(air_date=date(2024, 6, 30)).matches_wanted({"2024-07-01"})
|
|
|
|
|
|
def test_a_season_episode_exclusion_beats_the_date_key():
|
|
assert not make_episode(air_date=date(2024, 6, 30)).matches_wanted({"2024-06-30", "!2024x181"})
|
|
|
|
|
|
def test_an_undated_episode_is_unaffected_by_date_keys():
|
|
episode = make_episode()
|
|
assert not episode.matches_wanted({"2024-06-30"})
|
|
assert episode.matches_wanted({"2024x181"})
|
|
|
|
|
|
# --- the air-date guard -----------------------------------------------------
|
|
|
|
|
|
def test_a_pre_1970_air_date_is_rejected():
|
|
with pytest.raises(ValueError):
|
|
make_episode(air_date=date(1969, 12, 31))
|
|
|
|
|
|
def test_a_future_air_date_is_accepted():
|
|
future = date.today().replace(year=date.today().year + 1)
|
|
assert make_episode(air_date=future).air_date == future
|
|
|
|
|
|
def test_an_unparseable_air_date_string_is_kept_as_is():
|
|
assert make_episode(air_date="soon").air_date == "soon"
|