aboutsummaryrefslogtreecommitdiff
path: root/tests/test_tui.py
diff options
context:
space:
mode:
Diffstat (limited to 'tests/test_tui.py')
-rw-r--r--tests/test_tui.py76
1 files changed, 76 insertions, 0 deletions
diff --git a/tests/test_tui.py b/tests/test_tui.py
index 58d8273..c121d55 100644
--- a/tests/test_tui.py
+++ b/tests/test_tui.py
@@ -365,6 +365,82 @@ class LineEditTests(TuiTestCase):
self.assertEqual(value, "teq")
+class FormTests(TuiTestCase):
+ def _fields(self):
+ # Fresh dicts each call: form() edits field values in place, and a
+ # shared class attribute would leak edits between tests.
+ return [
+ {"key": "fmt", "label": "Format", "kind": "choice",
+ "value": "m4b", "choices": ["mp3", "m4b", "ogg"]},
+ {"key": "chunk", "label": "Chunk", "kind": "text",
+ "value": "250"},
+ ]
+
+ def test_save_returns_current_values(self):
+ screen = FakeScreen(keys=[9, 10]) # Tab -> Save, Enter
+ result = tui.form(screen, "Settings", self._fields())
+ self.assertEqual(result, {"fmt": "m4b", "chunk": "250"})
+
+ def test_cancel_returns_back_value(self):
+ marker = object()
+ # Tab -> buttons, Left -> Cancel, Enter.
+ screen = FakeScreen(keys=[9, FakeCurses.KEY_LEFT, 10])
+ result = tui.form(screen, "Settings", self._fields(),
+ back_value=marker)
+ self.assertIs(result, marker)
+
+ def test_esc_returns_back_value(self):
+ marker = object()
+ screen = FakeScreen(keys=[27])
+ self.assertIs(
+ tui.form(screen, "Settings", self._fields(), back_value=marker),
+ marker)
+
+ def test_q_still_aborts_with_back_value(self):
+ marker = object()
+ screen = FakeScreen(keys=[ord("q")])
+ with self.assertRaises(tui.WizardCancelled):
+ tui.form(screen, "Settings", self._fields(), back_value=marker)
+
+ def test_choice_field_picks_another_value(self):
+ # Enter opens the choice menu on 'm4b' (index 1); Down moves to
+ # 'ogg', Enter accepts; Tab -> Save, Enter.
+ screen = FakeScreen(keys=[10, FakeCurses.KEY_DOWN, 10, 9, 10])
+ result = tui.form(screen, "Settings", self._fields())
+ self.assertEqual(result, {"fmt": "ogg", "chunk": "250"})
+
+ def test_text_field_edits_then_saves(self):
+ # Down to the text row, Enter opens the editor, type 'x', Enter,
+ # then Tab -> Save, Enter.
+ screen = FakeScreen(
+ keys=[FakeCurses.KEY_DOWN, 10, ord("x"), 10, 9, 10])
+ result = tui.form(screen, "Settings", self._fields())
+ self.assertEqual(result, {"fmt": "m4b", "chunk": "250x"})
+
+ def test_validation_error_refuses_save_then_recovers(self):
+ fields = [
+ {"key": "chunk", "label": "Chunk", "kind": "text", "value": "bad",
+ "validate": lambda s: None if s.isdigit() else "digits only"},
+ {"key": "fmt", "label": "Format", "kind": "text", "value": "x"},
+ ]
+ # Tab->Save(Enter) fails, the flash consumes the next key; Enter
+ # reopens the editor, Ctrl-U clears 'bad', type '120', Enter; then
+ # Tab->Save(Enter).
+ keys = [9, 10, 10, 10, 21, ord("1"), ord("2"), ord("0"), 10, 9, 10]
+ screen = FakeScreen(keys=keys)
+ result = tui.form(screen, "Settings", fields)
+ self.assertEqual(result, {"chunk": "120", "fmt": "x"})
+
+ def test_rows_left_justified_inside_the_border(self):
+ screen = FakeScreen(keys=[9, 10])
+ tui.form(screen, "Settings", self._fields())
+ self.assert_inside_border(screen)
+
+ def test_empty_fields_rejected(self):
+ with self.assertRaises(ValueError):
+ tui.form(self.screen, "Settings", [])
+
+
def _accept_audio_cpp(entry: Path):
"""auto_select callback that accepts an 'audio.cpp' checkout root."""
if entry.name == "audio.cpp" and (entry / "model_specs").is_dir():