Files
MeshTerm/tests/test_pathgraph.py
T
Jean-Pierre MartineauandClaude Opus 4.8 4f78ba5a54 Path graph: keep node labels whole until they overflow the canvas
The fan-lane route graph clipped every label to a fixed 12-cell budget, so
node names past twelve characters ellipsized even with room to spare. Cap the
label at the physical canvas width instead: a name is kept whole unless it is
wider than the whole canvas (nowhere for the cells to go), and the placement
pass — which already slides an endpoint's label inward or drops a crowded
relay's — decides where it lands. Message-paths endpoints now read in full.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-15 15:50:56 -04:00

109 lines
3.6 KiB
Python

"""Unit tests for the shared route-graph widget (the fan-lane braille renderer)."""
from __future__ import annotations
import re
from meshterm.ui.pathgraph import DST_NODE, SRC_NODE, PathLayer, render_path_graph
_ANSI = re.compile(r"\x1b\[[0-9;]*m")
WHITE = (255, 255, 255)
GREEN = (74, 222, 128)
YELLOW = (250, 204, 21)
def _glyph(node: str) -> tuple[str, str]:
# Deliberately off-palette marker colours, so colour assertions about *edges*
# can never accidentally match a marker's escape sequence.
if node in (SRC_NODE, DST_NODE):
return ("★", "#123456")
return ("●", "#654321")
def _render(layers, label_of=None): # noqa: ANN001
return render_path_graph(
layers,
60,
glyph_of=_glyph,
label_of=label_of or (lambda node: "you" if node in (SRC_NODE, DST_NODE) else node[:2]),
label_rgb_of=lambda _node: WHITE,
)
def _sgr(rgb: tuple[int, int, int]) -> str:
r, g, b = rgb
return f"38;2;{r};{g};{b}m"
def test_no_layers_render_nothing() -> None:
assert render_path_graph(
[], 60, glyph_of=_glyph, label_of=lambda n: None, label_rgb_of=lambda n: WHITE
) == []
def test_identical_paths_collapse_to_the_top_layer() -> None:
"""The same route in two layers draws once, in the higher priority's colour."""
layers = [
PathLayer(("aa", "bb"), YELLOW, 2),
PathLayer(("aa", "bb"), WHITE, 4),
]
joined = "\n".join(_render(layers))
assert _sgr(WHITE) in joined
assert _sgr(YELLOW) not in joined
def test_distinct_layers_draw_in_their_own_colours() -> None:
"""Three different routes keep three edge colours on one canvas."""
layers = [
PathLayer(("aa", "bb"), YELLOW, 2),
PathLayer(("cc",), GREEN, 3),
PathLayer(("dd", "ee", "ff"), WHITE, 4),
]
joined = "\n".join(_render(layers))
for rgb in (YELLOW, GREEN, WHITE):
assert _sgr(rgb) in joined
def test_labels_follow_the_callback_only_self_named() -> None:
"""A ``None`` label leaves the marker bare — a caller's unnamed-relay mode."""
layers = [PathLayer(("ab", "cd"), WHITE, 4)]
lines = _render(
layers,
label_of=lambda node: "Base" if node in (SRC_NODE, DST_NODE) else None,
)
plain = _ANSI.sub("", "\n".join(lines))
assert "Base" in plain
assert "ab" not in plain and "cd" not in plain
def test_endpoint_labels_may_leave_the_marker_row() -> None:
"""Endpoints place like relays: a long name lands whole, even off the centre row."""
layers = [PathLayer(tuple(f"{i:02x}" for i in range(6)), WHITE, 4)]
lines = _render(
layers,
label_of=lambda node: "VeryLongStationName"
if node in (SRC_NODE, DST_NODE)
else None,
)
plain = _ANSI.sub("", "\n".join(lines))
# The name fits the 60-cell canvas, so it is kept whole — no fixed label budget clips it.
assert "VeryLongStationName" in plain
assert "…" not in plain
def test_labels_ellipsize_only_when_wider_than_the_canvas() -> None:
"""A name shortens only when it physically cannot fit — wider than the whole canvas."""
name = "x" * 30
lines = render_path_graph(
[PathLayer(("aa",), WHITE, 4)],
20,
glyph_of=_glyph,
label_of=lambda node: name if node in (SRC_NODE, DST_NODE) else None,
label_rgb_of=lambda _node: WHITE,
)
plain = _ANSI.sub("", "\n".join(lines))
assert name not in plain # the full 30-cell name cannot fit a 20-cell canvas
assert "…" in plain # so it is ellipsized to what fits
assert all(len(_ANSI.sub("", ln)) <= 20 for ln in lines) # never overruns the width