mirror of
https://github.com/esphome/esphome.git
synced 2026-10-04 10:09:13 +00:00
[image] Restructure into a platform component (#17416)
This commit is contained in:
@@ -1,6 +1,6 @@
|
||||
"""Unit tests for esphome.config module."""
|
||||
|
||||
from collections.abc import Generator
|
||||
from collections.abc import Callable, Generator
|
||||
import logging
|
||||
from pathlib import Path
|
||||
from unittest.mock import MagicMock, Mock, patch
|
||||
@@ -8,7 +8,8 @@ from unittest.mock import MagicMock, Mock, patch
|
||||
import pytest
|
||||
|
||||
from esphome import config, yaml_util
|
||||
from esphome.core import CORE
|
||||
from esphome.core import CORE, AutoLoad
|
||||
from esphome.types import ConfigType
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
@@ -116,6 +117,86 @@ def test_ota_with_platform_list_and_captive_portal(fixtures_dir: Path) -> None:
|
||||
assert "web_server" in platforms, f"Expected web_server platform in {platforms}"
|
||||
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# LEGACY_CONFIG_MIGRATE hook on LoadValidationStep -- the removable shim that
|
||||
# lets a platform component rewrite a pre-platform top-level config.
|
||||
# ---------------------------------------------------------------------------
|
||||
|
||||
|
||||
def _run_load_step(
|
||||
domain: str,
|
||||
conf: object,
|
||||
migrate: Callable[[ConfigType], list | None] | None,
|
||||
) -> config.Config:
|
||||
"""Run a LoadValidationStep for a platform component with a given migrate hook."""
|
||||
component = Mock()
|
||||
component.is_platform_component = True
|
||||
component.multi_conf_no_default = False
|
||||
component.legacy_config_migrate = migrate
|
||||
|
||||
result = config.Config()
|
||||
with (
|
||||
patch("esphome.config.get_component", return_value=component),
|
||||
patch("esphome.config._process_auto_load"),
|
||||
patch("esphome.config._process_platform_config"),
|
||||
):
|
||||
config.LoadValidationStep(domain, conf).run(result)
|
||||
return result
|
||||
|
||||
|
||||
def test_legacy_migrate_rewrites_conf() -> None:
|
||||
"""A legacy config that the hook migrates is replaced with the new list."""
|
||||
migrated = [{"platform": "file", "id": "a"}]
|
||||
migrate = Mock(return_value=migrated)
|
||||
|
||||
result = _run_load_step("image", [{"id": "a", "file": "x.png"}], migrate)
|
||||
|
||||
migrate.assert_called_once_with([{"id": "a", "file": "x.png"}])
|
||||
assert result["image"] == migrated
|
||||
|
||||
|
||||
def test_legacy_migrate_none_keeps_new_format() -> None:
|
||||
"""When the hook returns None the already-new config is left untouched."""
|
||||
new_format = [{"platform": "file", "id": "a"}]
|
||||
migrate = Mock(return_value=None)
|
||||
|
||||
result = _run_load_step("image", new_format, migrate)
|
||||
|
||||
migrate.assert_called_once_with(new_format)
|
||||
assert result["image"] == new_format
|
||||
|
||||
|
||||
def test_legacy_migrate_absent_hook_is_noop() -> None:
|
||||
"""A platform component without the hook normalizes without migration."""
|
||||
result = _run_load_step("image", {"id": "a"}, None)
|
||||
|
||||
# Bare dict still gets wrapped into a list by the normal normalization path.
|
||||
assert result["image"] == [{"id": "a"}]
|
||||
|
||||
|
||||
def test_legacy_migrate_skipped_for_empty_conf() -> None:
|
||||
"""An empty config short-circuits before the hook is consulted."""
|
||||
migrate = Mock(return_value=[{"platform": "file"}])
|
||||
|
||||
result = _run_load_step("image", [], migrate)
|
||||
|
||||
migrate.assert_not_called()
|
||||
assert result["image"] == []
|
||||
|
||||
|
||||
def test_legacy_migrate_skipped_for_autoload() -> None:
|
||||
"""An auto-loaded (AutoLoad) config is never migrated."""
|
||||
migrate = Mock(return_value=[{"platform": "file"}])
|
||||
auto = AutoLoad()
|
||||
auto["id"] = "a"
|
||||
|
||||
result = _run_load_step("image", auto, migrate)
|
||||
|
||||
migrate.assert_not_called()
|
||||
# AutoLoad is dict-like, so normalization wraps it into a single-entry list.
|
||||
assert result["image"] == [auto]
|
||||
|
||||
|
||||
def _write_merge_conflict_config(tmp_path: Path, *, suppress: bool) -> Path:
|
||||
"""Create a config where two `<<` includes both define `logger:`.
|
||||
|
||||
|
||||
Reference in New Issue
Block a user