From afe12061d2b26b62ce3f2262222cdac2f9e27690 Mon Sep 17 00:00:00 2001 From: "J. Nick Koston" Date: Fri, 21 Aug 2026 12:28:11 -0500 Subject: [PATCH] Track the per-platform shell quoting in the emission drift tests The asm -D/-I filter also strips a leading single quote now that POSIX tokens are single-quoted. --- esphome/build_gen/arduino8266.py | 5 +++-- .../unit_tests/build_gen/test_arduino8266.py | 22 ++++++++++--------- 2 files changed, 15 insertions(+), 12 deletions(-) diff --git a/esphome/build_gen/arduino8266.py b/esphome/build_gen/arduino8266.py index 3329a9c647..2716ed3bc7 100644 --- a/esphome/build_gen/arduino8266.py +++ b/esphome/build_gen/arduino8266.py @@ -590,12 +590,13 @@ def write_project(paths: InstalledPaths) -> bool: ) # PlatformIO's ASPPCOM carries defines and includes but not CCFLAGS, # so only -D/-I user flags reach assembly there; match it. The tokens - # are already shell-quoted, so test past a leading quote too. + # are already shell-quoted (per-platform style), so test past a + # leading quote too. asflags = ( _ASFLAGS + defines + includes - + [f for f in project_compile_flags if f.lstrip('"').startswith(("-D", "-I"))] + + [f for f in project_compile_flags if f.lstrip("\"'").startswith(("-D", "-I"))] ) # build_unflags applies to the framework flag sets too (compile and link), diff --git a/tests/unit_tests/build_gen/test_arduino8266.py b/tests/unit_tests/build_gen/test_arduino8266.py index f76b4856c2..1f5d02858c 100644 --- a/tests/unit_tests/build_gen/test_arduino8266.py +++ b/tests/unit_tests/build_gen/test_arduino8266.py @@ -61,6 +61,11 @@ def _set_flags(*flags: str) -> None: CORE.build_flags = set(flags) +def _shq(tok: str) -> str: + """The platform's shell_token quote wrapper (argv rule on Windows).""" + return f'"{tok}"' if os.name == "nt" else f"'{tok}'" + + def test_rule_map_covers_all_source_suffixes() -> None: """Every suffix a library manifest can select must map to a ninja rule.""" from esphome.platformio.library import SRC_FILE_EXTENSIONS @@ -256,9 +261,9 @@ def test_write_project_link_line_and_exclusions(tmp_path: Path) -> None: # str(Path(...)) so the separator matches the host platform. opt_blobs = str(Path("/opt/blobs")) spc_blobs = str(Path("/spc/blobs")) - assert f'-L"{opt_blobs}"' in content + assert f"-L{_shq(opt_blobs)}" in content assert "-luser_blob" in content - assert f'-L"{spc_blobs}"' in content + assert f"-L{_shq(spc_blobs)}" in content assert "-lspaced_blob" in content for line in content.splitlines(): if line.split(" = ")[0] in ("cflags", "cxxflags", "asflags"): @@ -495,11 +500,11 @@ def test_write_project_libraries_and_variant( # Library link flags reach the firmware link line; .cc compiles as C++ assert "-Wl,--wrap=malloc" in content assert "impl.cc.o: cxx" in content - assert f'-L"{lib_dir / "blobs"}"' in content + assert f"-L{_shq(str(lib_dir / 'blobs'))}" in content # Exceptions knob: -fexceptions and the exception-enabled stdc++ assert "-fexceptions" in content assert "-lstdc++-exc" in content - assert 'ccache = "/cc/ccache"' in content + assert f"ccache = {_shq('/cc/ccache')}" in content def test_get_flash_ld_path(tmp_path: Path) -> None: @@ -638,10 +643,7 @@ def test_project_flags_requotes_lexed_defines() -> None: ) # shlex folds the quotes (as PIO's ParseFlags does); _shell_token # re-quotes the spaced token so the shell passes one argv element - expected = ( - '"-DGREETING=hello world"' if os.name == "nt" else "'-DGREETING=hello world'" - ) - assert compile_flags == [expected] + assert compile_flags == [_shq("-DGREETING=hello world")] def test_write_project_empty_core_raises(tmp_path: Path) -> None: @@ -666,7 +668,7 @@ def test_flag_defines_joins_spaced_define() -> None: def test_ninja_path_escaping() -> None: """Build-statement paths and command-line paths escape differently.""" assert arduino8266._e("a b:$c") == "a$ b$:$$c" - assert arduino8266._q("/a b/$x") == '"/a b/$$x"' + assert arduino8266._q("/a b/$x") == _shq("/a b/$$x") def test_write_project_asm_excludes_non_define_user_flags(tmp_path: Path) -> None: @@ -821,7 +823,7 @@ def test_write_project_asm_keeps_quoted_defines(tmp_path: Path) -> None: _set_flags('-DGREETING="hello world"', "-Wno-volatile") content = _write_ninja(paths) asflags = next(line for line in content.splitlines() if line.startswith("asflags")) - assert '"-DGREETING=hello world"' in asflags + assert _shq("-DGREETING=hello world") in asflags assert "-Wno-volatile" not in asflags