Spaces:
Build error
Build error
"""Unit tests for AudioChunk value object.""" | |
import pytest | |
from src.domain.models.audio_chunk import AudioChunk | |
class TestAudioChunk: | |
"""Test cases for AudioChunk value object.""" | |
def test_valid_audio_chunk_creation(self): | |
"""Test creating valid AudioChunk instance.""" | |
chunk = AudioChunk( | |
data=b"fake_audio_chunk_data", | |
format="wav", | |
sample_rate=22050, | |
chunk_index=0, | |
is_final=False, | |
timestamp=1.5 | |
) | |
assert chunk.data == b"fake_audio_chunk_data" | |
assert chunk.format == "wav" | |
assert chunk.sample_rate == 22050 | |
assert chunk.chunk_index == 0 | |
assert chunk.is_final is False | |
assert chunk.timestamp == 1.5 | |
assert chunk.size_bytes == len(b"fake_audio_chunk_data") | |
def test_audio_chunk_with_defaults(self): | |
"""Test creating AudioChunk with default values.""" | |
chunk = AudioChunk( | |
data=b"fake_audio_chunk_data", | |
format="wav", | |
sample_rate=22050, | |
chunk_index=0 | |
) | |
assert chunk.is_final is False | |
assert chunk.timestamp is None | |
def test_final_chunk_creation(self): | |
"""Test creating final AudioChunk.""" | |
chunk = AudioChunk( | |
data=b"final_chunk_data", | |
format="wav", | |
sample_rate=22050, | |
chunk_index=5, | |
is_final=True | |
) | |
assert chunk.is_final is True | |
assert chunk.chunk_index == 5 | |
def test_non_bytes_data_raises_error(self): | |
"""Test that non-bytes data raises TypeError.""" | |
with pytest.raises(TypeError, match="Audio data must be bytes"): | |
AudioChunk( | |
data="not_bytes", # type: ignore | |
format="wav", | |
sample_rate=22050, | |
chunk_index=0 | |
) | |
def test_empty_data_raises_error(self): | |
"""Test that empty data raises ValueError.""" | |
with pytest.raises(ValueError, match="Audio data cannot be empty"): | |
AudioChunk( | |
data=b"", | |
format="wav", | |
sample_rate=22050, | |
chunk_index=0 | |
) | |
def test_unsupported_format_raises_error(self): | |
"""Test that unsupported format raises ValueError.""" | |
with pytest.raises(ValueError, match="Unsupported audio format: xyz"): | |
AudioChunk( | |
data=b"fake_data", | |
format="xyz", | |
sample_rate=22050, | |
chunk_index=0 | |
) | |
def test_supported_formats(self): | |
"""Test all supported audio formats.""" | |
supported_formats = ['wav', 'mp3', 'flac', 'ogg', 'raw'] | |
for fmt in supported_formats: | |
chunk = AudioChunk( | |
data=b"fake_data", | |
format=fmt, | |
sample_rate=22050, | |
chunk_index=0 | |
) | |
assert chunk.format == fmt | |
def test_non_integer_sample_rate_raises_error(self): | |
"""Test that non-integer sample rate raises ValueError.""" | |
with pytest.raises(ValueError, match="Sample rate must be a positive integer"): | |
AudioChunk( | |
data=b"fake_data", | |
format="wav", | |
sample_rate=22050.5, # type: ignore | |
chunk_index=0 | |
) | |
def test_negative_sample_rate_raises_error(self): | |
"""Test that negative sample rate raises ValueError.""" | |
with pytest.raises(ValueError, match="Sample rate must be a positive integer"): | |
AudioChunk( | |
data=b"fake_data", | |
format="wav", | |
sample_rate=-1, | |
chunk_index=0 | |
) | |
def test_zero_sample_rate_raises_error(self): | |
"""Test that zero sample rate raises ValueError.""" | |
with pytest.raises(ValueError, match="Sample rate must be a positive integer"): | |
AudioChunk( | |
data=b"fake_data", | |
format="wav", | |
sample_rate=0, | |
chunk_index=0 | |
) | |
def test_non_integer_chunk_index_raises_error(self): | |
"""Test that non-integer chunk index raises ValueError.""" | |
with pytest.raises(ValueError, match="Chunk index must be a non-negative integer"): | |
AudioChunk( | |
data=b"fake_data", | |
format="wav", | |
sample_rate=22050, | |
chunk_index=1.5 # type: ignore | |
) | |
def test_negative_chunk_index_raises_error(self): | |
"""Test that negative chunk index raises ValueError.""" | |
with pytest.raises(ValueError, match="Chunk index must be a non-negative integer"): | |
AudioChunk( | |
data=b"fake_data", | |
format="wav", | |
sample_rate=22050, | |
chunk_index=-1 | |
) | |
def test_valid_chunk_index_zero(self): | |
"""Test that chunk index of zero is valid.""" | |
chunk = AudioChunk( | |
data=b"fake_data", | |
format="wav", | |
sample_rate=22050, | |
chunk_index=0 | |
) | |
assert chunk.chunk_index == 0 | |
def test_non_boolean_is_final_raises_error(self): | |
"""Test that non-boolean is_final raises TypeError.""" | |
with pytest.raises(TypeError, match="is_final must be a boolean"): | |
AudioChunk( | |
data=b"fake_data", | |
format="wav", | |
sample_rate=22050, | |
chunk_index=0, | |
is_final="true" # type: ignore | |
) | |
def test_non_numeric_timestamp_raises_error(self): | |
"""Test that non-numeric timestamp raises ValueError.""" | |
with pytest.raises(ValueError, match="Timestamp must be a non-negative number"): | |
AudioChunk( | |
data=b"fake_data", | |
format="wav", | |
sample_rate=22050, | |
chunk_index=0, | |
timestamp="1.5" # type: ignore | |
) | |
def test_negative_timestamp_raises_error(self): | |
"""Test that negative timestamp raises ValueError.""" | |
with pytest.raises(ValueError, match="Timestamp must be a non-negative number"): | |
AudioChunk( | |
data=b"fake_data", | |
format="wav", | |
sample_rate=22050, | |
chunk_index=0, | |
timestamp=-1.0 | |
) | |
def test_valid_timestamp_zero(self): | |
"""Test that timestamp of zero is valid.""" | |
chunk = AudioChunk( | |
data=b"fake_data", | |
format="wav", | |
sample_rate=22050, | |
chunk_index=0, | |
timestamp=0.0 | |
) | |
assert chunk.timestamp == 0.0 | |
def test_valid_timestamp_values(self): | |
"""Test valid timestamp values.""" | |
valid_timestamps = [0.0, 1.5, 10, 100.123] | |
for timestamp in valid_timestamps: | |
chunk = AudioChunk( | |
data=b"fake_data", | |
format="wav", | |
sample_rate=22050, | |
chunk_index=0, | |
timestamp=timestamp | |
) | |
assert chunk.timestamp == timestamp | |
def test_size_bytes_property(self): | |
"""Test size_bytes property returns correct value.""" | |
test_data = b"test_audio_chunk_data_123" | |
chunk = AudioChunk( | |
data=test_data, | |
format="wav", | |
sample_rate=22050, | |
chunk_index=0 | |
) | |
assert chunk.size_bytes == len(test_data) | |
def test_duration_estimate_property(self): | |
"""Test duration_estimate property calculation.""" | |
# Create chunk with known data size | |
test_data = b"x" * 44100 # 44100 bytes | |
chunk = AudioChunk( | |
data=test_data, | |
format="wav", | |
sample_rate=22050, # 22050 samples per second | |
chunk_index=0 | |
) | |
# Expected duration: 44100 bytes / (22050 samples/sec * 2 bytes/sample) = 1.0 second | |
expected_duration = 44100 / (22050 * 2) | |
assert abs(chunk.duration_estimate - expected_duration) < 0.01 | |
def test_duration_estimate_with_zero_sample_rate(self): | |
"""Test duration_estimate with edge case of zero calculation.""" | |
# This shouldn't happen due to validation, but test the property logic | |
chunk = AudioChunk( | |
data=b"test_data", | |
format="wav", | |
sample_rate=22050, | |
chunk_index=0 | |
) | |
# Should return a reasonable estimate | |
assert chunk.duration_estimate >= 0 | |
def test_audio_chunk_is_immutable(self): | |
"""Test that AudioChunk is immutable (frozen dataclass).""" | |
chunk = AudioChunk( | |
data=b"fake_data", | |
format="wav", | |
sample_rate=22050, | |
chunk_index=0 | |
) | |
with pytest.raises(AttributeError): | |
chunk.format = "mp3" # type: ignore | |
def test_chunk_sequence_ordering(self): | |
"""Test that chunks can be ordered by chunk_index.""" | |
chunks = [ | |
AudioChunk(data=b"chunk2", format="wav", sample_rate=22050, chunk_index=2), | |
AudioChunk(data=b"chunk0", format="wav", sample_rate=22050, chunk_index=0), | |
AudioChunk(data=b"chunk1", format="wav", sample_rate=22050, chunk_index=1), | |
] | |
# Sort by chunk_index | |
sorted_chunks = sorted(chunks, key=lambda c: c.chunk_index) | |
assert sorted_chunks[0].chunk_index == 0 | |
assert sorted_chunks[1].chunk_index == 1 | |
assert sorted_chunks[2].chunk_index == 2 | |
def test_streaming_scenario(self): | |
"""Test typical streaming scenario with multiple chunks.""" | |
# First chunk | |
chunk1 = AudioChunk( | |
data=b"first_chunk_data", | |
format="wav", | |
sample_rate=22050, | |
chunk_index=0, | |
is_final=False, | |
timestamp=0.0 | |
) | |
# Middle chunk | |
chunk2 = AudioChunk( | |
data=b"middle_chunk_data", | |
format="wav", | |
sample_rate=22050, | |
chunk_index=1, | |
is_final=False, | |
timestamp=1.0 | |
) | |
# Final chunk | |
chunk3 = AudioChunk( | |
data=b"final_chunk_data", | |
format="wav", | |
sample_rate=22050, | |
chunk_index=2, | |
is_final=True, | |
timestamp=2.0 | |
) | |
assert not chunk1.is_final | |
assert not chunk2.is_final | |
assert chunk3.is_final | |
# Verify ordering | |
chunks = [chunk1, chunk2, chunk3] | |
for i, chunk in enumerate(chunks): | |
assert chunk.chunk_index == i | |
assert chunk.timestamp == float(i) |