teachingAssistant / tests /unit /application /dtos /test_processing_request_dto.py
Michael Hu
Create unit tests for application layer
acd758a
"""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 == {}