aboutsummaryrefslogtreecommitdiff
path: root/app/tests/test_backends_audiocpp.py
diff options
context:
space:
mode:
authorhistoria <historiavg@proton.me>2026-08-26 00:21:51 -0400
committerhistoria <historiavg@proton.me>2026-08-26 00:21:51 -0400
commitbbc568477b28241236c998071ad9c355f0d0e874 (patch)
tree8221b19f76879a13569a889caebfc75365980df4 /app/tests/test_backends_audiocpp.py
parent7cf7d2f7849936e3c84ee431433c2e8bcb6706ac (diff)
downloadtts-audiobook-generator-bbc568477b28241236c998071ad9c355f0d0e874.tar.gz
refactor(audiocpp): pin checkout to app/audio.cpp, report install results
Diffstat (limited to 'app/tests/test_backends_audiocpp.py')
-rw-r--r--app/tests/test_backends_audiocpp.py87
1 files changed, 66 insertions, 21 deletions
diff --git a/app/tests/test_backends_audiocpp.py b/app/tests/test_backends_audiocpp.py
index 3063e99..05b47bd 100644
--- a/app/tests/test_backends_audiocpp.py
+++ b/app/tests/test_backends_audiocpp.py
@@ -13,6 +13,7 @@ from unittest.mock import MagicMock, patch
from converter import config
from backends import audiocpp as make_server
+from backends import common
from ui import tui
FAKE_CONFIG = (
@@ -222,13 +223,14 @@ class ConfigPortTests(unittest.TestCase):
make_server.FALLBACK_PORT)
def test_url_with_port_replaces_port(self):
+ # audiocpp reuses the shared helper (backends.common.url_with_port).
self.assertEqual(
- make_server._url_with_port("http://127.0.0.1:8080", 9000),
+ make_server.url_with_port("http://127.0.0.1:8080", 9000),
"http://127.0.0.1:9000")
def test_url_without_port_adds_port(self):
self.assertEqual(
- make_server._url_with_port("http://localhost", 8080),
+ make_server.url_with_port("http://localhost", 8080),
"http://localhost:8080")
@@ -237,8 +239,11 @@ class UpdateConfigPortTests(unittest.TestCase):
self._tmp = tempfile.TemporaryDirectory()
self.config_path = Path(self._tmp.name) / "config.py"
self.config_path.write_text(FAKE_CONFIG, encoding="utf-8")
+ # The shared helper also mirrors values onto converter.config.
+ self._saved_url = config.AUDIOCPP_API_URL
def tearDown(self):
+ config.AUDIOCPP_API_URL = self._saved_url
self._tmp.cleanup()
def test_rewrites_port_preserving_comment(self):
@@ -258,8 +263,9 @@ class UpdateConfigPortTests(unittest.TestCase):
self.assertFalse(make_server.update_config_api_url_port(
8080, config_path=path))
- def test_returns_false_when_port_unchanged(self):
- self.assertFalse(make_server.update_config_api_url_port(
+ def test_port_unchanged_is_a_success_noop(self):
+ # The file already holds the port: success, nothing rewritten.
+ self.assertTrue(make_server.update_config_api_url_port(
9999, config_path=self.config_path))
self.assertEqual(self.config_path.read_text(encoding="utf-8"),
FAKE_CONFIG)
@@ -275,8 +281,13 @@ class UpdateConfigModelIdsTests(unittest.TestCase):
self.config_path = Path(self._tmp.name) / "config.py"
self.config_path.write_text(FAKE_CONFIG_WITH_MODEL_IDS,
encoding="utf-8")
+ # The shared helper also mirrors values onto converter.config.
+ self._saved_ids = (config.AUDIOCPP_MODEL_ID,
+ config.AUDIOCPP_CLONE_MODEL_ID)
def tearDown(self):
+ (config.AUDIOCPP_MODEL_ID,
+ config.AUDIOCPP_CLONE_MODEL_ID) = self._saved_ids
self._tmp.cleanup()
def test_rewrites_both_ids_preserving_lines(self):
@@ -297,10 +308,11 @@ class UpdateConfigModelIdsTests(unittest.TestCase):
self.assertIn('AUDIOCPP_MODEL_ID = "voxcpm2"', text)
self.assertIn('AUDIOCPP_CLONE_MODEL_ID = "qwen-clone"', text)
- def test_returns_false_when_ids_unchanged(self):
+ def test_ids_unchanged_is_a_success_noop(self):
+ # Both ids already hold their values: success, nothing rewritten.
changed = make_server.update_config_model_ids(
"qwen", "qwen-clone", config_path=self.config_path)
- self.assertFalse(changed)
+ self.assertTrue(changed)
self.assertEqual(self.config_path.read_text(encoding="utf-8"),
FAKE_CONFIG_WITH_MODEL_IDS)
@@ -355,22 +367,43 @@ class ResolveWavDirArgTests(unittest.TestCase):
class NormalizeDirArgTests(unittest.TestCase):
- """Path normalization for the audio.cpp checkout argument."""
+ """Path normalization for user-supplied directory arguments."""
def test_expands_tilde_and_resolves(self):
- with patch.object(make_server.os.path, "expanduser",
+ with patch.object(common.os.path, "expanduser",
return_value="/home/u/audio.cpp") as mock_expand:
- result = make_server.normalize_dir_arg("~/audio.cpp")
+ result = common.normalize_dir_arg("~/audio.cpp")
mock_expand.assert_called_once_with("~/audio.cpp")
self.assertEqual(result, Path("/home/u/audio.cpp").resolve())
def test_strips_quotes_and_whitespace(self):
- with patch.object(make_server.os.path, "expanduser",
+ with patch.object(common.os.path, "expanduser",
side_effect=lambda s: s):
- result = make_server.normalize_dir_arg(' "/tmp/foo" ')
+ result = common.normalize_dir_arg(' "/tmp/foo" ')
self.assertEqual(result, Path("/tmp/foo").resolve())
+class FindLocalCheckoutTests(unittest.TestCase):
+ """find_local_checkout resolves ./app/audio.cpp and nothing else."""
+
+ def test_none_when_no_checkout_in_app_dir(self):
+ with tempfile.TemporaryDirectory() as td, \
+ patch.object(make_server, "APP_DIR", Path(td)):
+ self.assertIsNone(make_server.find_local_checkout())
+
+ def test_returns_the_managed_checkout(self):
+ with tempfile.TemporaryDirectory() as td, \
+ patch.object(make_server, "APP_DIR", Path(td)):
+ checkout = _make_checkout(Path(td))
+ self.assertEqual(make_server.find_local_checkout(), checkout)
+
+ def test_none_when_checkout_lacks_model_specs(self):
+ with tempfile.TemporaryDirectory() as td, \
+ patch.object(make_server, "APP_DIR", Path(td)):
+ (Path(td) / "audio.cpp").mkdir()
+ self.assertIsNone(make_server.find_local_checkout())
+
+
class LoadModelCatalogTests(unittest.TestCase):
def setUp(self):
self._td = tempfile.TemporaryDirectory()
@@ -1082,11 +1115,15 @@ class NonInteractiveMainTests(unittest.TestCase):
def tearDown(self):
self._td.cleanup()
- def _run(self, argv, transcribe=None, whisper="faster_whisper"):
+ def _run(self, argv, transcribe=None, whisper="faster_whisper",
+ no_checkout=False):
argv = ["backends/audiocpp.py"] + argv
transcribe_effect = transcribe if transcribe is not None \
else MagicMock()
with patch.object(sys, "argv", argv), \
+ patch.object(make_server, "find_local_checkout",
+ return_value=None if no_checkout
+ else self.checkout), \
patch.object(make_server, "transcribe_reference_audio",
side_effect=transcribe_effect), \
patch.object(make_server, "whisper_backend_available",
@@ -1094,8 +1131,8 @@ class NonInteractiveMainTests(unittest.TestCase):
return make_server.main()
def _args(self, *extra):
- return ["--wavs", str(self.folder), "--output", str(self.output),
- "--audiocpp-dir", str(self.checkout)] + list(extra)
+ return ["--wavs", str(self.folder), "--output", str(self.output)] \
+ + list(extra)
def test_default_run_hosts_recommended_entry(self):
exit_code = self._run(
@@ -1198,18 +1235,16 @@ class NonInteractiveMainTests(unittest.TestCase):
self.assertEqual(ctx.exception.code, 2)
def test_missing_checkout_rejected(self):
- with patch.object(make_server, "find_local_checkout",
- return_value=None), \
- self.assertRaises(SystemExit) as ctx:
+ with self.assertRaises(SystemExit) as ctx:
self._run(["--families", "higgs_audio_tts", "--output",
- str(self.output), "--no-sync-model-ids"])
+ str(self.output), "--no-sync-model-ids"],
+ no_checkout=True)
self.assertEqual(ctx.exception.code, 2)
def test_missing_wav_dir_rejected(self):
missing = self.root / "nope"
with self.assertRaises(SystemExit) as ctx:
self._run(["--wavs", str(missing), "--output", str(self.output),
- "--audiocpp-dir", str(self.checkout),
"--families", "higgs_audio_tts", "--no-sync-model-ids"])
self.assertEqual(ctx.exception.code, 2)
@@ -1822,19 +1857,25 @@ class UninstallTests(unittest.TestCase):
checkout.mkdir()
with patch.object(make_server, "find_local_checkout",
return_value=checkout), \
+ patch.object(make_server.servers, "pid_for",
+ return_value=1234), \
patch.object(make_server.servers, "stop") as mk_stop:
rc = make_server.uninstall()
self.assertEqual(rc, 0)
self.assertFalse(checkout.exists())
mk_stop.assert_called_once_with("audiocpp")
- def test_no_checkout_is_a_noop(self):
+ def test_skips_stop_without_a_pid_file(self):
+ # No pid file: the server was never started by this tool, so
+ # stop (and its "stop it manually" noise) is skipped.
with patch.object(make_server, "find_local_checkout",
return_value=None), \
+ patch.object(make_server.servers, "pid_for",
+ return_value=None), \
patch.object(make_server.servers, "stop") as mk_stop:
rc = make_server.uninstall()
self.assertEqual(rc, 0)
- mk_stop.assert_called_once_with("audiocpp")
+ mk_stop.assert_not_called()
def test_accepts_task_view_kwargs_for_registry_symmetry(self):
# The hub calls uninstall(emit=..., cancel=...); emit is unused here
@@ -1844,6 +1885,8 @@ class UninstallTests(unittest.TestCase):
checkout.mkdir()
with patch.object(make_server, "find_local_checkout",
return_value=checkout), \
+ patch.object(make_server.servers, "pid_for",
+ return_value=1234), \
patch.object(make_server.servers, "stop"):
rc = make_server.uninstall(emit=lambda line: None,
cancel=None)
@@ -1860,6 +1903,8 @@ class UninstallTests(unittest.TestCase):
cancel.set()
with patch.object(make_server, "find_local_checkout",
return_value=checkout), \
+ patch.object(make_server.servers, "pid_for",
+ return_value=1234), \
patch.object(make_server.servers, "stop"):
rc = make_server.uninstall(cancel=cancel)
self.assertEqual(rc, 130)