"""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__])