"""Tests for downloading subtitles with mocked API responses.""" import os from unittest.mock import MagicMock, patch import pytest import responses from jimaku_dl.downloader import JimakuDownloader class TestMockDownload: """Test downloading subtitles with mocked API responses.""" @responses.activate def test_download_subtitle_flow(self, temp_dir, monkeypatch): """Test the full subtitle download flow with mocked responses.""" # Set up test environment monkeypatch.setenv("TESTING", "1") video_file = os.path.join(temp_dir, "test_video.mkv") with open(video_file, "w") as f: f.write("fake video content") # Mock AniList API response with proper structure responses.add( responses.POST, "https://graphql.anilist.co", json={ "data": { "Page": { "media": [ { "id": 123456, "title": { "english": "Test Anime", "romaji": "Test Anime", "native": "テストアニメ", }, "format": "TV", "episodes": 12, "seasonYear": 2023, "season": "WINTER", } ] } } }, status=200, ) # Mock Jimaku search API responses.add( responses.GET, "https://jimaku.cc/api/entries/search", json=[ { "id": 100, "english_name": "Test Anime", "japanese_name": "テストアニメ", } ], status=200, ) # Mock Jimaku files API responses.add( responses.GET, "https://jimaku.cc/api/entries/100/files", json=[ { "id": 200, "name": "test.srt", "url": "https://jimaku.cc/download/test.srt", } ], status=200, ) # Mock file download responses.add( responses.GET, "https://jimaku.cc/download/test.srt", body="1\n00:00:01,000 --> 00:00:05,000\nTest subtitle", status=200, ) # Mock the interactive menu selections downloader = JimakuDownloader(api_token="test_token") with patch.object(downloader, "fzf_menu") as mock_fzf: mock_fzf.side_effect = [ "1. Test Anime - テストアニメ", # Select entry "1. test.srt", # Select file ] # Mock parse_filename to avoid prompting with patch.object( downloader, "parse_filename", return_value=("Test Anime", 1, 1) ): # Execute the download result = downloader.download_subtitles(video_file) # Verify the result assert len(result) == 1 assert "test.srt" in result[0] @responses.activate def test_error_handling(self, temp_dir, monkeypatch): """Test error handling when AniList API fails.""" # Set up test environment monkeypatch.setenv("TESTING", "1") video_file = os.path.join(temp_dir, "test_video.mkv") with open(video_file, "w") as f: f.write("fake video content") # Mock AniList API with an error response responses.add( responses.POST, "https://graphql.anilist.co", status=404, # Simulate 404 error ) # Create downloader and attempt to download downloader = JimakuDownloader(api_token="test_token") with patch.object( downloader, "parse_filename", return_value=("Test Anime", 1, 1) ): with pytest.raises(ValueError) as exc_info: downloader.download_subtitles(video_file) # Check for the specific error message now assert "Network error querying AniList API" in str(exc_info.value) @responses.activate def test_unauthorized_api_error(self, temp_dir, monkeypatch): """Test error handling when Jimaku API returns unauthorized.""" # Set up test environment monkeypatch.setenv("TESTING", "1") video_file = os.path.join(temp_dir, "test_video.mkv") with open(video_file, "w") as f: f.write("fake video content") # Mock AniList API response with success to get past that check responses.add( responses.POST, "https://graphql.anilist.co", json={ "data": { "Page": { "media": [ { "id": 123456, "title": { "english": "Test Anime", "romaji": "Test Anime", "native": "テストアニメ", }, } ] } } }, status=200, ) # Mock Jimaku search API with 401 unauthorized error responses.add( responses.GET, "https://jimaku.cc/api/entries/search", json={"error": "Unauthorized"}, status=401, ) # Create downloader and attempt to download downloader = JimakuDownloader(api_token="invalid_token") with patch.object( downloader, "parse_filename", return_value=("Test Anime", 1, 1) ): with pytest.raises(ValueError) as exc_info: downloader.download_subtitles(video_file) # Now check for the Jimaku API error assert "Error querying Jimaku API" in str(exc_info.value) @responses.activate def test_no_subtitle_entries_found(self, temp_dir, monkeypatch): """Test handling when no subtitle entries are found.""" # Set up test environment monkeypatch.setenv("TESTING", "1") video_file = os.path.join(temp_dir, "test_video.mkv") with open(video_file, "w") as f: f.write("fake video content") # Mock AniList API response with success responses.add( responses.POST, "https://graphql.anilist.co", json={ "data": { "Page": { "media": [ { "id": 123456, "title": { "english": "Test Anime", "romaji": "Test Anime", "native": "テストアニメ", }, } ] } } }, status=200, ) # Mock Jimaku search API with empty response (no entries) responses.add( responses.GET, "https://jimaku.cc/api/entries/search", json=[], # Empty array indicates no entries found status=200, ) # Create downloader and attempt to download downloader = JimakuDownloader(api_token="test_token") with patch.object( downloader, "parse_filename", return_value=("Test Anime", 1, 1) ): with pytest.raises(ValueError) as exc_info: downloader.download_subtitles(video_file) assert "No subtitle entries found" in str(exc_info.value) @responses.activate def test_no_subtitle_files_found(self, temp_dir, monkeypatch): """Test handling when no subtitle files are available for an entry.""" # Set up test environment monkeypatch.setenv("TESTING", "1") video_file = os.path.join(temp_dir, "test_video.mkv") with open(video_file, "w") as f: f.write("fake video content") # Mock AniList API response with success responses.add( responses.POST, "https://graphql.anilist.co", json={ "data": { "Page": { "media": [ { "id": 123456, "title": { "english": "Test Anime", "romaji": "Test Anime", "native": "テストアニメ", }, } ] } } }, status=200, ) # Mock Jimaku search API with entries responses.add( responses.GET, "https://jimaku.cc/api/entries/search", json=[ { "id": 100, "english_name": "Test Anime", "japanese_name": "テストアニメ", } ], status=200, ) # Mock Jimaku files API with empty files responses.add( responses.GET, "https://jimaku.cc/api/entries/100/files", json=[], # Empty array = no files status=200, ) # Create downloader and attempt to download downloader = JimakuDownloader(api_token="test_token") with patch.object(downloader, "fzf_menu") as mock_fzf: # Mock entry selection mock_fzf.return_value = "1. Test Anime - テストアニメ" with patch.object( downloader, "parse_filename", return_value=("Test Anime", 1, 1) ): with pytest.raises(ValueError) as exc_info: downloader.download_subtitles(video_file) assert "No files found" in str(exc_info.value)