mirror of
https://github.com/esphome/esphome.git
synced 2026-08-22 22:26:21 +00:00
115 lines
4.0 KiB
Python
115 lines
4.0 KiB
Python
"""Validation tests for the sendspin image platform.
|
|
|
|
These cover the rejection branches, which a compile test cannot reach: a
|
|
`test*.yaml` can only assert that a configuration is accepted.
|
|
"""
|
|
|
|
from typing import Any
|
|
|
|
import pytest
|
|
|
|
from esphome import config_validation as cv
|
|
from esphome.components.sendspin import IMAGE_FORMAT_JPEG, MAX_ARTWORK_SLOTS, _get_data
|
|
from esphome.components.sendspin.image import CONFIG_SCHEMA, MAX_IMAGE_DIMENSION
|
|
from esphome.const import PlatformFramework
|
|
from esphome.types import ConfigType
|
|
from tests.component_tests.types import SetCoreConfigCallable
|
|
|
|
|
|
def _slot_config(**overrides: Any) -> ConfigType:
|
|
"""Build a minimal valid artwork slot config, allowing field overrides."""
|
|
config: ConfigType = {
|
|
"id": "album_slot",
|
|
"format": "JPEG",
|
|
"type": "RGB565",
|
|
"resize": "240x240",
|
|
"current_image": {"id": "album_art"},
|
|
}
|
|
config.update(overrides)
|
|
return config
|
|
|
|
|
|
def test_minimal_config_is_accepted(set_core_config: SetCoreConfigCallable) -> None:
|
|
"""The baseline the rejection tests vary is itself valid."""
|
|
set_core_config(PlatformFramework.ESP32_IDF)
|
|
|
|
config = CONFIG_SCHEMA(_slot_config())
|
|
|
|
assert config["slot"] == 0
|
|
assert config["source"] == "ALBUM"
|
|
assert config["display_offset"].total_milliseconds == 0
|
|
|
|
|
|
@pytest.mark.parametrize("image_format", ["JPEG", "JPG"])
|
|
def test_jpeg_alias_maps_to_one_enum(
|
|
set_core_config: SetCoreConfigCallable, image_format: str
|
|
) -> None:
|
|
"""runtime_image takes JPG as an alias for JPEG, so both spellings must reach the
|
|
library's single JPEG enum."""
|
|
set_core_config(PlatformFramework.ESP32_IDF)
|
|
|
|
CONFIG_SCHEMA(_slot_config(format=image_format))
|
|
|
|
assert _get_data().artwork_preferences[0]["format"] == IMAGE_FORMAT_JPEG
|
|
|
|
|
|
def test_too_many_slots_rejected(set_core_config: SetCoreConfigCallable) -> None:
|
|
"""Slot numbers run out after MAX_ARTWORK_SLOTS entries."""
|
|
set_core_config(PlatformFramework.ESP32_IDF)
|
|
|
|
for slot in range(MAX_ARTWORK_SLOTS):
|
|
assert CONFIG_SCHEMA(_slot_config(id=f"slot_{slot}"))["slot"] == slot
|
|
|
|
with pytest.raises(cv.Invalid, match="Too many Sendspin image slots"):
|
|
CONFIG_SCHEMA(_slot_config(id="one_too_many"))
|
|
|
|
|
|
@pytest.mark.parametrize(
|
|
"resize",
|
|
[f"{MAX_IMAGE_DIMENSION + 1}x240", f"240x{MAX_IMAGE_DIMENSION + 1}"],
|
|
)
|
|
def test_oversized_resize_rejected(
|
|
set_core_config: SetCoreConfigCallable, resize: str
|
|
) -> None:
|
|
"""Either dimension past the decoder's limit is refused."""
|
|
set_core_config(PlatformFramework.ESP32_IDF)
|
|
|
|
with pytest.raises(cv.Invalid, match=f"must be {MAX_IMAGE_DIMENSION} or less"):
|
|
CONFIG_SCHEMA(_slot_config(resize=resize))
|
|
|
|
|
|
def test_sub_millisecond_display_offset_rejected(
|
|
set_core_config: SetCoreConfigCallable,
|
|
) -> None:
|
|
"""The library field is whole milliseconds, so finer values are refused
|
|
rather than silently rounded down to zero."""
|
|
set_core_config(PlatformFramework.ESP32_IDF)
|
|
|
|
with pytest.raises(cv.Invalid, match="Maximum precision is milliseconds"):
|
|
CONFIG_SCHEMA(_slot_config(display_offset="500us"))
|
|
|
|
|
|
@pytest.mark.parametrize("display_offset", ["61s", "-61s"])
|
|
def test_out_of_range_display_offset_rejected(
|
|
set_core_config: SetCoreConfigCallable, display_offset: str
|
|
) -> None:
|
|
"""Offsets more than a minute either side of the boundary are refused."""
|
|
set_core_config(PlatformFramework.ESP32_IDF)
|
|
|
|
with pytest.raises(cv.Invalid, match="value must be at (most|least)"):
|
|
CONFIG_SCHEMA(_slot_config(display_offset=display_offset))
|
|
|
|
|
|
@pytest.mark.parametrize(
|
|
("display_offset", "expected_ms"), [("250ms", 250), ("-2s", -2000)]
|
|
)
|
|
def test_display_offset_accepted(
|
|
set_core_config: SetCoreConfigCallable, display_offset: str, expected_ms: int
|
|
) -> None:
|
|
"""Whole-millisecond offsets pass through in both directions."""
|
|
set_core_config(PlatformFramework.ESP32_IDF)
|
|
|
|
config = CONFIG_SCHEMA(_slot_config(display_offset=display_offset))
|
|
|
|
assert config["display_offset"].total_milliseconds == expected_ms
|