From bbc568477b28241236c998071ad9c355f0d0e874 Mon Sep 17 00:00:00 2001 From: historia Date: Wed, 26 Aug 2026 00:21:51 -0400 Subject: refactor(audiocpp): pin checkout to app/audio.cpp, report install results --- app/tests/test_backends_audiocpp.py | 87 ++++++++++++++++++++++++++++--------- 1 file changed, 66 insertions(+), 21 deletions(-) (limited to 'app/tests') 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) -- cgit v1.2.3