aboutsummaryrefslogtreecommitdiff
path: root/app/tests
diff options
context:
space:
mode:
Diffstat (limited to 'app/tests')
-rw-r--r--app/tests/test_converter.py9
-rw-r--r--app/tests/test_hub.py16
-rw-r--r--app/tests/test_tts.py63
3 files changed, 49 insertions, 39 deletions
diff --git a/app/tests/test_converter.py b/app/tests/test_converter.py
index 317e772..7aa9c69 100644
--- a/app/tests/test_converter.py
+++ b/app/tests/test_converter.py
@@ -131,7 +131,6 @@ class NarratorTagTests(unittest.TestCase):
converter.voice_clone_ref_audio = ref_audio
converter.backend = tts.BACKEND_QWEN
converter.voice = None
- converter.speaker = None
converter.instructions = instructions
return converter
@@ -160,12 +159,11 @@ class NarratorTagTests(unittest.TestCase):
self.assertEqual(self._converter(tts.VOICE_MODE_CLONE, "/x/???.wav")._narrator_tag(),
"narrator")
- def _audiocpp_converter(self, voice=None, instructions=None, speaker=None):
+ def _audiocpp_converter(self, voice=None, instructions=None):
converter = self._converter(tts.VOICE_MODE_CUSTOM,
instructions=instructions)
converter.backend = tts.BACKEND_AUDIOCPP
converter.voice = voice
- converter.speaker = speaker
return converter
def test_audiocpp_design_run_uses_designed_tag(self):
@@ -185,11 +183,11 @@ class NarratorTagTests(unittest.TestCase):
def test_audiocpp_explicit_speaker_uses_speaker_tag(self):
# A chosen CustomVoice speaker names the output, not config.SPEAKER.
- converter = self._audiocpp_converter(speaker="Ryan")
+ converter = self._audiocpp_converter(voice="Ryan")
self.assertEqual(converter._narrator_tag(), "Ryan")
def test_audiocpp_explicit_speaker_normalizes_display_name(self):
- converter = self._audiocpp_converter(speaker="Uncle_Fu")
+ converter = self._audiocpp_converter(voice="Uncle_Fu")
self.assertEqual(converter._narrator_tag(), "Uncle_Fu")
def test_preflight_design_run_uses_designed_tag(self):
@@ -558,7 +556,6 @@ class RunOverwritePromptTests(unittest.TestCase):
self.converter.voice_clone_ref_audio = None
self.converter.backend = tts.BACKEND_QWEN
self.converter.voice = None
- self.converter.speaker = None
self.converter.instructions = None
self.converter.speed = 1.0
self.converter.single_file = False
diff --git a/app/tests/test_hub.py b/app/tests/test_hub.py
index c5ca346..965cbaa 100644
--- a/app/tests/test_hub.py
+++ b/app/tests/test_hub.py
@@ -754,7 +754,8 @@ class ConvertFlowTests(unittest.TestCase):
def test_audiocpp_customvoice_entry_lists_builtin_speakers(self):
# A CustomVoice entry populates the Voice menu with the Qwen3-TTS
- # built-in speakers and maps the pick to --speaker.
+ # built-in speakers and maps the pick to --voice (which the client
+ # resolves as speaker mode).
self._patch_remote(
[{"id": "Qwen3-TTS-12Hz-1.7B-CustomVoice-GGUF",
"family": "qwen3_tts", "task": "tts"}])
@@ -765,9 +766,9 @@ class ConvertFlowTests(unittest.TestCase):
audiocpp_voice="Ryan", instructions="")
cmd = self._convert(
None, [self._remote("audiocpp", "audio.cpp")])
- # The speaker is passed as --speaker, not --voice.
- self.assertIsNone(cmd[2]["voice"])
- self.assertEqual(cmd[2]["speaker"], "Ryan")
+ # The picked speaker is passed as --voice; no separate speaker kwarg.
+ self.assertEqual(cmd[2]["voice"], "Ryan")
+ self.assertNotIn("speaker", cmd[2])
fields = self.tui.forms_seen[0][1]
voice_field = self._field("audiocpp_voice")
self.assertEqual(voice_field["choices"](fields),
@@ -792,7 +793,7 @@ class ConvertFlowTests(unittest.TestCase):
cmd = self._convert(
None, [self._remote("audiocpp", "audio.cpp")])
self.assertEqual(cmd[2]["voice"], "narrator")
- self.assertIsNone(cmd[2]["speaker"])
+ self.assertNotIn("speaker", cmd[2])
self.assertIsNone(cmd[2]["instructions"])
fields = self.tui.forms_seen[0][1]
voice_field = self._field("audiocpp_voice")
@@ -815,7 +816,7 @@ class ConvertFlowTests(unittest.TestCase):
None, [self._remote("audiocpp", "audio.cpp")])
self.assertIsNotNone(cmd)
self.assertIsNone(cmd[2]["voice"])
- self.assertIsNone(cmd[2]["speaker"])
+ self.assertNotIn("speaker", cmd[2])
voice_field = self._field("audiocpp_voice")
# Clone-only: an empty voice is refused (no built-in speaker option).
self.assertIsNotNone(voice_field["validate"](""))
@@ -948,8 +949,7 @@ class ConvertFlowTests(unittest.TestCase):
return_value=root), \
patch.object(hub.config, "AUDIOCPP_INSTRUCTIONS", ""):
self._answer_form(backend="audiocpp", model_id="qwen",
- audiocpp_voice="(built-in speaker)",
- instructions="")
+ audiocpp_voice="", instructions="")
cmd = self._convert(None, [
self._ready("audiocpp", "audio.cpp"),
self._remote("audiocpp", "audio.cpp")])
diff --git a/app/tests/test_tts.py b/app/tests/test_tts.py
index 0e35f78..c17609b 100644
--- a/app/tests/test_tts.py
+++ b/app/tests/test_tts.py
@@ -512,12 +512,11 @@ class AudioCppTTSClientHealthTests(unittest.TestCase):
raise AssertionError(f"unexpected URL: {url}")
return _dispatch
- def _client(self, voice=None, language=None, model_id=None, speaker=None,
- **kwargs):
+ def _client(self, voice=None, language=None, model_id=None, **kwargs):
with patch("converter.tts.urllib.request.urlopen",
side_effect=self._get_responses(**kwargs)):
return AudioCppTTSClient(voice=voice, language=language,
- model_id=model_id, speaker=speaker)
+ model_id=model_id)
def test_unreachable_server_raises_with_readme_pointer(self):
import urllib.error
@@ -549,34 +548,51 @@ class AudioCppTTSClientHealthTests(unittest.TestCase):
self.assertEqual(client.language, config.LANGUAGE)
self.assertEqual(client.voice, "Vivian")
self.assertFalse(client.preset_mode)
+ self.assertTrue(client.speaker_mode)
def test_speaker_mode_uses_configured_speaker(self):
with patch.object(config, "SPEAKER", "uncle_fu"):
client = self._client()
self.assertEqual(client.voice, "Uncle Fu")
+ self.assertTrue(client.speaker_mode)
- def test_explicit_speaker_selects_speaker_mode(self):
- # --speaker picks a CustomVoice speaker; the name is normalized to
- # its wire (display) form and no preset validation runs.
- client = self._client(speaker="Uncle_Fu")
+ def test_voice_speaker_name_selects_speaker_mode(self):
+ # --voice naming a built-in CustomVoice speaker selects speaker
+ # mode; the name is normalized to its wire (display) form and no
+ # preset validation runs.
+ client = self._client(voice="Uncle_Fu")
self.assertEqual(client.voice, "Uncle Fu")
self.assertFalse(client.preset_mode)
+ self.assertTrue(client.speaker_mode)
- def test_explicit_speaker_on_clone_entry_raises(self):
- # --speaker is meaningless on a clone-only (Base) entry.
+ def test_voice_speaker_name_on_clone_entry_is_a_preset(self):
+ # --voice on a clone-only (Base) entry is a server-side preset,
+ # not a built-in speaker, so the name is validated against the
+ # server's voice library.
with self.assertRaises(RuntimeError) as ctx:
- self._client(speaker="Ryan", model_id="Qwen3-TTS-12Hz-1.7B-Base-GGUF",
+ self._client(voice="Ryan", model_id="Qwen3-TTS-12Hz-1.7B-Base-GGUF",
models={"data": [
{"id": "Qwen3-TTS-12Hz-1.7B-Base-GGUF",
"family": "qwen3_tts"}]})
message = str(ctx.exception)
- self.assertIn("no built-in speakers", message)
+ self.assertIn("'Ryan'", message)
self.assertIn("--voice", message)
- def test_voice_and_speaker_are_mutually_exclusive(self):
- with self.assertRaises(ValueError) as ctx:
- AudioCppTTSClient(voice="narrator", speaker="Ryan")
- self.assertIn("mutually exclusive", str(ctx.exception))
+ def test_voice_speaker_name_does_not_reroute_to_clone_model(self):
+ # A built-in speaker name on a CustomVoice primary selects speaker
+ # mode without the AUDIOCPP_CLONE_MODEL_ID reroute.
+ with patch.object(config, "AUDIOCPP_MODEL_ID",
+ "Qwen3-TTS-CustomVoice"), \
+ patch.object(config, "AUDIOCPP_CLONE_MODEL_ID", "qwen3-tts-clone"):
+ client = self._client(
+ voice="Ryan",
+ models={"data": [{"id": "Qwen3-TTS-CustomVoice",
+ "family": "qwen3_tts"},
+ {"id": "qwen3-tts-clone",
+ "family": "qwen3_tts"}]})
+ self.assertEqual(client.model_id, "Qwen3-TTS-CustomVoice")
+ self.assertTrue(client.speaker_mode)
+ self.assertFalse(client.preset_mode)
def test_no_voice_on_base_entry_raises_instead_of_silent_speaker(self):
# The Base model has no built-in speakers: without --voice the run
@@ -1063,7 +1079,6 @@ class AudioCppTTSClientRequestTests(unittest.TestCase):
client.model_id = config.AUDIOCPP_MODEL_ID
client.preset_mode = preset_mode
client.voice = voice
- client.speaker = None
client.language = language
client._seed = seed
client.family = family
@@ -1518,8 +1533,8 @@ class AudioCppUnloadModelsTests(unittest.TestCase):
client.profile = tts.AUDIOCPP_FAMILY_PROFILES["qwen3_tts"]
client.design_mode = False
client.instruction_voice = False
+ client.speaker_mode = False
client.instructions = ""
- client.speaker = None
with patch.object(client, "_check_health"), \
patch.object(client, "_list_models",
return_value=[{"id": client.model_id,
@@ -1548,8 +1563,8 @@ class AudioCppUnloadModelsTests(unittest.TestCase):
client.profile = tts.AUDIOCPP_FAMILY_PROFILES["qwen3_tts"]
client.design_mode = False
client.instruction_voice = False
+ client.speaker_mode = False
client.instructions = ""
- client.speaker = None
with patch.object(client, "_check_health"), \
patch.object(client, "_list_models",
return_value=[{"id": client.model_id,
@@ -1591,8 +1606,7 @@ class BackendWiringTests(unittest.TestCase):
model_id=None,
instructions=None,
request_options={},
- api_url=None,
- speaker=None)
+ api_url=None)
mock_faster.assert_not_called()
mock_qwen.assert_not_called()
@@ -1604,8 +1618,7 @@ class BackendWiringTests(unittest.TestCase):
model_id=None,
instructions=None,
request_options={},
- api_url=None,
- speaker=None)
+ api_url=None)
def test_audiocpp_backend_model_id_is_wired_through(self):
with patch("converter.converter.AudioCppTTSClient") as mock_audiocpp:
@@ -1615,7 +1628,7 @@ class BackendWiringTests(unittest.TestCase):
mock_audiocpp.assert_called_once_with(
voice="narrator", language=config.LANGUAGE,
model_id="higgs", instructions=None,
- request_options={}, api_url=None, speaker=None)
+ request_options={}, api_url=None)
def test_audiocpp_backend_instructions_and_options_are_wired_through(self):
with patch("converter.converter.AudioCppTTSClient") as mock_audiocpp:
@@ -1629,7 +1642,7 @@ class BackendWiringTests(unittest.TestCase):
model_id=None,
instructions="A warm adult narrator",
request_options={"emotion": "neutral", "speed": "1.1"},
- api_url=None, speaker=None)
+ api_url=None)
def test_qwen_backend_uses_qwen_client(self):
with patch("converter.converter.FasterTTSClient") as mock_faster, \
@@ -1656,7 +1669,7 @@ class BackendWiringTests(unittest.TestCase):
mock_audiocpp.assert_called_once_with(
voice="narrator", language=config.LANGUAGE, model_id=None,
instructions=None, request_options={},
- api_url="http://10.0.0.5:8080", speaker=None)
+ api_url="http://10.0.0.5:8080")
with patch("converter.converter.FasterTTSClient") as mock_faster:
AudiobookConverter(voice_mode=tts.VOICE_MODE_CLONE,
backend=tts.BACKEND_FASTER, voice="narrator",