aboutsummaryrefslogtreecommitdiff
path: root/app/tests/test_taskview.py
diff options
context:
space:
mode:
authorhistoria <historiavg@proton.me>2026-08-25 19:03:09 -0400
committerhistoria <historiavg@proton.me>2026-08-25 19:03:09 -0400
commit8c9a782dfe94525dc5f0893c98fd19543648264b (patch)
treefdff70d967ef06f0da560ca284842427cbe647a8 /app/tests/test_taskview.py
parent64e9940d43fad1bc5908b39673b03e4fdc1e8f2f (diff)
downloadtts-audiobook-generator-8c9a782dfe94525dc5f0893c98fd19543648264b.tar.gz
fix: tui errors wait for getch()
Diffstat (limited to 'app/tests/test_taskview.py')
-rw-r--r--app/tests/test_taskview.py50
1 files changed, 50 insertions, 0 deletions
diff --git a/app/tests/test_taskview.py b/app/tests/test_taskview.py
index 4b03b41..6c984ad 100644
--- a/app/tests/test_taskview.py
+++ b/app/tests/test_taskview.py
@@ -276,6 +276,42 @@ class NoWaitTests(_FakeTui, unittest.TestCase):
self.assertNotIn("press any key", text)
+class InputModeRestoreTests(_FakeTui, unittest.TestCase):
+ """run() must leave the screen blocking again when the view exits.
+
+ The views drive their redraw loop with a timed getch; if that cadence
+ leaked into the hub, single-getch dialogs like tui.flash would dismiss
+ themselves after one timeout instead of waiting for a key.
+ """
+
+ def test_task_view_run_restores_blocking_getch(self):
+ def fake_worker_main(view):
+ view._queue.put({"kind": "step_start", "index": 0,
+ "title": "one"})
+ view._queue.put({"kind": "step_done", "index": 0, "rc": 0})
+ view._queue.put({"kind": "finish", "phase": "done", "rc": 0})
+
+ screen = FakeScreen(width=80, height=24)
+ with patch.object(taskview.TaskView, "_worker_main",
+ fake_worker_main):
+ view = taskview.TaskView(screen, "Setup", [_step("one")],
+ clock=lambda: 1000.0,
+ wait_on_finish=False)
+ view._worker = _SyncWorker(view._worker_main)
+ view.run()
+ self.assertEqual(screen.timeouts[-1], -1)
+
+ def test_lanes_view_run_restores_blocking_getch(self):
+ screen = FakeScreen(keys=[27]) # any key leaves the finished view
+ lanes = [taskview.TaskLane("A", [_step("a")]),
+ taskview.TaskLane("B", [_step("b")])]
+ view = taskview.LanesView(screen, "Setup", lanes,
+ clock=lambda: 1000.0)
+ with patch.object(taskview.threading, "Thread", _SyncThread):
+ view.run()
+ self.assertEqual(screen.timeouts[-1], -1)
+
+
class _SyncWorker:
"""A stand-in for threading.Thread that runs the target synchronously."""
@@ -286,6 +322,20 @@ class _SyncWorker:
self._fn()
+class _SyncThread:
+ """A threading.Thread stand-in that runs its target on start()."""
+
+ def __init__(self, target=None, args=(), kwargs=None, daemon=None):
+ self._target = target
+ self._args = args
+
+ def start(self):
+ self._target(*self._args)
+
+ def join(self, timeout=None):
+ pass
+
+
class LabelTests(unittest.TestCase):
def test_fmt_bytes(self):
self.assertEqual(taskview._fmt_bytes(512), "512B")