Files
beefy-player/tests/test_header.py
T

94 lines
3.2 KiB
Python

from __future__ import annotations
import re
import types
import pytest
from rich.cells import cell_len
from beefy_player.providers.somafm import SomaFMProvider
from beefy_player.providers.tilderadio import TilderadioProvider
from beefy_player.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, provider=None
) -> 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,
provider=provider or SomaFMProvider(),
)
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:
""""TILDERADIO" is shorter than "STREAMED BY / FOR USERS OF THE"; the
right block must not follow the length of the middle lines."""
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)
def test_somafm_hero_is_the_wordmark_and_its_taglines() -> None:
lines = render_header(143)
assert lines[0].startswith("▄▀▀▀ ▄▀▀▄ █▄ ▄█ ▄▀▀▄")
assert "SOMA FM RADIO" in lines[0]
assert "LISTENER SUPPORTED" in lines[1]
assert "SAN FRANCISCO" in lines[2]
def test_tilderadio_hero_is_its_own_art_and_motto() -> None:
provider = TilderadioProvider()
lines = render_header(143, height=len(provider.hero), provider=provider)
assert len(lines) == len(provider.hero)
# the caption block is centred against the seven-row radio icon
assert "TILDERADIO" in lines[2]
assert "STREAMED BY / FOR USERS OF THE" in lines[3]
assert "TILDEVERSE" in lines[4]
# the radio icon's signature green wave survives the conversion
styles = [
str(span.style)
for line in HeaderBar.render(_fake(provider)).renderables
for span in line.spans
]
assert any("green" in style for style in styles)
assert all("SOMA" not in line for line in lines)
def _fake(provider):
fake = type("Fake", (), {})()
fake.app = types.SimpleNamespace(
playing_state="playing",
volume=70,
current=None,
notice=None,
provider=provider,
)
fake.size = types.SimpleNamespace(width=143, height=len(provider.hero) or 3)
return fake