Skip to content

Commit 3324de9

Browse files
committed
[Utils] Adds support for diff based tests to lit's --update-tests (llvm#154147)
This adds an updater to lit's --update-tests flag with support for `diff`. If a RUN line containing the `diff` command fails, this function will use heuristics to try to deduce which file is the "reference" file, and copy the contents of the other file to the reference. If it cannot deduce which file is the reference file, it does nothing. The heuristics are currently: - does one of the files end in .expected while the other does not? Then the .expected file is the reference. - does one of the file paths contain the substring ".tmp" while the other does not? Then the file not containing ".tmp" is the reference. This matches cases where one file path is constructed using the `%t` substitution. (cherry picked from commit 6c3f18e)
1 parent eabe978 commit 3324de9

File tree

12 files changed

+102
-1
lines changed

12 files changed

+102
-1
lines changed

llvm/utils/lit/lit/DiffUpdater.py

Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
import shutil
2+
3+
"""
4+
This file provides the `diff_test_updater` function, which is invoked on failed RUN lines when lit is executed with --update-tests.
5+
It checks whether the failed command is `diff` and, if so, uses heuristics to determine which file is the checked-in reference file and which file is output from the test case.
6+
The heuristics are currently as follows:
7+
- if exactly one file ends with ".expected" (common pattern in LLVM), that file is the reference file and the other is the output file
8+
- if exactly one file path contains ".tmp" (e.g. because it contains the expansion of "%t"), that file is the reference file and the other is the output file
9+
If the command matches one of these patterns the output file content is copied to the reference file to make the test pass.
10+
Otherwise the test is ignored.
11+
12+
Possible improvements:
13+
- Support stdin patterns like "my_binary %s | diff expected.txt"
14+
- Scan RUN lines to see if a file is the source of output from a previous command.
15+
If it is then it is not a reference file that can be copied to, regardless of name, since the test will overwrite it anyways.
16+
- Only update the parts that need updating (based on the diff output). Could help avoid noisy updates when e.g. whitespace changes are ignored.
17+
"""
18+
19+
20+
def get_source_and_target(a, b):
21+
"""
22+
Try to figure out which file is the test output and which is the reference.
23+
"""
24+
expected_suffix = ".expected"
25+
if a.endswith(expected_suffix) and not b.endswith(expected_suffix):
26+
return b, a
27+
if b.endswith(expected_suffix) and not a.endswith(expected_suffix):
28+
return a, b
29+
30+
tmp_substr = ".tmp"
31+
if tmp_substr in a and not tmp_substr in b:
32+
return a, b
33+
if tmp_substr in b and not tmp_substr in a:
34+
return b, a
35+
36+
return None
37+
38+
39+
def filter_flags(args):
40+
return [arg for arg in args if not arg.startswith("-")]
41+
42+
43+
def diff_test_updater(result, test):
44+
args = filter_flags(result.command.args)
45+
if len(args) != 3:
46+
return None
47+
[cmd, a, b] = args
48+
if cmd != "diff":
49+
return None
50+
res = get_source_and_target(a, b)
51+
if not res:
52+
return f"update-diff-test: could not deduce source and target from {a} and {b}"
53+
source, target = res
54+
shutil.copy(source, target)
55+
return f"update-diff-test: copied {source} to {target}"

llvm/utils/lit/lit/LitConfig.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
import lit.formats
99
import lit.TestingConfig
1010
import lit.util
11+
from lit.DiffUpdater import diff_test_updater
1112

1213
# LitConfig must be a new style class for properties to work
1314
class LitConfig(object):
@@ -91,7 +92,7 @@ def __init__(
9192
self.per_test_coverage = per_test_coverage
9293
self.gtest_sharding = bool(gtest_sharding)
9394
self.update_tests = update_tests
94-
self.test_updaters = []
95+
self.test_updaters = [diff_test_updater]
9596

9697
@property
9798
def maxIndividualTestTime(self):
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
*.txt
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
FOO
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
BAR
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
# There is no indication here of which file is the reference file to update
2+
# RUN: diff %S/1.in %S/2.in
3+
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
# RUN: mkdir %t
2+
# RUN: cp %S/1.in %t/1.txt
3+
# RUN: cp %S/2.in %t/2.txt
4+
5+
# There is no indication here of which file is the reference file to update
6+
# RUN: diff %t/1.txt %t/2.txt
7+
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
# RUN: mkdir %t
2+
# RUN: cp %S/1.in %t/my-file.expected
3+
# RUN: cp %S/2.in %t/my-file.txt
4+
# RUN: diff %t/my-file.expected %t/my-file.txt
5+
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
# RUN: mkdir %t
2+
# RUN: touch %S/empty.txt
3+
# RUN: cp %S/1.in %t/1.txt
4+
5+
# RUN: diff %t/1.txt %S/empty.txt
6+
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
# RUN: cp %S/1.in %t.txt
2+
# RUN: cp %S/2.in %S/diff-t-out.txt
3+
# RUN: diff %t.txt %S/diff-t-out.txt

0 commit comments

Comments
 (0)