feat(2-6): stateful Renderer, DisplayInterface, and pipeline smoke test
Implements story 2-6: Renderer class with per-aircraft trail history (deque capped at TRAIL_MAX_DOTS=5), NullDisplay with DEBUG logging, WaveshareDisplay stub, and end-to-end pipeline smoke test. All 96 tests pass; ruff check and format clean. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
+61
-2
@@ -1,2 +1,61 @@
|
||||
def test_placeholder() -> None:
|
||||
pass
|
||||
from __future__ import annotations
|
||||
|
||||
import pathlib
|
||||
|
||||
import pytest
|
||||
from PIL import Image
|
||||
|
||||
from planemapper.models import Aircraft
|
||||
from planemapper.renderer.projection import MapBounds
|
||||
from planemapper.renderer.renderer import Renderer
|
||||
|
||||
FIXTURE_DIR = pathlib.Path(__file__).parent / "fixtures"
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def white_base_map() -> Image.Image:
|
||||
return Image.new("RGB", (800, 480), color=(255, 255, 255))
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def bounds() -> MapBounds:
|
||||
return MapBounds(home_lat=53.0, home_lon=-6.0, radius_nm=100.0)
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def renderer(
|
||||
white_base_map: Image.Image, bounds: MapBounds, monkeypatch: pytest.MonkeyPatch
|
||||
) -> Renderer:
|
||||
monkeypatch.setattr(
|
||||
"planemapper.renderer.airspace.AIRSPACE_PATH",
|
||||
FIXTURE_DIR / "airspace_sample.geojson",
|
||||
)
|
||||
return Renderer(white_base_map, bounds)
|
||||
|
||||
|
||||
def _aircraft(icao: str = "ABC123", **kwargs) -> Aircraft:
|
||||
defaults = {"lat": 53.1, "lon": -6.1}
|
||||
defaults.update(kwargs)
|
||||
return Aircraft(icao=icao, **defaults)
|
||||
|
||||
|
||||
def test_render_returns_800x480(renderer: Renderer) -> None:
|
||||
result = renderer.render([])
|
||||
assert isinstance(result, Image.Image)
|
||||
assert result.size == (800, 480)
|
||||
|
||||
|
||||
def test_trail_accumulated_across_renders(renderer: Renderer) -> None:
|
||||
ac = _aircraft(icao="ABC123")
|
||||
renderer.render([ac])
|
||||
renderer.render([ac])
|
||||
assert "ABC123" in renderer._trails
|
||||
assert len(renderer._trails["ABC123"]) == 2
|
||||
|
||||
|
||||
def test_absent_aircraft_trail_retained(renderer: Renderer) -> None:
|
||||
ac = _aircraft(icao="ABC123")
|
||||
renderer.render([ac])
|
||||
renderer.render([]) # aircraft absent
|
||||
assert "ABC123" in renderer._trails
|
||||
assert len(renderer._trails["ABC123"]) == 1
|
||||
|
||||
Reference in New Issue
Block a user