Merge branch 'esp8266-native-build-spec' into esp8266-native-ninja-emission

This commit is contained in:
J. Nick Koston
2026-08-22 21:29:33 -05:00
9 changed files with 117 additions and 20 deletions
+39 -5
View File
@@ -1143,7 +1143,7 @@ def test_generate_ld_scripts_unreadable_note_still_warns(
assert "could not be read" in caplog.text
@pytest.mark.parametrize("value", ["0x8000", "0xC000ul", "32768", "48UL"])
@pytest.mark.parametrize("value", ["0x8000", "0xC000ul", "0x10UL"])
def test_mmu_custom_numeric_sizes_accepted(value: str) -> None:
config = _resolve(
"-DPIO_FRAMEWORK_ARDUINO_MMU_CUSTOM",
@@ -1153,11 +1153,19 @@ def test_mmu_custom_numeric_sizes_accepted(value: str) -> None:
assert f"MMU_IRAM_SIZE={value}" in config.mmu_defines
@pytest.mark.parametrize("flag", ["-DMMU_IRAM_SIZE=48K", "-DMMU_IRAM_SIZE"])
@pytest.mark.parametrize(
"flag",
[
"-DMMU_IRAM_SIZE=48K",
# Decimal passes preprocessing but build_surgery's segment parser
# only reads hex, so testing-mode surgery would fail misleadingly
"-DMMU_IRAM_SIZE=32768",
],
)
def test_mmu_custom_malformed_size_raises(flag: str) -> None:
"""A bare or non-numeric size would corrupt the preprocessed segment
lengths and fail far away in ld; refuse by name."""
with pytest.raises(EsphomeError, match="MMU_IRAM_SIZE must be a numeric"):
"""A non-hex size would corrupt the preprocessed segment lengths (or
defeat the testing-mode surgery); refuse by name."""
with pytest.raises(EsphomeError, match="MMU_IRAM_SIZE must be a hex"):
_resolve(
"-DPIO_FRAMEWORK_ARDUINO_MMU_CUSTOM",
flag,
@@ -1165,6 +1173,32 @@ def test_mmu_custom_malformed_size_raises(flag: str) -> None:
)
def test_mmu_custom_valueless_switch_accepted_and_others_validated() -> None:
"""Valueless MMU switches (MMU_IRAM_HEAP) pass; every valued MMU_* is
hex-validated, not just the two required sizes."""
config = _resolve(
"-DPIO_FRAMEWORK_ARDUINO_MMU_CUSTOM",
"-DMMU_IRAM_SIZE=0x8000",
"-DMMU_ICACHE_SIZE=0x8000",
"-DMMU_IRAM_HEAP",
)
assert "MMU_IRAM_HEAP" in config.mmu_defines
with pytest.raises(EsphomeError, match="MMU_SEC_HEAP_SIZE must be a hex"):
_resolve(
"-DPIO_FRAMEWORK_ARDUINO_MMU_CUSTOM",
"-DMMU_IRAM_SIZE=0x8000",
"-DMMU_ICACHE_SIZE=0x8000",
"-DMMU_SEC_HEAP_SIZE=48K",
)
def test_mmu_no_knob_rejects_any_raw_mmu_flag() -> None:
"""The no-knob branch refuses every raw MMU_*, like the knob branch; a
lone switch would win the compile line but not the linker script."""
with pytest.raises(EsphomeError, match="Raw MMU_IRAM_HEAP"):
_resolve("-DMMU_IRAM_HEAP")
def test_raw_nonosdk_define_raises() -> None:
"""A raw NONOSDK* define would split the compile line from the linked
SDK libraries, like the lwIP knob overrides."""
@@ -169,6 +169,22 @@ def test_apply_extra_script_callable_target_and_str_flags(tmp_path) -> None:
assert c.data["build"]["flags"] == ["-DBASE=1", "-lesp8266"]
def test_apply_extra_script_subscript_env_read(tmp_path) -> None:
"""Scripts also read env["BOARD_MCU"]; the subscript form must work or
the broad handler discards every flag the script captured."""
(tmp_path / "src").mkdir()
script = tmp_path / "extra.py"
script.write_text("env.Append(LIBS=[env['BOARD_MCU']])\n")
c = IDFComponent("owner/name", "1.0", source=URLSource("http://dummy"))
c.path = tmp_path
c.data = {"build": {"extraScript": "extra.py"}}
apply_extra_script(c, board_mcu=lambda: "esp8266", pio_platform="espressif8266")
assert c.data["build"]["flags"] == ["-lesp8266"]
def test_apply_extra_script_no_script_and_no_flags(tmp_path) -> None:
# No extraScript declared: nothing happens, the target is never resolved
@@ -166,9 +166,13 @@ def caplog_at_info():
handler.emit = records.append
logger = logging.getLogger("esphome.platformio.library")
logger.addHandler(handler)
# The level must actually admit INFO or the no-INFO assertions are vacuous
old_level = logger.level
logger.setLevel(logging.INFO)
try:
yield records
finally:
logger.setLevel(old_level)
logger.removeHandler(handler)
@@ -625,3 +625,26 @@ def test_prefetch_packages_download_failure_is_debug(
assert mock_download.call_count == 2
assert "Prefetch of a failed" in caplog.text
assert "Prefetch of b failed" in caplog.text
def test_prefetch_packages_unexpected_failure_warns(
tmp_path: Path, caplog: pytest.LogCaptureFixture
) -> None:
"""A programming error (not a download failure) surfaces at WARNING
instead of becoming a permanent silent no-op."""
with (
patch.object(
registry, "download_with_resume", side_effect=TypeError("bad call")
),
patch.object(
registry, "registry_download", side_effect=_resolve_for({"a": 10, "b": 20})
),
):
registry.prefetch_packages(
[
("a", "1.0", tmp_path / "a", []),
("b", "2.0", tmp_path / "b", []),
],
tmp_path / "dl",
)
assert "TypeError" in caplog.text