diff --git a/esphome/build_helpers/ccache.py b/esphome/build_helpers/ccache.py index 8804e5028d..dfceaabf1c 100644 --- a/esphome/build_helpers/ccache.py +++ b/esphome/build_helpers/ccache.py @@ -11,6 +11,10 @@ from esphome.framework_helpers import strip_win_long_path_prefix, tool_version_r _LOGGER = logging.getLogger(__name__) +# esphome cv.boolean's spelling tables plus the 1/0 env convention +TRUTHY_ENV_STRINGS = frozenset({"1", "true", "yes", "on", "enable"}) +FALSY_ENV_STRINGS = frozenset({"0", "false", "no", "off", "disable"}) + def _ccache_runs(ccache: str) -> bool: """Return True when the ``ccache`` found on PATH actually runs.""" @@ -31,9 +35,9 @@ def parse_enable_env(name: str) -> bool | None: if raw is None: return None lowered = raw.strip().lower() - if lowered in ("1", "true", "yes", "on"): + if lowered in TRUTHY_ENV_STRINGS: return True - if lowered in ("0", "false", "no", "off"): + if lowered in FALSY_ENV_STRINGS: return False _LOGGER.warning("Ignoring unrecognized %s=%r; use 1 or 0", name, raw) return None diff --git a/tests/unit_tests/build_helpers/test_ccache.py b/tests/unit_tests/build_helpers/test_ccache.py index c612f79554..619a1a3476 100644 --- a/tests/unit_tests/build_helpers/test_ccache.py +++ b/tests/unit_tests/build_helpers/test_ccache.py @@ -97,3 +97,23 @@ def test_resolve_unrecognized_value_warns_and_probes( assert ccache.resolve_ccache_path() is None mock_probe.assert_called_once() assert "unrecognized ESPHOME_CCACHE_ENABLE" in caplog.text + + +@pytest.mark.parametrize( + ("raw", "expected"), + [ + ("1", True), + ("enable", True), + ("ON", True), + ("0", False), + ("disable", False), + ("Off", False), + ("maybe", None), + ], +) +def test_parse_enable_env_spelling_tables( + monkeypatch: pytest.MonkeyPatch, raw: str, expected: bool | None +) -> None: + """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 diff --git a/tests/unit_tests/test_platformio_library.py b/tests/unit_tests/test_platformio_library.py index f46f4e4fa2..50c2a14405 100644 --- a/tests/unit_tests/test_platformio_library.py +++ b/tests/unit_tests/test_platformio_library.py @@ -603,30 +603,6 @@ def test_lex_build_flags_dangling_flag_does_not_cross_entries( assert "Ignoring trailing '-I'" in caplog.text -def test_split_flag_entry_non_string_is_clean() -> None: - """A dict or number from a third-party manifest fails naming the entry, - not with an opaque shlex traceback.""" - - with pytest.raises(EsphomeError, match="Malformed build flag"): - split_flag_entry({"esp32": ["-DX"]}, "lib x") - with pytest.raises(EsphomeError, match="Malformed build flag 5"): - split_flag_entry(5, "lib x") - - -def test_source_kind_map_shape() -> None: - """The kind values the native compile rules key on, and the deliberate - AS/ASPP merge (.s and .S both map to asm).""" - - assert set(SOURCE_KIND_FOR_SUFFIX.values()) == {"c", "cxx", "asm"} - assert SOURCE_KIND_FOR_SUFFIX[".s"] == "asm" - assert SOURCE_KIND_FOR_SUFFIX[".S"] == "asm" - assert SOURCE_KIND_FOR_SUFFIX[".c"] == "c" - assert SOURCE_KIND_FOR_SUFFIX[".cpp"] == "cxx" - # SCons's case-sensitive C++ suffixes: PIO compiles .C as C++ - assert SOURCE_KIND_FOR_SUFFIX[".C"] == "cxx" - assert SOURCE_KIND_FOR_SUFFIX[".C++"] == "cxx" - - def test_normalize_dependencies_forms(caplog) -> None: """Every PIO-legal spelling normalizes; unrecognizable entries warn.""" from esphome.platformio.library import normalize_dependencies @@ -684,6 +660,54 @@ def test_walk_warns_for_properties_only_depends( assert "declares dependencies via library.properties" in caplog.text +def test_walk_warns_for_nonplatform_invalid_library( + tmp_path, monkeypatch, caplog: pytest.LogCaptureFixture +) -> None: + """A dependency dropped for any cause other than the routine platform + filter is visible in every backend.""" + _patch_download_with_manifests( + monkeypatch, + tmp_path, + {"esphome/A": {"name": "A", "dependencies": [{"name": "B", "version": "1.0"}]}}, + ) + calls = {"n": 0} + real = lib.check_library_data + + def flaky(data, platform, framework): + calls["n"] += 1 + if calls["n"] > 1: + raise InvalidLibrary("manifest is corrupt") + return real(data, platform, framework) + + monkeypatch.setattr(lib, "check_library_data", flaky) + convert_libraries([Library("esphome/A", None, None)], _backend()) + assert "Skipping dependency B of esphome/A: manifest is corrupt" in caplog.text + + +def test_split_flag_entry_non_string_is_clean() -> None: + """A dict or number from a third-party manifest fails naming the entry, + not with an opaque shlex traceback.""" + + with pytest.raises(EsphomeError, match="Malformed build flag"): + split_flag_entry({"esp32": ["-DX"]}, "lib x") + with pytest.raises(EsphomeError, match="Malformed build flag 5"): + split_flag_entry(5, "lib x") + + +def test_source_kind_map_shape() -> None: + """The kind values the native compile rules key on, and the deliberate + AS/ASPP merge (.s and .S both map to asm).""" + + assert set(SOURCE_KIND_FOR_SUFFIX.values()) == {"c", "cxx", "asm"} + assert SOURCE_KIND_FOR_SUFFIX[".s"] == "asm" + assert SOURCE_KIND_FOR_SUFFIX[".S"] == "asm" + assert SOURCE_KIND_FOR_SUFFIX[".c"] == "c" + assert SOURCE_KIND_FOR_SUFFIX[".cpp"] == "cxx" + # SCons's case-sensitive C++ suffixes: PIO compiles .C as C++ + assert SOURCE_KIND_FOR_SUFFIX[".C"] == "cxx" + assert SOURCE_KIND_FOR_SUFFIX[".C++"] == "cxx" + + def test_versionless_platform_filtered_dependency_stays_quiet( tmp_path, monkeypatch, caplog: pytest.LogCaptureFixture ) -> None: @@ -743,30 +767,6 @@ def test_versionless_dependency_without_provider_warns( ) -def test_walk_warns_for_nonplatform_invalid_library( - tmp_path, monkeypatch, caplog: pytest.LogCaptureFixture -) -> None: - """A dependency dropped for any cause other than the routine platform - filter is visible in every backend.""" - _patch_download_with_manifests( - monkeypatch, - tmp_path, - {"esphome/A": {"name": "A", "dependencies": [{"name": "B", "version": "1.0"}]}}, - ) - calls = {"n": 0} - real = lib.check_library_data - - def flaky(data, platform, framework): - calls["n"] += 1 - if calls["n"] > 1: - raise InvalidLibrary("manifest is corrupt") - return real(data, platform, framework) - - monkeypatch.setattr(lib, "check_library_data", flaky) - convert_libraries([Library("esphome/A", None, None)], _backend()) - assert "Skipping dependency B of esphome/A: manifest is corrupt" in caplog.text - - def test_versionless_owner_qualified_dependency_warns_despite_provides( tmp_path, monkeypatch, caplog: pytest.LogCaptureFixture ) -> None: