"""Unit tests for ProcessingRequestDto""" import pytest from src.application.dtos.processing_request_dto import ProcessingRequestDto from src.application.dtos.audio_upload_dto import AudioUploadDto class TestProcessingRequestDto: """Test cases for ProcessingRequestDto""" @pytest.fixture def sample_audio_upload(self): """Create sample audio upload DTO""" return AudioUploadDto( filename="test_audio.wav", content=b"fake_audio_content_" + b"x" * 1000, content_type="audio/wav" ) def test_valid_processing_request_dto(self, sample_audio_upload): """Test creating a valid ProcessingRequestDto""" dto = ProcessingRequestDto( audio=sample_audio_upload, asr_model="whisper-small", target_language="es", voice="kokoro", speed=1.0, source_language="en" ) assert dto.audio == sample_audio_upload assert dto.asr_model == "whisper-small" assert dto.target_language == "es" assert dto.voice == "kokoro" assert dto.speed == 1.0 assert dto.source_language == "en" assert dto.additional_params == {} def test_processing_request_dto_with_defaults(self, sample_audio_upload): """Test creating ProcessingRequestDto with default values""" dto = ProcessingRequestDto( audio=sample_audio_upload, asr_model="whisper-medium", target_language="fr", voice="dia" ) assert dto.speed == 1.0 # Default speed assert dto.source_language is None # Default source language assert dto.additional_params == {} # Default additional params def test_processing_request_dto_with_additional_params(self, sample_audio_upload): """Test creating ProcessingRequestDto with additional parameters""" additional_params = { "custom_param": "value", "another_param": 123 } dto = ProcessingRequestDto( audio=sample_audio_upload, asr_model="whisper-large", target_language="de", voice="cosyvoice2", additional_params=additional_params ) assert dto.additional_params == additional_params def test_invalid_audio_type_validation(self): """Test validation with invalid audio type""" with pytest.raises(ValueError, match="Audio must be an AudioUploadDto instance"): ProcessingRequestDto( audio="invalid_audio", # Not AudioUploadDto asr_model="whisper-small", target_language="es", voice="kokoro" ) def test_empty_asr_model_validation(self, sample_audio_upload): """Test validation with empty ASR model""" with pytest.raises(ValueError, match="ASR model cannot be empty"): ProcessingRequestDto( audio=sample_audio_upload, asr_model="", target_language="es", voice="kokoro" ) def test_unsupported_asr_model_validation(self, sample_audio_upload): """Test validation with unsupported ASR model""" with pytest.raises(ValueError, match="Unsupported ASR model"): ProcessingRequestDto( audio=sample_audio_upload, asr_model="invalid-model", target_language="es", voice="kokoro" ) def test_supported_asr_models(self, sample_audio_upload): """Test all supported ASR models""" supported_models = ['whisper-small', 'whisper-medium', 'whisper-large', 'parakeet'] for model in supported_models: # Should not raise exception dto = ProcessingRequestDto( audio=sample_audio_upload, asr_model=model, target_language="es", voice="kokoro" ) assert dto.asr_model == model def test_empty_target_language_validation(self, sample_audio_upload): """Test validation with empty target language""" with pytest.raises(ValueError, match="Target language cannot be empty"): ProcessingRequestDto( audio=sample_audio_upload, asr_model="whisper-small", target_language="", voice="kokoro" ) def test_unsupported_target_language_validation(self, sample_audio_upload): """Test validation with unsupported target language""" with pytest.raises(ValueError, match="Unsupported target language"): ProcessingRequestDto( audio=sample_audio_upload, asr_model="whisper-small", target_language="invalid-lang", voice="kokoro" ) def test_unsupported_source_language_validation(self, sample_audio_upload): """Test validation with unsupported source language""" with pytest.raises(ValueError, match="Unsupported source language"): ProcessingRequestDto( audio=sample_audio_upload, asr_model="whisper-small", target_language="es", voice="kokoro", source_language="invalid-lang" ) def test_supported_languages(self, sample_audio_upload): """Test all supported languages""" supported_languages = [ 'en', 'es', 'fr', 'de', 'it', 'pt', 'ru', 'ja', 'ko', 'zh', 'ar', 'hi', 'tr', 'pl', 'nl', 'sv', 'da', 'no', 'fi' ] for lang in supported_languages: # Should not raise exception dto = ProcessingRequestDto( audio=sample_audio_upload, asr_model="whisper-small", target_language=lang, voice="kokoro", source_language=lang ) assert dto.target_language == lang assert dto.source_language == lang def test_empty_voice_validation(self, sample_audio_upload): """Test validation with empty voice""" with pytest.raises(ValueError, match="Voice cannot be empty"): ProcessingRequestDto( audio=sample_audio_upload, asr_model="whisper-small", target_language="es", voice="" ) def test_unsupported_voice_validation(self, sample_audio_upload): """Test validation with unsupported voice""" with pytest.raises(ValueError, match="Unsupported voice"): ProcessingRequestDto( audio=sample_audio_upload, asr_model="whisper-small", target_language="es", voice="invalid-voice" ) def test_supported_voices(self, sample_audio_upload): """Test all supported voices""" supported_voices = ['kokoro', 'dia', 'cosyvoice2', 'dummy'] for voice in supported_voices: # Should not raise exception dto = ProcessingRequestDto( audio=sample_audio_upload, asr_model="whisper-small", target_language="es", voice=voice ) assert dto.voice == voice def test_speed_range_validation_too_low(self, sample_audio_upload): """Test validation with speed too low""" with pytest.raises(ValueError, match="Speed must be between 0.5 and 2.0"): ProcessingRequestDto( audio=sample_audio_upload, asr_model="whisper-small", target_language="es", voice="kokoro", speed=0.3 # Too low ) def test_speed_range_validation_too_high(self, sample_audio_upload): """Test validation with speed too high""" with pytest.raises(ValueError, match="Speed must be between 0.5 and 2.0"): ProcessingRequestDto( audio=sample_audio_upload, asr_model="whisper-small", target_language="es", voice="kokoro", speed=2.5 # Too high ) def test_valid_speed_range(self, sample_audio_upload): """Test valid speed range""" valid_speeds = [0.5, 1.0, 1.5, 2.0] for speed in valid_speeds: # Should not raise exception dto = ProcessingRequestDto( audio=sample_audio_upload, asr_model="whisper-small", target_language="es", voice="kokoro", speed=speed ) assert dto.speed == speed def test_invalid_additional_params_type(self, sample_audio_upload): """Test validation with invalid additional params type""" with pytest.raises(ValueError, match="Additional params must be a dictionary"): ProcessingRequestDto( audio=sample_audio_upload, asr_model="whisper-small", target_language="es", voice="kokoro", additional_params="invalid" # Not a dict ) def test_requires_translation_property_same_language(self, sample_audio_upload): """Test requires_translation property when source and target are same""" dto = ProcessingRequestDto( audio=sample_audio_upload, asr_model="whisper-small", target_language="en", voice="kokoro", source_language="en" ) assert dto.requires_translation is False def test_requires_translation_property_different_languages(self, sample_audio_upload): """Test requires_translation property when source and target are different""" dto = ProcessingRequestDto( audio=sample_audio_upload, asr_model="whisper-small", target_language="es", voice="kokoro", source_language="en" ) assert dto.requires_translation is True def test_requires_translation_property_no_source(self, sample_audio_upload): """Test requires_translation property when no source language specified""" dto = ProcessingRequestDto( audio=sample_audio_upload, asr_model="whisper-small", target_language="es", voice="kokoro" ) assert dto.requires_translation is True # Assume translation needed def test_to_dict_method(self, sample_audio_upload): """Test to_dict method""" dto = ProcessingRequestDto( audio=sample_audio_upload, asr_model="whisper-small", target_language="es", voice="kokoro", speed=1.5, source_language="en", additional_params={"custom": "value"} ) result = dto.to_dict() assert result['audio'] == sample_audio_upload.to_dict() assert result['asr_model'] == "whisper-small" assert result['target_language'] == "es" assert result['source_language'] == "en" assert result['voice'] == "kokoro" assert result['speed'] == 1.5 assert result['requires_translation'] is True assert result['additional_params'] == {"custom": "value"} def test_from_dict_method(self, sample_audio_upload): """Test from_dict class method""" data = { 'audio': sample_audio_upload, 'asr_model': 'whisper-medium', 'target_language': 'fr', 'voice': 'dia', 'speed': 1.2, 'source_language': 'en', 'additional_params': {'test': 'value'} } dto = ProcessingRequestDto.from_dict(data) assert dto.audio == sample_audio_upload assert dto.asr_model == 'whisper-medium' assert dto.target_language == 'fr' assert dto.voice == 'dia' assert dto.speed == 1.2 assert dto.source_language == 'en' assert dto.additional_params == {'test': 'value'} def test_from_dict_method_with_audio_dict(self): """Test from_dict method with audio as dictionary""" audio_data = { 'filename': 'test.wav', 'content': b'fake_content' + b'x' * 1000, 'content_type': 'audio/wav' } data = { 'audio': audio_data, 'asr_model': 'whisper-small', 'target_language': 'es', 'voice': 'kokoro' } dto = ProcessingRequestDto.from_dict(data) assert isinstance(dto.audio, AudioUploadDto) assert dto.audio.filename == 'test.wav' assert dto.audio.content_type == 'audio/wav' def test_from_dict_method_with_defaults(self, sample_audio_upload): """Test from_dict method with default values""" data = { 'audio': sample_audio_upload, 'asr_model': 'whisper-small', 'target_language': 'es', 'voice': 'kokoro' } dto = ProcessingRequestDto.from_dict(data) assert dto.speed == 1.0 # Default assert dto.source_language is None # Default assert dto.additional_params is None # Default def test_validation_called_on_init(self, sample_audio_upload): """Test that validation is called during initialization""" # This should trigger validation and raise an error with pytest.raises(ValueError): ProcessingRequestDto( audio=sample_audio_upload, asr_model="", # Invalid empty model target_language="es", voice="kokoro" ) def test_additional_params_default_initialization(self, sample_audio_upload): """Test that additional_params is initialized to empty dict if None""" dto = ProcessingRequestDto( audio=sample_audio_upload, asr_model="whisper-small", target_language="es", voice="kokoro", additional_params=None ) assert dto.additional_params == {}