Skip to content

Commit 1bfe28a

Browse files
committed
Add tests
1 parent cdab897 commit 1bfe28a

1 file changed

Lines changed: 81 additions & 0 deletions

File tree

tests/test_music_multipart.py

Lines changed: 81 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,81 @@
1+
import json
2+
3+
import pytest
4+
5+
from elevenlabs.music_custom import MusicClient, _find_audio_start
6+
7+
SAMPLE_JSON = {"compositionPlan": {"sections": []}, "songMetadata": {"title": "Test"}}
8+
SAMPLE_AUDIO = bytes(range(256)) * 4
9+
10+
11+
def _build_multipart(line_ending: bytes) -> bytes:
12+
"""Build a realistic multipart response with the given line ending."""
13+
boundary = b"--boundary123"
14+
nl = line_ending
15+
16+
parts = []
17+
parts.append(boundary + nl)
18+
parts.append(b"Content-Type: application/json" + nl)
19+
parts.append(nl)
20+
parts.append(json.dumps(SAMPLE_JSON).encode("utf-8") + nl)
21+
parts.append(boundary + nl)
22+
parts.append(b"Content-Type: audio/mpeg" + nl)
23+
parts.append(b'Content-Disposition: attachment; filename="test_song.mp3"' + nl)
24+
parts.append(nl)
25+
parts.append(SAMPLE_AUDIO)
26+
parts.append(nl + boundary + b"--" + nl)
27+
28+
return b"".join(parts)
29+
30+
31+
class TestFindAudioStart:
32+
def test_crlf(self):
33+
data = b"Header: value\r\n\r\naudio data here"
34+
assert _find_audio_start(data, 0) == data.index(b"audio")
35+
36+
def test_lf(self):
37+
data = b"Header: value\n\naudio data here"
38+
assert _find_audio_start(data, 0) == data.index(b"audio")
39+
40+
def test_crlf_preferred_over_lf(self):
41+
data = b"Header: value\r\n\r\naudio data here"
42+
pos = _find_audio_start(data, 0)
43+
assert data[pos : pos + 5] == b"audio"
44+
45+
def test_raises_when_no_separator(self):
46+
with pytest.raises(ValueError, match="header/body separator"):
47+
_find_audio_start(b"no blank line here", 0)
48+
49+
def test_start_offset_respected(self):
50+
data = b"skip\n\nHeader: value\r\n\r\naudio"
51+
pos = _find_audio_start(data, 6)
52+
assert data[pos : pos + 5] == b"audio"
53+
54+
55+
class TestParseMultipart:
56+
@staticmethod
57+
def _parse(data: bytes):
58+
return MusicClient._parse_multipart(None, iter([data])) # type: ignore[arg-type]
59+
60+
def test_crlf_line_endings(self):
61+
data = _build_multipart(b"\r\n")
62+
result = self._parse(data)
63+
assert result.audio.startswith(SAMPLE_AUDIO)
64+
assert result.json == SAMPLE_JSON
65+
assert result.filename == "test_song.mp3"
66+
67+
def test_lf_line_endings(self):
68+
data = _build_multipart(b"\n")
69+
result = self._parse(data)
70+
assert result.audio.startswith(SAMPLE_AUDIO)
71+
assert result.json == SAMPLE_JSON
72+
assert result.filename == "test_song.mp3"
73+
74+
def test_audio_bytes_not_corrupted(self):
75+
for nl in [b"\r\n", b"\n"]:
76+
data = _build_multipart(nl)
77+
result = self._parse(data)
78+
assert result.audio[:4] == SAMPLE_AUDIO[:4], (
79+
f"First 4 bytes mismatch with {nl!r} line endings — possible byte offset error"
80+
)
81+
assert result.audio[: len(SAMPLE_AUDIO)] == SAMPLE_AUDIO

0 commit comments

Comments
 (0)