"""Unit tests for minimal NFO creation when TMDB fails. Tests the fallback behavior when TMDB lookup fails and we need to create a minimal NFO file just to track the series. """ from pathlib import Path from unittest.mock import AsyncMock, patch import pytest from src.core.services.nfo_service import NFOService @pytest.fixture def nfo_service(tmp_path): """Create NFO service with test directory. Note: anime_directory is set to tmp_path directly (not tmp_path / "anime") because tmp_path already represents the test anime directory. """ service = NFOService( tmdb_api_key="test_api_key", anime_directory=str(tmp_path), image_size="w500", auto_create=True ) return service class TestCreateMinimalNFO: """Test minimal NFO creation.""" @pytest.mark.asyncio async def test_create_minimal_nfo_basic(self, nfo_service, tmp_path): """Test creating minimal NFO with just title.""" # Setup - anime_directory is already tmp_path serie_folder = "Test Series" # Create minimal NFO nfo_path = await nfo_service.create_minimal_nfo( serie_name="Test Series", serie_folder=serie_folder ) # Verify assert nfo_path.exists() assert nfo_path.name == "tvshow.nfo" content = nfo_path.read_text(encoding="utf-8") assert "Test Series" in content assert "No metadata available" in content @pytest.mark.asyncio async def test_create_minimal_nfo_with_year(self, nfo_service, tmp_path): """Test creating minimal NFO with year.""" # Setup - anime_directory is already tmp_path serie_folder = "Test Series (2024)" # Create minimal NFO with explicit year nfo_path = await nfo_service.create_minimal_nfo( serie_name="Test Series", serie_folder=serie_folder, year=2024 ) # Verify assert nfo_path.exists() content = nfo_path.read_text(encoding="utf-8") assert "Test Series" in content assert "2024" in content @pytest.mark.asyncio async def test_create_minimal_nfo_extracts_year_from_name(self, nfo_service, tmp_path): """Test that year is extracted from series name format (YYYY).""" # Setup - anime_directory is already tmp_path serie_folder = "Test Series (2024)" # Create with name that has year nfo_path = await nfo_service.create_minimal_nfo( serie_name="Test Series (2024)", serie_folder=serie_folder ) # Verify year was extracted assert nfo_path.exists() content = nfo_path.read_text(encoding="utf-8") assert "Test Series" in content assert "2024" in content @pytest.mark.asyncio async def test_create_minimal_nfo_creates_folder_if_missing(self, nfo_service, tmp_path): """Test that folder is created if it doesn't exist.""" # Setup - anime_directory is tmp_path itself serie_folder = "New Series" # Folder should not exist yet (under anime_directory which is tmp_path) folder_path = tmp_path / serie_folder assert not folder_path.exists() # Create minimal NFO nfo_path = await nfo_service.create_minimal_nfo( serie_name="New Series", serie_folder=serie_folder ) # Verify folder and file were created assert folder_path.exists() assert nfo_path.exists() @pytest.mark.asyncio async def test_create_minimal_nfo_xml_is_valid(self, nfo_service, tmp_path): """Test that generated XML is valid.""" # Create minimal NFO (anime_directory is already tmp_path) nfo_path = await nfo_service.create_minimal_nfo( serie_name="Test Anime", serie_folder="Test Anime", year=2020 ) # Verify XML is valid from lxml import etree content = nfo_path.read_text(encoding="utf-8") # Should parse without errors tree = etree.fromstring(content.encode("utf-8")) assert tree is not None assert tree.tag == "tvshow" # Check title element title = tree.find("title") assert title is not None assert title.text == "Test Anime" @pytest.mark.asyncio async def test_create_minimal_nfo_no_tmdb_id(self, nfo_service, tmp_path): """Test that minimal NFO has no TMDB ID.""" # Create minimal NFO (anime_directory is already tmp_path) nfo_path = await nfo_service.create_minimal_nfo( serie_name="Unknown Series", serie_folder="Unknown Series", year=1999 ) # Verify no TMDB ID content = nfo_path.read_text(encoding="utf-8") assert "" not in content assert "uniqueid" not in content @pytest.mark.asyncio async def test_create_minimal_nfo_has_plot_explanation(self, nfo_service, tmp_path): """Test that minimal NFO contains explanation in plot.""" # Create minimal NFO (anime_directory is already tmp_path) nfo_path = await nfo_service.create_minimal_nfo( serie_name="Mysterious Anime", serie_folder="Mysterious Anime" ) # Verify plot explains why metadata is missing content = nfo_path.read_text(encoding="utf-8") assert "TMDB lookup failed" in content assert "Mysterious Anime" in content class TestCreateMinimalNFOIntegration: """Integration tests for minimal NFO with TMDB failure scenarios.""" @pytest.mark.asyncio async def test_fallback_on_tmdb_search_failure(self, nfo_service, tmp_path): """Test that minimal NFO is created when TMDB search fails.""" # Mock TMDB client to raise error nfo_service.tmdb_client.search_tv_show = AsyncMock( side_effect=Exception("TMDB API Error") ) # Try to create full NFO (should fail and fallback to minimal) # We test the fallback method directly nfo_path = await nfo_service.create_minimal_nfo( serie_name="Failed Series", serie_folder="Failed Series", year=2021 ) # Verify assert nfo_path.exists() content = nfo_path.read_text(encoding="utf-8") assert "Failed Series" in content assert "2021" in content @pytest.mark.asyncio async def test_minimal_nfo_allows_series_tracking(self, nfo_service, tmp_path): """Test that minimal NFO allows series to be tracked.""" # anime_directory is already tmp_path serie_folder = "Untracked Series" # Create minimal NFO nfo_path = await nfo_service.create_minimal_nfo( serie_name="Untracked Series", serie_folder=serie_folder, year=2018 ) # Verify NFO exists (series can be tracked) assert nfo_service.has_nfo(serie_folder) is True # Verify minimal content content = nfo_path.read_text(encoding="utf-8") assert "Untracked Series" in content class TestMinimalNFOContent: """Test content of minimal NFO files.""" @pytest.mark.asyncio async def test_minimal_nfo_contains_required_elements(self, nfo_service, tmp_path): """Test that minimal NFO has title and plot.""" nfo_path = await nfo_service.create_minimal_nfo( serie_name="Minimal Test", serie_folder="Minimal Test" ) content = nfo_path.read_text(encoding="utf-8") # Must have title assert "Minimal Test" in content # Must have plot explaining situation assert "plot" in content.lower() assert "No metadata available" in content @pytest.mark.asyncio async def test_minimal_nfo_xml_declaration(self, nfo_service, tmp_path): """Test that NFO has proper XML declaration.""" nfo_path = await nfo_service.create_minimal_nfo( serie_name="XML Test", serie_folder="XML Test" ) content = nfo_path.read_text(encoding="utf-8") # Should have XML declaration assert content.startswith('