""" Unit tests for downloaders """ import pytest from unittest.mock import Mock, AsyncMock, patch, MagicMock from bs4 import BeautifulSoup from app.downloaders.base import BaseDownloader class TestBaseDownloader: """Tests for BaseDownloader abstract class""" def test_base_downloader_is_abstract(self): """Test that BaseDownloader cannot be instantiated directly""" with pytest.raises(TypeError): BaseDownloader() def test_base_downloader_can_handle_not_implemented(self): """Test that can_handle raises NotImplementedError""" from app.downloaders.uptobox import UptoboxDownloader downloader = UptoboxDownloader() # Test with unsupported URL assert downloader.can_handle("https://example.com") is False def test_base_downloader_get_download_link_not_implemented(self): """Test that get_download_link works in concrete implementation""" from app.downloaders.sendvid import SendVidDownloader downloader = SendVidDownloader() # Test that concrete implementation can be called # (actual functionality tested in integration tests) assert downloader.can_handle("https://sendvid.com/abc") is True @pytest.mark.asyncio async def test_base_downloader_fetch_page(self): """Test _fetch_page method""" class TestDownloader(BaseDownloader): def can_handle(self, url: str) -> bool: return True async def get_download_link(self, url: str): return ("http://example.com/download", "file.mp4") downloader = TestDownloader() # Mock the client.get method with patch.object(downloader.client, 'get') as mock_get: mock_response = Mock() mock_response.text = "Test content" mock_response.raise_for_status = Mock() mock_get.return_value = mock_response content = await downloader._fetch_page("https://example.com") assert content == "Test content" mock_get.assert_called_once_with("https://example.com") @pytest.mark.asyncio async def test_base_downloader_fetch_page_error(self): """Test _fetch_page method with HTTP error""" class TestDownloader(BaseDownloader): def can_handle(self, url: str) -> bool: return True async def get_download_link(self, url: str): return ("http://example.com/download", "file.mp4") downloader = TestDownloader() with patch.object(downloader.client, 'get') as mock_get: mock_response = Mock() mock_response.raise_for_status.side_effect = Exception("HTTP Error") mock_get.return_value = mock_response with pytest.raises(Exception): await downloader._fetch_page("https://example.com") def test_extract_filename_from_headers(self): """Test _extract_filename_from_headers method""" class TestDownloader(BaseDownloader): def can_handle(self, url: str) -> bool: return True async def get_download_link(self, url: str): return ("http://example.com/download", "file.mp4") downloader = TestDownloader() # Test with filename in headers headers = {"content-disposition": 'attachment; filename="test.mp4"'} filename = downloader._extract_filename_from_headers(headers) assert filename == "test.mp4" # Test without filename headers = {} filename = downloader._extract_filename_from_headers(headers) assert filename is None # Test with filename in single quotes headers = {"content-disposition": "attachment; filename='test.mp4'"} filename = downloader._extract_filename_from_headers(headers) assert filename == "'test.mp4'" @pytest.mark.asyncio async def test_search_anime_default(self): """Test default search_anime returns empty list""" class TestDownloader(BaseDownloader): def can_handle(self, url: str) -> bool: return True async def get_download_link(self, url: str): return ("http://example.com/download", "file.mp4") downloader = TestDownloader() results = await downloader.search_anime("naruto", "vostfr") assert results == [] @pytest.mark.asyncio async def test_get_episodes_default(self): """Test default get_episodes returns empty list""" class TestDownloader(BaseDownloader): def can_handle(self, url: str) -> bool: return True async def get_download_link(self, url: str): return ("http://example.com/download", "file.mp4") downloader = TestDownloader() episodes = await downloader.get_episodes("https://example.com/anime", "vostfr") assert episodes == [] @pytest.mark.asyncio async def test_close(self): """Test close method""" class TestDownloader(BaseDownloader): def can_handle(self, url: str) -> bool: return True async def get_download_link(self, url: str): return ("http://example.com/download", "file.mp4") downloader = TestDownloader() # Mock the client.aclose method with patch.object(downloader.client, 'aclose') as mock_aclose: mock_aclose.return_value = AsyncMock() await downloader.close() mock_aclose.assert_called_once() # Test for concrete downloader implementations class TestDownloaderRegistration: """Tests for downloader registration system""" def test_get_downloader_returns_downloader(self): """Test that get_downloader returns appropriate downloader""" from app.downloaders import get_downloader # Test with 1fichier URL downloader = get_downloader("https://1fichier.com/?abcdef") assert downloader is not None assert downloader.can_handle("https://1fichier.com/?abcdef") # Test with doodstream URL downloader = get_downloader("https://doodstream.com/d/abcdef") assert downloader is not None assert downloader.can_handle("https://doodstream.com/d/abcdef") def test_get_downloader_fallback(self): """Test that get_downloader falls back to other for unknown hosts""" from app.downloaders import get_downloader downloader = get_downloader("https://unknown-host.com/file") assert downloader is not None def test_all_downloaders_have_required_methods(self): """Test that all registered downloaders implement required methods""" from app.downloaders import get_downloader test_urls = [ "https://1fichier.com/?test", "https://doodstream.com/d/test", "https://rapidfile.net/test", "https://uptobox.com/test" ] for url in test_urls: downloader = get_downloader(url) assert hasattr(downloader, 'can_handle') assert hasattr(downloader, 'get_download_link') assert callable(downloader.can_handle) # get_download_link is async, so we can't test with callable() import inspect assert inspect.iscoroutinefunction(downloader.get_download_link) class TestDownloaderCanHandle: """Tests for can_handle method in concrete downloaders""" def test_unfichier_can_handle(self): """Test UnfichierDownloader.can_handle""" from app.downloaders.unfichier import UnFichierDownloader downloader = UnFichierDownloader() assert downloader.can_handle("https://1fichier.com/?abc123") is True assert downloader.can_handle("https://1fichier.fr/?abc123") is True assert downloader.can_handle("http://1fichier.com/?abc123") is True assert downloader.can_handle("https://doodstream.com/test") is False assert downloader.can_handle("https://example.com/test") is False def test_doodstream_can_handle(self): """Test DoodStreamDownloader.can_handle""" from app.downloaders.doodstream import DoodStreamDownloader downloader = DoodStreamDownloader() assert downloader.can_handle("https://doodstream.com/d/abc123") is True assert downloader.can_handle("https://dood.to/d/abc123") is True assert downloader.can_handle("https://dood.lol/d/abc123") is True assert downloader.can_handle("https://1fichier.com/?test") is False def test_rapidfile_can_handle(self): """Test RapidFileDownloader.can_handle""" from app.downloaders.rapidfile import RapidFileDownloader downloader = RapidFileDownloader() assert downloader.can_handle("https://rapidfile.net/abc123") is True assert downloader.can_handle("https://rapidfile.com/abc123") is True assert downloader.can_handle("https://doodstream.com/test") is False def test_uptobox_can_handle(self): """Test UptoboxDownloader.can_handle""" from app.downloaders.uptobox import UptoboxDownloader downloader = UptoboxDownloader() assert downloader.can_handle("https://uptobox.com/abc123") is True assert downloader.can_handle("https://uptobox.fr/abc123") is True assert downloader.can_handle("https://doodstream.com/test") is False def test_vidmoly_can_handle(self): """Test VidMolyDownloader.can_handle""" from app.downloaders.vidmoly import VidMolyDownloader downloader = VidMolyDownloader() assert downloader.can_handle("https://vidmoly.to/abc123") is True assert downloader.can_handle("https://vidmoly.org/abc123") is True assert downloader.can_handle("https://vidmoly.biz/abc123") is True assert downloader.can_handle("https://vidmoly.com/abc123") is False assert downloader.can_handle("https://doodstream.com/test") is False def test_sendvid_can_handle(self): """Test SendVidDownloader.can_handle""" from app.downloaders.sendvid import SendVidDownloader downloader = SendVidDownloader() assert downloader.can_handle("https://sendvid.com/abc123") is True assert downloader.can_handle("https://doodstream.com/test") is False class TestAnimeDownloaders: """Tests for anime provider downloaders""" @pytest.mark.asyncio async def test_anime_sama_search(self): """Test AnimeSamaDownloader.search_anime""" from app.downloaders.animesama import AnimeSamaDownloader downloader = AnimeSamaDownloader() with patch.object(downloader, '_fetch_page') as mock_fetch: # Mock HTML response mock_html = """
Test Anime

