mirror of
https://github.com/carbon-language/carbon-lang.git
synced 2026-09-25 13:40:12 +01:00
There's a small update to update_checks.py to handle the recursive directories. Also, I'm only using one level of nesting in this PR but really no reason we can't do more. I'm just not sure what clustering is best right now. As a pattern, I'm trying to name all failing tests `fail_*.carbon`.
102 lines
3.3 KiB
Python
Executable File
102 lines
3.3 KiB
Python
Executable File
#!/usr/bin/env python3
|
|
|
|
"""Updates the CHECK: lines in lit tests based on the AUTOUPDATE line."""
|
|
|
|
__copyright__ = """
|
|
Part of the Carbon Language project, under the Apache License v2.0 with LLVM
|
|
Exceptions. See /LICENSE for license information.
|
|
SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
|
"""
|
|
|
|
from concurrent import futures
|
|
import os
|
|
import subprocess
|
|
import sys
|
|
|
|
_BINDIR = "./bazel-bin/executable_semantics"
|
|
_TESTDATA = "executable_semantics/testdata"
|
|
|
|
# TODO: Right now this is a static string used. In theory maybe we should use
|
|
# the command; it's included for that flexibility.
|
|
_AUTOUPDATE_MARKER = "// AUTOUPDATE: executable_semantics %s\n"
|
|
|
|
|
|
def _get_tests():
|
|
"""Get the list of tests from the filesystem."""
|
|
tests = set()
|
|
for root, _, files in os.walk(_TESTDATA):
|
|
for f in files:
|
|
if f == "lit.cfg":
|
|
# Ignore the lit config.
|
|
continue
|
|
if os.path.splitext(f)[1] == ".carbon":
|
|
tests.add(os.path.join(root, f))
|
|
else:
|
|
sys.exit("Unrecognized file type in testdata: %s" % f)
|
|
return tests
|
|
|
|
|
|
def _update_check(test):
|
|
"""Updates the CHECK: lines for `test` by running executable_semantics."""
|
|
with open(test) as f:
|
|
orig_lines = f.readlines()
|
|
if _AUTOUPDATE_MARKER not in orig_lines:
|
|
raise ValueError("No autoupdate marker in %s" % test)
|
|
# Run executable_semantics to general output.
|
|
# (`bazel run` would serialize)
|
|
p = subprocess.run(
|
|
["%s/executable_semantics" % _BINDIR, test],
|
|
stdout=subprocess.PIPE,
|
|
stderr=subprocess.STDOUT,
|
|
)
|
|
out = p.stdout.decode("utf-8")
|
|
|
|
# `lit` uses full paths to the test file, so use a regex to ignore paths
|
|
# when used.
|
|
# TODO: Maybe revisit and see if lit can be convinced to give a
|
|
# root-relative path.
|
|
out = out.replace(test, "{{.*}}/%s" % test)
|
|
|
|
# Remove old OUT.
|
|
lines_without_check = [
|
|
x for x in orig_lines if not x.startswith("// CHECK:")
|
|
]
|
|
autoupdate_index = lines_without_check.index(_AUTOUPDATE_MARKER)
|
|
assert autoupdate_index >= 0
|
|
with open(test, "w") as f:
|
|
f.writelines(lines_without_check[: autoupdate_index + 1])
|
|
f.writelines(["// CHECK: %s\n" % x for x in out.splitlines()])
|
|
f.writelines(lines_without_check[autoupdate_index + 1 :])
|
|
|
|
print(".", end="", flush=True)
|
|
|
|
|
|
def _update_checks():
|
|
"""Runs bazel to update CHECK: lines in lit tests."""
|
|
# TODO: It may be helpful if a list of tests can be passed in args; would
|
|
# want to use argparse for this.
|
|
tests = _get_tests()
|
|
|
|
# Build all tests at once in order to allow parallel updates.
|
|
print("Building executable_semantics...")
|
|
subprocess.check_call(["bazel", "build", "//executable_semantics"])
|
|
|
|
print("Updating %d lit tests..." % len(tests))
|
|
with futures.ThreadPoolExecutor() as exec:
|
|
# list() iterates to propagate exceptions.
|
|
list(exec.map(_update_check, tests))
|
|
# Each update call indicates progress with a dot without a newline, so put a
|
|
# newline to wrap.
|
|
print("\nUpdated lit tests.")
|
|
|
|
|
|
def main():
|
|
# Go to the repository root so that paths will match bazel's view.
|
|
os.chdir(os.path.join(os.path.dirname(__file__), ".."))
|
|
|
|
_update_checks()
|
|
|
|
|
|
if __name__ == "__main__":
|
|
main()
|