Files
Aniworld/tests/unit/test_nfo_repair_service.py

141 lines
4.4 KiB
Python

"""Unit tests for NfoRepairService — Task 1."""
import shutil
from pathlib import Path
from unittest.mock import AsyncMock, MagicMock
import pytest
from src.core.services.nfo_repair_service import (
REQUIRED_TAGS,
NfoRepairService,
find_missing_tags,
nfo_needs_repair,
parse_nfo_tags,
)
REPO_ROOT = Path(__file__).parents[2]
BAD_NFO = REPO_ROOT / "tvshow.nfo.bad"
GOOD_NFO = REPO_ROOT / "tvshow.nfo.good"
# Tags known to be absent/empty in tvshow.nfo.bad
EXPECTED_MISSING_FROM_BAD = {
"originaltitle", "year", "plot", "runtime", "premiered",
"status", "imdbid", "genre", "studio", "country", "actor/name", "watched",
}
# ---------------------------------------------------------------------------
# Fixtures
# ---------------------------------------------------------------------------
@pytest.fixture()
def bad_nfo(tmp_path: Path) -> Path:
"""Copy tvshow.nfo.bad into a temp dir and return path to the copy."""
dest = tmp_path / "tvshow.nfo"
shutil.copy(BAD_NFO, dest)
return dest
@pytest.fixture()
def good_nfo(tmp_path: Path) -> Path:
"""Copy tvshow.nfo.good into a temp dir and return path to the copy."""
dest = tmp_path / "tvshow.nfo"
shutil.copy(GOOD_NFO, dest)
return dest
@pytest.fixture()
def mock_nfo_service() -> MagicMock:
"""Return a MagicMock NFOService with an async update_tvshow_nfo."""
svc = MagicMock()
svc.update_tvshow_nfo = AsyncMock(return_value=Path("/fake/tvshow.nfo"))
return svc
# ---------------------------------------------------------------------------
# find_missing_tags
# ---------------------------------------------------------------------------
def test_find_missing_tags_with_bad_nfo(bad_nfo: Path) -> None:
"""Bad NFO must report all 12 incomplete/missing tags."""
missing = find_missing_tags(bad_nfo)
assert set(missing) == EXPECTED_MISSING_FROM_BAD, (
f"Unexpected missing set: {set(missing)}"
)
def test_find_missing_tags_with_good_nfo(good_nfo: Path) -> None:
"""Good NFO must report no missing tags."""
missing = find_missing_tags(good_nfo)
assert missing == []
# ---------------------------------------------------------------------------
# nfo_needs_repair
# ---------------------------------------------------------------------------
def test_nfo_needs_repair_returns_true_for_bad_nfo(bad_nfo: Path) -> None:
assert nfo_needs_repair(bad_nfo) is True
def test_nfo_needs_repair_returns_false_for_good_nfo(good_nfo: Path) -> None:
assert nfo_needs_repair(good_nfo) is False
# ---------------------------------------------------------------------------
# NfoRepairService.repair_series
# ---------------------------------------------------------------------------
@pytest.mark.asyncio
async def test_repair_series_calls_update_when_nfo_needs_repair(
tmp_path: Path, mock_nfo_service: MagicMock
) -> None:
"""repair_series must call update_tvshow_nfo exactly once for a bad NFO."""
shutil.copy(BAD_NFO, tmp_path / "tvshow.nfo")
service = NfoRepairService(mock_nfo_service)
result = await service.repair_series(tmp_path, "Test Series")
assert result is True
mock_nfo_service.update_tvshow_nfo.assert_called_once_with(
"Test Series", download_media=False
)
@pytest.mark.asyncio
async def test_repair_series_skips_when_nfo_is_complete(
tmp_path: Path, mock_nfo_service: MagicMock
) -> None:
"""repair_series must NOT call update_tvshow_nfo for a complete NFO."""
shutil.copy(GOOD_NFO, tmp_path / "tvshow.nfo")
service = NfoRepairService(mock_nfo_service)
result = await service.repair_series(tmp_path, "Test Series")
assert result is False
mock_nfo_service.update_tvshow_nfo.assert_not_called()
# ---------------------------------------------------------------------------
# parse_nfo_tags edge cases
# ---------------------------------------------------------------------------
def test_parse_nfo_tags_handles_missing_file_gracefully() -> None:
"""parse_nfo_tags must return empty dict for non-existent path."""
result = parse_nfo_tags(Path("/nonexistent/dir/tvshow.nfo"))
assert result == {}
def test_parse_nfo_tags_handles_malformed_xml_gracefully(tmp_path: Path) -> None:
"""parse_nfo_tags must return empty dict for malformed XML."""
bad_xml = tmp_path / "tvshow.nfo"
bad_xml.write_text("<<< not valid xml >>>", encoding="utf-8")
result = parse_nfo_tags(bad_xml)
assert result == {}