feat: Standardize SerieList to use key as primary identifier (Task 1.2)

- Renamed folderDict to keyDict for clarity
- Updated internal storage to use serie.key instead of serie.folder
- Optimized contains() from O(n) to O(1) with direct key lookup
- Added get_by_key() as primary lookup method
- Added get_by_folder() for backward compatibility
- Enhanced docstrings to clarify key vs folder usage
- Created comprehensive test suite (12 tests, all passing)
- Verified no breaking changes (16 SeriesApp tests pass)

This establishes key as the single source of truth for series
identification while maintaining folder as metadata for filesystem
operations only.
This commit is contained in:
2025-11-23 12:25:08 +01:00
parent 048434d49c
commit 8b5b06ca9a
3 changed files with 310 additions and 24 deletions

View File

@@ -0,0 +1,203 @@
"""Tests for SerieList class - identifier standardization."""
import os
import tempfile
import pytest
from src.core.entities.SerieList import SerieList
from src.core.entities.series import Serie
@pytest.fixture
def temp_directory():
"""Create a temporary directory for testing."""
with tempfile.TemporaryDirectory() as tmpdir:
yield tmpdir
@pytest.fixture
def sample_serie():
"""Create a sample Serie for testing."""
return Serie(
key="attack-on-titan",
name="Attack on Titan",
site="https://aniworld.to/anime/stream/attack-on-titan",
folder="Attack on Titan (2013)",
episodeDict={1: [1, 2, 3]}
)
class TestSerieListKeyBasedStorage:
"""Test SerieList uses key for internal storage."""
def test_init_creates_empty_keydict(self, temp_directory):
"""Test initialization creates keyDict."""
serie_list = SerieList(temp_directory)
assert hasattr(serie_list, 'keyDict')
assert isinstance(serie_list.keyDict, dict)
def test_add_stores_by_key(self, temp_directory, sample_serie):
"""Test add() stores series by key."""
serie_list = SerieList(temp_directory)
serie_list.add(sample_serie)
# Verify stored by key, not folder
assert sample_serie.key in serie_list.keyDict
assert serie_list.keyDict[sample_serie.key] == sample_serie
def test_contains_checks_by_key(self, temp_directory, sample_serie):
"""Test contains() checks by key."""
serie_list = SerieList(temp_directory)
serie_list.add(sample_serie)
assert serie_list.contains(sample_serie.key)
assert not serie_list.contains("nonexistent-key")
def test_add_prevents_duplicates_by_key(
self, temp_directory, sample_serie
):
"""Test add() prevents duplicates based on key."""
serie_list = SerieList(temp_directory)
# Add same serie twice
serie_list.add(sample_serie)
initial_count = len(serie_list.keyDict)
serie_list.add(sample_serie)
# Should still have only one entry
assert len(serie_list.keyDict) == initial_count
assert len(serie_list.keyDict) == 1
def test_get_by_key_returns_correct_serie(
self, temp_directory, sample_serie
):
"""Test get_by_key() retrieves series correctly."""
serie_list = SerieList(temp_directory)
serie_list.add(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, temp_directory):
"""Test get_by_key() returns None for nonexistent key."""
serie_list = SerieList(temp_directory)
result = serie_list.get_by_key("nonexistent-key")
assert result is None
def test_get_by_folder_backward_compatibility(
self, temp_directory, sample_serie
):
"""Test get_by_folder() provides backward compatibility."""
serie_list = SerieList(temp_directory)
serie_list.add(sample_serie)
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, temp_directory):
"""Test get_by_folder() returns None for nonexistent folder."""
serie_list = SerieList(temp_directory)
result = serie_list.get_by_folder("Nonexistent Folder")
assert result is None
def test_get_all_returns_all_series(self, temp_directory, sample_serie):
"""Test get_all() returns all series from keyDict."""
serie_list = SerieList(temp_directory)
serie_list.add(sample_serie)
serie2 = Serie(
key="naruto",
name="Naruto",
site="https://aniworld.to/anime/stream/naruto",
folder="Naruto (2002)",
episodeDict={1: [1, 2]}
)
serie_list.add(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, temp_directory
):
"""Test get_missing_episodes() returns only series with episodes."""
serie_list = SerieList(temp_directory)
# Serie with missing episodes
serie_with_episodes = Serie(
key="serie-with-episodes",
name="Serie With Episodes",
site="https://aniworld.to/anime/stream/serie-with-episodes",
folder="Serie With Episodes (2020)",
episodeDict={1: [1, 2, 3]}
)
# Serie without missing episodes
serie_without_episodes = Serie(
key="serie-without-episodes",
name="Serie Without Episodes",
site="https://aniworld.to/anime/stream/serie-without-episodes",
folder="Serie Without Episodes (2021)",
episodeDict={}
)
serie_list.add(serie_with_episodes)
serie_list.add(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
def test_load_series_stores_by_key(self, temp_directory, sample_serie):
"""Test load_series() stores series by key when loading from disk."""
# Create directory structure and save serie
folder_path = os.path.join(temp_directory, sample_serie.folder)
os.makedirs(folder_path, exist_ok=True)
data_path = os.path.join(folder_path, "data")
sample_serie.save_to_file(data_path)
# Create new SerieList (triggers load_series in __init__)
serie_list = SerieList(temp_directory)
# Verify loaded by key
assert sample_serie.key in serie_list.keyDict
loaded_serie = serie_list.keyDict[sample_serie.key]
assert loaded_serie.key == sample_serie.key
assert loaded_serie.name == sample_serie.name
class TestSerieListPublicAPI:
"""Test that public API still works correctly."""
def test_public_methods_work(self, temp_directory, sample_serie):
"""Test that all public methods work correctly after refactoring."""
serie_list = SerieList(temp_directory)
# Test add
serie_list.add(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 new helper methods
assert serie_list.get_by_key(sample_serie.key) is not None
assert serie_list.get_by_folder(sample_serie.folder) is not None