diff options
| author | historia <historiavg@proton.me> | 2026-08-23 23:48:25 -0400 |
|---|---|---|
| committer | historia <historiavg@proton.me> | 2026-08-23 23:48:25 -0400 |
| commit | 5bfbdcb5765fd4eb57d13c67169bb3c2706ead75 (patch) | |
| tree | a07a27976f56a449e8c33641161553aa0989f5c2 /tests/test_hub.py | |
| parent | 07f7b351f2956b6c92761877c9a4314bcede3b6e (diff) | |
| download | tts-audiobook-generator-5bfbdcb5765fd4eb57d13c67169bb3c2706ead75.tar.gz | |
feat: audiobook.py tui: convert, modify, or install backends
Diffstat (limited to 'tests/test_hub.py')
| -rw-r--r-- | tests/test_hub.py | 91 |
1 files changed, 91 insertions, 0 deletions
diff --git a/tests/test_hub.py b/tests/test_hub.py new file mode 100644 index 0000000..5f6d992 --- /dev/null +++ b/tests/test_hub.py @@ -0,0 +1,91 @@ +"""Tests for the TUI hub (hub.py) menu and helpers. + +The hub drives the same curses widgets as tui.py, so these tests reuse the +fake curses/screen from test_tui to run the menu without a terminal. +""" + +import unittest +from pathlib import Path +from unittest.mock import patch + +import hub +import tui +from tests.test_tui import FakeCurses, FakeScreen + + +class HubHelperTests(unittest.TestCase): + """Pure helpers in hub.py (no curses).""" + + def test_is_float(self): + self.assertTrue(hub._is_float("1.0")) + self.assertTrue(hub._is_float("2")) + self.assertFalse(hub._is_float("abc")) + self.assertFalse(hub._is_float("")) + + def test_list_voices_from_dir(self): + with __import__("tempfile").TemporaryDirectory() as td: + d = Path(td) + (d / "Narrator.wav").write_bytes(b"x") + (d / "Alpha.WAV").write_bytes(b"x") + (d / "notes.txt").write_bytes(b"x") + voices = hub._list_voices(str(d)) + # Stems preserve case; sorting is case-insensitive. + self.assertEqual(voices, ["Alpha", "Narrator"]) + + def test_list_voices_missing_dir(self): + self.assertEqual(hub._list_voices("/no/such/dir"), []) + + def test_status_mark(self): + from backends import BackendStatus + ready = BackendStatus("k", "l", installed=True, configured=True) + half = BackendStatus("k", "l", installed=True, configured=False) + none = BackendStatus("k", "l", installed=False, configured=False) + self.assertEqual(hub._status_mark("k", [ready]), "ready") + self.assertEqual(hub._status_mark("k", [half]), "installed") + self.assertEqual(hub._status_mark("k", [none]), "not set up") + self.assertEqual(hub._status_mark("missing", []), "not set up") + + +class HubMenuTests(unittest.TestCase): + """Drive _hub_menu with a fake screen (no terminal).""" + + def setUp(self): + tui._THEME.clear() + self.curses = FakeCurses() + from unittest.mock import patch as _patch + self._patcher = _patch.dict("sys.modules", {"curses": self.curses}) + self._patcher.start() + self.addCleanup(self._patcher.stop) + self.addCleanup(tui._THEME.clear) + + def test_quit_returns_none(self): + # Main menu: move to "Quit" (4th option, index 3) and press Enter. + screen = FakeScreen(keys=[FakeCurses.KEY_DOWN, FakeCurses.KEY_DOWN, + FakeCurses.KEY_DOWN, 10]) + with patch.object(hub, "detect_all", return_value=[]): + result = hub._hub_menu(screen) + self.assertIsNone(result) + + def test_convert_with_no_ready_backend_offers_setup(self): + # Convert -> "Set up a backend..." is the only entry -> Enter selects + # it -> setup menu lists 3 backends; press Esc to go back -> convert + # returns None -> main menu loops. Then quit (Down x3 + Enter). + from backends import BackendInfo, BackendStatus + none = BackendStatus("k", "l", installed=False, configured=False) + infos = [BackendInfo("audiocpp", "audio.cpp", lambda: none, + lambda: 0), + BackendInfo("qwen", "Qwen", lambda: none, lambda: 0), + BackendInfo("faster", "faster", lambda: none, lambda: 0)] + with patch.object(hub, "detect_all", return_value=[none, none, none]), \ + patch.object(hub, "REGISTRY", infos): + # Convert(Enter), setup-entry(Enter), Esc on setup menu, + # back at main menu -> Down x3 -> Enter (Quit). + screen = FakeScreen(keys=[10, 10, 27, + FakeCurses.KEY_DOWN, FakeCurses.KEY_DOWN, + FakeCurses.KEY_DOWN, 10]) + result = hub._hub_menu(screen) + self.assertIsNone(result) + + +if __name__ == "__main__": + unittest.main() |
