mirror of
https://github.com/esphome/esphome.git
synced 2026-09-11 15:27:33 +00:00
Merge branch 'esp8266-native-pch' into esp32-idf-pch
This commit is contained in:
@@ -10,6 +10,7 @@ from unittest.mock import patch
|
||||
import pytest
|
||||
|
||||
from esphome.build_helpers import ccache
|
||||
from esphome.core import CORE
|
||||
|
||||
|
||||
def test_resolve_opt_out() -> None:
|
||||
@@ -120,3 +121,11 @@ def test_parse_enable_env_spelling_tables(
|
||||
"""cv.boolean's spelling tables plus the 1/0 env convention."""
|
||||
monkeypatch.setenv("ESPHOME_CCACHE_ENABLE", raw)
|
||||
assert ccache.parse_enable_env("ESPHOME_CCACHE_ENABLE") is expected
|
||||
|
||||
|
||||
def test_effective_ccache_basedir_prefers_user_value(tmp_path: Path) -> None:
|
||||
CORE.build_path = tmp_path
|
||||
with patch.dict(os.environ, {"CCACHE_BASEDIR": "/custom/base"}, clear=True):
|
||||
assert ccache.effective_ccache_basedir() == "/custom/base"
|
||||
with patch.dict(os.environ, {}, clear=True):
|
||||
assert ccache.effective_ccache_basedir() == str(tmp_path.resolve())
|
||||
|
||||
@@ -0,0 +1,116 @@
|
||||
"""Tests for esphome.build_helpers.pch."""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
import os
|
||||
from pathlib import Path
|
||||
from unittest.mock import patch
|
||||
|
||||
import pytest
|
||||
|
||||
from esphome.build_helpers import pch
|
||||
|
||||
|
||||
def _write(src_dir: Path, name: str, content: str) -> None:
|
||||
path = src_dir / name
|
||||
path.parent.mkdir(parents=True, exist_ok=True)
|
||||
path.write_text(content)
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
("value", "expected"),
|
||||
[
|
||||
(None, True),
|
||||
("1", True),
|
||||
("0", False),
|
||||
("false", False),
|
||||
("", False),
|
||||
],
|
||||
)
|
||||
def test_pch_enabled(value: str | None, expected: bool) -> None:
|
||||
env = {} if value is None else {"ESPHOME_PCH_ENABLE": value}
|
||||
with patch.dict(os.environ, env, clear=True):
|
||||
assert pch.pch_enabled() is expected
|
||||
|
||||
|
||||
def test_ccache_pch_env_enabled() -> None:
|
||||
with patch.dict(os.environ, {}, clear=True):
|
||||
env = pch.ccache_pch_env()
|
||||
assert env["CCACHE_SLOPPINESS"] == "pch_defines,time_macros"
|
||||
assert env["CCACHE_PCH_EXTSUM"] == "true"
|
||||
|
||||
|
||||
def test_ccache_pch_env_disabled() -> None:
|
||||
with patch.dict(os.environ, {"ESPHOME_PCH_ENABLE": "0"}, clear=True):
|
||||
assert pch.ccache_pch_env() == {}
|
||||
|
||||
|
||||
def test_ccache_pch_env_respects_user_values() -> None:
|
||||
with patch.dict(os.environ, {"CCACHE_SLOPPINESS": "locale"}, clear=True):
|
||||
env = pch.ccache_pch_env()
|
||||
assert "CCACHE_SLOPPINESS" not in env
|
||||
assert env["CCACHE_PCH_EXTSUM"] == "true"
|
||||
|
||||
|
||||
def test_pch_header_text_preserves_order() -> None:
|
||||
text = pch.pch_header_text(["b.h", "a.h"])
|
||||
assert text == '#include "b.h"\n#include "a.h"\n'
|
||||
|
||||
|
||||
def test_include_closure_resolves_relative_and_root(tmp_path: Path) -> None:
|
||||
"""Sibling includes resolve against the includer's directory first,
|
||||
full paths against the src root; unresolvable names end the walk."""
|
||||
_write(tmp_path, "esphome/components/x/a.h", '#include "b.h"\n')
|
||||
_write(
|
||||
tmp_path,
|
||||
"esphome/components/x/b.h",
|
||||
'#include "esphome/core/deep.h"\n#include <system.h>\n#include "missing.h"\n',
|
||||
)
|
||||
_write(tmp_path, "esphome/core/deep.h", "")
|
||||
closure = pch._include_closure(tmp_path, ["esphome/components/x/a.h"])
|
||||
assert sorted(closure) == [
|
||||
"esphome/components/x/a.h",
|
||||
"esphome/components/x/b.h",
|
||||
"esphome/core/deep.h",
|
||||
]
|
||||
|
||||
|
||||
def test_include_closure_handles_cycles(tmp_path: Path) -> None:
|
||||
_write(tmp_path, "a.h", '#include "b.h"\n')
|
||||
_write(tmp_path, "b.h", '#include "a.h"\n')
|
||||
assert sorted(pch._include_closure(tmp_path, ["a.h"])) == ["a.h", "b.h"]
|
||||
|
||||
|
||||
def test_include_closure_blocks_parent_escape(tmp_path: Path) -> None:
|
||||
_write(tmp_path / "src", "a.h", '#include "../outside.h"\n')
|
||||
(tmp_path / "outside.h").write_text("")
|
||||
assert sorted(pch._include_closure(tmp_path / "src", ["a.h"])) == ["a.h"]
|
||||
|
||||
|
||||
def test_pch_checksum_tracks_closure_content(tmp_path: Path) -> None:
|
||||
"""A transitive header edit or an extra-identity change must change the
|
||||
digest; unrelated files must not."""
|
||||
_write(tmp_path, "root.h", '#include "nested.h"\n')
|
||||
_write(tmp_path, "nested.h", "int a;\n")
|
||||
_write(tmp_path, "unrelated.h", "int u;\n")
|
||||
base = pch.pch_checksum(tmp_path, ["root.h"], ["id"])
|
||||
assert base == pch.pch_checksum(tmp_path, ["root.h"], ["id"])
|
||||
assert base != pch.pch_checksum(tmp_path, ["root.h"], ["other-id"])
|
||||
_write(tmp_path, "unrelated.h", "int changed;\n")
|
||||
assert base == pch.pch_checksum(tmp_path, ["root.h"], ["id"])
|
||||
_write(tmp_path, "nested.h", "int b;\n")
|
||||
assert base != pch.pch_checksum(tmp_path, ["root.h"], ["id"])
|
||||
|
||||
|
||||
@pytest.mark.skipif(
|
||||
os.name == "nt" or os.geteuid() == 0, reason="chmod is ineffective here"
|
||||
)
|
||||
def test_include_closure_skips_unreadable(tmp_path: Path) -> None:
|
||||
_write(tmp_path, "a.h", '#include "locked.h"\n')
|
||||
locked = tmp_path / "locked.h"
|
||||
locked.write_text("")
|
||||
locked.chmod(0)
|
||||
try:
|
||||
assert sorted(pch._include_closure(tmp_path, ["a.h"])) == ["a.h"]
|
||||
finally:
|
||||
locked.chmod(0o644)
|
||||
Reference in New Issue
Block a user