Spaces:
Build error
Build error
File size: 8,511 Bytes
48f8a08 |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 |
"""Unit tests for IAudioProcessingService interface contract."""
import pytest
from abc import ABC
from unittest.mock import Mock
from src.domain.interfaces.audio_processing import IAudioProcessingService
from src.domain.models.audio_content import AudioContent
from src.domain.models.voice_settings import VoiceSettings
from src.domain.models.processing_result import ProcessingResult
from src.domain.models.text_content import TextContent
class TestIAudioProcessingService:
"""Test cases for IAudioProcessingService interface contract."""
def test_interface_is_abstract(self):
"""Test that IAudioProcessingService is an abstract base class."""
assert issubclass(IAudioProcessingService, ABC)
# Should not be able to instantiate directly
with pytest.raises(TypeError):
IAudioProcessingService() # type: ignore
def test_interface_has_required_method(self):
"""Test that interface defines the required abstract method."""
# Check that the method exists and is abstract
assert hasattr(IAudioProcessingService, 'process_audio_pipeline')
assert getattr(IAudioProcessingService.process_audio_pipeline, '__isabstractmethod__', False)
def test_method_signature(self):
"""Test that the method has the correct signature."""
import inspect
method = IAudioProcessingService.process_audio_pipeline
signature = inspect.signature(method)
# Check parameter names and types
params = list(signature.parameters.keys())
expected_params = ['self', 'audio', 'target_language', 'voice_settings']
assert params == expected_params
# Check return annotation
assert signature.return_annotation == "'ProcessingResult'"
def test_concrete_implementation_must_implement_method(self):
"""Test that concrete implementations must implement the abstract method."""
class IncompleteImplementation(IAudioProcessingService):
pass
# Should not be able to instantiate without implementing abstract method
with pytest.raises(TypeError, match="Can't instantiate abstract class"):
IncompleteImplementation() # type: ignore
def test_concrete_implementation_with_method(self):
"""Test that concrete implementation with method can be instantiated."""
class ConcreteImplementation(IAudioProcessingService):
def process_audio_pipeline(self, audio, target_language, voice_settings):
return ProcessingResult.success_result(
original_text=TextContent(text="test", language="en")
)
# Should be able to instantiate
implementation = ConcreteImplementation()
assert isinstance(implementation, IAudioProcessingService)
def test_method_contract_with_mock(self):
"""Test the method contract using a mock implementation."""
class MockImplementation(IAudioProcessingService):
def __init__(self):
self.mock_method = Mock()
def process_audio_pipeline(self, audio, target_language, voice_settings):
return self.mock_method(audio, target_language, voice_settings)
# Create test data
audio = AudioContent(
data=b"test_audio",
format="wav",
sample_rate=22050,
duration=5.0
)
voice_settings = VoiceSettings(
voice_id="test_voice",
speed=1.0,
language="es"
)
expected_result = ProcessingResult.success_result(
original_text=TextContent(text="test", language="en")
)
# Setup mock
implementation = MockImplementation()
implementation.mock_method.return_value = expected_result
# Call method
result = implementation.process_audio_pipeline(
audio=audio,
target_language="es",
voice_settings=voice_settings
)
# Verify call and result
implementation.mock_method.assert_called_once_with(audio, "es", voice_settings)
assert result == expected_result
def test_interface_docstring_requirements(self):
"""Test that the interface method has proper documentation."""
method = IAudioProcessingService.process_audio_pipeline
assert method.__doc__ is not None
docstring = method.__doc__
# Check that docstring contains key information
assert "Process audio through the complete pipeline" in docstring
assert "STT -> Translation -> TTS" in docstring
assert "Args:" in docstring
assert "Returns:" in docstring
assert "Raises:" in docstring
assert "AudioProcessingException" in docstring
def test_interface_type_hints(self):
"""Test that the interface uses proper type hints."""
import inspect
from typing import get_type_hints
# Get type hints (this will resolve string annotations)
try:
hints = get_type_hints(IAudioProcessingService.process_audio_pipeline)
except NameError:
# If forward references can't be resolved, check annotations directly
method = IAudioProcessingService.process_audio_pipeline
annotations = getattr(method, '__annotations__', {})
assert 'audio' in annotations
assert 'target_language' in annotations
assert 'voice_settings' in annotations
assert 'return' in annotations
# Check that type annotations are strings (forward references)
assert annotations['audio'] == "'AudioContent'"
assert annotations['target_language'] == str
assert annotations['voice_settings'] == "'VoiceSettings'"
assert annotations['return'] == "'ProcessingResult'"
def test_multiple_implementations_possible(self):
"""Test that multiple implementations of the interface are possible."""
class Implementation1(IAudioProcessingService):
def process_audio_pipeline(self, audio, target_language, voice_settings):
return ProcessingResult.success_result(
original_text=TextContent(text="impl1", language="en")
)
class Implementation2(IAudioProcessingService):
def process_audio_pipeline(self, audio, target_language, voice_settings):
return ProcessingResult.failure_result(error_message="impl2 failed")
impl1 = Implementation1()
impl2 = Implementation2()
assert isinstance(impl1, IAudioProcessingService)
assert isinstance(impl2, IAudioProcessingService)
assert type(impl1) != type(impl2)
def test_interface_method_can_be_called_polymorphically(self):
"""Test that interface methods can be called polymorphically."""
class TestImplementation(IAudioProcessingService):
def __init__(self, result):
self.result = result
def process_audio_pipeline(self, audio, target_language, voice_settings):
return self.result
# Create different implementations
success_result = ProcessingResult.success_result(
original_text=TextContent(text="success", language="en")
)
failure_result = ProcessingResult.failure_result(error_message="failed")
implementations = [
TestImplementation(success_result),
TestImplementation(failure_result)
]
# Test polymorphic usage
audio = AudioContent(data=b"test", format="wav", sample_rate=22050, duration=1.0)
voice_settings = VoiceSettings(voice_id="test", speed=1.0, language="en")
results = []
for impl in implementations:
# Can call the same method on different implementations
result = impl.process_audio_pipeline(audio, "en", voice_settings)
results.append(result)
assert len(results) == 2
assert results[0].success is True
assert results[1].success is False
def test_interface_inheritance_chain(self):
"""Test the inheritance chain of the interface."""
# Check that it inherits from ABC
assert ABC in IAudioProcessingService.__mro__
# Check that it's at the right position in MRO
mro = IAudioProcessingService.__mro__
assert mro[0] == IAudioProcessingService
assert ABC in mro |