You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
RedditVideoMakerBot/tests/test_cambai.py

146 lines
6.0 KiB

import os
import tempfile
import pytest
from unittest.mock import patch, Mock, MagicMock
class TestCambAITTSUnit:
"""Unit tests for CambAITTS — all mocked, no API key needed."""
def test_max_chars_is_5000(self):
with patch("TTS.cambai.settings") as mock_settings:
from TTS.cambai import CambAITTS
tts = CambAITTS()
assert tts.max_chars == 5000
def test_initialize_raises_without_api_key(self):
with patch("TTS.cambai.settings") as mock_settings:
mock_settings.config = {"settings": {"tts": {"cambai_api_key": ""}}}
from TTS.cambai import CambAITTS
tts = CambAITTS()
with pytest.raises(ValueError, match="CAMB AI API key"):
tts.initialize()
def test_initialize_creates_client(self):
with patch("TTS.cambai.settings") as mock_settings, \
patch("TTS.cambai.CambAI") as mock_camb:
mock_settings.config = {"settings": {"tts": {"cambai_api_key": "test-key"}}}
from TTS.cambai import CambAITTS
tts = CambAITTS()
tts.initialize()
mock_camb.assert_called_once_with(api_key="test-key")
assert tts.client is not None
def test_run_generates_mp3(self):
with patch("TTS.cambai.settings") as mock_settings, \
patch("TTS.cambai.CambAI") as mock_camb_cls, \
patch("TTS.cambai.save_stream_to_file") as mock_save, \
patch("TTS.cambai.StreamTtsOutputConfiguration") as mock_config:
mock_settings.config = {
"settings": {"tts": {
"cambai_api_key": "test-key",
"cambai_voice_id": "147320",
"cambai_language": "en-us",
"cambai_speech_model": "mars-flash",
}}
}
mock_client = Mock()
mock_client.text_to_speech.tts.return_value = iter([b"fake-audio"])
mock_camb_cls.return_value = mock_client
from TTS.cambai import CambAITTS
tts = CambAITTS()
tts.run("Hello world", "/tmp/test.mp3", random_voice=False)
mock_client.text_to_speech.tts.assert_called_once()
call_kwargs = mock_client.text_to_speech.tts.call_args
assert call_kwargs.kwargs["text"] == "Hello world"
assert call_kwargs.kwargs["voice_id"] == 147320
assert call_kwargs.kwargs["language"] == "en-us"
assert call_kwargs.kwargs["speech_model"] == "mars-flash"
mock_save.assert_called_once()
assert mock_save.call_args[0][1] == "/tmp/test.mp3"
def test_run_reads_config_voice_id(self):
with patch("TTS.cambai.settings") as mock_settings, \
patch("TTS.cambai.CambAI") as mock_camb_cls, \
patch("TTS.cambai.save_stream_to_file"), \
patch("TTS.cambai.StreamTtsOutputConfiguration"):
mock_settings.config = {
"settings": {"tts": {
"cambai_api_key": "test-key",
"cambai_voice_id": "99999",
"cambai_language": "es-es",
"cambai_speech_model": "mars-pro",
}}
}
mock_client = Mock()
mock_client.text_to_speech.tts.return_value = iter([b"audio"])
mock_camb_cls.return_value = mock_client
from TTS.cambai import CambAITTS
tts = CambAITTS()
tts.run("test", "/tmp/out.mp3")
call_kwargs = mock_client.text_to_speech.tts.call_args.kwargs
assert call_kwargs["voice_id"] == 99999
assert call_kwargs["language"] == "es-es"
assert call_kwargs["speech_model"] == "mars-pro"
def test_random_voice_picks_from_list(self):
with patch("TTS.cambai.settings") as mock_settings, \
patch("TTS.cambai.CambAI") as mock_camb_cls, \
patch("TTS.cambai.save_stream_to_file"), \
patch("TTS.cambai.StreamTtsOutputConfiguration"), \
patch("TTS.cambai.random") as mock_random:
mock_settings.config = {"settings": {"tts": {"cambai_api_key": "test-key"}}}
mock_client = Mock()
mock_client.voice_cloning.list_voices.return_value = [
{"id": 111, "voice_name": "Voice A"},
{"id": 222, "voice_name": "Voice B"},
]
mock_client.text_to_speech.tts.return_value = iter([b"audio"])
mock_camb_cls.return_value = mock_client
mock_random.choice.return_value = {"id": 222, "voice_name": "Voice B"}
from TTS.cambai import CambAITTS
tts = CambAITTS()
tts.run("test", "/tmp/out.mp3", random_voice=True)
mock_client.voice_cloning.list_voices.assert_called_once()
mock_random.choice.assert_called_once()
@pytest.mark.integration
class TestCambAITTSIntegration:
"""Integration tests — require CAMB_API_KEY env var."""
@pytest.fixture(autouse=True)
def skip_without_key(self):
if not os.environ.get("CAMB_API_KEY"):
pytest.skip("CAMB_API_KEY not set")
def test_real_api_generates_audio(self):
from camb.client import CambAI, save_stream_to_file
from camb.types import StreamTtsOutputConfiguration
client = CambAI(api_key=os.environ["CAMB_API_KEY"])
with tempfile.NamedTemporaryFile(suffix=".mp3", delete=False) as f:
filepath = f.name
try:
stream = client.text_to_speech.tts(
text="Integration test for RedditVideoMakerBot.",
language="en-us",
voice_id=147320,
speech_model="mars-flash",
output_configuration=StreamTtsOutputConfiguration(format="mp3"),
)
save_stream_to_file(stream, filepath)
assert os.path.exists(filepath)
assert os.path.getsize(filepath) > 0
finally:
if os.path.exists(filepath):
os.remove(filepath)