[lit] Port Support %if ... %else syntax for RUN lines from upstream (#5227)

* [lit] Port Support %if ... %else syntax for RUN lines from upstream

Based on
1041a9642b

This syntax allows to modify RUN lines based on features
available. For example:

    RUN: ... | FileCheck %s --check-prefix=%if windows %{CHECK-W%} %else %{CHECK-NON-W%}
    CHECK-W: ...
    CHECK-NON-W: ...

This is merged to allow dxilver check apply on each RUN line.
This commit is contained in:
Xiang Li 2023-05-26 17:10:34 -04:00 коммит произвёл GitHub
Родитель 4e0ef84941
Коммит 18c9e114f9
Не найден ключ, соответствующий данной подписи
Идентификатор ключа GPG: 4AEE18F83AFDEB23
10 изменённых файлов: 250 добавлений и 0 удалений

Просмотреть файл

@ -199,6 +199,40 @@ suite they are in, and their relative path inside the test suite. For
appropriately configured projects, this allows :program:`lit` to provide
convenient and flexible support for out-of-tree builds.
Substitutions
-------------
Besides replacing LLVM tool names the following substitutions are performed in
RUN lines:
``%s``
File path to the test case's source. This is suitable for passing on the
command line as the input to an LLVM tool.
Example: ``/home/user/llvm/test/MC/ELF/foo_test.s``
``%S``
Directory path to the test case's source.
Example: ``/home/user/llvm/test/MC/ELF``
``%t``
File path to a temporary file name that could be used for this test case.
The file name won't conflict with other test cases. You can append to it
if you need multiple temporaries. This is useful as the destination of
some redirected output.
Example: ``/home/user/llvm.build/test/MC/ELF/Output/foo_test.s.tmp``
``%T``
Directory of ``%t``. Deprecated. Shouldn't be used, because it can be easily
misused and cause race conditions between tests.
Use ``rm -rf %t && mkdir %t`` instead if a temporary directory is necessary.
Example: ``/home/user/llvm.build/test/MC/ELF/Output``
``%if feature %{<if branch>%} %else %{<else branch>%}``
Conditional substitution: if ``feature`` is available it expands to
``<if branch>``, otherwise it expands to ``<else branch>``.
``%else %{<else branch>%}`` is optional and treated like ``%else %{%}``
if not present.
.. _test-status-results:
TEST STATUS RESULTS

Просмотреть файл

@ -437,6 +437,13 @@ def parseIntegratedTestScript(test, normalize_slashes=False,
('%/T', tmpDir.replace('\\', '/')),
])
# re for %if
re_cond_end = re.compile('%{')
re_if = re.compile('(.*?)(?:%if)')
re_nested_if = re.compile('(.*?)(?:%if|%})')
re_else = re.compile('^\s*%else\s*(%{)?')
# Collect the test lines from the script.
script = []
requires = []
@ -475,11 +482,104 @@ def parseIntegratedTestScript(test, normalize_slashes=False,
raise ValueError("unknown script command type: %r" % (
command_type,))
def substituteIfElse(ln):
# early exit to avoid wasting time on lines without
# conditional substitutions
if ln.find('%if ') == -1:
return ln
def tryParseIfCond(ln):
# space is important to not conflict with other (possible)
# substitutions
if not ln.startswith('%if '):
return None, ln
ln = ln[4:]
# stop at '%{'
match = re_cond_end.search(ln)
if not match:
raise ValueError("'%{' is missing for %if substitution")
cond = ln[:match.start()]
# eat '%{' as well
ln = ln[match.end():]
return cond, ln
def tryParseElse(ln):
match = re_else.search(ln)
if not match:
return False, ln
if not match.group(1):
raise ValueError("'%{' is missing for %else substitution")
return True, ln[match.end():]
def tryParseEnd(ln):
if ln.startswith('%}'):
return True, ln[2:]
return False, ln
def parseText(ln, isNested):
# parse everything until %if, or %} if we're parsing a
# nested expression.
re_pat = re_nested_if if isNested else re_if
match = re_pat.search(ln)
if not match:
# there is no terminating pattern, so treat the whole
# line as text
return ln, ''
text_end = match.end(1)
return ln[:text_end], ln[text_end:]
def parseRecursive(ln, isNested):
result = ''
while len(ln):
if isNested:
found_end, _ = tryParseEnd(ln)
if found_end:
break
# %if cond %{ branch_if %} %else %{ branch_else %}
cond, ln = tryParseIfCond(ln)
if cond:
branch_if, ln = parseRecursive(ln, isNested=True)
found_end, ln = tryParseEnd(ln)
if not found_end:
raise ValueError("'%}' is missing for %if substitution")
branch_else = ''
found_else, ln = tryParseElse(ln)
if found_else:
branch_else, ln = parseRecursive(ln, isNested=True)
found_end, ln = tryParseEnd(ln)
if not found_end:
raise ValueError("'%}' is missing for %else substitution")
cond = cond.strip()
if cond in test.config.available_features:
result += branch_if
else:
result += branch_else
continue
# The rest is handled as plain text.
text, ln = parseText(ln, isNested)
result += text
return result, ln
result, ln = parseRecursive(ln, isNested=False)
assert len(ln) == 0
return result
# Apply substitutions to the script. Allow full regular
# expression syntax. Replace each matching occurrence of regular
# expression pattern a with substitution b in line ln.
def processLine(ln):
# Apply substitutions
ln = substituteIfElse(ln)
for a,b in substitutions:
if kIsWindows:
b = b.replace("\\","\\\\")

Просмотреть файл

@ -62,6 +62,9 @@ class TestingProgressDisplay(object):
print(test.result.output)
print("*" * 20)
if self.opts.showAllOutput:
print(test.result.output)
# Report test metrics, if present.
if test.result.metrics:
print("%s TEST '%s' RESULTS %s" % ('*'*10, test.getFullName(),
@ -163,6 +166,10 @@ def main(builtinParameters = {}):
group.add_option("-v", "--verbose", dest="showOutput",
help="Show all test output",
action="store_true", default=False)
group.add_option("-a", "--show-all",
dest="showAllOutput",
help="Display all commandlines and output",
action="store_true", default=False)
group.add_option("-o", "--output", dest="output_path",
help="Write test results to the provided path",
action="store", type=str, metavar="PATH")

Просмотреть файл

@ -0,0 +1,8 @@
import lit.formats
config.name = 'shtest-if-else'
config.test_format = lit.formats.ShTest()
config.test_source_root = None
config.test_exec_root = None
config.suffixes = ['.txt']
config.available_features.add('feature')
config.substitutions.append(('%{sub}', 'ok'))

Просмотреть файл

@ -0,0 +1,3 @@
# CHECK: ValueError: '%{' is missing for %if substitution
#
# RUN: %if feature echo "test-1"

Просмотреть файл

@ -0,0 +1,3 @@
# CHECK: ValueError: '%}' is missing for %if substitution
#
# RUN: %if feature %{ echo

Просмотреть файл

@ -0,0 +1,3 @@
# CHECK: ValueError: '%{' is missing for %else substitution
#
# RUN: %if feature %{ echo %} %else fail

Просмотреть файл

@ -0,0 +1,3 @@
# CHECK: ValueError: '%}' is missing for %else substitution
#
# RUN: %if feature %{ echo %} %else %{ fail

Просмотреть файл

@ -0,0 +1,75 @@
# CHECK: -- Testing:{{.*}}
# CHECK-NEXT: PASS: shtest-if-else :: test.txt (1 of 1)
# CHECK-NEXT: Script:
# CHECK-NEXT: --
# RUN: %if feature %{ echo "feature" %} %else %{ echo "missing feature" %}
# CHECK-NEXT: echo "feature"
#
# RUN: %if nofeature %{ echo "found unicorn" %} %else %{ echo "nofeature" %}
# CHECK-NEXT: "nofeature"
# CHECK-NOT: found unicorn
# Spaces inside curly braces are not ignored
#
# RUN: echo test-%if feature %{ 3 %} %else %{ echo "fail" %}-test
# RUN: echo test-%if feature %{ 4 4 %} %else %{ echo "fail" %}-test
# RUN: echo test-%if nofeature %{ echo "fail" %} %else %{ 5 5 %}-test
# CHECK-NEXT: echo test- 3 -test
# CHECK-NOT: echo "fail"
# CHECK-NEXT: echo test- 4 4 -test
# CHECK-NOT: echo "fail"
# CHECK-NEXT: echo test- 5 5 -test
# CHECK-NOT: echo "fail"
# Escape line breaks for multi-line expressions
#
# RUN: %if feature \
# RUN: %{ echo \
# RUN: "test-5" \
# RUN: %} %else %{ echo "fail" %}
# CHECK-NEXT: echo "test-5"
# RUN: %if nofeature \
# RUN: %{ echo "fail" %} \
# RUN: %else \
# RUN: %{ echo "test-6" %}
# CHECK-NEXT: echo "test-6"
# RUN: echo "test%if feature %{%} %else %{%}-7"
# CHECK-NEXT: echo "test-7"
# Nested expressions are supported:
#
# RUN: echo %if feature %{ %if feature %{ %if nofeature %{"fail"%} %else %{"test-9"%} %} %}
# CHECK-NEXT: echo "test-9"
# Spaces between %if and %else are ignored. If there is no %else -
# space after %if %{...%} is not ignored.
#
# RUN: echo XX %if feature %{YY%} ZZ
# RUN: echo AA %if feature %{BB%} %else %{CC%} DD
# RUN: echo AA %if nofeature %{BB%} %else %{CC%} DD
# CHECK-NEXT: echo XX YY ZZ
# CHECK-NEXT: echo AA BB DD
# CHECK-NEXT: echo AA CC DD
# '{' and '}' can be used without escaping
#
# RUN: %if feature %{echo {}%}
# CHECK-NEXT: echo {}
# Spaces are not required
#
# RUN: echo %if feature%{"ok"%}%else%{"fail"%}
# CHECK-NEXT: echo "ok"
# Substitutions with braces are handled correctly
#
# RUN: echo %{sub} %if feature%{test-%{sub}%}%else%{"fail"%}
# CHECK-NEXT: echo ok test-ok
# CHECK-NEXT: --
# CHECK-NEXT: Exit Code: 0

Просмотреть файл

@ -0,0 +1,14 @@
# RUN: %{lit} -v --show-all %{inputs}/shtest-if-else/test.txt \
# RUN: | FileCheck %{inputs}/shtest-if-else/test.txt
# RUN: not %{lit} -v %{inputs}/shtest-if-else/test-neg1.txt 2>&1 \
# RUN: | FileCheck %{inputs}/shtest-if-else/test-neg1.txt
# RUN: not %{lit} -v %{inputs}/shtest-if-else/test-neg2.txt 2>&1 \
# RUN: | FileCheck %{inputs}/shtest-if-else/test-neg2.txt
# RUN: not %{lit} -v %{inputs}/shtest-if-else/test-neg3.txt 2>&1 \
# RUN: | FileCheck %{inputs}/shtest-if-else/test-neg3.txt
# RUN: not %{lit} -v %{inputs}/shtest-if-else/test-neg4.txt 2>&1 \
# RUN: | FileCheck %{inputs}/shtest-if-else/test-neg4.txt