Aniworld/tests/unit/test_anime_models.py
2025-12-04 19:22:42 +01:00

153 lines
4.7 KiB
Python

"""Unit tests for anime Pydantic models.
This module tests all anime-related models including validation,
serialization, and field constraints.
"""
import pytest
from pydantic import ValidationError
from src.server.models.anime import (
AnimeSeriesResponse,
EpisodeInfo,
MissingEpisodeInfo,
SearchRequest,
SearchResult,
)
class TestEpisodeInfo:
"""Tests for EpisodeInfo model."""
def test_episode_info_basic(self):
"""Test creating a basic episode info."""
ep = EpisodeInfo(episode_number=1, title="Pilot", duration_seconds=1500)
assert ep.episode_number == 1
assert ep.title == "Pilot"
assert ep.duration_seconds == 1500
assert ep.available is True
def test_episode_info_without_optional_fields(self):
"""Test episode info with only required fields."""
ep = EpisodeInfo(episode_number=5)
assert ep.episode_number == 5
assert ep.title is None
assert ep.duration_seconds is None
assert ep.available is True
def test_invalid_episode_number(self):
"""Test that episode number must be positive."""
with pytest.raises(ValidationError):
EpisodeInfo(episode_number=0)
class TestMissingEpisodeInfo:
"""Tests for MissingEpisodeInfo model."""
def test_missing_episode_count(self):
"""Test count property calculation."""
m = MissingEpisodeInfo(from_episode=5, to_episode=7)
assert m.count == 3
def test_single_missing_episode(self):
"""Test count for single missing episode."""
m = MissingEpisodeInfo(from_episode=5, to_episode=5)
assert m.count == 1
class TestAnimeSeriesResponse:
"""Tests for AnimeSeriesResponse model."""
def test_anime_series_response_with_key(self):
"""Test creating series response with key as identifier."""
ep = EpisodeInfo(episode_number=1, title="Ep1")
series = AnimeSeriesResponse(
key="attack-on-titan",
title="Attack on Titan",
folder="Attack on Titan (2013)",
episodes=[ep],
)
assert series.key == "attack-on-titan"
assert series.title == "Attack on Titan"
assert series.folder == "Attack on Titan (2013)"
assert series.episodes[0].title == "Ep1"
def test_key_normalization(self):
"""Test that key is normalized to lowercase."""
series = AnimeSeriesResponse(
key="ATTACK-ON-TITAN",
title="Attack on Titan"
)
assert series.key == "attack-on-titan"
def test_key_whitespace_stripped(self):
"""Test that key whitespace is stripped."""
series = AnimeSeriesResponse(
key=" attack-on-titan ",
title="Attack on Titan"
)
assert series.key == "attack-on-titan"
def test_folder_is_optional(self):
"""Test that folder is optional metadata."""
series = AnimeSeriesResponse(
key="my-anime",
title="My Anime"
)
assert series.folder is None
class TestSearchRequest:
"""Tests for SearchRequest model."""
def test_search_request_validation(self):
"""Test valid search request."""
req = SearchRequest(query="naruto", limit=5)
assert req.query == "naruto"
assert req.limit == 5
def test_search_request_empty_query_rejected(self):
"""Test that empty query is rejected."""
with pytest.raises(ValidationError):
SearchRequest(query="", limit=5)
def test_search_request_defaults(self):
"""Test default values."""
req = SearchRequest(query="test")
assert req.limit == 10
assert req.include_adult is False
class TestSearchResult:
"""Tests for SearchResult model."""
def test_search_result_with_key(self):
"""Test search result with key as identifier."""
res = SearchResult(
key="naruto",
title="Naruto",
folder="Naruto (2002)",
snippet="A ninja story",
score=0.9
)
assert res.key == "naruto"
assert res.title == "Naruto"
assert res.folder == "Naruto (2002)"
assert res.score == 0.9
def test_key_normalization(self):
"""Test that key is normalized to lowercase."""
res = SearchResult(key="NARUTO", title="Naruto")
assert res.key == "naruto"
def test_folder_is_optional(self):
"""Test that folder is optional metadata."""
res = SearchResult(key="test", title="Test")
assert res.folder is None
def test_optional_fields(self):
"""Test optional fields."""
res = SearchResult(key="s1", title="T1", snippet="snip", score=0.9)
assert res.score == 0.9
assert res.snippet == "snip"