from __future__ import annotations import os from pathlib import Path import sys import tempfile import unittest from unittest.mock import patch from click.testing import CliRunner SRC_ROOT = Path(__file__).resolve().parents[2] / "src" if str(SRC_ROOT) not in sys.path: sys.path.insert(0, str(SRC_ROOT)) from ffx import cli # noqa: E402 class _FakePattern: def __init__(self, pattern_id: int): self._pattern_id = pattern_id def getId(self): return self._pattern_id class _FakeFileProperties: def __init__(self, context, source_path): self.source_path = source_path def getShowId(self): return 42 if self.source_path.endswith("mapped.mkv") else -1 def getSeason(self): if self.source_path.endswith("unknown.mkv"): return -1 return 1 def getEpisode(self): if self.source_path.endswith("unknown.mkv"): return -1 return 3 def getPattern(self): if self.source_path.endswith("mapped.mkv"): return _FakePattern(7) return None class _FakeShiftedSeasonController: def __init__(self, context): self.context = context def resolveShiftSeason(self, show_id, season, episode, patternId=None): if patternId is not None: return 2, 1, "pattern" return season, episode, "default" class InspectShiftCliTests(unittest.TestCase): def setUp(self): self.tempdir = tempfile.TemporaryDirectory() self.home_dir = Path(self.tempdir.name) / "home" self.home_dir.mkdir() self.database_path = Path(self.tempdir.name) / "test.db" self.source_dir = Path(self.tempdir.name) / "source" self.source_dir.mkdir() self.mapped_path = self.source_dir / "mapped.mkv" self.mapped_path.write_bytes(b"mapped") self.identity_path = self.source_dir / "identity.mkv" self.identity_path.write_bytes(b"identity") self.unknown_path = self.source_dir / "unknown.mkv" self.unknown_path.write_bytes(b"unknown") def tearDown(self): self.tempdir.cleanup() def test_inspect_shift_prints_resolved_mapping_for_each_file(self): runner = CliRunner() with ( patch("ffx.file_properties.FileProperties", _FakeFileProperties), patch( "ffx.shifted_season_controller.ShiftedSeasonController", _FakeShiftedSeasonController, ), ): result = runner.invoke( cli.ffx, [ "--database-file", str(self.database_path), "inspect", "--shift", str(self.mapped_path), str(self.identity_path), str(self.unknown_path), ], env={**os.environ, "HOME": str(self.home_dir)}, ) self.assertEqual(0, result.exit_code, result.output) self.assertIn( f"{self.mapped_path}: 1/3 -> 2/1 from pattern", result.output, ) self.assertIn( f"{self.identity_path}: none", result.output, ) self.assertIn( f"{self.unknown_path}: no season/episode recognized", result.output, ) def test_inspect_without_shift_requires_exactly_one_filename(self): runner = CliRunner() result = runner.invoke( cli.ffx, [ "--database-file", str(self.database_path), "inspect", str(self.mapped_path), str(self.unknown_path), ], env={**os.environ, "HOME": str(self.home_dir)}, ) self.assertNotEqual(0, result.exit_code) self.assertIn( "Inspect without --shift requires exactly one filename.", result.output, ) if __name__ == "__main__": unittest.main()