Task 3 (NFO data): - Add parse_nfo_ids() method to NFOService - Extract TMDB/TVDB IDs from NFO files during scan - Update database with extracted IDs - Add comprehensive unit and integration tests Task 4 (Media scan): - Track initial media scan with SystemSettings flag - Run background loading only on first startup - Skip media scan on subsequent runs
199 lines
6.4 KiB
Python
199 lines
6.4 KiB
Python
"""Unit tests for NFO ID parsing functionality."""
|
|
|
|
import tempfile
|
|
from pathlib import Path
|
|
|
|
import pytest
|
|
|
|
from src.core.services.nfo_service import NFOService
|
|
|
|
|
|
class TestNFOIDParsing:
|
|
"""Test NFO ID parsing from XML files."""
|
|
|
|
@pytest.fixture
|
|
def nfo_service(self):
|
|
"""Create NFO service for testing."""
|
|
with tempfile.TemporaryDirectory() as tmpdir:
|
|
service = NFOService(
|
|
tmdb_api_key="test_key",
|
|
anime_directory=tmpdir,
|
|
auto_create=False
|
|
)
|
|
yield service
|
|
|
|
@pytest.fixture
|
|
def temp_nfo_file(self):
|
|
"""Create a temporary NFO file for testing."""
|
|
with tempfile.NamedTemporaryFile(
|
|
mode='w',
|
|
suffix='.nfo',
|
|
delete=False,
|
|
encoding='utf-8'
|
|
) as f:
|
|
nfo_path = Path(f.name)
|
|
yield nfo_path
|
|
# Cleanup
|
|
if nfo_path.exists():
|
|
nfo_path.unlink()
|
|
|
|
def test_parse_nfo_ids_with_uniqueid_elements(
|
|
self, nfo_service, temp_nfo_file
|
|
):
|
|
"""Test parsing IDs from uniqueid elements."""
|
|
nfo_content = """<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
|
|
<tvshow>
|
|
<title>Attack on Titan</title>
|
|
<uniqueid type="tmdb" default="true">1429</uniqueid>
|
|
<uniqueid type="tvdb">295739</uniqueid>
|
|
<uniqueid type="imdb">tt2560140</uniqueid>
|
|
</tvshow>"""
|
|
temp_nfo_file.write_text(nfo_content, encoding='utf-8')
|
|
|
|
result = nfo_service.parse_nfo_ids(temp_nfo_file)
|
|
|
|
assert result["tmdb_id"] == 1429
|
|
assert result["tvdb_id"] == 295739
|
|
|
|
def test_parse_nfo_ids_with_dedicated_elements(
|
|
self, nfo_service, temp_nfo_file
|
|
):
|
|
"""Test parsing IDs from dedicated tmdbid/tvdbid elements."""
|
|
nfo_content = """<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
|
|
<tvshow>
|
|
<title>One Piece</title>
|
|
<tmdbid>37854</tmdbid>
|
|
<tvdbid>81797</tvdbid>
|
|
</tvshow>"""
|
|
temp_nfo_file.write_text(nfo_content, encoding='utf-8')
|
|
|
|
result = nfo_service.parse_nfo_ids(temp_nfo_file)
|
|
|
|
assert result["tmdb_id"] == 37854
|
|
assert result["tvdb_id"] == 81797
|
|
|
|
def test_parse_nfo_ids_mixed_formats(
|
|
self, nfo_service, temp_nfo_file
|
|
):
|
|
"""Test parsing with both uniqueid and dedicated elements.
|
|
|
|
uniqueid elements should take precedence.
|
|
"""
|
|
nfo_content = """<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
|
|
<tvshow>
|
|
<title>Naruto</title>
|
|
<uniqueid type="tmdb" default="true">31910</uniqueid>
|
|
<tmdbid>99999</tmdbid>
|
|
<tvdbid>78857</tvdbid>
|
|
</tvshow>"""
|
|
temp_nfo_file.write_text(nfo_content, encoding='utf-8')
|
|
|
|
result = nfo_service.parse_nfo_ids(temp_nfo_file)
|
|
|
|
# uniqueid should take precedence over tmdbid element
|
|
assert result["tmdb_id"] == 31910
|
|
assert result["tvdb_id"] == 78857
|
|
|
|
def test_parse_nfo_ids_only_tmdb(
|
|
self, nfo_service, temp_nfo_file
|
|
):
|
|
"""Test parsing when only TMDB ID is present."""
|
|
nfo_content = """<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
|
|
<tvshow>
|
|
<title>Dragon Ball Z</title>
|
|
<uniqueid type="tmdb" default="true">1553</uniqueid>
|
|
</tvshow>"""
|
|
temp_nfo_file.write_text(nfo_content, encoding='utf-8')
|
|
|
|
result = nfo_service.parse_nfo_ids(temp_nfo_file)
|
|
|
|
assert result["tmdb_id"] == 1553
|
|
assert result["tvdb_id"] is None
|
|
|
|
def test_parse_nfo_ids_only_tvdb(
|
|
self, nfo_service, temp_nfo_file
|
|
):
|
|
"""Test parsing when only TVDB ID is present."""
|
|
nfo_content = """<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
|
|
<tvshow>
|
|
<title>Bleach</title>
|
|
<uniqueid type="tvdb" default="true">74796</uniqueid>
|
|
</tvshow>"""
|
|
temp_nfo_file.write_text(nfo_content, encoding='utf-8')
|
|
|
|
result = nfo_service.parse_nfo_ids(temp_nfo_file)
|
|
|
|
assert result["tmdb_id"] is None
|
|
assert result["tvdb_id"] == 74796
|
|
|
|
def test_parse_nfo_ids_no_ids(
|
|
self, nfo_service, temp_nfo_file
|
|
):
|
|
"""Test parsing when no IDs are present."""
|
|
nfo_content = """<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
|
|
<tvshow>
|
|
<title>Unknown Series</title>
|
|
<plot>A series without any IDs.</plot>
|
|
</tvshow>"""
|
|
temp_nfo_file.write_text(nfo_content, encoding='utf-8')
|
|
|
|
result = nfo_service.parse_nfo_ids(temp_nfo_file)
|
|
|
|
assert result["tmdb_id"] is None
|
|
assert result["tvdb_id"] is None
|
|
|
|
def test_parse_nfo_ids_invalid_id_format(
|
|
self, nfo_service, temp_nfo_file
|
|
):
|
|
"""Test parsing with invalid ID formats (non-numeric)."""
|
|
nfo_content = """<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
|
|
<tvshow>
|
|
<title>Invalid IDs</title>
|
|
<uniqueid type="tmdb" default="true">not_a_number</uniqueid>
|
|
<uniqueid type="tvdb">also_invalid</uniqueid>
|
|
</tvshow>"""
|
|
temp_nfo_file.write_text(nfo_content, encoding='utf-8')
|
|
|
|
result = nfo_service.parse_nfo_ids(temp_nfo_file)
|
|
|
|
# Should return None for invalid formats instead of crashing
|
|
assert result["tmdb_id"] is None
|
|
assert result["tvdb_id"] is None
|
|
|
|
def test_parse_nfo_ids_file_not_found(self, nfo_service):
|
|
"""Test parsing when NFO file doesn't exist."""
|
|
non_existent = Path("/tmp/non_existent_nfo_file.nfo")
|
|
|
|
result = nfo_service.parse_nfo_ids(non_existent)
|
|
|
|
assert result["tmdb_id"] is None
|
|
assert result["tvdb_id"] is None
|
|
|
|
def test_parse_nfo_ids_invalid_xml(
|
|
self, nfo_service, temp_nfo_file
|
|
):
|
|
"""Test parsing with invalid XML."""
|
|
nfo_content = """<?xml version="1.0" encoding="UTF-8"?>
|
|
<tvshow>
|
|
<title>Broken XML
|
|
<!-- Missing closing tags -->
|
|
"""
|
|
temp_nfo_file.write_text(nfo_content, encoding='utf-8')
|
|
|
|
result = nfo_service.parse_nfo_ids(temp_nfo_file)
|
|
|
|
# Should handle error gracefully and return None values
|
|
assert result["tmdb_id"] is None
|
|
assert result["tvdb_id"] is None
|
|
|
|
def test_parse_nfo_ids_empty_file(
|
|
self, nfo_service, temp_nfo_file
|
|
):
|
|
"""Test parsing an empty file."""
|
|
temp_nfo_file.write_text("", encoding='utf-8')
|
|
|
|
result = nfo_service.parse_nfo_ids(temp_nfo_file)
|
|
|
|
assert result["tmdb_id"] is None
|
|
assert result["tvdb_id"] is None
|