import pytest from backend.services.video_service import VideoService from backend.core.exceptions import ValidationError, UnsupportedFormatError, ErrorCode class TestVideoService: @pytest.fixture def video_service(self): return VideoService() def test_extract_video_id_standard_url(self, video_service): """Test extraction from standard YouTube watch URLs.""" test_cases = [ ("https://youtube.com/watch?v=dQw4w9WgXcQ", "dQw4w9WgXcQ"), ("https://www.youtube.com/watch?v=dQw4w9WgXcQ", "dQw4w9WgXcQ"), ("http://youtube.com/watch?v=dQw4w9WgXcQ", "dQw4w9WgXcQ"), ("youtube.com/watch?v=dQw4w9WgXcQ", "dQw4w9WgXcQ"), ("https://youtube.com/watch?v=dQw4w9WgXcQ&t=30s", "dQw4w9WgXcQ"), ("https://youtube.com/watch?v=dQw4w9WgXcQ&feature=share", "dQw4w9WgXcQ"), ] for url, expected_id in test_cases: result = video_service.extract_video_id(url) assert result == expected_id, f"Failed for URL: {url}" def test_extract_video_id_short_url(self, video_service): """Test extraction from youtu.be short URLs.""" test_cases = [ ("https://youtu.be/dQw4w9WgXcQ", "dQw4w9WgXcQ"), ("http://youtu.be/dQw4w9WgXcQ", "dQw4w9WgXcQ"), ("youtu.be/dQw4w9WgXcQ", "dQw4w9WgXcQ"), ("https://youtu.be/dQw4w9WgXcQ?t=30", "dQw4w9WgXcQ"), ] for url, expected_id in test_cases: result = video_service.extract_video_id(url) assert result == expected_id, f"Failed for URL: {url}" def test_extract_video_id_embed_url(self, video_service): """Test extraction from embed URLs.""" test_cases = [ ("https://youtube.com/embed/dQw4w9WgXcQ", "dQw4w9WgXcQ"), ("https://www.youtube.com/embed/dQw4w9WgXcQ", "dQw4w9WgXcQ"), ("http://youtube.com/embed/dQw4w9WgXcQ", "dQw4w9WgXcQ"), ("youtube.com/embed/dQw4w9WgXcQ", "dQw4w9WgXcQ"), ] for url, expected_id in test_cases: result = video_service.extract_video_id(url) assert result == expected_id, f"Failed for URL: {url}" def test_extract_video_id_mobile_url(self, video_service): """Test extraction from mobile YouTube URLs.""" test_cases = [ ("https://m.youtube.com/watch?v=dQw4w9WgXcQ", "dQw4w9WgXcQ"), ("http://m.youtube.com/watch?v=dQw4w9WgXcQ", "dQw4w9WgXcQ"), ("m.youtube.com/watch?v=dQw4w9WgXcQ", "dQw4w9WgXcQ"), ] for url, expected_id in test_cases: result = video_service.extract_video_id(url) assert result == expected_id, f"Failed for URL: {url}" def test_extract_video_id_invalid_url(self, video_service): """Test that invalid URLs raise ValidationError.""" invalid_urls = [ "https://vimeo.com/123456789", "https://dailymotion.com/video/x123456", "not-a-url-at-all", "https://example.com", "https://youtube.com/", "https://youtube.com/channel/UCxxxxx", ] for url in invalid_urls: with pytest.raises(ValidationError) as exc_info: video_service.extract_video_id(url) assert exc_info.value.error_code == ErrorCode.INVALID_URL def test_extract_video_id_invalid_video_id_length(self, video_service): """Test that video IDs with incorrect length are rejected.""" invalid_urls = [ "https://youtube.com/watch?v=short", # Too short "https://youtube.com/watch?v=thisistoolong123", # Too long "https://youtu.be/abc", # Too short ] for url in invalid_urls: with pytest.raises(ValidationError) as exc_info: video_service.extract_video_id(url) assert exc_info.value.error_code == ErrorCode.INVALID_URL def test_extract_video_id_playlist_url(self, video_service): """Test that playlist URLs raise UnsupportedFormatError.""" playlist_urls = [ "https://youtube.com/playlist?list=PLrAXtmErZgOeiKm4sgNOknGvNjby9efdf", "https://www.youtube.com/watch?v=dQw4w9WgXcQ&list=PLrAXtmErZgOeiKm4sgNOknGvNjby9efdf", "https://youtube.com/watch?v=dQw4w9WgXcQ&list=PLxxxxx&index=2", ] for url in playlist_urls: with pytest.raises(UnsupportedFormatError) as exc_info: video_service.extract_video_id(url) assert exc_info.value.error_code == ErrorCode.UNSUPPORTED_FORMAT assert "playlist" in exc_info.value.message.lower() def test_extract_video_id_empty_url(self, video_service): """Test that empty URL raises ValidationError.""" with pytest.raises(ValidationError) as exc_info: video_service.extract_video_id("") assert exc_info.value.error_code == ErrorCode.INVALID_URL assert "empty" in exc_info.value.message.lower() with pytest.raises(ValidationError) as exc_info: video_service.extract_video_id(None) assert exc_info.value.error_code == ErrorCode.INVALID_URL def test_validate_video_id(self, video_service): """Test video ID validation logic.""" # Valid IDs valid_ids = [ "dQw4w9WgXcQ", "aB3-567_890", "___________", # All underscores "-----------", # All hyphens "ABCDEFGHIJK", # All uppercase "abcdefghijk", # All lowercase "12345678901", # All numbers ] for video_id in valid_ids: assert video_service._validate_video_id(video_id) is True # Invalid IDs invalid_ids = [ "short", # Too short "thisistoolong", # Too long "has space11", # Contains space "has@special", # Contains special char "", # Empty None, # None ] for video_id in invalid_ids: assert video_service._validate_video_id(video_id) is False def test_normalize_url(self, video_service): """Test URL normalization.""" video_id = "dQw4w9WgXcQ" expected = "https://youtube.com/watch?v=dQw4w9WgXcQ" assert video_service.normalize_url(video_id) == expected def test_get_supported_formats(self, video_service): """Test getting supported formats list.""" formats = video_service.get_supported_formats() assert isinstance(formats, list) assert len(formats) > 0 assert all("VIDEO_ID" in fmt for fmt in formats)