Files
esphome/tests/unit_tests/test_config_helpers.py
T
J. Nick Koston cf31c08a5c
CI / Create common environment (push) Canceled after 0s
CI / Seed apt package cache (push) Canceled after 0s
CI / Determine which jobs to run (push) Canceled after 0s
CI / Run script/ci-custom (push) Canceled after 0s
CI / Check pylint (push) Canceled after 0s
CI / Check lint and formatting (push) Canceled after 0s
CI / Run pytest (macOS-latest, 3.12) (push) Canceled after 0s
CI / Run pytest (macOS-latest, 3.14) (push) Canceled after 0s
CI / Run pytest (ubuntu-latest, 3.12) (push) Canceled after 0s
CI / Run pytest (ubuntu-latest, 3.13) (push) Canceled after 0s
CI / Run pytest (ubuntu-latest, 3.14) (push) Canceled after 0s
CI / Run pytest (windows-latest, 3.12) (push) Canceled after 0s
CI / Run pytest (windows-latest, 3.14) (push) Canceled after 0s
CI / Report no coverage to Codecov (push) Canceled after 0s
CI / Run integration tests () (push) Canceled after 0s
CI / Check import esphome.__main__ time (push) Canceled after 0s
CI / Run CodSpeed benchmarks (push) Canceled after 0s
CI / Run C++ unit tests (push) Canceled after 0s
CI / Run script/clang-tidy for LibreTiny (push) Canceled after 0s
CI / Run script/clang-tidy for ESP8266 (push) Canceled after 0s
CI / Run script/clang-tidy for RP2 (push) Canceled after 0s
CI / Run script/clang-tidy for ESP32 Arduino (push) Canceled after 0s
CI / Run script/clang-tidy for ZEPHYR (push) Canceled after 0s
CI / Run script/clang-tidy for ESP32 IDF (push) Canceled after 0s
CI / Run script/clang-tidy for ESP32 IDF 1/3 (push) Canceled after 0s
CI / Run script/clang-tidy for ESP32 IDF 2/3 (push) Canceled after 0s
CI / Run script/clang-tidy for ESP32 IDF 3/3 (push) Canceled after 0s
CI / Run script/clang-tidy for ESP32 C6 (push) Canceled after 0s
CI / Run script/clang-tidy for ESP32 P4 (push) Canceled after 0s
CI / Run script/clang-tidy for ESP32 S3 (push) Canceled after 0s
CI / Test components batch () (push) Canceled after 0s
CI / Test esp32 components with PlatformIO (push) Canceled after 0s
CI / Test downstream esphome/device-builder (push) Canceled after 0s
CI / Build target branch for memory impact (push) Canceled after 0s
CI / Build PR branch for memory impact (push) Canceled after 0s
CI / Comment memory impact (push) Canceled after 0s
CI / CI Status (push) Canceled after 0s
[core] Skip copying entity automation and filter sources when unused (#18602)
2026-08-23 09:05:04 -05:00

175 lines
6.2 KiB
Python

"""Unit tests for esphome.config_helpers module."""
from collections.abc import Callable
from unittest.mock import patch
import pytest
from esphome.config_helpers import (
filter_source_files_from_defines,
filter_source_files_from_platform,
frameworks_for_platforms,
get_logger_level,
)
from esphome.const import (
CONF_LEVEL,
CONF_LOGGER,
KEY_CORE,
KEY_TARGET_FRAMEWORK,
KEY_TARGET_PLATFORM,
PlatformFramework,
)
from esphome.core import Define
def test_filter_source_files_from_platform_esp32() -> None:
"""Test that filter_source_files_from_platform correctly filters files for ESP32 platform."""
# Define test file mappings
files_map: dict[str, set[PlatformFramework]] = {
"logger_esp32.cpp": {
PlatformFramework.ESP32_ARDUINO,
PlatformFramework.ESP32_IDF,
},
"logger_esp8266.cpp": {PlatformFramework.ESP8266_ARDUINO},
"logger_host.cpp": {PlatformFramework.HOST_NATIVE},
"logger_common.cpp": {
PlatformFramework.ESP32_ARDUINO,
PlatformFramework.ESP32_IDF,
PlatformFramework.ESP8266_ARDUINO,
PlatformFramework.HOST_NATIVE,
},
}
# Create the filter function
filter_func: Callable[[], list[str]] = filter_source_files_from_platform(files_map)
# Test ESP32 with Arduino framework
mock_core_data: dict[str, dict[str, str]] = {
KEY_CORE: {
KEY_TARGET_PLATFORM: "esp32",
KEY_TARGET_FRAMEWORK: "arduino",
}
}
with patch("esphome.config_helpers.CORE.data", mock_core_data):
excluded: list[str] = filter_func()
# ESP32 Arduino should exclude ESP8266 and HOST files
assert "logger_esp8266.cpp" in excluded
assert "logger_host.cpp" in excluded
# But not ESP32 or common files
assert "logger_esp32.cpp" not in excluded
assert "logger_common.cpp" not in excluded
def test_filter_source_files_from_platform_host() -> None:
"""Test that filter_source_files_from_platform correctly filters files for HOST platform."""
# Define test file mappings
files_map: dict[str, set[PlatformFramework]] = {
"logger_esp32.cpp": {
PlatformFramework.ESP32_ARDUINO,
PlatformFramework.ESP32_IDF,
},
"logger_esp8266.cpp": {PlatformFramework.ESP8266_ARDUINO},
"logger_host.cpp": {PlatformFramework.HOST_NATIVE},
"logger_common.cpp": {
PlatformFramework.ESP32_ARDUINO,
PlatformFramework.ESP32_IDF,
PlatformFramework.ESP8266_ARDUINO,
PlatformFramework.HOST_NATIVE,
},
}
# Create the filter function
filter_func: Callable[[], list[str]] = filter_source_files_from_platform(files_map)
# Test Host platform
mock_core_data: dict[str, dict[str, str]] = {
KEY_CORE: {
KEY_TARGET_PLATFORM: "host",
KEY_TARGET_FRAMEWORK: "host", # Framework.NATIVE is "host"
}
}
with patch("esphome.config_helpers.CORE.data", mock_core_data):
excluded: list[str] = filter_func()
# Host should exclude ESP32 and ESP8266 files
assert "logger_esp32.cpp" in excluded
assert "logger_esp8266.cpp" in excluded
# But not host or common files
assert "logger_host.cpp" not in excluded
assert "logger_common.cpp" not in excluded
def test_filter_source_files_from_platform_handles_missing_data() -> None:
"""Test that filter_source_files_from_platform returns empty list when platform/framework data is missing."""
# Define test file mappings
files_map: dict[str, set[PlatformFramework]] = {
"logger_esp32.cpp": {PlatformFramework.ESP32_ARDUINO},
"logger_host.cpp": {PlatformFramework.HOST_NATIVE},
}
# Create the filter function
filter_func: Callable[[], list[str]] = filter_source_files_from_platform(files_map)
# Test case: Missing platform/framework data
mock_core_data: dict[str, dict[str, str]] = {KEY_CORE: {}}
with patch("esphome.config_helpers.CORE.data", mock_core_data):
excluded: list[str] = filter_func()
# Should return empty list when platform/framework not set
assert excluded == []
def test_get_logger_level() -> None:
"""Test get_logger_level helper function."""
# Test no logger config - should return default DEBUG
mock_config = {}
with patch("esphome.config_helpers.CORE.config", mock_config):
assert get_logger_level() == "DEBUG"
# Test with logger set to INFO
mock_config = {CONF_LOGGER: {CONF_LEVEL: "INFO"}}
with patch("esphome.config_helpers.CORE.config", mock_config):
assert get_logger_level() == "INFO"
# Test with VERY_VERBOSE
mock_config = {CONF_LOGGER: {CONF_LEVEL: "VERY_VERBOSE"}}
with patch("esphome.config_helpers.CORE.config", mock_config):
assert get_logger_level() == "VERY_VERBOSE"
# Test with logger missing level (uses default DEBUG)
mock_config = {CONF_LOGGER: {}}
with patch("esphome.config_helpers.CORE.config", mock_config):
assert get_logger_level() == "DEBUG"
def test_frameworks_for_platforms_derives_and_rejects_unknown() -> None:
assert frameworks_for_platforms(["esp32"]) == {
PlatformFramework.ESP32_ARDUINO,
PlatformFramework.ESP32_IDF,
}
with pytest.raises(ValueError, match="unknown platform"):
frameworks_for_platforms(["esp32", "not_a_platform"])
def test_filter_source_files_from_defines() -> None:
"""Files are excluded unless one of their defines is set."""
files_map: dict[str, str | tuple[str, ...]] = {
"filter.cpp": "USE_SENSOR_FILTER",
"automation.cpp": ("USE_CLICK", "USE_MULTI_CLICK"),
}
filter_func: Callable[[], list[str]] = filter_source_files_from_defines(files_map)
with patch("esphome.config_helpers.CORE") as mock_core:
mock_core.defines = {Define("USE_SENSOR_FILTER")}
assert filter_func() == ["automation.cpp"]
mock_core.defines = {Define("USE_MULTI_CLICK")}
assert filter_func() == ["filter.cpp"]
mock_core.defines = {Define("USE_SENSOR_FILTER"), Define("USE_CLICK")}
assert filter_func() == []
mock_core.defines = set()
assert sorted(filter_func()) == ["automation.cpp", "filter.cpp"]