|
| 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}" |
0 commit comments