Skip to content

[UTC] Add --dry-run/-n functionality#193739

Open
madhur13490 wants to merge 1 commit intollvm:mainfrom
madhur13490:utc-dry-run
Open

[UTC] Add --dry-run/-n functionality#193739
madhur13490 wants to merge 1 commit intollvm:mainfrom
madhur13490:utc-dry-run

Conversation

@madhur13490
Copy link
Copy Markdown
Contributor

Often, developers need to see the diff before updating the tests with the scripts. This patch adds --dry-run option to UTC which one can use to see diff on stdout. The stdout can further be piped to tools like delta or diff for better viewing.

Often, developers needs to see the diff before updating
the tests with the scripts. This patch adds --dry-run option to UTC
which one can use to see diff on stdout. The stdout can further be piped
to tools like delta or diff for better viewing.
@llvmbot
Copy link
Copy Markdown
Member

llvmbot commented Apr 23, 2026

@llvm/pr-subscribers-testing-tools

Author: Madhur Amilkanthwar (madhur13490)

Changes

Often, developers need to see the diff before updating the tests with the scripts. This patch adds --dry-run option to UTC which one can use to see diff on stdout. The stdout can further be piped to tools like delta or diff for better viewing.


Full diff: https://github.com/llvm/llvm-project/pull/193739.diff

3 Files Affected:

  • (added) llvm/test/tools/UpdateTestChecks/update_test_checks/dry-run.test (+36)
  • (modified) llvm/utils/UpdateTestChecks/common.py (+1)
  • (modified) llvm/utils/update_test_checks.py (+26-1)
diff --git a/llvm/test/tools/UpdateTestChecks/update_test_checks/dry-run.test b/llvm/test/tools/UpdateTestChecks/update_test_checks/dry-run.test
new file mode 100644
index 0000000000000..e2da30ef81e87
--- /dev/null
+++ b/llvm/test/tools/UpdateTestChecks/update_test_checks/dry-run.test
@@ -0,0 +1,36 @@
+## Verify that `update_test_checks.py --dry-run` prints a unified diff to
+## stdout and does not modify the test file on disk.
+
+## Case 1: running --dry-run on a file that is already up-to-date with UTC
+## must produce no diff on stdout and must leave the file unchanged.
+# RUN: cp -f %S/Inputs/basic.ll.expected %t.ll
+# RUN: %update_test_checks --dry-run %t.ll > %t.diff
+# RUN: diff -u %t.ll %S/Inputs/basic.ll.expected
+# RUN: count 0 < %t.diff
+
+## Case 2: running --dry-run on a file with a stale CHECK line must emit a
+## non-empty unified diff on stdout, must leave the file unchanged on
+## disk, and must not record --dry-run / UTC_ARGS into the diff (i.e. the
+## flag must not leak into the in-file footer).
+# RUN: cp -f %S/Inputs/basic.ll.expected %t.ll
+# RUN: sed -i.bak -e 's/ret i32 0/ret i32 WRONG/' %t.ll && rm -f %t.ll.bak
+# RUN: %update_test_checks --dry-run %t.ll > %t.diff
+# RUN: FileCheck --input-file=%t.diff %s --check-prefix=DIFF
+# RUN: not grep -q UTC_ARGS %t.diff
+# RUN: FileCheck --input-file=%t.ll %s --check-prefix=STALE
+
+## Case 3: the short flag -n behaves identically to --dry-run.
+# RUN: cp -f %S/Inputs/basic.ll.expected %t.ll
+# RUN: %update_test_checks -n %t.ll > %t.diff
+# RUN: diff -u %t.ll %S/Inputs/basic.ll.expected
+# RUN: count 0 < %t.diff
+
+## The diff emitted in case 2 must show exactly the correction UTC would
+## apply: replacing the stale `ret i32 WRONG` check with `ret i32 0`.
+# DIFF: @@
+# DIFF: -; CHECK-NEXT:    ret i32 WRONG
+# DIFF: +; CHECK-NEXT:    ret i32 0
+
+## The on-disk file in case 2 must still contain the stale check; UTC must
+## not have written anything.
+# STALE: ret i32 WRONG
diff --git a/llvm/utils/UpdateTestChecks/common.py b/llvm/utils/UpdateTestChecks/common.py
index f01b6900b38b0..635b8598da3bf 100644
--- a/llvm/utils/UpdateTestChecks/common.py
+++ b/llvm/utils/UpdateTestChecks/common.py
@@ -2738,6 +2738,7 @@ def get_autogennote_suffix(parser, args):
             "force_update",
             "reset_variable_names",
             "llvm_mc_binary",
+            "dry_run",
         ):
             continue
         value = getattr(args, action.dest)
diff --git a/llvm/utils/update_test_checks.py b/llvm/utils/update_test_checks.py
index 74e87787fd5b8..0462624f7adfe 100755
--- a/llvm/utils/update_test_checks.py
+++ b/llvm/utils/update_test_checks.py
@@ -37,6 +37,7 @@
 from sys import stderr
 from traceback import print_exc
 import argparse
+import difflib
 import os  # Used to advertise this file's name ("autogenerated_note").
 import re
 import sys
@@ -315,10 +316,27 @@ def update_test(ti: common.TestInfo):
         output_lines.extend(
             ti.get_checks_for_unused_prefixes(prefix_list, generated_prefixes)
         )
+    new_content = "".join("{}\n".format(l) for l in output_lines)
+
+    if ti.args.dry_run:
+        try:
+            with open(ti.path, "r", encoding="utf-8") as f:
+                old_content = f.read()
+        except FileNotFoundError:
+            old_content = ""
+        diff = difflib.unified_diff(
+            old_content.splitlines(keepends=True),
+            new_content.splitlines(keepends=True),
+            fromfile=ti.path,
+            tofile=ti.path,
+        )
+        sys.stdout.writelines(diff)
+        return
+
     common.debug("Writing %d lines to %s..." % (len(output_lines), ti.path))
 
     with open(ti.path, "wb") as f:
-        f.writelines(["{}\n".format(l).encode("utf-8") for l in output_lines])
+        f.write(new_content.encode("utf-8"))
 
 
 def main():
@@ -376,6 +394,13 @@ def main():
         help="Reset all variable names to correspond closely to the variable names in IR. "
         "This tends to result in larger diffs.",
     )
+    parser.add_argument(
+        "-n",
+        "--dry-run",
+        action="store_true",
+        help="Do not modify the test file. Emit a unified diff of the "
+        "changes that would be written to stdout.",
+    )
     parser.add_argument("tests", nargs="+")
     initial_args = common.parse_commandline_args(parser)
 

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants