Files
MeshTerm/tests/test_cardputer_zero_chrome.py
Jean-Pierre MartineauandClaude Opus 5.5 11b5274b31 Docstrings and comments of the tests are in ASD-STE100
Each test docstring states the behaviour that the test proves, in the
simple present. No assertion message, test id, or other string literal
changed. Four statements now agree with the code: the Trace highlight
stays on the last row, a menu count, and two others.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-10-06 21:36:50 -04:00

159 lines
6.6 KiB
Python

# SPDX-License-Identifier: Apache-2.0
"""The frame of the Cardputer: no header row, its atoms on the title bar, dialogs over the bar."""
from __future__ import annotations
from types import SimpleNamespace
from rich.cells import cell_len
from rich.text import Text
from meshterm import __version__
from meshterm.platforms import CARDPUTER_ZERO, PICOCALC_LYRA, set_platform
from meshterm.ui import menu
from meshterm.ui.tui import frame
from meshterm.ui.tui.screen import ScrollScreen
from meshterm.ui.widgets import battery_cell
from tests.conftest import plain as _plain
ROWS, COLS = CARDPUTER_ZERO.readable_rows, CARDPUTER_ZERO.readable_cols
def _status() -> Text:
"""Three unread messages and a battery at 87%.
This is what the header callback gives to the frame.
"""
status = Text()
status.append("●", style="err")
status.append(" 3", style="warn")
return Text(" ").join([status, battery_cell(87)])
def _screen(title: str = "Chrome probe", hint: str = "↑↓ move · Esc back") -> ScrollScreen:
body = Text("\n".join(f"row {i}" for i in range(40)))
screen = ScrollScreen(body, title=title, floating=False)
screen._footer_hint = hint
return screen
def _rows(header: Text, cols: int = COLS, rows: int = ROWS, **lane) -> list[str]:
"""The composed base frame, with one ANSI string for each row."""
return frame.compose_base(header, _screen(), "", cols, rows, **lane).split("\n")
def test_the_cardputer_has_no_header_row() -> None:
"""The title bar is the top row, and each screen uses the row of the header for its body."""
set_platform(CARDPUTER_ZERO)
assert not CARDPUTER_ZERO.header_row
assert frame.header_lines(_status(), COLS) == []
composed = [_plain(line) for line in _rows(_status())]
assert len(composed) == ROWS
assert composed[0].startswith("↑↓ ") and "Chrome probe" in composed[0]
assert composed[1].startswith("row 0")
# The bar, then twelve body rows, then the footer. The row of the header goes to the body.
assert composed[12].startswith("row 11")
def test_a_platform_with_a_header_row_keeps_it() -> None:
"""The PicoCalc does not change.
The header is on top, the bar is under it, and the bar has no status.
"""
set_platform(PICOCALC_LYRA)
composed = [_plain(line) for line in _rows(Text("hdr"), 53, 26)]
assert composed[0].startswith("hdr")
assert composed[1].startswith("↑↓ ") and "hdr" not in composed[1]
def test_the_status_sits_in_the_corner_after_the_way_out() -> None:
"""``↑↓ ── Title ──── Esc back ● 3 ⣷ 87%``: the badges and battery stay in their corner."""
set_platform(CARDPUTER_ZERO)
bar = frame._title_bar(_screen(), COLS, False, True, _status()).plain
assert cell_len(bar) == COLS
assert bar.endswith("Esc back " + _status().plain)
assert bar.startswith("↑↓ ─") and "Chrome probe" in bar
def test_an_empty_status_draws_the_bar_as_it_always_was() -> None:
"""With nothing unread and no battery, the bar is the bar of a screen with a header row."""
set_platform(CARDPUTER_ZERO)
plain_bar = frame._title_bar(_screen(), COLS, False, True).plain
assert frame._title_bar(_screen(), COLS, False, True, Text()).plain == plain_bar
def test_a_long_title_gives_way_before_the_status_does() -> None:
"""The way out goes first, then the title is cut short. The status is never pushed off."""
set_platform(CARDPUTER_ZERO)
status = _status()
long_title = "Trace — Hilltop-Repeater over a much longer spec than fits"
bar = frame._title_bar(_screen(long_title), COLS, False, True, status).plain
assert cell_len(bar) == COLS
assert bar.endswith(" " + status.plain)
assert "Esc" not in bar
assert "…" in bar and "Trace — Hilltop" in bar
def test_the_header_is_its_atoms_alone_without_a_row() -> None:
"""The header has only its atoms and no row: no version, no pulse, no padding.
The badges and the battery have one space between them.
"""
set_platform(CARDPUTER_ZERO)
ctx = SimpleNamespace(
mock=False,
chat=SimpleNamespace(unread_total=lambda: 3),
watchtower=SimpleNamespace(unacked_count=lambda: 1),
battery=SimpleNamespace(reading=lambda: SimpleNamespace(percent=87, charging=False)),
)
header = menu._header(ctx, {}, COLS)
assert header.plain == f"● 3 ▲ 1 {battery_cell(87).plain}"
ctx.chat = SimpleNamespace(unread_total=lambda: 0)
ctx.watchtower = SimpleNamespace(unacked_count=lambda: 0)
ctx.battery = SimpleNamespace(reading=lambda: None)
assert menu._header(ctx, {}, COLS).plain == ""
def test_the_main_menu_wears_the_wordmark_where_no_header_row_does() -> None:
"""If there is no header row, the title of the root screen is ``MeshTerm vX``.
The title has the colours of the header. If there is a header row, the title is the question.
"""
set_platform(CARDPUTER_ZERO)
assert menu._menu_title() == f"MeshTerm v{__version__}"
screen = menu._MainMenu(menu._menu_title(), [], footer_hint="↑↓ move · ^Q quit?")
bar = frame._title_bar(screen, COLS, False, False, _status())
start = bar.plain.index("MeshTerm")
styles = {str(span.style) for span in bar.spans if span.start <= start < span.end}
assert "brand" in styles
set_platform(PICOCALC_LYRA)
assert menu._menu_title() == "What would you like to do?"
def test_a_tall_dialog_covers_the_bar_and_blanks_its_ends() -> None:
"""The dialog covers the bar, but never the lane. No part of the bar shows beside the box.
The lane of a dialog belongs to the dialog and names keys nowhere else, so the box stops
one row before the lane. On the bar, the cells on each side of the box are blank. If they
are not blank, a stray ``7%`` looks like the battery.
"""
set_platform(CARDPUTER_ZERO)
assert ROWS - 2 - CARDPUTER_ZERO.dialog_row_margin == 11 # the rows that the dialog can use
base = _rows(_status(), footer_lane=lambda: Text("LANE"))
box = "\n".join("|" + "x" * 45 + "|" for _ in range(ROWS - 1))
rows = [_plain(row) for row in frame.composite_float(base, box, COLS, ROWS)]
assert rows[0].strip() == "|" + "x" * 45 + "|" # the ends of the bar are blank
assert rows[1].startswith("ro") # the backdrop is still visible in the gutter below the bar
assert rows[ROWS - 1].startswith("LANE")
def test_a_short_dialog_leaves_the_bar_whole() -> None:
"""A box that does not reach the top row leaves the bar, and its status, visible."""
set_platform(CARDPUTER_ZERO)
base = _rows(_status())
rows = frame.composite_float(base, "\n".join(["[box]"] * 5), COLS, ROWS)
assert rows[0] == base[0]
assert _plain(rows[0]).endswith(_status().plain)