#[cfg(test)]
mod tests {
use crate::channels::voice::voicebox_stt;
use crate::channels::voice::voicebox_tts::VoiceboxTts;
#[tokio::test]
async fn tts_new_creates_client() {
let _tts = VoiceboxTts::new("http://localhost:8000", "profile-abc", "xtts");
}
#[tokio::test]
async fn tts_empty_text_rejected() {
let tts = VoiceboxTts::new("http://localhost:8000", "profile-abc", "xtts");
let result = tts.synthesize("").await;
assert!(result.is_err());
assert!(result.unwrap_err().to_string().contains("empty text"));
}
#[tokio::test]
async fn tts_successful_synthesis_reads_audio_file() {
let mut server = mockito::Server::new_async().await;
let mock_url = server.url();
let fake_audio = vec![0x52, 0x49, 0x46, 0x46, 0x00, 0x01, 0x02, 0x03];
let _generate = server
.mock("POST", "/generate")
.match_body(mockito::Matcher::Json(serde_json::json!({
"profile_id": "profile-abc",
"text": "hello voicebox",
"engine": "xtts"
})))
.with_status(200)
.with_header("content-type", "application/json")
.with_body(
serde_json::json!({
"id": "gen-123",
"status": "completed",
"audio_path": "/audio/gen-123.wav",
"duration": 1.5,
"error": null
})
.to_string(),
)
.create_async()
.await;
let _audio = server
.mock("GET", "/audio/gen-123.wav")
.with_status(200)
.with_body(fake_audio.clone())
.create_async()
.await;
let tts = VoiceboxTts::new(&mock_url, "profile-abc", "xtts");
let result = tts.synthesize("hello voicebox").await;
assert!(result.is_ok());
let bytes = result.unwrap();
assert_eq!(bytes, fake_audio);
}
#[tokio::test]
async fn tts_audio_fetch_fails_on_404() {
let mut server = mockito::Server::new_async().await;
let mock_url = server.url();
let _generate = server
.mock("POST", "/generate")
.with_status(200)
.with_header("content-type", "application/json")
.with_body(
serde_json::json!({
"id": "gen-123",
"status": "completed",
"audio_path": "/audio/missing.wav",
"duration": 1.0,
"error": null
})
.to_string(),
)
.create_async()
.await;
let _audio = server
.mock("GET", "/audio/missing.wav")
.with_status(404)
.with_body("not found")
.create_async()
.await;
let tts = VoiceboxTts::new(&mock_url, "profile-abc", "xtts");
let result = tts.synthesize("hello").await;
assert!(result.is_err());
let err = result.unwrap_err().to_string();
assert!(err.contains("404") || err.contains("error"));
}
#[tokio::test]
async fn tts_server_error_propagated() {
let mut server = mockito::Server::new_async().await;
let mock_url = server.url();
let _mock = server
.mock("POST", "/generate")
.with_status(500)
.with_body(r#"{"error": "GPU out of memory"}"#)
.create_async()
.await;
let tts = VoiceboxTts::new(&mock_url, "profile-abc", "xtts");
let result = tts.synthesize("hello").await;
assert!(result.is_err());
let err = result.unwrap_err().to_string();
assert!(err.contains("500"));
assert!(err.contains("GPU out of memory"));
}
#[tokio::test]
async fn tts_connection_refused_on_bad_url() {
let tts = VoiceboxTts::new("http://localhost:1", "profile", "xtts");
let result = tts.synthesize("hello").await;
assert!(result.is_err());
}
#[tokio::test]
async fn stt_mocks_successful_transcription() {
let mut server = mockito::Server::new_async().await;
let mock_url = server.url();
let _mock = server
.mock("POST", "/transcribe")
.with_status(200)
.with_header("content-type", "application/json")
.with_body(r#"{"text": "voicebox transcription works"}"#)
.create_async()
.await;
let result = voicebox_stt::transcribe(vec![0x00, 0x01, 0x02, 0x03], &mock_url).await;
assert!(result.is_ok());
let text = result.unwrap();
assert_eq!(text, "voicebox transcription works");
}
#[tokio::test]
async fn stt_server_error_propagated() {
let mut server = mockito::Server::new_async().await;
let mock_url = server.url();
let _mock = server
.mock("POST", "/transcribe")
.with_status(503)
.with_body(r#"{"error": "STT model not loaded"}"#)
.create_async()
.await;
let result = voicebox_stt::transcribe(vec![0x00, 0x01], &mock_url).await;
assert!(result.is_err());
let err = result.unwrap_err().to_string();
assert!(err.contains("503"));
assert!(err.contains("STT model not loaded"));
}
#[tokio::test]
async fn stt_invalid_json_response() {
let mut server = mockito::Server::new_async().await;
let mock_url = server.url();
let _mock = server
.mock("POST", "/transcribe")
.with_status(200)
.with_header("content-type", "application/json")
.with_body(r#"{"not_text": "missing text field"}"#)
.create_async()
.await;
let result = voicebox_stt::transcribe(vec![0x00, 0x01], &mock_url).await;
assert!(result.is_err());
let err = result.unwrap_err().to_string();
assert!(err.contains("parse") || err.contains("text") || err.contains("Failed"));
}
#[tokio::test]
async fn stt_connection_refused_on_bad_url() {
let result = voicebox_stt::transcribe(vec![0x00, 0x01], "http://localhost:1").await;
assert!(result.is_err());
}
}