mirror of
https://github.com/esphome/esphome.git
synced 2026-06-24 11:07:33 +00:00
[mipi_spi] Cache code generation across display tests
The native.yaml and lvgl.yaml fixtures are each compiled twice; once by the codegen assertions in test_init.py and once by the metadata assertions in test_display_metadata.py. Add a session scoped cache so each fixture is generated once, with the resulting main.cpp text and a snapshot of the display metadata reused across tests. CI hits the duplicated tests in well under 10ms instead of paying the full generation cost a second time.
This commit is contained in:
@@ -1,11 +1,13 @@
|
||||
"""Tests for mpip_spi configuration validation."""
|
||||
|
||||
from collections.abc import Callable, Generator
|
||||
from pathlib import Path
|
||||
from unittest import mock
|
||||
|
||||
import pytest
|
||||
|
||||
from esphome import config_validation as cv
|
||||
from esphome.components.display import DisplayMetaData, get_all_display_metadata
|
||||
from esphome.components.esp32 import KEY_ESP32, KEY_VARIANT, VARIANTS
|
||||
from esphome.components.esp32.gpio import validate_gpio_pin
|
||||
from esphome.const import CONF_INPUT, CONF_OUTPUT
|
||||
@@ -23,6 +25,40 @@ def mock_spi_final_validate():
|
||||
yield
|
||||
|
||||
|
||||
@pytest.fixture(scope="session")
|
||||
def _generation_cache() -> dict[Path, tuple[str, dict[str, DisplayMetaData]]]:
|
||||
"""Session-wide cache of generation output keyed by fixture yaml path.
|
||||
|
||||
Stores ``(main_cpp_text, display_metadata_snapshot)`` so multiple tests
|
||||
that exercise the same fixture only pay for code generation once.
|
||||
"""
|
||||
return {}
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def cached_generate_main(
|
||||
generate_main: Callable[[str | Path], str],
|
||||
_generation_cache: dict[Path, tuple[str, dict[str, DisplayMetaData]]],
|
||||
) -> Callable[[Path], tuple[str, dict[str, DisplayMetaData]]]:
|
||||
"""Like ``generate_main`` but caches results across the test session.
|
||||
|
||||
Returns ``(main_cpp_text, display_metadata_snapshot)``; the snapshot is
|
||||
captured at generation time so callers see the same data after CORE has
|
||||
been reset for the next test.
|
||||
"""
|
||||
|
||||
def _get(path: Path) -> tuple[str, dict[str, DisplayMetaData]]:
|
||||
path = Path(path)
|
||||
cached = _generation_cache.get(path)
|
||||
if cached is None:
|
||||
main_cpp = generate_main(path)
|
||||
cached = (main_cpp, dict(get_all_display_metadata()))
|
||||
_generation_cache[path] = cached
|
||||
return cached
|
||||
|
||||
return _get
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def choose_variant_with_pins() -> Generator[Callable[[list], None]]:
|
||||
"""
|
||||
|
||||
@@ -173,12 +173,11 @@ def test_metadata_multiple_displays_independent(
|
||||
|
||||
|
||||
def test_metadata_via_code_generation_native(
|
||||
generate_main: Callable[[str | Path], str],
|
||||
cached_generate_main: Callable[[Path], tuple[str, dict[str, DisplayMetaData]]],
|
||||
component_fixture_path: Callable[[str], Path],
|
||||
) -> None:
|
||||
"""Full code generation for native.yaml should produce correct metadata."""
|
||||
generate_main(component_fixture_path("native.yaml"))
|
||||
all_meta = get_all_display_metadata()
|
||||
_, all_meta = cached_generate_main(component_fixture_path("native.yaml"))
|
||||
# native.yaml: model JC3636W518 -> 360x360, no writer, full hardware rotation
|
||||
assert len(all_meta) == 1
|
||||
meta = next(iter(all_meta.values()))
|
||||
@@ -188,12 +187,11 @@ def test_metadata_via_code_generation_native(
|
||||
|
||||
|
||||
def test_metadata_via_code_generation_lvgl(
|
||||
generate_main: Callable[[str | Path], str],
|
||||
cached_generate_main: Callable[[Path], tuple[str, dict[str, DisplayMetaData]]],
|
||||
component_fixture_path: Callable[[str], Path],
|
||||
) -> None:
|
||||
"""Full code generation for lvgl.yaml should produce correct metadata."""
|
||||
generate_main(component_fixture_path("lvgl.yaml"))
|
||||
all_meta = get_all_display_metadata()
|
||||
_, all_meta = cached_generate_main(component_fixture_path("lvgl.yaml"))
|
||||
# lvgl.yaml: model ST7735 -> 128x160, no writer (lvgl draws directly), full hw rotation
|
||||
assert len(all_meta) == 1
|
||||
meta = next(iter(all_meta.values()))
|
||||
|
||||
@@ -307,12 +307,12 @@ def test_all_predefined_models(
|
||||
|
||||
|
||||
def test_native_generation(
|
||||
generate_main: Callable[[str | Path], str],
|
||||
cached_generate_main: Callable[[Path], tuple[str, dict[str, Any]]],
|
||||
component_fixture_path: Callable[[str], Path],
|
||||
) -> None:
|
||||
"""Test code generation for display."""
|
||||
|
||||
main_cpp = generate_main(component_fixture_path("native.yaml"))
|
||||
main_cpp, _ = cached_generate_main(component_fixture_path("native.yaml"))
|
||||
assert (
|
||||
"mipi_spi::MipiSpiBuffer<uint16_t, mipi_spi::PIXEL_MODE_16, true, mipi_spi::PIXEL_MODE_16, mipi_spi::BUS_TYPE_QUAD, 360, 360, 0, 1, 0, true, 1, 1>()"
|
||||
in main_cpp
|
||||
@@ -323,12 +323,12 @@ def test_native_generation(
|
||||
|
||||
|
||||
def test_lvgl_generation(
|
||||
generate_main: Callable[[str | Path], str],
|
||||
cached_generate_main: Callable[[Path], tuple[str, dict[str, Any]]],
|
||||
component_fixture_path: Callable[[str], Path],
|
||||
) -> None:
|
||||
"""Test LVGL generation configuration."""
|
||||
|
||||
main_cpp = generate_main(component_fixture_path("lvgl.yaml"))
|
||||
main_cpp, _ = cached_generate_main(component_fixture_path("lvgl.yaml"))
|
||||
assert (
|
||||
"mipi_spi::MipiSpi<uint16_t, mipi_spi::PIXEL_MODE_16, true, mipi_spi::PIXEL_MODE_16, mipi_spi::BUS_TYPE_SINGLE, 128, 160, 0, 0, 0, true>();"
|
||||
in main_cpp
|
||||
|
||||
Reference in New Issue
Block a user