Task 4.7: Update template helpers to use key identifier

- Add series context helpers: prepare_series_context, get_series_by_key, filter_series_by_missing_episodes
- Update module docstring with identifier convention documentation
- Add unit tests for new series context helper functions
- Update infrastructure.md with template helpers documentation
- Mark Phase 4 (API Layer) as complete
This commit is contained in:
2025-11-28 16:00:15 +01:00
parent 014e22390e
commit 5934c7666c
4 changed files with 329 additions and 55 deletions

View File

@@ -1,15 +1,19 @@
"""
Tests for template helper utilities.
This module tests the template helper functions.
This module tests the template helper functions including series context
preparation using `key` as the primary identifier.
"""
from unittest.mock import Mock
import pytest
from src.server.utils.template_helpers import (
filter_series_by_missing_episodes,
get_base_context,
get_series_by_key,
list_available_templates,
prepare_series_context,
validate_template_exists,
)
@@ -84,3 +88,156 @@ class TestTemplateHelpers:
"""Test that all required templates exist."""
assert validate_template_exists(template_name), \
f"Required template {template_name} does not exist"
class TestSeriesContextHelpers:
"""Test series context helper functions.
These tests verify that series helpers use `key` as the primary
identifier following the project's identifier convention.
"""
def test_prepare_series_context_uses_key(self):
"""Test that prepare_series_context uses key as primary identifier."""
series_data = [
{
"key": "attack-on-titan",
"name": "Attack on Titan",
"folder": "Attack on Titan (2013)",
},
{
"key": "one-piece",
"name": "One Piece",
"folder": "One Piece (1999)",
},
]
prepared = prepare_series_context(series_data)
assert len(prepared) == 2
# Verify key is present and used
assert prepared[0]["key"] in ("attack-on-titan", "one-piece")
assert all("key" in item for item in prepared)
assert all("folder" in item for item in prepared)
def test_prepare_series_context_sorts_by_name(self):
"""Test that series are sorted by name by default."""
series_data = [
{"key": "z-series", "name": "Zebra Anime", "folder": "z"},
{"key": "a-series", "name": "Alpha Anime", "folder": "a"},
]
prepared = prepare_series_context(series_data, sort_by="name")
assert prepared[0]["name"] == "Alpha Anime"
assert prepared[1]["name"] == "Zebra Anime"
def test_prepare_series_context_sorts_by_key(self):
"""Test that series can be sorted by key."""
series_data = [
{"key": "z-series", "name": "Zebra", "folder": "z"},
{"key": "a-series", "name": "Alpha", "folder": "a"},
]
prepared = prepare_series_context(series_data, sort_by="key")
assert prepared[0]["key"] == "a-series"
assert prepared[1]["key"] == "z-series"
def test_prepare_series_context_empty_list(self):
"""Test prepare_series_context with empty list."""
prepared = prepare_series_context([])
assert prepared == []
def test_prepare_series_context_skips_missing_key(self):
"""Test that items without key are skipped with warning."""
series_data = [
{"key": "valid-series", "name": "Valid", "folder": "valid"},
{"name": "No Key", "folder": "nokey"}, # Missing key
]
prepared = prepare_series_context(series_data)
assert len(prepared) == 1
assert prepared[0]["key"] == "valid-series"
def test_prepare_series_context_preserves_extra_fields(self):
"""Test that extra fields are preserved."""
series_data = [
{
"key": "test",
"name": "Test",
"folder": "test",
"missing_episodes": {"1": [1, 2]},
"site": "aniworld.to",
}
]
prepared = prepare_series_context(series_data)
assert prepared[0]["missing_episodes"] == {"1": [1, 2]}
assert prepared[0]["site"] == "aniworld.to"
def test_get_series_by_key_found(self):
"""Test finding a series by key."""
series_data = [
{"key": "attack-on-titan", "name": "Attack on Titan"},
{"key": "one-piece", "name": "One Piece"},
]
result = get_series_by_key(series_data, "attack-on-titan")
assert result is not None
assert result["name"] == "Attack on Titan"
def test_get_series_by_key_not_found(self):
"""Test that None is returned when key not found."""
series_data = [
{"key": "attack-on-titan", "name": "Attack on Titan"},
]
result = get_series_by_key(series_data, "non-existent")
assert result is None
def test_get_series_by_key_empty_list(self):
"""Test get_series_by_key with empty list."""
result = get_series_by_key([], "any-key")
assert result is None
def test_filter_series_by_missing_episodes(self):
"""Test filtering series with missing episodes."""
series_data = [
{
"key": "has-missing",
"name": "Has Missing",
"missing_episodes": {"1": [1, 2, 3]},
},
{
"key": "no-missing",
"name": "No Missing",
"missing_episodes": {},
},
{
"key": "empty-seasons",
"name": "Empty Seasons",
"missing_episodes": {"1": [], "2": []},
},
]
filtered = filter_series_by_missing_episodes(series_data)
assert len(filtered) == 1
assert filtered[0]["key"] == "has-missing"
def test_filter_series_by_missing_episodes_empty(self):
"""Test filter with empty list."""
filtered = filter_series_by_missing_episodes([])
assert filtered == []
def test_filter_preserves_key_identifier(self):
"""Test that filter preserves key as identifier."""
series_data = [
{
"key": "test-series",
"folder": "Test Series (2020)",
"name": "Test",
"missing_episodes": {"1": [1]},
}
]
filtered = filter_series_by_missing_episodes(series_data)
assert filtered[0]["key"] == "test-series"
assert filtered[0]["folder"] == "Test Series (2020)"