Spaces:
Build error
Build error
File size: 9,653 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 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 |
"""Unit tests for ISpeechRecognitionService interface contract."""
import pytest
from abc import ABC
from unittest.mock import Mock
from src.domain.interfaces.speech_recognition import ISpeechRecognitionService
from src.domain.models.audio_content import AudioContent
from src.domain.models.text_content import TextContent
class TestISpeechRecognitionService:
"""Test cases for ISpeechRecognitionService interface contract."""
def test_interface_is_abstract(self):
"""Test that ISpeechRecognitionService is an abstract base class."""
assert issubclass(ISpeechRecognitionService, ABC)
# Should not be able to instantiate directly
with pytest.raises(TypeError):
ISpeechRecognitionService() # 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(ISpeechRecognitionService, 'transcribe')
assert getattr(ISpeechRecognitionService.transcribe, '__isabstractmethod__', False)
def test_method_signature(self):
"""Test that the method has the correct signature."""
import inspect
method = ISpeechRecognitionService.transcribe
signature = inspect.signature(method)
# Check parameter names
params = list(signature.parameters.keys())
expected_params = ['self', 'audio', 'model']
assert params == expected_params
# Check return annotation
assert signature.return_annotation == "'TextContent'"
def test_concrete_implementation_must_implement_method(self):
"""Test that concrete implementations must implement the abstract method."""
class IncompleteImplementation(ISpeechRecognitionService):
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(ISpeechRecognitionService):
def transcribe(self, audio, model):
return TextContent(text="transcribed text", language="en")
# Should be able to instantiate
implementation = ConcreteImplementation()
assert isinstance(implementation, ISpeechRecognitionService)
def test_method_contract_with_mock(self):
"""Test the method contract using a mock implementation."""
class MockImplementation(ISpeechRecognitionService):
def __init__(self):
self.mock_method = Mock()
def transcribe(self, audio, model):
return self.mock_method(audio, model)
# Create test data
audio = AudioContent(
data=b"test_audio",
format="wav",
sample_rate=22050,
duration=5.0
)
model = "whisper-base"
expected_result = TextContent(text="Hello world", language="en")
# Setup mock
implementation = MockImplementation()
implementation.mock_method.return_value = expected_result
# Call method
result = implementation.transcribe(audio=audio, model=model)
# Verify call and result
implementation.mock_method.assert_called_once_with(audio, model)
assert result == expected_result
def test_interface_docstring_requirements(self):
"""Test that the interface method has proper documentation."""
method = ISpeechRecognitionService.transcribe
assert method.__doc__ is not None
docstring = method.__doc__
# Check that docstring contains key information
assert "Transcribe audio content to text" in docstring
assert "Args:" in docstring
assert "Returns:" in docstring
assert "Raises:" in docstring
assert "SpeechRecognitionException" in docstring
def test_interface_type_hints(self):
"""Test that the interface uses proper type hints."""
method = ISpeechRecognitionService.transcribe
annotations = getattr(method, '__annotations__', {})
assert 'audio' in annotations
assert 'model' in annotations
assert 'return' in annotations
# Check that type annotations are correct
assert annotations['audio'] == "'AudioContent'"
assert annotations['model'] == str
assert annotations['return'] == "'TextContent'"
def test_multiple_implementations_possible(self):
"""Test that multiple implementations of the interface are possible."""
class WhisperImplementation(ISpeechRecognitionService):
def transcribe(self, audio, model):
return TextContent(text="whisper transcription", language="en")
class ParakeetImplementation(ISpeechRecognitionService):
def transcribe(self, audio, model):
return TextContent(text="parakeet transcription", language="en")
whisper = WhisperImplementation()
parakeet = ParakeetImplementation()
assert isinstance(whisper, ISpeechRecognitionService)
assert isinstance(parakeet, ISpeechRecognitionService)
assert type(whisper) != type(parakeet)
def test_interface_method_can_be_called_polymorphically(self):
"""Test that interface methods can be called polymorphically."""
class TestImplementation(ISpeechRecognitionService):
def __init__(self, transcription_text):
self.transcription_text = transcription_text
def transcribe(self, audio, model):
return TextContent(text=self.transcription_text, language="en")
# Create different implementations
implementations = [
TestImplementation("first transcription"),
TestImplementation("second transcription")
]
# Test polymorphic usage
audio = AudioContent(data=b"test", format="wav", sample_rate=22050, duration=1.0)
model = "test-model"
results = []
for impl in implementations:
# Can call the same method on different implementations
result = impl.transcribe(audio, model)
results.append(result.text)
assert results == ["first transcription", "second transcription"]
def test_interface_inheritance_chain(self):
"""Test the inheritance chain of the interface."""
# Check that it inherits from ABC
assert ABC in ISpeechRecognitionService.__mro__
# Check that it's at the right position in MRO
mro = ISpeechRecognitionService.__mro__
assert mro[0] == ISpeechRecognitionService
assert ABC in mro
def test_method_parameter_validation_in_implementation(self):
"""Test that implementations can validate parameters."""
class ValidatingImplementation(ISpeechRecognitionService):
def transcribe(self, audio, model):
if not isinstance(audio, AudioContent):
raise TypeError("audio must be AudioContent")
if not isinstance(model, str):
raise TypeError("model must be string")
if not model.strip():
raise ValueError("model cannot be empty")
return TextContent(text="validated transcription", language="en")
impl = ValidatingImplementation()
# Valid call should work
audio = AudioContent(data=b"test", format="wav", sample_rate=22050, duration=1.0)
result = impl.transcribe(audio, "whisper-base")
assert result.text == "validated transcription"
# Invalid calls should raise appropriate errors
with pytest.raises(TypeError, match="audio must be AudioContent"):
impl.transcribe("not audio", "whisper-base") # type: ignore
with pytest.raises(TypeError, match="model must be string"):
impl.transcribe(audio, 123) # type: ignore
with pytest.raises(ValueError, match="model cannot be empty"):
impl.transcribe(audio, "")
def test_implementation_can_handle_different_models(self):
"""Test that implementations can handle different model types."""
class MultiModelImplementation(ISpeechRecognitionService):
def transcribe(self, audio, model):
model_responses = {
"whisper-tiny": "tiny transcription",
"whisper-base": "base transcription",
"whisper-large": "large transcription",
"parakeet": "parakeet transcription"
}
transcription = model_responses.get(model, "unknown model transcription")
return TextContent(text=transcription, language="en")
impl = MultiModelImplementation()
audio = AudioContent(data=b"test", format="wav", sample_rate=22050, duration=1.0)
# Test different models
models_and_expected = [
("whisper-tiny", "tiny transcription"),
("whisper-base", "base transcription"),
("whisper-large", "large transcription"),
("parakeet", "parakeet transcription"),
("unknown-model", "unknown model transcription")
]
for model, expected_text in models_and_expected:
result = impl.transcribe(audio, model)
assert result.text == expected_text
assert result.language == "en" |