diff options
Diffstat (limited to 'app/tests/test_tui.py')
| -rw-r--r-- | app/tests/test_tui.py | 106 |
1 files changed, 94 insertions, 12 deletions
diff --git a/app/tests/test_tui.py b/app/tests/test_tui.py index eb6872a..916f434 100644 --- a/app/tests/test_tui.py +++ b/app/tests/test_tui.py @@ -267,7 +267,7 @@ class MenuTests(TuiTestCase): def test_suffix_renders_in_its_theme_color(self): # default_index=1 keeps the suffixed option unselected, so its # segments keep their own colors instead of the cursor bar. - options = [("Build audio.cpp server", "build", + options = [("Build audio.cpp Server", "build", ("[recommended]", "warn")), ("other", "other")] screen = FakeScreen(keys=[10]) tui.menu(screen, "Pick", options, default_index=1) @@ -276,7 +276,7 @@ class MenuTests(TuiTestCase): if drawn == text) self.assertEqual(attr, tui._THEME["warn"]) label_attr = next(a for _, _, drawn, a in screen.strings - if drawn == "Build audio.cpp server") + if drawn == "Build audio.cpp Server") self.assertEqual(label_attr, tui._THEME["body"]) def test_selected_row_has_arrow_in_the_margin(self): @@ -317,7 +317,7 @@ class MenuTableTests(TuiTestCase): def test_name_column_left_aligned_at_margin(self): screen = FakeScreen(keys=[10]) tui.menu(screen, "Hub", [("Quit", "quit")], - table_title="Backend status", table_rows=self.ROWS) + table_title="Backend Status", table_rows=self.ROWS) x0, _ = self.dialog_box(screen) margin = x0 + 1 + tui.Frame.LIST_MARGIN for name, _, _ in self.ROWS: @@ -328,7 +328,7 @@ class MenuTableTests(TuiTestCase): def test_status_column_aligned_at_one_fixed_offset(self): screen = FakeScreen(keys=[10]) tui.menu(screen, "Hub", [("Quit", "quit")], - table_title="Backend status", table_rows=self.ROWS) + table_title="Backend Status", table_rows=self.ROWS) x0, _ = self.dialog_box(screen) margin = x0 + 1 + tui.Frame.LIST_MARGIN name_w = max(len(name) for name, _, _ in self.ROWS) @@ -341,7 +341,7 @@ class MenuTableTests(TuiTestCase): def test_status_text_uses_the_theme_kind_color(self): screen = FakeScreen(keys=[10]) tui.menu(screen, "Hub", [("Quit", "quit")], - table_title="Backend status", table_rows=self.ROWS) + table_title="Backend Status", table_rows=self.ROWS) want = {"err": tui._THEME["err"], "warn": tui._THEME["warn"], "ok": tui._THEME["ok"]} for _, status, kind in self.ROWS: @@ -362,7 +362,7 @@ class MenuTableTests(TuiTestCase): def test_three_element_rows_default_to_body_names(self): screen = FakeScreen(keys=[10]) tui.menu(screen, "Hub", [("Quit", "quit")], - table_title="Backend status", table_rows=self.ROWS) + table_title="Backend Status", table_rows=self.ROWS) for name, _, _ in self.ROWS: attr = next(a for _, _, text, a in screen.strings if text.rstrip() == name) @@ -371,24 +371,24 @@ class MenuTableTests(TuiTestCase): def test_table_title_is_dim_and_left_aligned(self): screen = FakeScreen(keys=[10]) tui.menu(screen, "Hub", [("Quit", "quit")], - table_title="Backend status", table_rows=self.ROWS) + table_title="Backend Status", table_rows=self.ROWS) x0, _ = self.dialog_box(screen) margin = x0 + 1 + tui.Frame.LIST_MARGIN x, attr = next((x, a) for _, x, text, a in screen.strings - if text == "Backend status") + if text == "Backend Status") self.assertEqual(x, margin) self.assertEqual(attr, tui._THEME["dim"]) def test_table_does_not_paint_over_the_border(self): screen = FakeScreen(keys=[10]) tui.menu(screen, "Hub", [("Quit", "quit")], - table_title="Backend status", table_rows=self.ROWS) + table_title="Backend Status", table_rows=self.ROWS) self.assert_inside_border(screen) def test_notice_line_is_red_and_above_the_table(self): screen = FakeScreen(keys=[10]) tui.menu(screen, "Hub", [("Quit", "quit")], - table_title="Backend status", table_rows=self.ROWS, + table_title="Backend Status", table_rows=self.ROWS, notice_lines=[("Warning: ffmpeg not installed!", "err")]) x0, _ = self.dialog_box(screen) margin = x0 + 1 + tui.Frame.LIST_MARGIN @@ -396,11 +396,11 @@ class MenuTableTests(TuiTestCase): if text == "Warning: ffmpeg not installed!") self.assertEqual(x, margin) self.assertEqual(attr, tui._THEME["err"]) - # The notice sits above the table title ("Backend status"). + # The notice sits above the table title ("Backend Status"). notice_y = next(y for y, _, text, _ in screen.strings if text == "Warning: ffmpeg not installed!") title_y = next(y for y, _, text, _ in screen.strings - if text == "Backend status") + if text == "Backend Status") self.assertLess(notice_y, title_y) self.assert_inside_border(screen) @@ -1283,6 +1283,88 @@ class FlashTests(TuiTestCase): self.assertIsNone(frame.status) +class TextViewerTests(TuiTestCase): + """tui.text_viewer: a scrollable read-only dialog; Esc/q/Enter closes.""" + + LINES = ["first line", "second line", "third line"] + + def test_lines_render_and_enter_closes(self): + marker = object() + screen = FakeScreen(keys=[10]) + self.assertIs( + tui.text_viewer(screen, "Help", self.LINES, back_value=marker), + marker) + for line in self.LINES: + self.assertTrue(any(text == line for _, _, text, _ + in screen.strings), line) + self.assert_inside_border(screen) + + def test_esc_returns_back_value(self): + marker = object() + screen = FakeScreen(keys=[27]) + self.assertIs( + tui.text_viewer(screen, "Help", self.LINES, back_value=marker), + marker) + + def test_q_returns_back_value_like_esc(self): + marker = object() + screen = FakeScreen(keys=[ord("q")]) + self.assertIs( + tui.text_viewer(screen, "Help", self.LINES, back_value=marker), + marker) + + def test_esc_aborts_without_back_value(self): + screen = FakeScreen(keys=[27]) + with self.assertRaises(tui.WizardCancelled): + tui.text_viewer(screen, "Help", self.LINES) + + def test_enter_aborts_without_back_value(self): + screen = FakeScreen(keys=[10]) + with self.assertRaises(tui.WizardCancelled): + tui.text_viewer(screen, "Help", self.LINES) + + def test_no_cursor_bar_is_drawn(self): + # Read-only: no row is selectable, so even with the cursor on a + # line the cyan selection bar never paints. + screen = FakeScreen(keys=[FakeCurses.KEY_END, ord("q")]) + tui.text_viewer(screen, "Help", self.LINES, back_value=object()) + bars = [s for s in screen.strings + if s[3] == tui._THEME["bar"] and not s[2].strip()] + self.assertEqual(bars, []) + + def test_end_scrolls_the_last_line_into_view(self): + # Content taller than the terminal: End shows the last line and + # the frame's scroll indicator appears in the border. + lines = [f"line {i}" for i in range(40)] + screen = FakeScreen(keys=[FakeCurses.KEY_END, ord("q")]) + tui.text_viewer(screen, "Help", lines, back_value=object()) + drawn = [text for _, _, text, _ in screen.strings] + self.assertIn("line 39", drawn) + self.assertTrue(any("/40" in text for text in drawn)) + + def test_home_returns_to_the_top(self): + lines = [f"line {i}" for i in range(40)] + screen = FakeScreen(keys=[FakeCurses.KEY_END, FakeCurses.KEY_HOME, + ord("q")]) + tui.text_viewer(screen, "Help", lines, back_value=object()) + drawn = [text for _, _, text, _ in screen.strings] + self.assertIn("line 0", drawn) + + def test_page_down_moves_a_full_page(self): + # PageDown from the top lands one page (17 visible rows) down: + # the first line scrolls off, the next one is at the top. + lines = [f"line {i}" for i in range(40)] + screen = FakeScreen(keys=[FakeCurses.KEY_NPAGE, ord("q")]) + tui.text_viewer(screen, "Help", lines, back_value=object()) + # Only the final frame counts: strings accumulate across redraws. + titles = [i for i, entry in enumerate(screen.strings) + if entry[2] == " Help "] + drawn = [entry[2] for entry in screen.strings[titles[-1]:]] + self.assertIn("line 1", drawn) + self.assertNotIn("line 0", drawn) + self.assertIn(" 2/40 ", drawn) + + class WizardTests(unittest.TestCase): """The tui.Wizard screen-stack driver: Esc steps back one screen.""" |
