Spaces:
Build error
Build error
File size: 13,936 Bytes
5009cb8 48f8a08 5009cb8 48f8a08 5009cb8 48f8a08 5009cb8 48f8a08 5009cb8 48f8a08 5009cb8 48f8a08 5009cb8 48f8a08 5009cb8 48f8a08 5009cb8 48f8a08 5009cb8 48f8a08 5009cb8 48f8a08 5009cb8 48f8a08 5009cb8 48f8a08 5009cb8 48f8a08 5009cb8 48f8a08 5009cb8 48f8a08 5009cb8 48f8a08 5009cb8 48f8a08 5009cb8 48f8a08 5009cb8 48f8a08 5009cb8 48f8a08 5009cb8 48f8a08 5009cb8 48f8a08 5009cb8 48f8a08 5009cb8 48f8a08 5009cb8 48f8a08 5009cb8 48f8a08 5009cb8 48f8a08 5009cb8 48f8a08 5009cb8 48f8a08 5009cb8 48f8a08 5009cb8 48f8a08 5009cb8 48f8a08 5009cb8 48f8a08 5009cb8 48f8a08 5009cb8 48f8a08 5009cb8 48f8a08 5009cb8 48f8a08 5009cb8 48f8a08 5009cb8 48f8a08 5009cb8 48f8a08 5009cb8 48f8a08 5009cb8 48f8a08 5009cb8 48f8a08 5009cb8 48f8a08 5009cb8 48f8a08 5009cb8 48f8a08 5009cb8 48f8a08 5009cb8 48f8a08 5009cb8 48f8a08 5009cb8 48f8a08 5009cb8 48f8a08 5009cb8 48f8a08 5009cb8 48f8a08 5009cb8 48f8a08 5009cb8 48f8a08 5009cb8 48f8a08 5009cb8 48f8a08 5009cb8 48f8a08 5009cb8 48f8a08 5009cb8 48f8a08 5009cb8 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 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 |
"""Unit tests for SpeechSynthesisRequest value object."""
import pytest
from src.domain.models.speech_synthesis_request import SpeechSynthesisRequest
from src.domain.models.text_content import TextContent
from src.domain.models.voice_settings import VoiceSettings
class TestSpeechSynthesisRequest:
"""Test cases for SpeechSynthesisRequest value object."""
@pytest.fixture
def sample_text_content(self):
"""Sample text content for testing."""
return TextContent(
text="Hello, world!",
language="en"
)
@pytest.fixture
def sample_voice_settings(self):
"""Sample voice settings for testing."""
return VoiceSettings(
voice_id="en_male_001",
speed=1.0,
language="en"
)
def test_valid_speech_synthesis_request_creation(self, sample_text_content, sample_voice_settings):
"""Test creating valid SpeechSynthesisRequest instance."""
request = SpeechSynthesisRequest(
text_content=sample_text_content,
voice_settings=sample_voice_settings,
output_format="wav",
sample_rate=22050
)
assert request.text_content == sample_text_content
assert request.voice_settings == sample_voice_settings
assert request.output_format == "wav"
assert request.sample_rate == 22050
assert request.effective_sample_rate == 22050
def test_speech_synthesis_request_with_defaults(self, sample_text_content, sample_voice_settings):
"""Test creating SpeechSynthesisRequest with default values."""
request = SpeechSynthesisRequest(
text_content=sample_text_content,
voice_settings=sample_voice_settings
)
assert request.output_format == "wav"
assert request.sample_rate is None
assert request.effective_sample_rate == 22050 # Default
def test_non_text_content_raises_error(self, sample_voice_settings):
"""Test that non-TextContent raises TypeError."""
with pytest.raises(TypeError, match="Text must be a TextContent instance"):
SpeechSynthesisRequest(
text_content="not a TextContent", # type: ignore
voice_settings=sample_voice_settings
)
def test_non_voice_settings_raises_error(self, sample_text_content):
"""Test that non-VoiceSettings raises TypeError."""
with pytest.raises(TypeError, match="Voice settings must be a VoiceSettings instance"):
SpeechSynthesisRequest(
text_content=sample_text_content,
voice_settings="not voice settings" # type: ignore
)
def test_non_string_output_format_raises_error(self, sample_text_content, sample_voice_settings):
"""Test that non-string output format raises TypeError."""
with pytest.raises(TypeError, match="Output format must be a string"):
SpeechSynthesisRequest(
text_content=sample_text_content,
voice_settings=sample_voice_settings,
output_format=123 # type: ignore
)
def test_unsupported_output_format_raises_error(self, sample_text_content, sample_voice_settings):
"""Test that unsupported output format raises ValueError."""
with pytest.raises(ValueError, match="Unsupported output format: xyz"):
SpeechSynthesisRequest(
text_content=sample_text_content,
voice_settings=sample_voice_settings,
output_format="xyz"
)
def test_supported_output_formats(self, sample_text_content, sample_voice_settings):
"""Test all supported output formats."""
supported_formats = ['wav', 'mp3', 'flac', 'ogg']
for fmt in supported_formats:
request = SpeechSynthesisRequest(
text_content=sample_text_content,
voice_settings=sample_voice_settings,
output_format=fmt
)
assert request.output_format == fmt
def test_non_integer_sample_rate_raises_error(self, sample_text_content, sample_voice_settings):
"""Test that non-integer sample rate raises TypeError."""
with pytest.raises(TypeError, match="Sample rate must be an integer"):
SpeechSynthesisRequest(
text_content=sample_text_content,
voice_settings=sample_voice_settings,
sample_rate=22050.5 # type: ignore
)
def test_negative_sample_rate_raises_error(self, sample_text_content, sample_voice_settings):
"""Test that negative sample rate raises ValueError."""
with pytest.raises(ValueError, match="Sample rate must be positive"):
SpeechSynthesisRequest(
text_content=sample_text_content,
voice_settings=sample_voice_settings,
sample_rate=-1
)
def test_zero_sample_rate_raises_error(self, sample_text_content, sample_voice_settings):
"""Test that zero sample rate raises ValueError."""
with pytest.raises(ValueError, match="Sample rate must be positive"):
SpeechSynthesisRequest(
text_content=sample_text_content,
voice_settings=sample_voice_settings,
sample_rate=0
)
def test_sample_rate_too_low_raises_error(self, sample_text_content, sample_voice_settings):
"""Test that sample rate below 8000 raises ValueError."""
with pytest.raises(ValueError, match="Sample rate must be between 8000 and 192000 Hz"):
SpeechSynthesisRequest(
text_content=sample_text_content,
voice_settings=sample_voice_settings,
sample_rate=7999
)
def test_sample_rate_too_high_raises_error(self, sample_text_content, sample_voice_settings):
"""Test that sample rate above 192000 raises ValueError."""
with pytest.raises(ValueError, match="Sample rate must be between 8000 and 192000 Hz"):
SpeechSynthesisRequest(
text_content=sample_text_content,
voice_settings=sample_voice_settings,
sample_rate=192001
)
def test_valid_sample_rate_boundaries(self, sample_text_content, sample_voice_settings):
"""Test valid sample rate boundaries."""
# Test minimum valid sample rate
request_min = SpeechSynthesisRequest(
text_content=sample_text_content,
voice_settings=sample_voice_settings,
sample_rate=8000
)
assert request_min.sample_rate == 8000
# Test maximum valid sample rate
request_max = SpeechSynthesisRequest(
text_content=sample_text_content,
voice_settings=sample_voice_settings,
sample_rate=192000
)
assert request_max.sample_rate == 192000
def test_language_mismatch_raises_error(self, sample_voice_settings):
"""Test that language mismatch between text and voice raises ValueError."""
text_content = TextContent(text="Hola mundo", language="es")
with pytest.raises(ValueError, match="Text language \\(es\\) must match voice language \\(en\\)"):
SpeechSynthesisRequest(
text_content=text_content,
voice_settings=sample_voice_settings # language="en"
)
def test_matching_languages_success(self):
"""Test that matching languages between text and voice works."""
text_content = TextContent(text="Hola mundo", language="es")
voice_settings = VoiceSettings(voice_id="es_female_001", speed=1.0, language="es")
request = SpeechSynthesisRequest(
text_content=text_content,
voice_settings=voice_settings
)
assert request.text_content.language == request.voice_settings.language
def test_estimated_duration_seconds_property(self, sample_text_content, sample_voice_settings):
"""Test estimated_duration_seconds property calculation."""
request = SpeechSynthesisRequest(
text_content=sample_text_content,
voice_settings=sample_voice_settings
)
# Should be based on word count and speed
expected_duration = (sample_text_content.word_count / (175 / sample_voice_settings.speed)) * 60
assert abs(request.estimated_duration_seconds - expected_duration) < 0.01
def test_estimated_duration_with_different_speed(self, sample_text_content):
"""Test estimated duration with different speech speed."""
fast_voice = VoiceSettings(voice_id="test", speed=2.0, language="en")
slow_voice = VoiceSettings(voice_id="test", speed=0.5, language="en")
fast_request = SpeechSynthesisRequest(
text_content=sample_text_content,
voice_settings=fast_voice
)
slow_request = SpeechSynthesisRequest(
text_content=sample_text_content,
voice_settings=slow_voice
)
# Faster speed should result in shorter duration
assert fast_request.estimated_duration_seconds < slow_request.estimated_duration_seconds
def test_is_long_text_property(self, sample_voice_settings):
"""Test is_long_text property."""
# Short text
short_text = TextContent(text="Hello", language="en")
short_request = SpeechSynthesisRequest(
text_content=short_text,
voice_settings=sample_voice_settings
)
assert short_request.is_long_text is False
# Long text (over 5000 characters)
long_text = TextContent(text="a" * 5001, language="en")
long_request = SpeechSynthesisRequest(
text_content=long_text,
voice_settings=sample_voice_settings
)
assert long_request.is_long_text is True
def test_with_output_format_method(self, sample_text_content, sample_voice_settings):
"""Test with_output_format method creates new instance."""
original = SpeechSynthesisRequest(
text_content=sample_text_content,
voice_settings=sample_voice_settings,
output_format="wav",
sample_rate=22050
)
new_request = original.with_output_format("mp3")
assert new_request.output_format == "mp3"
assert new_request.text_content == original.text_content
assert new_request.voice_settings == original.voice_settings
assert new_request.sample_rate == original.sample_rate
assert new_request is not original # Different instances
def test_with_sample_rate_method(self, sample_text_content, sample_voice_settings):
"""Test with_sample_rate method creates new instance."""
original = SpeechSynthesisRequest(
text_content=sample_text_content,
voice_settings=sample_voice_settings,
sample_rate=22050
)
new_request = original.with_sample_rate(44100)
assert new_request.sample_rate == 44100
assert new_request.text_content == original.text_content
assert new_request.voice_settings == original.voice_settings
assert new_request.output_format == original.output_format
assert new_request is not original # Different instances
def test_with_sample_rate_none(self, sample_text_content, sample_voice_settings):
"""Test with_sample_rate method with None value."""
original = SpeechSynthesisRequest(
text_content=sample_text_content,
voice_settings=sample_voice_settings,
sample_rate=22050
)
new_request = original.with_sample_rate(None)
assert new_request.sample_rate is None
assert new_request.effective_sample_rate == 22050 # Default
def test_with_voice_settings_method(self, sample_text_content, sample_voice_settings):
"""Test with_voice_settings method creates new instance."""
new_voice_settings = VoiceSettings(voice_id="en_female_001", speed=1.5, language="en")
original = SpeechSynthesisRequest(
text_content=sample_text_content,
voice_settings=sample_voice_settings
)
new_request = original.with_voice_settings(new_voice_settings)
assert new_request.voice_settings == new_voice_settings
assert new_request.text_content == original.text_content
assert new_request.output_format == original.output_format
assert new_request.sample_rate == original.sample_rate
assert new_request is not original # Different instances
def test_speech_synthesis_request_is_immutable(self, sample_text_content, sample_voice_settings):
"""Test that SpeechSynthesisRequest is immutable (frozen dataclass)."""
request = SpeechSynthesisRequest(
text_content=sample_text_content,
voice_settings=sample_voice_settings
)
with pytest.raises(AttributeError):
request.output_format = "mp3" # type: ignore
def test_effective_sample_rate_with_none(self, sample_text_content, sample_voice_settings):
"""Test effective_sample_rate when sample_rate is None."""
request = SpeechSynthesisRequest(
text_content=sample_text_content,
voice_settings=sample_voice_settings,
sample_rate=None
)
assert request.effective_sample_rate == 22050 # Default value
def test_effective_sample_rate_with_value(self, sample_text_content, sample_voice_settings):
"""Test effective_sample_rate when sample_rate has a value."""
request = SpeechSynthesisRequest(
text_content=sample_text_content,
voice_settings=sample_voice_settings,
sample_rate=44100
)
assert request.effective_sample_rate == 44100 |