youtube-summarizer/backend/tests/unit/test_video_service.py

159 lines
6.6 KiB
Python

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)