test(release): adapt suite to explicit ReleaseKnowledge injection
- test_release.py / test_release_fixtures.py: module-level _KB = YamlReleaseKnowledge() + thin _parse(name) helper threading it into parse_release. test_show_folder_name_strips_windows_chars renamed to test_show_folder_name_uses_already_safe_title to reflect the Option B contract (caller sanitizes via kb.sanitize_for_fs). - test_detect_media_type.py: same _KB pattern, all detect_media_type(parsed, path) calls now pass kb. - test_filesystem_extras.py: find_video_file(path) calls now pass kb. - test_enrich_from_probe.py: _bare() helper adds the new title_sanitized field. - test_resolve_destination.py: drop _sanitize import + TestSanitize class (helper deleted), add tmdb_title_safe arg to _resolve_series_folder calls. 987 passed, 8 skipped.
This commit is contained in:
@@ -20,16 +20,19 @@ import pytest
|
||||
|
||||
from alfred.application.filesystem.detect_media_type import detect_media_type
|
||||
from alfred.domain.release.services import parse_release
|
||||
from alfred.infrastructure.knowledge.release_kb import YamlReleaseKnowledge
|
||||
|
||||
_KB = YamlReleaseKnowledge()
|
||||
|
||||
|
||||
def _parsed(media_type: str = "movie"):
|
||||
"""Build a ParsedRelease with the requested media_type via the real parser."""
|
||||
if media_type == "tv_show":
|
||||
return parse_release("Show.S01E01.1080p-GRP")
|
||||
return parse_release("Show.S01E01.1080p-GRP", _KB)
|
||||
if media_type == "movie":
|
||||
return parse_release("Movie.2020.1080p-GRP")
|
||||
return parse_release("Movie.2020.1080p-GRP", _KB)
|
||||
# "unknown" / other — feed a name the parser can't classify
|
||||
return parse_release("randomthing")
|
||||
return parse_release("randomthing", _KB)
|
||||
|
||||
|
||||
# --------------------------------------------------------------------------- #
|
||||
@@ -41,30 +44,30 @@ class TestFile:
|
||||
def test_video_file_preserves_parsed_type(self, tmp_path: Path):
|
||||
f = tmp_path / "x.mkv"
|
||||
f.write_bytes(b"")
|
||||
assert detect_media_type(_parsed("movie"), f) == "movie"
|
||||
assert detect_media_type(_parsed("movie"), f, _KB) == "movie"
|
||||
|
||||
def test_video_file_preserves_tv_type(self, tmp_path: Path):
|
||||
f = tmp_path / "ep.mp4"
|
||||
f.write_bytes(b"")
|
||||
assert detect_media_type(_parsed("tv_show"), f) == "tv_show"
|
||||
assert detect_media_type(_parsed("tv_show"), f, _KB) == "tv_show"
|
||||
|
||||
def test_non_video_file_returns_other(self, tmp_path: Path):
|
||||
f = tmp_path / "x.iso"
|
||||
f.write_bytes(b"")
|
||||
assert detect_media_type(_parsed("movie"), f) == "other"
|
||||
assert detect_media_type(_parsed("movie"), f, _KB) == "other"
|
||||
|
||||
@pytest.mark.parametrize("ext", [".rar", ".zip", ".7z", ".exe", ".dmg"])
|
||||
def test_various_non_video_extensions(self, tmp_path: Path, ext):
|
||||
f = tmp_path / f"x{ext}"
|
||||
f.write_bytes(b"")
|
||||
assert detect_media_type(_parsed("movie"), f) == "other"
|
||||
assert detect_media_type(_parsed("movie"), f, _KB) == "other"
|
||||
|
||||
def test_metadata_only_file_keeps_parsed_type(self, tmp_path: Path):
|
||||
# Metadata extension is stripped from conclusive set — no video, no
|
||||
# non-video → falls through to parsed.media_type.
|
||||
f = tmp_path / "x.nfo"
|
||||
f.write_bytes(b"")
|
||||
assert detect_media_type(_parsed("movie"), f) == "movie"
|
||||
assert detect_media_type(_parsed("movie"), f, _KB) == "movie"
|
||||
|
||||
|
||||
# --------------------------------------------------------------------------- #
|
||||
@@ -75,27 +78,27 @@ class TestFile:
|
||||
class TestFolder:
|
||||
def test_folder_with_video_keeps_parsed_type(self, tmp_path: Path):
|
||||
(tmp_path / "main.mkv").write_bytes(b"")
|
||||
assert detect_media_type(_parsed("movie"), tmp_path) == "movie"
|
||||
assert detect_media_type(_parsed("movie"), tmp_path, _KB) == "movie"
|
||||
|
||||
def test_folder_only_non_video_returns_other(self, tmp_path: Path):
|
||||
(tmp_path / "disc.iso").write_bytes(b"")
|
||||
(tmp_path / "part.rar").write_bytes(b"")
|
||||
assert detect_media_type(_parsed("movie"), tmp_path) == "other"
|
||||
assert detect_media_type(_parsed("movie"), tmp_path, _KB) == "other"
|
||||
|
||||
def test_folder_mixed_returns_unknown(self, tmp_path: Path):
|
||||
(tmp_path / "main.mkv").write_bytes(b"")
|
||||
(tmp_path / "extras.iso").write_bytes(b"")
|
||||
assert detect_media_type(_parsed("movie"), tmp_path) == "unknown"
|
||||
assert detect_media_type(_parsed("movie"), tmp_path, _KB) == "unknown"
|
||||
|
||||
def test_empty_folder_keeps_parsed_type(self, tmp_path: Path):
|
||||
assert detect_media_type(_parsed("tv_show"), tmp_path) == "tv_show"
|
||||
assert detect_media_type(_parsed("tv_show"), tmp_path, _KB) == "tv_show"
|
||||
|
||||
def test_folder_only_metadata_keeps_parsed_type(self, tmp_path: Path):
|
||||
(tmp_path / "info.nfo").write_bytes(b"")
|
||||
(tmp_path / "cover.jpg").write_bytes(b"")
|
||||
(tmp_path / "subs.srt").write_bytes(b"")
|
||||
# All metadata → conclusive set empty → falls through.
|
||||
assert detect_media_type(_parsed("movie"), tmp_path) == "movie"
|
||||
assert detect_media_type(_parsed("movie"), tmp_path, _KB) == "movie"
|
||||
|
||||
|
||||
# --------------------------------------------------------------------------- #
|
||||
@@ -109,18 +112,18 @@ class TestMetadataIgnored:
|
||||
(tmp_path / "info.nfo").write_bytes(b"")
|
||||
(tmp_path / "cover.jpg").write_bytes(b"")
|
||||
(tmp_path / "subs.srt").write_bytes(b"")
|
||||
assert detect_media_type(_parsed("movie"), tmp_path) == "movie"
|
||||
assert detect_media_type(_parsed("movie"), tmp_path, _KB) == "movie"
|
||||
|
||||
def test_non_video_plus_metadata_still_other(self, tmp_path: Path):
|
||||
(tmp_path / "disc.iso").write_bytes(b"")
|
||||
(tmp_path / "info.nfo").write_bytes(b"")
|
||||
assert detect_media_type(_parsed("movie"), tmp_path) == "other"
|
||||
assert detect_media_type(_parsed("movie"), tmp_path, _KB) == "other"
|
||||
|
||||
def test_case_insensitive_extensions(self, tmp_path: Path):
|
||||
# Suffix is lowercased before classification.
|
||||
f = tmp_path / "X.MKV"
|
||||
f.write_bytes(b"")
|
||||
assert detect_media_type(_parsed("movie"), f) == "movie"
|
||||
assert detect_media_type(_parsed("movie"), f, _KB) == "movie"
|
||||
|
||||
|
||||
# --------------------------------------------------------------------------- #
|
||||
@@ -132,11 +135,11 @@ class TestMissing:
|
||||
def test_nonexistent_path_keeps_parsed_type(self, tmp_path: Path):
|
||||
missing = tmp_path / "does_not_exist.mkv"
|
||||
# Doesn't exist → empty extension set → falls through.
|
||||
assert detect_media_type(_parsed("movie"), missing) == "movie"
|
||||
assert detect_media_type(_parsed("movie"), missing, _KB) == "movie"
|
||||
|
||||
def test_nonexistent_folder_keeps_parsed_type(self, tmp_path: Path):
|
||||
missing = tmp_path / "ghost"
|
||||
assert detect_media_type(_parsed("tv_show"), missing) == "tv_show"
|
||||
assert detect_media_type(_parsed("tv_show"), missing, _KB) == "tv_show"
|
||||
|
||||
def test_subfolder_not_recursed(self, tmp_path: Path):
|
||||
# _collect_extensions scans only the first level — files inside
|
||||
@@ -145,4 +148,4 @@ class TestMissing:
|
||||
sub.mkdir()
|
||||
(sub / "deep.mkv").write_bytes(b"")
|
||||
# Top level has no files at all → empty → falls through to parsed type.
|
||||
assert detect_media_type(_parsed("movie"), tmp_path) == "movie"
|
||||
assert detect_media_type(_parsed("movie"), tmp_path, _KB) == "movie"
|
||||
|
||||
@@ -37,6 +37,7 @@ def _bare(**overrides) -> ParsedRelease:
|
||||
raw="X",
|
||||
normalised="X",
|
||||
title="X",
|
||||
title_sanitized="X",
|
||||
year=None,
|
||||
season=None,
|
||||
episode=None,
|
||||
|
||||
@@ -9,7 +9,6 @@ Four use cases compute library paths from a release name + TMDB metadata:
|
||||
|
||||
Coverage:
|
||||
|
||||
- ``TestSanitize`` — Windows-forbidden chars stripped.
|
||||
- ``TestFindExistingTvshowFolders`` — empty root, prefix match (case + space → dot).
|
||||
- ``TestResolveSeriesFolderInternal`` — confirmed_folder, no existing, single match,
|
||||
ambiguous → _Clarification.
|
||||
@@ -32,7 +31,6 @@ from alfred.application.filesystem.resolve_destination import (
|
||||
_Clarification,
|
||||
_find_existing_tvshow_folders,
|
||||
_resolve_series_folder,
|
||||
_sanitize,
|
||||
resolve_episode_destination,
|
||||
resolve_movie_destination,
|
||||
resolve_season_destination,
|
||||
@@ -51,15 +49,6 @@ REL_SERIES = "Oz.Complete.Series.1080p.WEBRip.x265-KONTRAST"
|
||||
# --------------------------------------------------------------------------- #
|
||||
|
||||
|
||||
class TestSanitize:
|
||||
def test_passthrough_safe_chars(self):
|
||||
assert _sanitize("Oz.1997.1080p-GRP") == "Oz.1997.1080p-GRP"
|
||||
|
||||
def test_strips_windows_forbidden(self):
|
||||
# ? : * " < > | \
|
||||
assert _sanitize('a?b:c*d"e<f>g|h\\i') == "abcdefghi"
|
||||
|
||||
|
||||
# --------------------------------------------------------------------------- #
|
||||
# _find_existing_tvshow_folders #
|
||||
# --------------------------------------------------------------------------- #
|
||||
@@ -107,6 +96,7 @@ class TestResolveSeriesFolderInternal:
|
||||
out = _resolve_series_folder(
|
||||
tmp_path,
|
||||
"Oz",
|
||||
"Oz",
|
||||
1997,
|
||||
"Oz.1997.WEBRip-KONTRAST",
|
||||
confirmed_folder="Oz.1997.X-GRP",
|
||||
@@ -117,6 +107,7 @@ class TestResolveSeriesFolderInternal:
|
||||
out = _resolve_series_folder(
|
||||
tmp_path,
|
||||
"Oz",
|
||||
"Oz",
|
||||
1997,
|
||||
"Oz.1997.WEBRip-KONTRAST",
|
||||
confirmed_folder="Oz.1997.New-X",
|
||||
@@ -125,21 +116,21 @@ class TestResolveSeriesFolderInternal:
|
||||
|
||||
def test_no_existing_returns_computed_as_new(self, tmp_path):
|
||||
out = _resolve_series_folder(
|
||||
tmp_path, "Oz", 1997, "Oz.1997.WEBRip-KONTRAST", None
|
||||
tmp_path, "Oz", "Oz", 1997, "Oz.1997.WEBRip-KONTRAST", None
|
||||
)
|
||||
assert out == ("Oz.1997.WEBRip-KONTRAST", True)
|
||||
|
||||
def test_single_existing_matching_computed_returns_existing(self, tmp_path):
|
||||
(tmp_path / "Oz.1997.WEBRip-KONTRAST").mkdir()
|
||||
out = _resolve_series_folder(
|
||||
tmp_path, "Oz", 1997, "Oz.1997.WEBRip-KONTRAST", None
|
||||
tmp_path, "Oz", "Oz", 1997, "Oz.1997.WEBRip-KONTRAST", None
|
||||
)
|
||||
assert out == ("Oz.1997.WEBRip-KONTRAST", False)
|
||||
|
||||
def test_single_existing_different_name_returns_clarification(self, tmp_path):
|
||||
(tmp_path / "Oz.1997.BluRay-OTHER").mkdir()
|
||||
out = _resolve_series_folder(
|
||||
tmp_path, "Oz", 1997, "Oz.1997.WEBRip-KONTRAST", None
|
||||
tmp_path, "Oz", "Oz", 1997, "Oz.1997.WEBRip-KONTRAST", None
|
||||
)
|
||||
assert isinstance(out, _Clarification)
|
||||
assert "Oz" in out.question
|
||||
@@ -149,7 +140,7 @@ class TestResolveSeriesFolderInternal:
|
||||
def test_multiple_existing_returns_clarification(self, tmp_path):
|
||||
(tmp_path / "Oz.1997.A-GRP").mkdir()
|
||||
(tmp_path / "Oz.1997.B-GRP").mkdir()
|
||||
out = _resolve_series_folder(tmp_path, "Oz", 1997, "Oz.1997.A-GRP", None)
|
||||
out = _resolve_series_folder(tmp_path, "Oz", "Oz", 1997, "Oz.1997.A-GRP", None)
|
||||
assert isinstance(out, _Clarification)
|
||||
# Computed already in existing → not duplicated.
|
||||
assert out.options.count("Oz.1997.A-GRP") == 1
|
||||
|
||||
Reference in New Issue
Block a user