"""Unit tests for NFO generator.""" import pytest from lxml import etree from src.core.entities.nfo_models import ( ActorInfo, ImageInfo, RatingInfo, TVShowNFO, UniqueID, ) from src.core.utils.nfo_generator import generate_tvshow_nfo, validate_nfo_xml class TestGenerateTVShowNFO: """Test generate_tvshow_nfo function.""" def test_generate_minimal_nfo(self): """Test generation with minimal required fields.""" nfo = TVShowNFO( title="Test Show", plot="A test show" ) xml_string = generate_tvshow_nfo(nfo) assert xml_string.startswith('') assert "Test Show" in xml_string assert "A test show" in xml_string def test_generate_complete_nfo(self): """Test generation with all fields populated.""" nfo = TVShowNFO( title="Complete Show", originaltitle="Original Title", year=2020, plot="Complete test", runtime=45, premiered="2020-01-15", status="Continuing", genre=["Action", "Drama"], studio=["Studio 1"], country=["USA"], ratings=[RatingInfo( name="themoviedb", value=8.5, votes=1000, max_rating=10, default=True )], actors=[ActorInfo( name="Test Actor", role="Main Character" )], thumb=[ImageInfo(url="https://test.com/poster.jpg")], uniqueid=[UniqueID(type="tmdb", value="12345")] ) xml_string = generate_tvshow_nfo(nfo) # Verify all elements present assert "Complete Show" in xml_string assert "Original Title" in xml_string assert "2020" in xml_string assert "45" in xml_string assert "2020-01-15" in xml_string assert "Continuing" in xml_string assert "Action" in xml_string assert "Drama" in xml_string assert "Studio 1" in xml_string assert "USA" in xml_string assert "Test Actor" in xml_string assert "Main Character" in xml_string def test_generate_nfo_with_ratings(self): """Test NFO with multiple ratings.""" nfo = TVShowNFO( title="Rated Show", plot="Test", ratings=[ RatingInfo( name="themoviedb", value=8.5, votes=1000, max_rating=10, default=True ), RatingInfo( name="imdb", value=8.2, votes=5000, max_rating=10, default=False ) ] ) xml_string = generate_tvshow_nfo(nfo) assert '' in xml_string assert '' in xml_string assert '8.5' in xml_string assert '1000' in xml_string assert '' in xml_string def test_generate_nfo_with_actors(self): """Test NFO with multiple actors.""" nfo = TVShowNFO( title="Cast Show", plot="Test", actors=[ ActorInfo(name="Actor 1", role="Hero"), ActorInfo(name="Actor 2", role="Villain", thumb="https://test.com/actor2.jpg") ] ) xml_string = generate_tvshow_nfo(nfo) assert '' in xml_string assert 'Actor 1' in xml_string assert 'Hero' in xml_string assert 'Actor 2' in xml_string assert 'https://test.com/actor2.jpg' in xml_string def test_generate_nfo_with_images(self): """Test NFO with various image types.""" nfo = TVShowNFO( title="Image Show", plot="Test", thumb=[ ImageInfo(url="https://test.com/poster.jpg", aspect="poster"), ImageInfo(url="https://test.com/logo.png", aspect="clearlogo") ], fanart=[ ImageInfo(url="https://test.com/fanart.jpg") ] ) xml_string = generate_tvshow_nfo(nfo) assert 'https://test.com/poster.jpg' in xml_string assert 'https://test.com/logo.png' in xml_string assert '' in xml_string assert 'https://test.com/fanart.jpg' in xml_string def test_generate_nfo_with_unique_ids(self): """Test NFO with multiple unique IDs.""" nfo = TVShowNFO( title="ID Show", plot="Test", uniqueid=[ UniqueID(type="tmdb", value="12345", default=False), UniqueID(type="tvdb", value="67890", default=True), UniqueID(type="imdb", value="tt1234567", default=False) ] ) xml_string = generate_tvshow_nfo(nfo) assert '12345' in xml_string assert '67890' in xml_string assert 'tt1234567' in xml_string def test_generate_nfo_escapes_special_chars(self): """Test that special XML characters are escaped.""" nfo = TVShowNFO( title="Show & special \"chars\"", plot="Plot with & ampersand" ) xml_string = generate_tvshow_nfo(nfo) # XML should escape special characters assert "<" in xml_string or "" in xml_string assert "&" in xml_string or "&" in xml_string def test_generate_nfo_valid_xml(self): """Test that generated XML is valid.""" nfo = TVShowNFO( title="Valid Show", plot="Test", year=2020, genre=["Action"], ratings=[RatingInfo(name="test", value=8.0)] ) xml_string = generate_tvshow_nfo(nfo) # Should be parseable as XML root = etree.fromstring(xml_string.encode('utf-8')) assert root.tag == "tvshow" def test_generate_nfo_none_values_omitted(self): """Test that None values are omitted from XML.""" nfo = TVShowNFO( title="Sparse Show", plot="Test", year=None, runtime=None, premiered=None ) xml_string = generate_tvshow_nfo(nfo) # None values should not appear in XML assert "<year>" not in xml_string assert "<runtime>" not in xml_string assert "<premiered>" not in xml_string class TestValidateNFOXML: """Test validate_nfo_xml function.""" def test_validate_valid_xml(self): """Test validation of valid XML.""" nfo = TVShowNFO(title="Test", plot="Test") xml_string = generate_tvshow_nfo(nfo) # Should not raise exception validate_nfo_xml(xml_string) def test_validate_invalid_xml(self): """Test validation of invalid XML.""" invalid_xml = "<?xml version='1.0'?><tvshow><title>Unclosed" with pytest.raises(ValueError, match="Invalid XML"): validate_nfo_xml(invalid_xml) def test_validate_missing_tvshow_root(self): """Test validation rejects non-tvshow root.""" invalid_xml = '<?xml version="1.0"?><movie><title>Test' with pytest.raises(ValueError, match="root element must be"): validate_nfo_xml(invalid_xml) def test_validate_empty_string(self): """Test validation rejects empty string.""" with pytest.raises(ValueError): validate_nfo_xml("") def test_validate_well_formed_structure(self): """Test validation accepts well-formed structure.""" xml = """ Test Show Test plot 2020 """ validate_nfo_xml(xml) class TestNFOGeneratorEdgeCases: """Test edge cases in NFO generation.""" def test_empty_lists(self): """Test generation with empty lists.""" nfo = TVShowNFO( title="Empty Lists", plot="Test", genre=[], studio=[], actors=[] ) xml_string = generate_tvshow_nfo(nfo) # Should generate valid XML even with empty lists root = etree.fromstring(xml_string.encode('utf-8')) assert root.tag == "tvshow" def test_unicode_characters(self): """Test handling of Unicode characters.""" nfo = TVShowNFO( title="アニメ Show 中文", plot="Plot with émojis 🎬 and spëcial çhars" ) xml_string = generate_tvshow_nfo(nfo) # Should encode Unicode properly assert "アニメ" in xml_string assert "中文" in xml_string assert "émojis" in xml_string def test_very_long_plot(self): """Test handling of very long plot text.""" long_plot = "A" * 10000 nfo = TVShowNFO( title="Long Plot", plot=long_plot ) xml_string = generate_tvshow_nfo(nfo) assert long_plot in xml_string def test_multiple_studios(self): """Test handling multiple studios.""" nfo = TVShowNFO( title="Multi Studio", plot="Test", studio=["Studio A", "Studio B", "Studio C"] ) xml_string = generate_tvshow_nfo(nfo) assert xml_string.count("") == 3 assert "Studio A" in xml_string assert "Studio B" in xml_string assert "Studio C" in xml_string def test_special_date_formats(self): """Test various date format inputs.""" nfo = TVShowNFO( title="Date Test", plot="Test", premiered="2020-01-01" ) xml_string = generate_tvshow_nfo(nfo) assert "2020-01-01" in xml_string