[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:
Родитель
4e0ef84941
Коммит
18c9e114f9
|
@ -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
|
Загрузка…
Ссылка в новой задаче