""" Unit tests for Pydantic models """ import pytest from datetime import datetime from pydantic import ValidationError from app.models import ( DownloadTask, DownloadStatus, DownloadRequest, HostType, AnimeMetadata, AnimeSearchResult ) class TestDownloadStatus: """Tests for DownloadStatus enum""" def test_status_values(self): """Test that all status values are correct""" assert DownloadStatus.PENDING == "pending" assert DownloadStatus.DOWNLOADING == "downloading" assert DownloadStatus.PAUSED == "paused" assert DownloadStatus.COMPLETED == "completed" assert DownloadStatus.FAILED == "failed" assert DownloadStatus.CANCELLED == "cancelled" def test_status_comparison(self): """Test status comparison""" status1 = DownloadStatus.PENDING status2 = DownloadStatus.DOWNLOADING assert status1 != status2 assert status1 == "pending" class TestHostType: """Tests for HostType enum""" def test_host_values(self): """Test that all host type values are correct""" assert HostType.RAPIDFILE == "rapidfile" assert HostType.UNFICHIER == "1fichier" assert HostType.DOODSTREAM == "doodstream" assert HostType.OTHER == "other" class TestDownloadTask: """Tests for DownloadTask model""" def test_create_download_task_valid(self, sample_download_task): """Test creating a valid download task""" task = sample_download_task assert task.id == "test-task-123" assert task.url == "https://example.com/file.mp4" assert task.filename == "test_video.mp4" assert task.host == HostType.OTHER assert task.status == DownloadStatus.PENDING assert task.progress == 0.0 assert task.downloaded_bytes == 0 assert task.total_bytes is None assert task.speed == 0.0 def test_download_task_with_optional_fields(self): """Test download task with all optional fields""" now = datetime.now() task = DownloadTask( id="task-456", url="https://example.com/file2.mp4", filename="file2.mp4", host=HostType.DOODSTREAM, status=DownloadStatus.DOWNLOADING, progress=50.0, downloaded_bytes=5000000, total_bytes=10000000, speed=1000000.0, error="Test error", created_at=now, started_at=now, completed_at=None, file_path="/downloads/file2.mp4" ) assert task.progress == 50.0 assert task.downloaded_bytes == 5000000 assert task.total_bytes == 10000000 assert task.speed == 1000000.0 assert task.error == "Test error" assert task.started_at is not None assert task.completed_at is None assert task.file_path == "/downloads/file2.mp4" def test_download_task_default_values(self): """Test download task with default values""" task = DownloadTask( id="task-default", url="https://example.com/file.mp4", filename="file.mp4", host=HostType.OTHER, status=DownloadStatus.PENDING, created_at=datetime.now() ) assert task.progress == 0.0 assert task.downloaded_bytes == 0 assert task.speed == 0.0 assert task.total_bytes is None assert task.error is None assert task.started_at is None assert task.completed_at is None assert task.file_path is None def test_download_task_invalid_url(self): """Test that task accepts any URL string (Pydantic v2 doesn't validate URL by default)""" # Pydantic v2 doesn't validate URL format by default unless explicitly configured # This test documents the current behavior task = DownloadTask( id="task-invalid", url="not-a-valid-url", filename="file.mp4", host=HostType.OTHER, status=DownloadStatus.PENDING, created_at=datetime.now() ) assert task.url == "not-a-valid-url" def test_download_task_negative_progress(self): """Test that negative progress is accepted (validation not configured)""" # Pydantic v2 doesn't validate ranges by default task = DownloadTask( id="task-negative", url="https://example.com/file.mp4", filename="file.mp4", host=HostType.OTHER, status=DownloadStatus.PENDING, progress=-10.0, # Accepted but not ideal created_at=datetime.now() ) assert task.progress == -10.0 def test_download_task_progress_over_100(self): """Test that progress over 100 is accepted (validation not configured)""" # Pydantic v2 doesn't validate ranges by default task = DownloadTask( id="task-over100", url="https://example.com/file.mp4", filename="file.mp4", host=HostType.OTHER, status=DownloadStatus.PENDING, progress=150.0, # Accepted but not ideal created_at=datetime.now() ) assert task.progress == 150.0 class TestDownloadRequest: """Tests for DownloadRequest model""" def test_create_request_with_filename(self, sample_download_request): """Test creating download request with filename""" request = sample_download_request assert request.url == "https://example.com/file.mp4" assert request.filename == "test_video.mp4" def test_create_request_without_filename(self): """Test creating download request without filename""" request = DownloadRequest(url="https://example.com/file.mp4") assert request.url == "https://example.com/file.mp4" assert request.filename is None def test_request_invalid_url(self): """Test that request accepts any URL string""" # Pydantic v2 doesn't validate URL format by default request = DownloadRequest(url="not-a-url") assert request.url == "not-a-url" def test_request_empty_url(self): """Test that empty URL is accepted""" # Pydantic v2 doesn't validate empty strings by default request = DownloadRequest(url="") assert request.url == "" class TestAnimeMetadata: """Tests for AnimeMetadata model""" def test_create_metadata_all_fields(self): """Test creating metadata with all fields""" metadata = AnimeMetadata( synopsis="Test anime about adventure", genres=["Action", "Adventure", "Fantasy"], rating="8.5/10", release_year=2023, studio="Test Studio", poster_image="https://example.com/poster.jpg", banner_image="https://example.com/banner.jpg", total_episodes=12, status="Completed", alternative_titles=["Test Anime 1", "Test Anime 2"] ) assert metadata.synopsis == "Test anime about adventure" assert len(metadata.genres) == 3 assert metadata.rating == "8.5/10" assert metadata.release_year == 2023 assert metadata.studio == "Test Studio" assert metadata.poster_image is not None assert metadata.banner_image is not None assert metadata.total_episodes == 12 assert metadata.status == "Completed" assert len(metadata.alternative_titles) == 2 def test_create_metadata_minimal(self): """Test creating metadata with minimal fields""" metadata = AnimeMetadata() assert metadata.synopsis is None assert metadata.genres == [] assert metadata.rating is None assert metadata.release_year is None assert metadata.studio is None assert metadata.poster_image is None assert metadata.banner_image is None assert metadata.total_episodes is None assert metadata.status is None assert metadata.alternative_titles == [] def test_metadata_with_some_fields(self): """Test creating metadata with only some fields""" metadata = AnimeMetadata( genres=["Action"], rating="PG-13", release_year=2020 ) assert len(metadata.genres) == 1 assert metadata.genres == ["Action"] assert metadata.rating == "PG-13" assert metadata.release_year == 2020 assert metadata.synopsis is None assert metadata.studio is None def test_metadata_empty_genres_list(self): """Test metadata with empty genres list""" metadata = AnimeMetadata(genres=[]) assert metadata.genres == [] def test_metadata_negative_year(self): """Test that negative year is handled""" # Pydantic doesn't validate range by default metadata = AnimeMetadata(release_year=-2023) assert metadata.release_year == -2023 def test_metadata_zero_episodes(self): """Test metadata with zero episodes""" metadata = AnimeMetadata(total_episodes=0) assert metadata.total_episodes == 0 class TestAnimeSearchResult: """Tests for AnimeSearchResult model""" def test_create_search_result_full(self): """Test creating search result with all fields""" metadata = AnimeMetadata( synopsis="Test", genres=["Action"], rating="8.0/10" ) result = AnimeSearchResult( title="Test Anime", url="https://example.com/anime", cover_image="https://example.com/cover.jpg", type="search_result", metadata=metadata ) assert result.title == "Test Anime" assert result.url == "https://example.com/anime" assert result.cover_image == "https://example.com/cover.jpg" assert result.type == "search_result" assert result.metadata is not None assert result.metadata.synopsis == "Test" def test_create_search_result_minimal(self): """Test creating minimal search result""" result = AnimeSearchResult( title="Minimal Anime", url="https://example.com/minimal", type="direct" ) assert result.title == "Minimal Anime" assert result.url == "https://example.com/minimal" assert result.type == "direct" assert result.cover_image is None assert result.metadata is None def test_search_result_invalid_type(self): """Test that any type string is accepted""" # Pydantic v2 doesn't validate literal values by default result = AnimeSearchResult( title="Test", url="https://example.com", type="invalid_type" # Accepted ) assert result.type == "invalid_type" def test_search_result_empty_title(self): """Test that empty title is accepted""" # Pydantic v2 doesn't validate empty strings by default result = AnimeSearchResult( title="", url="https://example.com", type="search_result" ) assert result.title == "" def test_search_result_invalid_url(self): """Test that any URL string is accepted""" # Pydantic v2 doesn't validate URL format by default result = AnimeSearchResult( title="Test", url="not-a-url", type="search_result" ) assert result.url == "not-a-url"