From d85426069c66e0a8314b5d42731bb04f2c87f6b7 Mon Sep 17 00:00:00 2001 From: dantdmdarealguy Date: Wed, 21 Oct 2026 21:05:31 -0500 Subject: [PATCH] fix(tools): decode Ninja's header dependencies as UTF-8 in select_tests MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ninja -t deps lists the paths GCC wrote to its depfiles. WinLibs GCC 15.2.0 runs with the UTF-8 active code page, while its Ninja 1.13.2 reports an ANSI build-file encoding, so a header under C:\Users\José\... decoded with mbcs became José, fell outside the source tree and dropped out of every test's inputs. Decode the dependency lines as UTF-8 and keep the build-file encoding for the outputs they belong to. --- tools/select_tests.py | 9 +++++---- tools/tests/test_select_tests.py | 25 +++++++++++++++++++++++++ 2 files changed, 30 insertions(+), 4 deletions(-) diff --git a/tools/select_tests.py b/tools/select_tests.py index efb972d0a1..08c715d642 100644 --- a/tools/select_tests.py +++ b/tools/select_tests.py @@ -125,11 +125,12 @@ def chunks(names): def dump(build, out): deps = collections.defaultdict(set) current = None - for line in build.run("-t", "deps").splitlines(): - if not line.startswith(" ") and ": #deps" in line: - current = build.key(line.split(": #deps")[0]) + recorded = subprocess.run([build.program, "-C", build.path, "-t", "deps"], capture_output=True, check=True).stdout + for line in recorded.splitlines(): + if not line.startswith(b" ") and b": #deps" in line: + current = build.key(line.split(b": #deps")[0].decode(build.encoding)) elif line.strip() and current: - path = build.repo(line.strip()) + path = build.repo(line.strip().decode("utf-8")) if path: deps[current].add(path) listing, listed = build.tests() diff --git a/tools/tests/test_select_tests.py b/tools/tests/test_select_tests.py index e86b16ccad..8b9a7873f6 100644 --- a/tools/tests/test_select_tests.py +++ b/tools/tests/test_select_tests.py @@ -207,6 +207,31 @@ class FixtureBuildTests(unittest.TestCase): self.assertIn(name, output) +@unittest.skipUnless(shutil.which("ninja") and (shutil.which("gcc") or shutil.which("cc")), "needs ninja and a C compiler") +class NonAsciiDirectoryTests(unittest.TestCase): + def test_header_under_a_non_ascii_directory_is_an_input_of_its_tests(self): + with tempfile.TemporaryDirectory() as directory: + root = Path(directory) / "ação" + if os.name == "nt": + try: + str(root).encode("mbcs", "strict") + except UnicodeEncodeError: + self.skipTest("the ANSI code page cannot represent the fixture directory") + source, build, graph = root / "source", root / "build", root / "graph.json" + for name, content in PROJECT.items(): + (source / name).parent.mkdir(parents=True, exist_ok=True) + (source / name).write_text(content, encoding="utf-8") + compiler = shutil.which("gcc") or shutil.which("cc") + subprocess.run(["cmake", "-S", str(source), "-B", str(build), "-G", "Ninja", f"-DCMAKE_C_COMPILER={compiler}"], + check=True, capture_output=True) + subprocess.run(["cmake", "--build", str(build)], check=True, capture_output=True) + SelectTests.tool("dump", build, graph) + reasons = {} + select_tests.select(json.loads(graph.read_text(encoding="utf-8")), ["alpha/alpha.h"], reasons) + self.assertIn("input: alpha/alpha.h", reasons["alpha"]) + self.assertIn("input: alpha/alpha.h", reasons["alpha_data"]) + + class BuildErrorTests(unittest.TestCase): def run_tool(self, *args): return subprocess.run([sys.executable, "-I", str(TOOL), *map(str, args)], capture_output=True, text=True, timeout=60)