"""Tests for SerieList class - DB-only operations.""" from unittest.mock import MagicMock import pytest from src.server.database.SerieList import SerieList @pytest.fixture def sample_serie(): """Create a sample AnimeSeries mock for testing.""" anime = MagicMock() anime.key = "attack-on-titan" anime.name = "Attack on Titan" anime.site = "https://aniworld.to/anime/stream/attack-on-titan" anime.folder = "Attack on Titan (2013)" anime.year = 2013 anime.nfo_path = None anime.episodeDict = {1: [1, 2, 3]} return anime class TestSerieListKeyBasedStorage: """Test SerieList uses key for internal storage.""" def test_init_creates_empty_keydict(self, tmp_path): """Test initialization creates keyDict.""" serie_list = SerieList(str(tmp_path)) assert hasattr(serie_list, 'keyDict') assert isinstance(serie_list.keyDict, dict) assert len(serie_list.keyDict) == 0 def test_contains_checks_by_key(self, tmp_path, sample_serie): """Test contains() checks by key.""" serie_list = SerieList(str(tmp_path)) serie_list.keyDict[sample_serie.key] = sample_serie assert serie_list.contains(sample_serie.key) assert not serie_list.contains("nonexistent-key") def test_get_by_key_returns_correct_serie(self, tmp_path, sample_serie): """Test get_by_key() retrieves series correctly.""" serie_list = SerieList(str(tmp_path)) serie_list.keyDict[sample_serie.key] = sample_serie result = serie_list.get_by_key(sample_serie.key) assert result is not None assert result.key == sample_serie.key assert result.name == sample_serie.name def test_get_by_key_returns_none_for_missing(self, tmp_path): """Test get_by_key() returns None for nonexistent key.""" serie_list = SerieList(str(tmp_path)) result = serie_list.get_by_key("nonexistent-key") assert result is None def test_get_by_folder_backward_compatibility(self, tmp_path, sample_serie): """Test get_by_folder() provides backward compatibility.""" import warnings serie_list = SerieList(str(tmp_path)) serie_list.keyDict[sample_serie.key] = sample_serie with warnings.catch_warnings(): warnings.simplefilter("ignore", DeprecationWarning) result = serie_list.get_by_folder(sample_serie.folder) assert result is not None assert result.key == sample_serie.key assert result.folder == sample_serie.folder def test_get_by_folder_returns_none_for_missing(self, tmp_path): """Test get_by_folder() returns None for nonexistent folder.""" import warnings serie_list = SerieList(str(tmp_path)) with warnings.catch_warnings(): warnings.simplefilter("ignore", DeprecationWarning) result = serie_list.get_by_folder("Nonexistent Folder") assert result is None def test_get_all_returns_all_series(self, tmp_path, sample_serie): """Test get_all() returns all series from keyDict.""" serie_list = SerieList(str(tmp_path)) serie2 = MagicMock() serie2.key = "naruto" serie2.name = "Naruto" serie2.site = "https://aniworld.to/anime/stream/naruto" serie2.folder = "Naruto (2002)" serie2.episodeDict = {1: [1, 2]} serie_list.keyDict[sample_serie.key] = sample_serie serie_list.keyDict[serie2.key] = serie2 all_series = serie_list.get_all() assert len(all_series) == 2 assert sample_serie in all_series assert serie2 in all_series def test_get_missing_episodes_filters_by_episode_dict(self, tmp_path): """Test get_missing_episodes() returns only series with episodes.""" serie_list = SerieList(str(tmp_path)) serie_with_episodes = MagicMock() serie_with_episodes.key = "serie-with-episodes" serie_with_episodes.name = "Serie With Episodes" serie_with_episodes.episodeDict = {1: [1, 2, 3]} serie_without_episodes = MagicMock() serie_without_episodes.key = "serie-without-episodes" serie_without_episodes.name = "Serie Without Episodes" serie_without_episodes.episodeDict = {} serie_list.keyDict[serie_with_episodes.key] = serie_with_episodes serie_list.keyDict[serie_without_episodes.key] = serie_without_episodes missing = serie_list.get_missing_episodes() assert len(missing) == 1 assert serie_with_episodes in missing assert serie_without_episodes not in missing class TestSerieListPublicAPI: """Test that public API still works correctly.""" def test_public_methods_work(self, tmp_path, sample_serie): """Test that all public methods work correctly after refactoring.""" serie_list = SerieList(str(tmp_path)) # Add directly to keyDict (simulating DB load) serie_list.keyDict[sample_serie.key] = sample_serie # Test contains assert serie_list.contains(sample_serie.key) # Test GetList/get_all assert len(serie_list.GetList()) == 1 assert len(serie_list.get_all()) == 1 # Test GetMissingEpisode/get_missing_episodes assert len(serie_list.GetMissingEpisode()) == 1 assert len(serie_list.get_missing_episodes()) == 1 # Test get_by_key assert serie_list.get_by_key(sample_serie.key) is not None class TestSerieListDeprecationWarnings: """Test deprecation warnings are raised for deprecated methods.""" def test_get_by_folder_raises_deprecation_warning(self, tmp_path, sample_serie): """Test get_by_folder() raises deprecation warning.""" import warnings serie_list = SerieList(str(tmp_path)) serie_list.keyDict[sample_serie.key] = sample_serie with warnings.catch_warnings(record=True) as w: warnings.simplefilter("always") serie_list.get_by_folder(sample_serie.folder) # Check deprecation warning was raised assert len(w) == 1 assert issubclass(w[0].category, DeprecationWarning) assert "get_by_key()" in str(w[0].message) class TestInvalidateCache: """Test invalidate_cache method.""" def test_invalidate_cache_clears_keydict(self, tmp_path, sample_serie): """Verify invalidate_cache clears the in-memory cache.""" serie_list = SerieList(str(tmp_path)) serie_list.keyDict[sample_serie.key] = sample_serie assert len(serie_list.keyDict) == 1 serie_list.invalidate_cache() assert len(serie_list.keyDict) == 0