TUI 改为左右分栏: 左侧栏目, 右侧内容
This commit is contained in:
1 parent
f9874454f0
commit
e06c57b7ad
17 files changed
+815
-425
No files matched your search
@@ -0,0 +1,115 @@
|
||||
import unittest
|
||||
from unittest import mock
|
||||
|
||||
from sbp.tui import frame
|
||||
from sbp.tui.term import Term
|
||||
|
||||
|
||||
class FakeScreen:
|
||||
def __init__(self, height: int = 24, width: int = 80) -> None:
|
||||
self.height = height
|
||||
self.width = width
|
||||
self.writes: list[tuple[int, int, str]] = []
|
||||
|
||||
def getmaxyx(self):
|
||||
return self.height, self.width
|
||||
|
||||
def addstr(self, y, x, text, attr=0):
|
||||
if y >= self.height or x + len(text) > self.width:
|
||||
raise AssertionError(f"write out of bounds: y={y} x={x} len={len(text)}")
|
||||
self.writes.append((y, x, text))
|
||||
|
||||
def erase(self):
|
||||
self.writes.clear()
|
||||
|
||||
def refresh(self):
|
||||
pass
|
||||
|
||||
def keypad(self, flag):
|
||||
pass
|
||||
|
||||
def getch(self):
|
||||
return -1
|
||||
|
||||
def text(self) -> str:
|
||||
return "\n".join(text for _, _, text in self.writes)
|
||||
|
||||
|
||||
def make_term(screen: FakeScreen) -> Term:
|
||||
with mock.patch.object(frame_term_curses(), "has_colors", return_value=False), \
|
||||
mock.patch.object(frame_term_curses(), "curs_set", return_value=None):
|
||||
return Term(screen)
|
||||
|
||||
|
||||
def frame_term_curses():
|
||||
import sbp.tui.term as module
|
||||
|
||||
return module.curses
|
||||
|
||||
|
||||
class WindowOffsetTest(unittest.TestCase):
|
||||
def test_no_scroll_when_everything_fits(self) -> None:
|
||||
self.assertEqual(frame.window_offset(3, 5, 10), 0)
|
||||
|
||||
def test_keeps_selection_visible(self) -> None:
|
||||
self.assertEqual(frame.window_offset(7, 20, 5), 3)
|
||||
|
||||
def test_clamps_to_last_page(self) -> None:
|
||||
self.assertEqual(frame.window_offset(19, 20, 5), 15)
|
||||
|
||||
|
||||
class SidebarWidthTest(unittest.TestCase):
|
||||
def test_minimum(self) -> None:
|
||||
self.assertEqual(frame.sidebar_width(["A"]), frame.SIDEBAR_MIN)
|
||||
|
||||
def test_grows_with_titles(self) -> None:
|
||||
self.assertGreater(
|
||||
frame.sidebar_width(["VeryLongSectionName"]), frame.sidebar_width(["A"])
|
||||
)
|
||||
|
||||
def test_capped(self) -> None:
|
||||
self.assertEqual(frame.sidebar_width(["x" * 100]), frame.SIDEBAR_MAX)
|
||||
|
||||
|
||||
class DrawTest(unittest.TestCase):
|
||||
def setUp(self) -> None:
|
||||
self.screen = FakeScreen()
|
||||
self.term = make_term(self.screen)
|
||||
|
||||
def draw(self, rows=None, index=0, width=80):
|
||||
rows = rows or [frame.Row("first", action=lambda app: None), frame.Row("second")]
|
||||
frame.draw(
|
||||
self.term,
|
||||
title="sbp 2.0.0",
|
||||
subtitle="host active",
|
||||
sidebar=["Dashboard", "Protocols", "Users", "Settings", "Logs"],
|
||||
sidebar_index=1,
|
||||
sidebar_focused=False,
|
||||
content_title="Protocols",
|
||||
rows=rows,
|
||||
index=index,
|
||||
content_focused=True,
|
||||
footer="keys",
|
||||
)
|
||||
|
||||
def test_draws_both_panes(self) -> None:
|
||||
self.draw()
|
||||
text = self.screen.text()
|
||||
for word in ("Dashboard", "Protocols", "Users", "Settings", "Logs", "first", "second", "keys"):
|
||||
self.assertIn(word, text)
|
||||
|
||||
def test_selected_row_is_padded_for_highlight(self) -> None:
|
||||
self.draw(index=1)
|
||||
row = [text for y, _, text in self.screen.writes if text.startswith("second")]
|
||||
self.assertTrue(row)
|
||||
self.assertGreater(len(row[0]), len("second"))
|
||||
|
||||
def test_small_terminal_shows_hint(self) -> None:
|
||||
self.screen = FakeScreen(height=8, width=40)
|
||||
self.term.screen = self.screen
|
||||
self.draw()
|
||||
self.assertIn("terminal too small", self.screen.text())
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
unittest.main()
|
||||
Reference in new issue
Block a user