Point analyze-memory at the platformio escape hatch, test the backend-table invariant instead of asserting at import, fail blank component lists under the flag, clean the arduino idedata cache

This commit is contained in:
J. Nick Koston
2026-08-23 20:53:55 -05:00
parent bae1291d73
commit 985a784f5e
6 changed files with 42 additions and 11 deletions
+1 -4
View File
@@ -48,7 +48,6 @@ from esphome.const import (
ENV_NOGITIGNORE,
KEY_ESP32,
KEY_VARIANT,
NATIVE_TOOLCHAINS,
SECRETS_FILES,
Toolchain,
)
@@ -1932,8 +1931,6 @@ _NATIVE_TOOLCHAIN_MODULES = {
("esp32", Toolchain.ESP_IDF): "esphome.espidf.toolchain",
("esp8266", Toolchain.ARDUINO): "esphome.arduino8266.toolchain",
}
# Structure over prose: a native toolchain the table does not serve is a bug
assert {tc for _, tc in _NATIVE_TOOLCHAIN_MODULES} == set(NATIVE_TOOLCHAINS)
def _native_toolchain_module():
@@ -2002,7 +1999,7 @@ def command_analyze_memory(args: ArgsProtocol, config: ConfigType) -> int:
if native_toolchain is None and not CORE.using_toolchain_platformio:
_LOGGER.error(
"analyze-memory is not supported with the '%s' toolchain on %s; "
"it requires a PlatformIO, ESP-IDF, or native Arduino build",
"re-run with --toolchain platformio",
CORE.toolchain.value if CORE.toolchain else "unresolved",
CORE.target_platform,
)
+8 -6
View File
@@ -610,12 +610,14 @@ def clean_build(clear_pio_cache: bool = True, *, full: bool = False):
_LOGGER.info("Deleting %s", idf_path)
rmtree(idf_path)
# The idedata cache is derived from the build but lives under the data dir,
# not the build path, so it must be removed separately in both modes.
idedata_cache = CORE.relative_internal_path("idedata", f"{CORE.name}.json")
if idedata_cache.is_file():
_LOGGER.info("Deleting %s", idedata_cache)
idedata_cache.unlink()
# The idedata caches are derived from the build but live under the data
# dir, not the build path, so they must be removed separately in both
# modes (the .arduino.json variant is the native esp8266 toolchain's).
for cache_name in (f"{CORE.name}.json", f"{CORE.name}.arduino.json"):
idedata_cache = CORE.relative_internal_path("idedata", cache_name)
if idedata_cache.is_file():
_LOGGER.info("Deleting %s", idedata_cache)
idedata_cache.unlink()
if not clear_pio_cache:
return
+7
View File
@@ -1074,6 +1074,13 @@ def test_components(
)
)
# The flag's contract is "no test matched fails": a fully blank pattern
# list would otherwise slide into the reference-baseline fallback and
# exit green while building nothing a caller asked for
if fail_on_no_tests and not any(component_patterns):
print("No components requested (blank component list)")
return 1
# Renamed or removed fixtures must shrink coverage loudly, and the
# reference-baseline fallback below must not mask an empty match. The
# check is per platform: a component whose fixture exists only for other
@@ -273,6 +273,18 @@ def test_components_component_with_no_base_file_fails_with_flag(
)
def test_components_blank_list_fails_with_flag(
capsys: pytest.CaptureFixture[str],
) -> None:
"""A fully blank component list must not slide into the baseline
fallback and exit green under the flag."""
rc = tbc.test_components(
[""], "esp8266-ard", "compile", False, fail_on_no_tests=True
)
assert rc == 1
assert "blank component list" in capsys.readouterr().out
def test_components_empty_match_tolerated_without_flag() -> None:
"""The esp32-ard smoke leg deliberately builds only the subset with a
matching fixture; without the flag an empty match stays green."""
+9
View File
@@ -7390,6 +7390,15 @@ def test_compile_program_espidf_idedata_none_warns(
assert "No idedata was generated" in caplog.text
def test_native_toolchain_table_serves_every_native_toolchain() -> None:
"""Every member of NATIVE_TOOLCHAINS has a backend entry; a gap would
surface as a targeted EsphomeError on the one affected config, and this
pin keeps the table from drifting when a toolchain is added."""
from esphome.const import NATIVE_TOOLCHAINS
assert {tc for _, tc in main._NATIVE_TOOLCHAIN_MODULES} == set(NATIVE_TOOLCHAINS)
def test_native_toolchain_module_missing_backend_raises(tmp_path: Path) -> None:
"""A native toolchain missing from the backend table is a bug and must
fail, not silently degrade to the PlatformIO path."""
+5 -1
View File
@@ -517,10 +517,13 @@ def test_clean_build(
dependencies_lock = tmp_path / "dependencies.lock"
dependencies_lock.write_text("lock file")
# idedata cache lives under the data dir, not the build path.
# idedata caches live under the data dir, not the build path; the
# .arduino.json variant is the native esp8266 toolchain's.
idedata_cache = tmp_path / "idedata" / "test.json"
idedata_cache.parent.mkdir()
idedata_cache.write_text("{}")
arduino_idedata_cache = tmp_path / "idedata" / "test.arduino.json"
arduino_idedata_cache.write_text("{}")
# Native ESP-IDF toolchain artifacts.
idf_build_dir = tmp_path / "build"
@@ -581,6 +584,7 @@ def test_clean_build(
assert not piolibdeps_dir.exists()
assert not dependencies_lock.exists()
assert not idedata_cache.exists()
assert not arduino_idedata_cache.exists()
assert not idf_build_dir.exists()
assert not managed_components_dir.exists()
assert not pio_components_dir.exists()