diff options
| author | historia <historiavg@proton.me> | 2026-09-01 03:17:01 -0400 |
|---|---|---|
| committer | historia <historiavg@proton.me> | 2026-09-01 03:17:01 -0400 |
| commit | 058b19e7a65b40b1024a4fdeb2233062ff273cfd (patch) | |
| tree | fe3643872cd6b317a88eec950ae6ecc4d81d843d /app/tests/test_hub.py | |
| parent | 10e72d4960e865acf5346ab8cf518ed5844fe45c (diff) | |
| download | tts-audiobook-generator-058b19e7a65b40b1024a4fdeb2233062ff273cfd.tar.gz | |
fix: better errors for generate all models
Diffstat (limited to 'app/tests/test_hub.py')
| -rw-r--r-- | app/tests/test_hub.py | 64 |
1 files changed, 64 insertions, 0 deletions
diff --git a/app/tests/test_hub.py b/app/tests/test_hub.py index b1a91ed..80a97d0 100644 --- a/app/tests/test_hub.py +++ b/app/tests/test_hub.py @@ -1218,6 +1218,52 @@ class ConvertFlowTests(unittest.TestCase): "beta": [("book.txt", "planned")]}) self.assertNotIn("planned", kwargs) + def test_all_pick_skips_non_narrating_families_with_a_notice(self): + # Speech-to-speech-only families (PersonaPlex) cannot narrate text: + # every request would fail, so the All pick drops them, records a + # run notice naming what was skipped, and keeps them single-pickable. + spec_cache = audiocpp_client._FAMILY_SPECS + spec_cache["personaplex"] = {"tasks": ["s2s"]} + self.addCleanup(spec_cache.pop, "personaplex", None) + self._patch_remote( + [{"id": "alpha", "family": "higgs_audio_tts", "task": "tts"}, + {"id": "plex", "family": "personaplex", "task": "tts"}], + voices=["narrator"]) + self._mock_preflight() + self._answer_form(backend="audiocpp-remote", + model_id=hub.AUDIOCPP_MODEL_ALL, + audiocpp_voice="narrator", instructions="") + cmd = self._convert(None, [self._remote("audiocpp", "audio.cpp")]) + kwargs = cmd[2] + self.assertEqual(kwargs["model_ids"], ["alpha"]) + self.assertEqual(kwargs["model_voices"], {"alpha": "narrator"}) + self.assertEqual(kwargs["run_notice"], + "skipped non-TTS model(s): plex") + + def test_all_pick_refuses_when_every_model_is_non_narrating(self): + # With nothing left to generate with after the skip, the All pick + # is refused up front instead of starting a doomed run. + spec_cache = audiocpp_client._FAMILY_SPECS + spec_cache["personaplex"] = {"tasks": ["s2s"]} + self.addCleanup(spec_cache.pop, "personaplex", None) + self._patch_remote( + [{"id": "plex-1", "family": "personaplex", "task": "tts"}, + {"id": "plex-2", "family": "personaplex", "task": "tts"}], + voices=["narrator"]) + self._mock_preflight() + self._answer_form(backend="audiocpp-remote", + model_id=hub.AUDIOCPP_MODEL_ALL, + audiocpp_voice="narrator", instructions="") + self._convert(None, [self._remote("audiocpp", "audio.cpp")]) + fields = self.tui.forms_seen[0][1] + voice_field = self._field("audiocpp_voice") + self._field("model_id")["value"] = hub.AUDIOCPP_MODEL_ALL + error = voice_field["validate"]("narrator") + self.assertIsNotNone(error) + self.assertIn("plex-1", error) + self.assertIn("plex-2", error) + self.assertIn("synthesize text", error) + def test_all_voice_falls_back_per_capability(self): # A CustomVoice entry cannot clone: it synthesizes with a built-in # speaker (the pick when it names one, the first speaker when it @@ -2448,6 +2494,24 @@ class PrepareRunConfigTests(unittest.TestCase): self.assertIn("clon", cfg.notice) self.assertNotIn("restarted", cfg.notice) + def test_run_notice_is_popped_and_joined_with_the_server_notice(self): + # The form's pre-flight warning (e.g. the All run's skipped + # non-narrating models) rides to the run view's notice line, and + # multiple notices accumulate instead of overwriting each other. + spec = self._spec("audiocpp", "http://127.0.0.1:8080") + status = BackendStatus("audiocpp", "audio.cpp", installed=True, + configured=True, servers=[spec]) + kwargs = {"run_notice": "skipped non-TTS model(s): plex", + "restart_server": "audiocpp", "audiocpp_rehost": True} + with patch.object(hub, "detect_all", return_value=[status]), \ + patch("backends.common.server_running", + return_value=True), \ + patch.object(hub.servers, "alive", return_value=True): + cfg = hub._prepare_run_config("audiocpp", kwargs) + self.assertNotIn("run_notice", kwargs) + self.assertIn("skipped non-TTS model(s): plex", cfg.notice) + self.assertIn("re-hosted clone-only", cfg.notice) + def test_stop_and_exit_travels_on_the_config_not_the_kwargs(self): # The run-view toggle is not a converter kwarg: it moves onto the # config (and defaults to off when the form did not send it). |
