testsAndMisc/python_pkg/app_icons/tests/test_fit.py
Krzysztof kuhy Rudnicki 35b497b409
Some checks failed
dependency freshness / dependencies on newest stable (push) Has been cancelled
md-naming / markdown naming convention (push) Has been cancelled
Pre-commit checks / pre-commit (${{ matrix.group }}) (mypy, mypy) (push) Has been cancelled
Pre-commit checks / pre-commit (${{ matrix.group }}) (pylint, pylint) (push) Has been cancelled
Pre-commit checks / pre-commit (${{ matrix.group }}) (rest, ) (push) Has been cancelled
Pre-commit checks / pre-commit (${{ matrix.group }}) (shellcheck, shellcheck) (push) Has been cancelled
Python tests / test (push) Has been cancelled
repo-contract / repo contract (push) Has been cancelled
Shell tests / shell-tests (push) Has been cancelled
Shell tests / lib-tests (push) Has been cancelled
Shell tests / arch-tests (push) Has been cancelled
app_icons: fit every glyph to one ink circle, launcher-name rules
- fit.py: centre each glyph and scale it so its furthest ink sits at
  INK_RADIUS = 340px, compensating the unscaled stroke width
- style.py: INK_RADIUS plus INK_RADIUS_DP for vector-drawable consumers
- labels.py/_label_widths.py: LABELS registry; names start with a
  capital, ASCII letters only, <= 10 chars, <= 522 wide in the Pixel
  launcher font
- drop centre_offset, safe_box_overflow and the CLI safe-box warning
- add prompt-bubble (sufler) and camera (macro_cam) glyphs and apps

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_012kQ5PCKqBHAkAVkPSvp6dk
2026-10-23 14:35:00 +02:00

85 lines
3.1 KiB
Python

"""Tests for app_icons.fit: every glyph fills exactly the same circle."""
from __future__ import annotations
from pathlib import Path
import pytest
from python_pkg.app_icons import apps, fit, glyphs, render, style
from python_pkg.app_icons.glyphs import Glyph
SMALL = Glyph("small", "a short bar", ' <path d="M 480 512 L 544 512"/>')
NESTED = Glyph(
"nested",
"inner group with its own scale",
' <g transform="translate(400,400) scale(10)" stroke-width="{{STROKE/10}}">'
'<path d="M 0 0 L 20 0"/></g>',
)
def _rendered_radius(glyph: Glyph, tmp_path: Path) -> tuple[float, float, float]:
placement = fit.placement(glyph, "#FFFFFF")
png = tmp_path / f"{glyph.name}.png"
svg = render.build_svg(glyph, "#FFFFFF", with_background=False, offset=placement)
render.rasterise(svg, png, style.CANVAS)
return fit.ink_geometry(png)
class TestPlacement:
@pytest.mark.parametrize("key", sorted(apps.APPS))
def test_every_app_hits_the_family_radius(self, key: str, tmp_path: Path) -> None:
glyph = glyphs.get_glyph(apps.get_app(key).glyph)
radius, cx, cy = _rendered_radius(glyph, tmp_path)
assert radius == pytest.approx(style.INK_RADIUS, rel=0.01)
assert cx == pytest.approx(style.CENTRE, abs=2)
assert cy == pytest.approx(style.CENTRE, abs=2)
def test_tiny_glyph_is_scaled_up(self, tmp_path: Path) -> None:
radius, _cx, _cy = _rendered_radius(SMALL, tmp_path)
assert radius == pytest.approx(style.INK_RADIUS, rel=0.01)
def test_stroke_weight_is_not_scaled(self) -> None:
placement = fit.placement(SMALL, "#FFFFFF")
svg = render.build_svg(
SMALL, "#FFFFFF", with_background=False, offset=placement
)
assert placement.scale > 1
assert f'stroke-width="{style.STROKE_WIDTH / placement.scale:g}"' in svg
def test_nested_scale_marker_is_compensated(self) -> None:
placement = render.Placement(0, 0, 2)
svg = render.build_svg(
NESTED, "#FFFFFF", with_background=False, offset=placement
)
assert f'stroke-width="{style.STROKE_WIDTH / 20:g}"' in svg
assert "{{STROKE" not in svg
class TestInkGeometry:
def test_blank_image_is_zero(self, tmp_path: Path) -> None:
png = tmp_path / "blank.png"
render.rasterise(
render.build_svg(Glyph("none", "", ""), "#FFFFFF", with_background=False),
png,
64,
)
assert fit.ink_geometry(png) == (0.0, 0.0, 0.0)
def test_empty_glyph_raises(self) -> None:
with pytest.raises(render.EmptyGlyphError) as excinfo:
fit.placement(Glyph("none", "", ""), "#FFFFFF")
assert excinfo.value.name == "none"
def test_round_cap_returns_best_effort(
self, monkeypatch: pytest.MonkeyPatch
) -> None:
monkeypatch.setattr(fit, "_MAX_ROUNDS", 1)
assert fit.placement(SMALL, "#FFFFFF").scale > 1
def test_ink_circle_is_inside_android_visible_zone() -> None:
# Android guarantees a 66dp circle (radius 33dp) survives every mask.
assert pytest.approx(24.39, abs=0.01) == style.INK_RADIUS_DP
assert style.INK_RADIUS_DP < 33