from __future__ import annotations import re import types import pytest from rich.cells import cell_len from somafm_tui.widgets.header import HeaderBar TIME = re.compile(r"\d\d:\d\d:\d\d$") DATE = re.compile(r"[A-Z][a-z]{2} \d\d [A-Z][a-z]{2}$") VOLUME = re.compile(r"vol \d+%$") def render_header(width: int, height: int = 3) -> list[str]: """Render the header without a running app, as plain text per line.""" fake = type("Fake", (), {})() fake.app = types.SimpleNamespace( playing_state="playing", volume=70, current=None, notice=None ) fake.size = types.SimpleNamespace(width=width, height=height) return [line.plain.rstrip() for line in HeaderBar.render(fake).renderables] @pytest.mark.parametrize("width", [54, 60, 100, 143, 200]) def test_right_block_is_flush_right(width: int) -> None: """Clock, date and volume all end on the same column, at the edge.""" clock, date, volume = render_header(width) assert [cell_len(line) for line in (clock, date, volume)] == [width] * 3 assert TIME.search(clock) assert DATE.search(date) assert VOLUME.search(volume) def test_ragged_middle_does_not_shift_the_right_block() -> None: """"SOMA FM RADIO" and "SAN FRANCISCO" are shorter than "LISTENER SUPPORTED"; the right block must not follow their length.""" clock, date, volume = render_header(143) assert cell_len(clock) == cell_len(date) == cell_len(volume) == 143 def test_right_block_hidden_on_narrow_terminals() -> None: """Below the threshold the right block is dropped, not squashed.""" lines = render_header(30) assert all(":" not in line for line in lines)