aboutsummaryrefslogtreecommitdiff
path: root/app/tests
diff options
context:
space:
mode:
Diffstat (limited to 'app/tests')
-rw-r--r--app/tests/test_hub.py224
1 files changed, 154 insertions, 70 deletions
diff --git a/app/tests/test_hub.py b/app/tests/test_hub.py
index fd22a4e..3550f5b 100644
--- a/app/tests/test_hub.py
+++ b/app/tests/test_hub.py
@@ -370,10 +370,14 @@ class HubMenuTests(unittest.TestCase):
self.assertIn("6. Generated audiobooks (m4b, mp3, etc.) will "
"output here:", text)
# The three folder paths are their own indented, white-bold
- # ("input") rows; the numbered steps start at the margin.
- self.assertIn(([(str(hub.BOOKS_FOLDER), "input")], 1), items)
+ # ("input") rows; the numbered steps start at the margin. They
+ # resolve live from the converter module, so a Settings change
+ # this session is reflected.
+ self.assertIn(([(str(hub.converter_mod.BOOKS_FOLDER), "input")], 1),
+ items)
self.assertIn(([(str(hub.common.VOICES_DIR), "input")], 1), items)
- self.assertIn(([(str(hub.AUDIOBOOKS_FOLDER), "input")], 1), items)
+ self.assertIn(([(str(hub.converter_mod.AUDIOBOOKS_FOLDER), "input")],
+ 1), items)
self.assertEqual(items[0][1], 0)
@@ -812,16 +816,16 @@ class ConvertFlowTests(unittest.TestCase):
# Keys shared by every backend entry; a "-remote" backend's other
# option keys are namespaced under "<entry>." in the form dict
# (mirroring hub.py), so _form_values maps them automatically.
- _COMMON_KEYS = frozenset(("backend", "output_format", "language",
- "speed", "single_file", "debug",
- "stop_and_exit"))
+ _COMMON_KEYS = frozenset(("backend", "single_file"))
def _form_values(self, **overrides):
- """A fully-populated form result, with sensible defaults."""
- values = {"output_format": "m4b", "language": "English",
- "speed": "1.0",
- "single_file": False, "debug": False,
- "stop_and_exit": True}
+ """A fully-populated form result, with sensible defaults.
+
+ Output format, language, speed, debug, and stop-and-exit are no
+ longer form fields: they live in config.py (Settings) and reach
+ the run kwargs via _common_kwargs().
+ """
+ values = {"single_file": False}
values.update(overrides)
backend = values.get("backend") or ""
if backend.endswith("-remote"):
@@ -897,13 +901,16 @@ class ConvertFlowTests(unittest.TestCase):
self._patch_remote(
[{"id": "higgs", "family": "higgs_audio_tts", "task": "tts"}],
voices=["narrator"])
- # Pin the seeded toggle so this test does not depend on the user's
- # saved STOP_SERVER_AND_EXIT value in config.py.
+ # Pin the config settings the common kwargs are built from, so
+ # this test does not depend on the user's saved config.py values.
with patch.object(hub.config, "STOP_SERVER_AND_EXIT", True), \
+ patch.object(hub.config, "AUDIO_FORMAT", "m4b"), \
+ patch.object(hub.config, "LANGUAGE", "English"), \
+ patch.object(hub.config, "SPEED", 1.25), \
+ patch.object(hub.config, "DEBUG", False), \
patch.object(hub.config, "AUDIOCPP_INSTRUCTIONS", ""):
self._answer_form(backend="audiocpp-remote", model_id="higgs",
- audiocpp_voice="narrator", instructions="",
- speed="1.5")
+ audiocpp_voice="narrator", instructions="")
cmd = self._convert(
None, [self._remote("audiocpp", "audio.cpp")])
self.assertEqual(cmd[0], "convert")
@@ -913,10 +920,14 @@ class ConvertFlowTests(unittest.TestCase):
self.assertEqual(kwargs["voice"], "narrator")
self.assertIsNone(kwargs["instructions"])
self.assertEqual(kwargs["api_url"], "http://audiocpp.local:8080")
+ # The output settings come from config (the Settings menu), not
+ # the form.
self.assertEqual(kwargs["output_format"], "m4b")
- self.assertEqual(kwargs["speed"], 1.5)
+ self.assertEqual(kwargs["language"], "English")
+ self.assertEqual(kwargs["speed"], 1.25)
self.assertFalse(kwargs["single_file"])
self.assertFalse(kwargs["debug"])
+ self.assertTrue(kwargs["stop_and_exit"])
# One form, not a cascade of menus/editors.
self.assertEqual(len(self.tui.forms_seen), 1)
title, fields, form_kwargs = self.tui.forms_seen[0]
@@ -926,15 +937,9 @@ class ConvertFlowTests(unittest.TestCase):
"audiocpp-remote.audiocpp_voice",
"audiocpp-remote.instructions",
"audiocpp-remote.request_options",
- "output_format", "language",
- "speed", "single_file", "debug", "stop_and_exit"])
+ "single_file"])
self.assertEqual(form_kwargs["buttons"], ("Generate!", "Cancel"))
self.assertTrue(form_kwargs["start_on_buttons"])
- # The stop-and-exit toggle ships on by default.
- stop_field = self._field("stop_and_exit")
- self.assertEqual(stop_field["kind"], "bool")
- self.assertTrue(stop_field["value"])
- self.assertTrue(cmd[2]["stop_and_exit"])
# The backend field offers the remote entry under a [remote] label.
self.assertEqual(fields[0]["choices"],
[("audio.cpp [remote]", "audiocpp-remote")])
@@ -1353,14 +1358,17 @@ class ConvertFlowTests(unittest.TestCase):
self.assertIn("KEY=VALUE", help_text)
self.assertIn("emotion=neutral", help_text)
- def test_language_passes_through_normalized(self):
+ def test_language_passes_through_from_config(self):
+ # The Settings Language setting travels on the run kwargs as-is;
+ # the converter normalizes it (short codes included).
with patch.object(hub.qwen_backend, "QWEN_SPEAKERS", ["Vivian"]), \
- patch.object(hub.config, "SPEAKER", "Vivian"):
+ patch.object(hub.config, "SPEAKER", "Vivian"), \
+ patch.object(hub.config, "LANGUAGE", "en"):
self._answer_form(backend="qwen", mode="custom",
- speaker="Vivian", clone="", language="en")
+ speaker="Vivian", clone="")
cmd = self._convert(None,
[self._ready("qwen", "qwen-tts")])
- self.assertEqual(cmd[2]["language"], "English")
+ self.assertEqual(cmd[2]["language"], "en")
def test_audiocpp_remote_unreachable_models_flash_and_abort(self):
self._patch_remote(None) # endpoint did not answer valid JSON
@@ -1472,9 +1480,7 @@ class ConvertFlowTests(unittest.TestCase):
voices=["narrator"])
statuses = [self._ready("audiocpp", "audio.cpp"),
self._remote("audiocpp", "audio.cpp")]
- common = {"output_format": "m4b", "speed": "1.0",
- "single_file": False, "debug": False,
- "stop_and_exit": True}
+ common = {"single_file": False}
with tempfile.TemporaryDirectory() as td:
root = Path(td)
(root / "server.json").write_text(json.dumps({
@@ -1523,17 +1529,18 @@ class ConvertFlowTests(unittest.TestCase):
self.assertEqual(cmd[2]["api_url"], "http://10.0.0.5:8080")
# ------------------------------------------------------------------
- # common fields: output format, speed, single-file, debug
+ # common fields: the per-run combine-all-chapters toggle
# ------------------------------------------------------------------
def test_common_fields_hide_combine_for_m4b(self):
+ # The toggle's visibility tracks the configured output format
+ # (the Settings menu's Audio format), not a form field.
fields = hub._common_fields()
- fmt = next(f for f in fields if f["key"] == "output_format")
single = next(f for f in fields if f["key"] == "single_file")
- fmt["value"] = "m4b"
- self.assertFalse(single["visible"](fields))
- fmt["value"] = "mp3"
- self.assertTrue(single["visible"](fields))
+ with patch.object(hub.config, "AUDIO_FORMAT", "m4b"):
+ self.assertFalse(single["visible"](fields))
+ with patch.object(hub.config, "AUDIO_FORMAT", "mp3"):
+ self.assertTrue(single["visible"](fields))
# ------------------------------------------------------------------
# qwen: model picker (Base / CustomVoice / VoiceDesign)
@@ -1566,10 +1573,7 @@ class ConvertFlowTests(unittest.TestCase):
fields = self.tui.forms_seen[0][1]
self.assertEqual([f["key"] for f in fields],
["backend", "mode", "speaker", "clone",
- "qwen_instructions",
- "output_format", "language", "speed",
- "single_file", "debug",
- "stop_and_exit"])
+ "qwen_instructions", "single_file"])
mode_field = self._field("mode")
self.assertEqual(mode_field["choices"],
[("CustomVoice (built-in voices)", "custom"),
@@ -1654,9 +1658,6 @@ class ConvertFlowTests(unittest.TestCase):
# faster voices are server-side clone references.
self.assertEqual(self._field("faster_voice")["label"],
"Voice to clone")
- # Language is server-owned on faster: the per-run field is hidden.
- fields = self.tui.forms_seen[0][1]
- self.assertFalse(self._field("language")["visible"](fields))
def test_faster_local_still_lists_voices_json(self):
with tempfile.TemporaryDirectory() as td:
@@ -1704,16 +1705,15 @@ class ConvertFlowTests(unittest.TestCase):
self.assertIs(self.nav, hub.tui.Wizard.BACK)
def test_settings_default_feeds_the_stop_and_exit_toggle(self):
- # The Settings menu's "Default stop server and exit" value seeds the
- # generate-form toggle (and so the run's stop-and-exit behavior).
+ # The Settings menu's "Stop server and exit" value decides the
+ # run's stop-and-exit behavior (it travels on the run kwargs).
st = self._remote("faster", "faster-qwen3-tts",
url="http://10.0.0.5:8000")
with patch.object(hub.config, "STOP_SERVER_AND_EXIT", False):
self._answer_form(backend="faster-remote",
- faster_voice="obama", stop_and_exit=False)
+ faster_voice="obama")
cmd = self._convert(None, [st])
self.assertIsNotNone(cmd)
- self.assertFalse(self._field("stop_and_exit")["value"])
self.assertFalse(cmd[2]["stop_and_exit"])
def test_qwen_remote_limited_modes_and_api_url(self):
@@ -1765,9 +1765,7 @@ class ConvertFlowTests(unittest.TestCase):
[f["key"] for f in fields],
["backend", "model_id", "audiocpp_voice", "instructions",
"request_options", "mode", "speaker", "clone",
- "qwen_instructions",
- "output_format", "language", "speed",
- "single_file", "debug", "stop_and_exit"])
+ "qwen_instructions", "single_file"])
# The form opens on the configured default (audio.cpp): its fields
# show, the other backend's hide. Instructions shows too (optional
# style/delivery control even on the clone-only higgs entry), while
@@ -1776,15 +1774,12 @@ class ConvertFlowTests(unittest.TestCase):
for key in ("model_id", "audiocpp_voice", "instructions"):
self.assertTrue(self._field(key)["visible"](fields))
self.assertFalse(self._field("request_options")["visible"](fields))
- # Language shows for every backend except faster entries.
- self.assertTrue(self._field("language")["visible"](fields))
for key in ("mode", "speaker", "clone", "qwen_instructions"):
self.assertFalse(self._field(key)["visible"](fields))
# Picking qwen in the Backend field swaps which options show.
fields[0]["value"] = "qwen"
self.assertTrue(self._field("mode")["visible"](fields))
self.assertTrue(self._field("speaker")["visible"](fields))
- self.assertTrue(self._field("language")["visible"](fields))
self.assertFalse(self._field("clone")["visible"](fields))
# qwen's clone mode hides the speaker and shows the .wav path.
self._field("mode")["value"] = "clone"
@@ -2128,7 +2123,8 @@ class SettingsTests(unittest.TestCase):
# Keys _apply_settings persists; every test that triggers a real or
# fake config write restores these afterwards.
_SETTING_KEYS = ("AUDIO_FORMAT", "AUDIO_BITRATE", "LANGUAGE",
- "CHUNK_SIZE", "STOP_SERVER_AND_EXIT",
+ "CHUNK_SIZE", "INPUT_DIR", "OUTPUT_DIR",
+ "SPEED", "DEBUG", "STOP_SERVER_AND_EXIT",
"AUDIOCPP_UNLOAD_MODELS",
"QWEN_API_URL",
"FASTER_API_URL", "AUDIOCPP_API_URL",
@@ -2191,8 +2187,18 @@ class SettingsTests(unittest.TestCase):
return True
self._snapshot_settings()
+ # _apply_settings re-derives the converter module's folder
+ # globals; restore them afterwards.
+ original_folders = (hub.converter_mod.BOOKS_FOLDER,
+ hub.converter_mod.AUDIOBOOKS_FOLDER)
+ self.addCleanup(setattr, hub.converter_mod, "BOOKS_FOLDER",
+ original_folders[0])
+ self.addCleanup(setattr, hub.converter_mod, "AUDIOBOOKS_FOLDER",
+ original_folders[1])
values = {"audio_format": "ogg", "audio_bitrate": " 192k ",
"language": "en", "chunk_size": "300",
+ "input_dir": " /books ", "output_dir": "/audiobooks",
+ "speed": "1.5", "debug": True,
"stop_and_exit": False,
"unload_models": True,
"qwen_port": "7862",
@@ -2210,6 +2216,10 @@ class SettingsTests(unittest.TestCase):
"AUDIO_BITRATE": "192k",
"LANGUAGE": "English",
"CHUNK_SIZE": 300,
+ "INPUT_DIR": "/books",
+ "OUTPUT_DIR": "/audiobooks",
+ "SPEED": 1.5,
+ "DEBUG": True,
"STOP_SERVER_AND_EXIT": False,
"AUDIOCPP_UNLOAD_MODELS": True,
"QWEN_API_URL": "http://127.0.0.1:7862",
@@ -2221,22 +2231,32 @@ class SettingsTests(unittest.TestCase):
"http://10.0.0.6:8000",
"AUDIOCPP_REMOTE_URL":
"http://10.0.0.5:8080"})
- # In-memory config is reloaded so this session sees the change.
+ # In-memory config is reloaded so this session sees the change,
+ # and the converter module's folder globals follow the directories.
self.assertEqual(hub.config.AUDIO_FORMAT, "ogg")
self.assertEqual(hub.config.AUDIO_BITRATE, "192k")
self.assertEqual(hub.config.LANGUAGE, "English")
self.assertEqual(hub.config.CHUNK_SIZE, 300)
+ self.assertEqual(hub.config.INPUT_DIR, "/books")
+ self.assertEqual(hub.config.OUTPUT_DIR, "/audiobooks")
+ self.assertEqual(hub.config.SPEED, 1.5)
+ self.assertEqual(hub.config.DEBUG, True)
self.assertEqual(hub.config.STOP_SERVER_AND_EXIT, False)
self.assertEqual(hub.config.AUDIOCPP_UNLOAD_MODELS, True)
self.assertEqual(hub.config.QWEN_API_URL, "http://127.0.0.1:7862")
self.assertEqual(hub.config.FASTER_API_URL, "http://127.0.0.1:8001")
self.assertEqual(hub.config.AUDIOCPP_REMOTE_URL,
"http://10.0.0.5:8080")
+ self.assertEqual(hub.converter_mod.BOOKS_FOLDER, Path("/books"))
+ self.assertEqual(hub.converter_mod.AUDIOBOOKS_FOLDER,
+ Path("/audiobooks"))
def test_apply_settings_rejects_bad_values(self):
self._snapshot_settings()
base = {"audio_format": "m4b", "audio_bitrate": "128k",
"language": "English", "chunk_size": "250",
+ "input_dir": "./input", "output_dir": "./output",
+ "speed": "1.0", "debug": False,
"stop_and_exit": True,
"unload_models": True,
"qwen_port": "7860",
@@ -2247,6 +2267,14 @@ class SettingsTests(unittest.TestCase):
with self.assertRaises(ValueError):
hub._apply_settings({**base, "chunk_size": "0"})
with self.assertRaises(ValueError):
+ hub._apply_settings({**base, "speed": "0"})
+ with self.assertRaises(ValueError):
+ hub._apply_settings({**base, "speed": "fast"})
+ with self.assertRaises(ValueError):
+ hub._apply_settings({**base, "input_dir": " "})
+ with self.assertRaises(ValueError):
+ hub._apply_settings({**base, "output_dir": ""})
+ with self.assertRaises(ValueError):
hub._apply_settings({**base, "audiocpp_port": "70000"})
with self.assertRaises(ValueError):
hub._apply_settings({**base,
@@ -2262,6 +2290,17 @@ class SettingsTests(unittest.TestCase):
self.assertIsNone(hub._validate_chunk_size("250"))
self.assertIsNotNone(hub._validate_chunk_size("abc"))
self.assertIsNotNone(hub._validate_chunk_size("0"))
+ self.assertIsNone(hub._validate_speed("1.0"))
+ self.assertIsNone(hub._validate_speed("1.5"))
+ self.assertIsNone(hub._validate_speed(" 2 "))
+ self.assertIsNotNone(hub._validate_speed("0"))
+ self.assertIsNotNone(hub._validate_speed("-1"))
+ self.assertIsNotNone(hub._validate_speed("fast"))
+ self.assertIsNotNone(hub._validate_speed(""))
+ self.assertIsNone(hub._validate_dir("./input"))
+ self.assertIsNone(hub._validate_dir(Path("/books")))
+ self.assertIsNotNone(hub._validate_dir(""))
+ self.assertIsNotNone(hub._validate_dir(" "))
self.assertIsNone(hub._validate_port("8080"))
self.assertIsNone(hub._validate_port("1"))
self.assertIsNone(hub._validate_port("65535"))
@@ -2270,9 +2309,9 @@ class SettingsTests(unittest.TestCase):
self.assertIsNotNone(hub._validate_port("abc"))
def test_language_fields_are_pickers_with_edit_hint(self):
- # Both Language fields (Settings and Generate Audiobooks) are
- # static pickers over the audio.cpp-menu languages, with a dim
- # hint inside their edit dialog. Common languages lead.
+ # The Settings Language field is a static picker over the
+ # audio.cpp-menu languages, with a dim hint inside its edit
+ # dialog. Common languages lead.
expected_choices = ["English", "Spanish", "Chinese", "French",
"German", "Italian", "Portuguese", "Japanese",
"Korean", "Russian", "Arabic", "Hindi",
@@ -2284,19 +2323,34 @@ class SettingsTests(unittest.TestCase):
fields = hub._settings_fields()
field = next(f for f in fields if f["key"] == "language")
- self.assertEqual(field["label"], "Default Language")
+ self.assertEqual(field["label"], "Language")
self.assertEqual(field["kind"], "choice")
self.assertEqual(field["choices"], expected_choices)
self.assertEqual(field["help"], hint)
self.assertEqual(field["value"], hub.config.LANGUAGE)
- for gen_fields in (hub._common_fields(),):
- field = next(f for f in gen_fields
- if f["key"] == "language")
- self.assertEqual(field["label"], "Language")
- self.assertEqual(field["kind"], "choice")
- self.assertEqual(field["choices"], expected_choices)
- self.assertEqual(field["help"], hint)
+ def test_directory_fields_are_browsers(self):
+ # The Input/Output Directory settings use the DOS-style directory
+ # browser, seeded with the configured folder resolved against the
+ # project root.
+ fields = hub._settings_fields()
+ for key, config_name in (("input_dir", "INPUT_DIR"),
+ ("output_dir", "OUTPUT_DIR")):
+ field = next(f for f in fields if f["key"] == key)
+ self.assertEqual(field["kind"], "dir")
+ self.assertTrue(field["label"].endswith("Directory"))
+ self.assertEqual(field["value"],
+ hub.converter_mod.resolve_dir(
+ getattr(hub.config, config_name),
+ key.removesuffix("_dir")))
+ self.assertIsNone(field["validate"](str(field["value"])))
+ self.assertIsNotNone(field["validate"](" "))
+ with patch.object(hub.config, "INPUT_DIR", "books"):
+ fields = hub._settings_fields()
+ field = next(f for f in fields if f["key"] == "input_dir")
+ self.assertEqual(
+ field["value"],
+ hub.converter_mod.BASE_DIR / "books")
def test_settings_menu_builds_form_and_saves(self):
captured = {}
@@ -2305,6 +2359,8 @@ class SettingsTests(unittest.TestCase):
captured["fields"] = fields
return {"audio_format": "ogg", "audio_bitrate": "192k",
"language": "English", "chunk_size": "300",
+ "input_dir": "/books", "output_dir": "/audiobooks",
+ "speed": "1.0", "debug": False,
"stop_and_exit": True,
"unload_models": True,
"qwen_port": "7860",
@@ -2324,13 +2380,19 @@ class SettingsTests(unittest.TestCase):
hub._Hub(None).screen_settings()
self.assertEqual([f["key"] for f in captured["fields"]],
["audio_format", "audio_bitrate", "language",
- "chunk_size", "stop_and_exit", "unload_models",
+ "chunk_size", "input_dir", "output_dir",
+ "speed", "debug", "stop_and_exit",
+ "unload_models",
"audiocpp_port",
"faster_port", "qwen_port", "audiocpp_remote_url",
"faster_remote_url", "qwen_remote_url"])
kinds = {f["key"]: f["kind"] for f in captured["fields"]}
self.assertEqual(kinds["audio_format"], "choice")
self.assertEqual(kinds["audio_bitrate"], "text")
+ self.assertEqual(kinds["input_dir"], "dir")
+ self.assertEqual(kinds["output_dir"], "dir")
+ self.assertEqual(kinds["speed"], "text")
+ self.assertEqual(kinds["debug"], "bool")
self.assertEqual(kinds["audiocpp_port"], "text")
self.assertEqual(kinds["stop_and_exit"], "bool")
self.assertEqual(kinds["unload_models"], "bool")
@@ -2339,22 +2401,32 @@ class SettingsTests(unittest.TestCase):
self.assertEqual(labels["qwen_port"], "qwen-tts port")
self.assertEqual(labels["audiocpp_remote_url"],
"audio.cpp remote URL")
+ self.assertEqual(labels["input_dir"], "Input Directory")
+ self.assertEqual(labels["output_dir"], "Output Directory")
self.assertNotIn("(clone)", " ".join(labels.values()))
- # The language setting is a picker labelled "Default Language".
- self.assertEqual(labels["language"], "Default Language")
+ # The language setting is a picker labelled "Language".
+ self.assertEqual(labels["language"], "Language")
self.assertEqual(kinds["language"], "choice")
# The ports section note hangs off the first port field, the remote
# section note off the first remote URL field.
notes = {f["key"]: f.get("note") for f in captured["fields"]}
+ self.assertTrue(notes["input_dir"])
+ self.assertTrue(notes["output_dir"])
+ self.assertTrue(notes["debug"])
self.assertTrue(notes["stop_and_exit"])
self.assertTrue(notes["audiocpp_port"])
self.assertTrue(notes["audiocpp_remote_url"])
self.assertIsNone(notes["audio_format"])
+ self.assertIsNone(notes["speed"])
self.assertIsNone(notes["qwen_port"])
self.assertEqual(applied, [{"audio_format": "ogg",
"audio_bitrate": "192k",
"language": "English",
"chunk_size": "300",
+ "input_dir": "/books",
+ "output_dir": "/audiobooks",
+ "speed": "1.0",
+ "debug": False,
"stop_and_exit": True,
"unload_models": True,
"qwen_port": "7860",
@@ -2468,6 +2540,8 @@ class SettingsTests(unittest.TestCase):
return back_value # first exit: Esc
return {"audio_format": "m4b", "audio_bitrate": "128k",
"language": "English", "chunk_size": "250",
+ "input_dir": "./input", "output_dir": "./output",
+ "speed": "1.0", "debug": False,
"stop_and_exit": True, "unload_models": True,
"qwen_port": "7860",
"faster_port": "8000", "audiocpp_port": "8080"}
@@ -2499,7 +2573,8 @@ class SettingsTests(unittest.TestCase):
original = {name: getattr(hub.config, name) for name in
("AUDIO_FORMAT", "AUDIO_BITRATE", "LANGUAGE",
- "CHUNK_SIZE", "STOP_SERVER_AND_EXIT",
+ "CHUNK_SIZE", "INPUT_DIR", "OUTPUT_DIR",
+ "SPEED", "DEBUG", "STOP_SERVER_AND_EXIT",
"AUDIOCPP_UNLOAD_MODELS",
"QWEN_API_URL",
"FASTER_API_URL", "AUDIOCPP_API_URL",
@@ -2517,6 +2592,10 @@ class SettingsTests(unittest.TestCase):
'LANGUAGE = "English"\n'
"\n"
"CHUNK_SIZE = 250\n"
+ 'INPUT_DIR = "./input"\n'
+ 'OUTPUT_DIR = "./output"\n'
+ "SPEED = 1.0\n"
+ "DEBUG = False\n"
"STOP_SERVER_AND_EXIT = True\n"
"AUDIOCPP_UNLOAD_MODELS = True\n"
'QWEN_API_URL = "http://127.0.0.1:7860"\n'
@@ -2538,6 +2617,11 @@ class SettingsTests(unittest.TestCase):
text = path.read_text(encoding="utf-8")
self.assertIn('AUDIO_FORMAT = "m4b"', text)
self.assertIn("CHUNK_SIZE = 300", text)
+ # The settings-only fields are written back unchanged.
+ self.assertIn('INPUT_DIR = "', text)
+ self.assertIn('OUTPUT_DIR = "', text)
+ self.assertIn("SPEED = 1.0", text)
+ self.assertIn("DEBUG = False", text)
# The running session also picked up the change in-memory.
self.assertEqual(hub.config.CHUNK_SIZE, 300)