Files
Aniworld/tests/unit/test_nfo_factory.py
Lukas 5b3fbf36b9 Task 4: Add Services & Utilities tests (66 tests)
- test_media_utils.py: 29 tests for check_media_files, get_media_file_paths,
  has_all_images, count_video_files, has_video_files, constants
- test_nfo_factory.py: 11 tests for NFOServiceFactory.create, create_optional,
  get_nfo_factory singleton, create_nfo_service convenience
- test_series_manager_service.py: 15 tests for init, from_settings,
  process_nfo_for_series, scan_and_process_nfo, close
- test_templates_utils.py: 4 tests for TEMPLATES_DIR path resolution
- test_error_controller.py: 7 tests for 404/500 handlers (API vs HTML)
2026-02-15 17:49:11 +01:00

190 lines
7.0 KiB
Python

"""Unit tests for NFO service factory module.
Tests factory instantiation, configuration precedence, singleton pattern,
and convenience functions for creating NFOService instances.
"""
from unittest.mock import MagicMock, patch
import pytest
from src.core.services.nfo_factory import (
NFOServiceFactory,
create_nfo_service,
get_nfo_factory,
)
class TestNFOServiceFactoryCreate:
"""Tests for NFOServiceFactory.create method."""
@patch("src.core.services.nfo_factory.NFOService")
@patch("src.core.services.nfo_factory.settings")
def test_create_with_explicit_api_key(self, mock_settings, mock_nfo_cls):
"""Explicit API key takes priority over settings."""
mock_settings.tmdb_api_key = "settings_key"
mock_settings.anime_directory = "/anime"
mock_settings.nfo_image_size = "original"
mock_settings.nfo_auto_create = False
factory = NFOServiceFactory()
factory.create(tmdb_api_key="explicit_key")
mock_nfo_cls.assert_called_once_with(
tmdb_api_key="explicit_key",
anime_directory="/anime",
image_size="original",
auto_create=False,
)
@patch("src.core.services.nfo_factory.NFOService")
@patch("src.core.services.nfo_factory.settings")
def test_create_falls_back_to_settings(self, mock_settings, mock_nfo_cls):
"""Falls back to settings when no explicit key provided."""
mock_settings.tmdb_api_key = "settings_key"
mock_settings.anime_directory = "/anime"
mock_settings.nfo_image_size = "w500"
mock_settings.nfo_auto_create = True
factory = NFOServiceFactory()
factory.create()
mock_nfo_cls.assert_called_once_with(
tmdb_api_key="settings_key",
anime_directory="/anime",
image_size="w500",
auto_create=True,
)
@patch("src.core.services.nfo_factory.settings")
def test_create_raises_without_api_key(self, mock_settings):
"""Raises ValueError when no API key available from any source."""
mock_settings.tmdb_api_key = None
factory = NFOServiceFactory()
factory._get_api_key_from_config = MagicMock(return_value=None)
with pytest.raises(ValueError, match="TMDB API key not configured"):
factory.create()
@patch("src.core.services.nfo_factory.NFOService")
@patch("src.core.services.nfo_factory.settings")
def test_create_with_all_custom_params(self, mock_settings, mock_nfo_cls):
"""All parameters can be overridden."""
mock_settings.tmdb_api_key = "default"
mock_settings.anime_directory = "/default"
mock_settings.nfo_image_size = "original"
mock_settings.nfo_auto_create = False
factory = NFOServiceFactory()
factory.create(
tmdb_api_key="custom",
anime_directory="/custom",
image_size="w300",
auto_create=True,
)
mock_nfo_cls.assert_called_once_with(
tmdb_api_key="custom",
anime_directory="/custom",
image_size="w300",
auto_create=True,
)
@patch("src.core.services.nfo_factory.NFOService")
@patch("src.core.services.nfo_factory.settings")
def test_create_uses_config_json_fallback(self, mock_settings, mock_nfo_cls):
"""Falls back to config.json when settings has no key."""
mock_settings.tmdb_api_key = None
mock_settings.anime_directory = "/anime"
mock_settings.nfo_image_size = "original"
mock_settings.nfo_auto_create = False
factory = NFOServiceFactory()
factory._get_api_key_from_config = MagicMock(return_value="config_key")
factory.create()
mock_nfo_cls.assert_called_once()
call_kwargs = mock_nfo_cls.call_args[1]
assert call_kwargs["tmdb_api_key"] == "config_key"
class TestNFOServiceFactoryCreateOptional:
"""Tests for NFOServiceFactory.create_optional method."""
@patch("src.core.services.nfo_factory.settings")
def test_returns_none_without_api_key(self, mock_settings):
"""Returns None instead of raising when no API key."""
mock_settings.tmdb_api_key = None
factory = NFOServiceFactory()
factory._get_api_key_from_config = MagicMock(return_value=None)
result = factory.create_optional()
assert result is None
@patch("src.core.services.nfo_factory.NFOService")
@patch("src.core.services.nfo_factory.settings")
def test_returns_service_when_configured(self, mock_settings, mock_nfo_cls):
"""Returns NFOService when configuration is available."""
mock_settings.tmdb_api_key = "key123"
mock_settings.anime_directory = "/anime"
mock_settings.nfo_image_size = "original"
mock_settings.nfo_auto_create = False
factory = NFOServiceFactory()
result = factory.create_optional()
assert result is not None
class TestGetNfoFactory:
"""Tests for get_nfo_factory singleton function."""
def test_returns_factory_instance(self):
"""Returns an NFOServiceFactory instance."""
import src.core.services.nfo_factory as mod
old = mod._factory_instance
try:
mod._factory_instance = None
factory = get_nfo_factory()
assert isinstance(factory, NFOServiceFactory)
finally:
mod._factory_instance = old
def test_returns_same_instance(self):
"""Repeated calls return the same singleton."""
import src.core.services.nfo_factory as mod
old = mod._factory_instance
try:
mod._factory_instance = None
f1 = get_nfo_factory()
f2 = get_nfo_factory()
assert f1 is f2
finally:
mod._factory_instance = old
class TestCreateNfoService:
"""Tests for create_nfo_service convenience function."""
@patch("src.core.services.nfo_factory.NFOService")
@patch("src.core.services.nfo_factory.settings")
def test_convenience_function_creates_service(
self, mock_settings, mock_nfo_cls
):
"""Convenience function delegates to factory.create()."""
mock_settings.tmdb_api_key = "key"
mock_settings.anime_directory = "/anime"
mock_settings.nfo_image_size = "original"
mock_settings.nfo_auto_create = False
result = create_nfo_service()
mock_nfo_cls.assert_called_once()
@patch("src.core.services.nfo_factory.settings")
def test_convenience_function_raises_without_key(self, mock_settings):
"""Convenience function raises ValueError without key."""
mock_settings.tmdb_api_key = None
import src.core.services.nfo_factory as mod
old = mod._factory_instance
try:
mod._factory_instance = None
factory = get_nfo_factory()
factory._get_api_key_from_config = MagicMock(return_value=None)
with pytest.raises(ValueError):
factory.create()
finally:
mod._factory_instance = old