Test Anime

""" mock_fetch.return_value = mock_html results = await downloader.search_anime("test anime", "vostfr") # Should return results based on the mocked HTML assert isinstance(results, list) @pytest.mark.asyncio async def test_neko_sama_can_handle(self): """Test NekoSamaDownloader.can_handle""" from app.downloaders.nekosama import NekoSamaDownloader downloader = NekoSamaDownloader() assert downloader.can_handle("https://neko-sama.fr/test") is True assert downloader.can_handle("https://nekosama.fr/test") is True assert downloader.can_handle("https://www.neko-sama.fr/test") is True assert downloader.can_handle("https://anime-sama.si/test") is False @pytest.mark.asyncio async def test_anime_ultime_can_handle(self): """Test AnimeUltimeDownloader.can_handle""" from app.downloaders.animeultime import AnimeUltimeDownloader downloader = AnimeUltimeDownloader() assert downloader.can_handle("https://anime-ultime.net/test") is True assert downloader.can_handle("https://anime-sama.si/test") is False @pytest.mark.asyncio async def test_vostfree_can_handle(self): """Test VostfreeDownloader.can_handle""" from app.downloaders.vostfree import VostfreeDownloader downloader = VostfreeDownloader() assert downloader.can_handle("https://vostfree.tv/test") is True assert downloader.can_handle("https://www.vostfree.tv/test") is True assert downloader.can_handle("https://anime-sama.si/test") is False class TestDownloaderUrlExtraction: """Tests for URL extraction methods""" @pytest.mark.asyncio async def test_get_download_link_mock(self): """Test get_download_link with mocked response""" from app.downloaders.unfichier import UnFichierDownloader downloader = UnfichierDownloader() with patch.object(downloader, '_fetch_page') as mock_fetch: # Mock a simple HTML page mock_fetch.return_value = "Test page" # This should not crash try: download_url, filename = await downloader.get_download_link("https://1fichier.com/?test") # Result may vary based on actual implementation assert isinstance(download_url, str) assert isinstance(filename, str) except Exception as e: # Some downloaders might fail with mock HTML assert isinstance(e, (ValueError, AttributeError, KeyError))