346 lines
14 KiB
Python
346 lines
14 KiB
Python
"""Unit tests for concrete service implementations."""
|
|
|
|
import pytest
|
|
from pathlib import Path
|
|
from typing import Any, Dict, List
|
|
from unittest.mock import AsyncMock, MagicMock, patch
|
|
|
|
from src.services.protocols import (
|
|
YouTubeServiceProtocol,
|
|
MediaServiceProtocol,
|
|
TranscriptionServiceProtocol,
|
|
EnhancementServiceProtocol,
|
|
ExportServiceProtocol,
|
|
BatchProcessorProtocol,
|
|
validate_protocol_implementation,
|
|
get_missing_methods,
|
|
)
|
|
|
|
|
|
class TestYouTubeServiceImplementation:
|
|
"""Test YouTube service protocol implementation."""
|
|
|
|
@pytest.fixture
|
|
def mock_youtube_service(self):
|
|
"""Create a mock YouTube service that implements the protocol."""
|
|
service = MagicMock()
|
|
|
|
# Mock the required methods
|
|
service.extract_metadata = AsyncMock(return_value={
|
|
"title": "Test Video",
|
|
"duration": 120,
|
|
"channel": "Test Channel"
|
|
})
|
|
|
|
service.batch_extract = AsyncMock(return_value=[
|
|
{"success": True, "data": {"title": "Video 1"}, "url": "http://example.com/1"},
|
|
{"success": True, "data": {"title": "Video 2"}, "url": "http://example.com/2"}
|
|
])
|
|
|
|
return service
|
|
|
|
def test_youtube_service_protocol_compliance(self, mock_youtube_service):
|
|
"""Test that YouTube service implements the protocol correctly."""
|
|
from src.services.protocols import YouTubeServiceProtocol
|
|
|
|
# Test protocol validation
|
|
assert validate_protocol_implementation(mock_youtube_service, YouTubeServiceProtocol)
|
|
|
|
# Test that no methods are missing
|
|
missing_methods = get_missing_methods(mock_youtube_service, YouTubeServiceProtocol)
|
|
assert len(missing_methods) == 0
|
|
|
|
@pytest.mark.asyncio
|
|
async def test_youtube_service_methods(self, mock_youtube_service):
|
|
"""Test YouTube service method calls."""
|
|
# Test extract_metadata
|
|
result = await mock_youtube_service.extract_metadata("http://example.com/video")
|
|
assert isinstance(result, dict)
|
|
assert "title" in result
|
|
|
|
# Test batch_extract
|
|
results = await mock_youtube_service.batch_extract(["http://example.com/1", "http://example.com/2"])
|
|
assert isinstance(results, list)
|
|
assert len(results) == 2
|
|
assert all("success" in result for result in results)
|
|
|
|
|
|
class TestMediaServiceImplementation:
|
|
"""Test Media service protocol implementation."""
|
|
|
|
@pytest.fixture
|
|
def mock_media_service(self):
|
|
"""Create a mock Media service that implements the protocol."""
|
|
service = MagicMock()
|
|
|
|
# Mock all required methods
|
|
service.download_media = AsyncMock()
|
|
service.preprocess_audio = AsyncMock(return_value=True)
|
|
service.validate_file_size = AsyncMock(return_value=True)
|
|
service.check_audio_quality = AsyncMock(return_value=True)
|
|
service.get_media_info = AsyncMock(return_value={"duration": 120, "format": "mp4"})
|
|
service.create_media_file_record = AsyncMock()
|
|
service.update_media_file_status = AsyncMock()
|
|
service.get_media_file_by_id = AsyncMock()
|
|
service.get_pending_media_files = AsyncMock(return_value=[])
|
|
service.get_ready_media_files = AsyncMock(return_value=[])
|
|
service.process_media_pipeline = AsyncMock()
|
|
service.get_telemetry_data = MagicMock(return_value=[])
|
|
service.clear_telemetry_data = MagicMock()
|
|
|
|
return service
|
|
|
|
def test_media_service_protocol_compliance(self, mock_media_service):
|
|
"""Test that Media service implements the protocol correctly."""
|
|
from src.services.protocols import MediaServiceProtocol
|
|
|
|
# Test protocol validation
|
|
assert validate_protocol_implementation(mock_media_service, MediaServiceProtocol)
|
|
|
|
# Test that no methods are missing
|
|
missing_methods = get_missing_methods(mock_media_service, MediaServiceProtocol)
|
|
assert len(missing_methods) == 0
|
|
|
|
@pytest.mark.asyncio
|
|
async def test_media_service_methods(self, mock_media_service):
|
|
"""Test Media service method calls."""
|
|
# Test download_media
|
|
await mock_media_service.download_media("http://example.com/video", Path("/tmp"))
|
|
mock_media_service.download_media.assert_called_once()
|
|
|
|
# Test preprocess_audio
|
|
result = await mock_media_service.preprocess_audio(Path("/input.wav"), Path("/output.wav"))
|
|
assert result is True
|
|
|
|
# Test validate_file_size
|
|
result = await mock_media_service.validate_file_size(Path("/test.mp4"))
|
|
assert result is True
|
|
|
|
# Test get_media_info
|
|
info = await mock_media_service.get_media_info(Path("/test.mp4"))
|
|
assert isinstance(info, dict)
|
|
assert "duration" in info
|
|
|
|
|
|
class TestTranscriptionServiceImplementation:
|
|
"""Test Transcription service protocol implementation."""
|
|
|
|
@pytest.fixture
|
|
def mock_transcription_service(self):
|
|
"""Create a mock Transcription service that implements the protocol."""
|
|
service = MagicMock()
|
|
|
|
# Mock all required methods
|
|
service.transcribe_file = AsyncMock()
|
|
service.transcribe_audio = AsyncMock()
|
|
service.create_transcription_job = AsyncMock()
|
|
service.get_job_status = AsyncMock()
|
|
service.cancel_job = AsyncMock(return_value=True)
|
|
|
|
return service
|
|
|
|
def test_transcription_service_protocol_compliance(self, mock_transcription_service):
|
|
"""Test that Transcription service implements the protocol correctly."""
|
|
from src.services.protocols import TranscriptionServiceProtocol
|
|
|
|
# Test protocol validation
|
|
assert validate_protocol_implementation(mock_transcription_service, TranscriptionServiceProtocol)
|
|
|
|
# Test that no methods are missing
|
|
missing_methods = get_missing_methods(mock_transcription_service, TranscriptionServiceProtocol)
|
|
assert len(missing_methods) == 0
|
|
|
|
@pytest.mark.asyncio
|
|
async def test_transcription_service_methods(self, mock_transcription_service):
|
|
"""Test Transcription service method calls."""
|
|
# Test transcribe_file
|
|
await mock_transcription_service.transcribe_file(MagicMock())
|
|
mock_transcription_service.transcribe_file.assert_called_once()
|
|
|
|
# Test transcribe_audio
|
|
await mock_transcription_service.transcribe_audio(Path("/test.wav"))
|
|
mock_transcription_service.transcribe_audio.assert_called_once()
|
|
|
|
# Test cancel_job
|
|
result = await mock_transcription_service.cancel_job("job-id")
|
|
assert result is True
|
|
|
|
|
|
class TestEnhancementServiceImplementation:
|
|
"""Test Enhancement service protocol implementation."""
|
|
|
|
@pytest.fixture
|
|
def mock_enhancement_service(self):
|
|
"""Create a mock Enhancement service that implements the protocol."""
|
|
service = MagicMock()
|
|
|
|
# Mock all required methods
|
|
service.initialize = AsyncMock()
|
|
service.enhance_transcript = AsyncMock()
|
|
service.enhance_transcript_batch = AsyncMock()
|
|
service.enhance_transcription_result = AsyncMock()
|
|
|
|
return service
|
|
|
|
def test_enhancement_service_protocol_compliance(self, mock_enhancement_service):
|
|
"""Test that Enhancement service implements the protocol correctly."""
|
|
from src.services.protocols import EnhancementServiceProtocol
|
|
|
|
# Test protocol validation
|
|
assert validate_protocol_implementation(mock_enhancement_service, EnhancementServiceProtocol)
|
|
|
|
# Test that no methods are missing
|
|
missing_methods = get_missing_methods(mock_enhancement_service, EnhancementServiceProtocol)
|
|
assert len(missing_methods) == 0
|
|
|
|
@pytest.mark.asyncio
|
|
async def test_enhancement_service_methods(self, mock_enhancement_service):
|
|
"""Test Enhancement service method calls."""
|
|
# Test initialize
|
|
await mock_enhancement_service.initialize()
|
|
mock_enhancement_service.initialize.assert_called_once()
|
|
|
|
# Test enhance_transcript
|
|
await mock_enhancement_service.enhance_transcript("test transcript")
|
|
mock_enhancement_service.enhance_transcript.assert_called_once()
|
|
|
|
# Test enhance_transcript_batch
|
|
await mock_enhancement_service.enhance_transcript_batch(["transcript1", "transcript2"])
|
|
mock_enhancement_service.enhance_transcript_batch.assert_called_once()
|
|
|
|
|
|
class TestExportServiceImplementation:
|
|
"""Test Export service protocol implementation."""
|
|
|
|
@pytest.fixture
|
|
def mock_export_service(self):
|
|
"""Create a mock Export service that implements the protocol."""
|
|
service = MagicMock()
|
|
|
|
# Mock all required methods
|
|
service.export_transcript = AsyncMock()
|
|
service.export_batch = AsyncMock()
|
|
service.get_supported_formats = MagicMock(return_value=["json", "txt", "srt"])
|
|
|
|
return service
|
|
|
|
def test_export_service_protocol_compliance(self, mock_export_service):
|
|
"""Test that Export service implements the protocol correctly."""
|
|
from src.services.protocols import ExportServiceProtocol
|
|
|
|
# Test protocol validation
|
|
assert validate_protocol_implementation(mock_export_service, ExportServiceProtocol)
|
|
|
|
# Test that no methods are missing
|
|
missing_methods = get_missing_methods(mock_export_service, ExportServiceProtocol)
|
|
assert len(missing_methods) == 0
|
|
|
|
def test_export_service_methods(self, mock_export_service):
|
|
"""Test Export service method calls."""
|
|
# Test get_supported_formats
|
|
formats = mock_export_service.get_supported_formats()
|
|
assert isinstance(formats, list)
|
|
assert "json" in formats
|
|
|
|
# Test export_transcript
|
|
mock_export_service.export_transcript(MagicMock(), Path("/output"), "json")
|
|
mock_export_service.export_transcript.assert_called_once()
|
|
|
|
|
|
class TestBatchProcessorImplementation:
|
|
"""Test Batch processor protocol implementation."""
|
|
|
|
@pytest.fixture
|
|
def mock_batch_processor(self):
|
|
"""Create a mock Batch processor that implements the protocol."""
|
|
processor = MagicMock()
|
|
|
|
# Mock all required methods
|
|
processor.add_task = AsyncMock(return_value="task-id")
|
|
processor.process_tasks = AsyncMock()
|
|
processor.get_progress = AsyncMock()
|
|
processor.cancel_task = AsyncMock(return_value=True)
|
|
processor.get_task_status = AsyncMock()
|
|
processor.get_completed_tasks = AsyncMock(return_value=[])
|
|
|
|
return processor
|
|
|
|
def test_batch_processor_protocol_compliance(self, mock_batch_processor):
|
|
"""Test that Batch processor implements the protocol correctly."""
|
|
from src.services.protocols import BatchProcessorProtocol
|
|
|
|
# Test protocol validation
|
|
assert validate_protocol_implementation(mock_batch_processor, BatchProcessorProtocol)
|
|
|
|
# Test that no methods are missing
|
|
missing_methods = get_missing_methods(mock_batch_processor, BatchProcessorProtocol)
|
|
assert len(missing_methods) == 0
|
|
|
|
@pytest.mark.asyncio
|
|
async def test_batch_processor_methods(self, mock_batch_processor):
|
|
"""Test Batch processor method calls."""
|
|
# Test add_task
|
|
task_id = await mock_batch_processor.add_task("transcription", {"url": "test"})
|
|
assert task_id == "task-id"
|
|
|
|
# Test process_tasks
|
|
await mock_batch_processor.process_tasks(max_workers=4)
|
|
mock_batch_processor.process_tasks.assert_called_once_with(max_workers=4)
|
|
|
|
# Test cancel_task
|
|
result = await mock_batch_processor.cancel_task("task-id")
|
|
assert result is True
|
|
|
|
|
|
class TestProtocolValidationUtilities:
|
|
"""Test protocol validation utility functions."""
|
|
|
|
def test_validate_protocol_implementation_with_valid_instance(self):
|
|
"""Test protocol validation with a valid instance."""
|
|
class ValidService:
|
|
def extract_metadata(self, url: str) -> Dict[str, Any]:
|
|
return {"title": "Test"}
|
|
|
|
def batch_extract(self, urls: List[str]) -> List[Dict[str, Any]]:
|
|
return [{"title": "Test"}]
|
|
|
|
service = ValidService()
|
|
from src.services.protocols import YouTubeServiceProtocol
|
|
|
|
# This should work at runtime since we have the required methods
|
|
# Note: This is a runtime check, not a static type check
|
|
assert hasattr(service, 'extract_metadata')
|
|
assert hasattr(service, 'batch_extract')
|
|
|
|
def test_get_missing_methods_with_incomplete_implementation(self):
|
|
"""Test getting missing methods from incomplete implementation."""
|
|
class IncompleteService:
|
|
def extract_metadata(self, url: str) -> Dict[str, Any]:
|
|
return {"title": "Test"}
|
|
# Missing batch_extract method
|
|
|
|
service = IncompleteService()
|
|
from src.services.protocols import YouTubeServiceProtocol
|
|
|
|
missing_methods = get_missing_methods(service, YouTubeServiceProtocol)
|
|
assert "batch_extract" in missing_methods
|
|
|
|
def test_get_missing_methods_with_complete_implementation(self):
|
|
"""Test getting missing methods from complete implementation."""
|
|
class CompleteService:
|
|
def extract_metadata(self, url: str) -> Dict[str, Any]:
|
|
return {"title": "Test"}
|
|
|
|
def batch_extract(self, urls: List[str]) -> List[Dict[str, Any]]:
|
|
return [{"title": "Test"}]
|
|
|
|
service = CompleteService()
|
|
from src.services.protocols import YouTubeServiceProtocol
|
|
|
|
missing_methods = get_missing_methods(service, YouTubeServiceProtocol)
|
|
assert len(missing_methods) == 0
|
|
|
|
|
|
if __name__ == "__main__":
|
|
pytest.main([__file__])
|