mirror of
https://github.com/llvm/llvm-project.git
synced 2025-04-29 15:56:06 +00:00

My #73541 added lines to `llvm/utils/lit/tests/Inputs/testrunner-custom-parsers/test.txt` so what was previously on line 7 is now on line 12. Before:28412d1800/llvm/utils/lit/tests/Inputs/testrunner-custom-parsers/test.txt (L7-L8)
After:6fb7c2d713/llvm/utils/lit/tests/Inputs/testrunner-custom-parsers/test.txt (L12-L13)
This didn't show up in the PR checks, but caused a buildbot failure after merging, https://lab.llvm.org/buildbot/#/builders/139/builds/54597 : ``` # | ====================================================================== # | FAIL: test_commands (__main__.TestIntegratedTestKeywordParser) # | ---------------------------------------------------------------------- # | Traceback (most recent call last): # | File "/home/buildbot/buildbot-root/llvm-clang-x86_64-sie-ubuntu-fast/build/utils/lit/tests/unit/TestRunner.py", line 135, in test_commands # | self.assertEqual(value[1].command.strip(), "%dbg(MY_RUN: at line 7) foo bar") # | AssertionError: '%dbg(MY_RUN: at line 12) foo bar' != '%dbg(MY_RUN: at line 7) foo bar' # | - %dbg(MY_RUN: at line 12) foo bar # | ? ^^ # | + %dbg(MY_RUN: at line 7) foo bar # | ? ^ ``` Apologies for the build break 🙀
388 lines
14 KiB
Python
388 lines
14 KiB
Python
# RUN: %{python} %s
|
|
#
|
|
# END.
|
|
|
|
|
|
import os.path
|
|
import platform
|
|
import unittest
|
|
|
|
import lit.discovery
|
|
import lit.LitConfig
|
|
import lit.Test as Test
|
|
from lit.TestRunner import (
|
|
ParserKind,
|
|
IntegratedTestKeywordParser,
|
|
parseIntegratedTestScript,
|
|
)
|
|
|
|
|
|
class TestIntegratedTestKeywordParser(unittest.TestCase):
|
|
inputTestCase = None
|
|
|
|
@staticmethod
|
|
def load_keyword_parser_lit_tests():
|
|
"""
|
|
Create and load the LIT test suite and test objects used by
|
|
TestIntegratedTestKeywordParser
|
|
"""
|
|
# Create the global config object.
|
|
lit_config = lit.LitConfig.LitConfig(
|
|
progname="lit",
|
|
path=[],
|
|
quiet=False,
|
|
useValgrind=False,
|
|
valgrindLeakCheck=False,
|
|
valgrindArgs=[],
|
|
noExecute=False,
|
|
debug=False,
|
|
isWindows=(platform.system() == "Windows"),
|
|
order="smart",
|
|
params={},
|
|
)
|
|
TestIntegratedTestKeywordParser.litConfig = lit_config
|
|
# Perform test discovery.
|
|
test_path = os.path.dirname(os.path.dirname(__file__))
|
|
inputs = [os.path.join(test_path, "Inputs/testrunner-custom-parsers/")]
|
|
assert os.path.isdir(inputs[0])
|
|
tests = lit.discovery.find_tests_for_inputs(lit_config, inputs)
|
|
assert len(tests) == 1 and "there should only be one test"
|
|
TestIntegratedTestKeywordParser.inputTestCase = tests[0]
|
|
|
|
@staticmethod
|
|
def make_parsers():
|
|
def custom_parse(line_number, line, output):
|
|
if output is None:
|
|
output = []
|
|
output += [part for part in line.split(" ") if part.strip()]
|
|
return output
|
|
|
|
return [
|
|
IntegratedTestKeywordParser("MY_TAG.", ParserKind.TAG),
|
|
IntegratedTestKeywordParser("MY_DNE_TAG.", ParserKind.TAG),
|
|
IntegratedTestKeywordParser("MY_LIST:", ParserKind.LIST),
|
|
IntegratedTestKeywordParser("MY_SPACE_LIST:", ParserKind.SPACE_LIST),
|
|
IntegratedTestKeywordParser("MY_BOOL:", ParserKind.BOOLEAN_EXPR),
|
|
IntegratedTestKeywordParser("MY_INT:", ParserKind.INTEGER),
|
|
IntegratedTestKeywordParser("MY_RUN:", ParserKind.COMMAND),
|
|
IntegratedTestKeywordParser("MY_CUSTOM:", ParserKind.CUSTOM, custom_parse),
|
|
IntegratedTestKeywordParser("MY_DEFINE:", ParserKind.DEFINE),
|
|
IntegratedTestKeywordParser("MY_REDEFINE:", ParserKind.REDEFINE),
|
|
]
|
|
|
|
@staticmethod
|
|
def get_parser(parser_list, keyword):
|
|
for p in parser_list:
|
|
if p.keyword == keyword:
|
|
return p
|
|
assert False and "parser not found"
|
|
|
|
@staticmethod
|
|
def parse_test(parser_list, allow_result=False):
|
|
script = parseIntegratedTestScript(
|
|
TestIntegratedTestKeywordParser.inputTestCase,
|
|
additional_parsers=parser_list,
|
|
require_script=False,
|
|
)
|
|
if isinstance(script, lit.Test.Result):
|
|
assert allow_result
|
|
else:
|
|
assert isinstance(script, list)
|
|
assert len(script) == 0
|
|
return script
|
|
|
|
def test_tags(self):
|
|
parsers = self.make_parsers()
|
|
self.parse_test(parsers)
|
|
tag_parser = self.get_parser(parsers, "MY_TAG.")
|
|
dne_tag_parser = self.get_parser(parsers, "MY_DNE_TAG.")
|
|
self.assertTrue(tag_parser.getValue())
|
|
self.assertFalse(dne_tag_parser.getValue())
|
|
|
|
def test_lists(self):
|
|
parsers = self.make_parsers()
|
|
self.parse_test(parsers)
|
|
list_parser = self.get_parser(parsers, "MY_LIST:")
|
|
self.assertEqual(list_parser.getValue(), ["one", "two", "three", "four"])
|
|
|
|
def test_space_lists(self):
|
|
parsers = self.make_parsers()
|
|
self.parse_test(parsers)
|
|
space_list_parser = self.get_parser(parsers, "MY_SPACE_LIST:")
|
|
self.assertEqual(
|
|
space_list_parser.getValue(),
|
|
[
|
|
"orange",
|
|
"tabby",
|
|
"tortie",
|
|
"tuxedo",
|
|
"void",
|
|
"multiple",
|
|
"spaces",
|
|
"cute,",
|
|
"fluffy,",
|
|
"kittens",
|
|
],
|
|
)
|
|
|
|
def test_commands(self):
|
|
parsers = self.make_parsers()
|
|
self.parse_test(parsers)
|
|
cmd_parser = self.get_parser(parsers, "MY_RUN:")
|
|
value = cmd_parser.getValue()
|
|
self.assertEqual(len(value), 2) # there are only two run lines
|
|
self.assertEqual(value[0].command.strip(), "%dbg(MY_RUN: at line 4) baz")
|
|
self.assertEqual(value[1].command.strip(), "%dbg(MY_RUN: at line 12) foo bar")
|
|
|
|
def test_boolean(self):
|
|
parsers = self.make_parsers()
|
|
self.parse_test(parsers)
|
|
bool_parser = self.get_parser(parsers, "MY_BOOL:")
|
|
value = bool_parser.getValue()
|
|
self.assertEqual(len(value), 2) # there are only two run lines
|
|
self.assertEqual(value[0].strip(), "a && (b)")
|
|
self.assertEqual(value[1].strip(), "d")
|
|
|
|
def test_integer(self):
|
|
parsers = self.make_parsers()
|
|
self.parse_test(parsers)
|
|
int_parser = self.get_parser(parsers, "MY_INT:")
|
|
value = int_parser.getValue()
|
|
self.assertEqual(len(value), 2) # there are only two MY_INT: lines
|
|
self.assertEqual(type(value[0]), int)
|
|
self.assertEqual(value[0], 4)
|
|
self.assertEqual(type(value[1]), int)
|
|
self.assertEqual(value[1], 6)
|
|
|
|
def test_bad_parser_type(self):
|
|
parsers = self.make_parsers() + ["BAD_PARSER_TYPE"]
|
|
script = self.parse_test(parsers, allow_result=True)
|
|
self.assertTrue(isinstance(script, lit.Test.Result))
|
|
self.assertEqual(script.code, lit.Test.UNRESOLVED)
|
|
self.assertEqual(
|
|
"Additional parser must be an instance of " "IntegratedTestKeywordParser",
|
|
script.output,
|
|
)
|
|
|
|
def test_duplicate_keyword(self):
|
|
parsers = self.make_parsers() + [
|
|
IntegratedTestKeywordParser("KEY:", ParserKind.BOOLEAN_EXPR),
|
|
IntegratedTestKeywordParser("KEY:", ParserKind.BOOLEAN_EXPR),
|
|
]
|
|
script = self.parse_test(parsers, allow_result=True)
|
|
self.assertTrue(isinstance(script, lit.Test.Result))
|
|
self.assertEqual(script.code, lit.Test.UNRESOLVED)
|
|
self.assertEqual("Parser for keyword 'KEY:' already exists", script.output)
|
|
|
|
def test_boolean_unterminated(self):
|
|
parsers = self.make_parsers() + [
|
|
IntegratedTestKeywordParser(
|
|
"MY_BOOL_UNTERMINATED:", ParserKind.BOOLEAN_EXPR
|
|
)
|
|
]
|
|
script = self.parse_test(parsers, allow_result=True)
|
|
self.assertTrue(isinstance(script, lit.Test.Result))
|
|
self.assertEqual(script.code, lit.Test.UNRESOLVED)
|
|
self.assertEqual(
|
|
"Test has unterminated 'MY_BOOL_UNTERMINATED:' lines " "(with '\\')",
|
|
script.output,
|
|
)
|
|
|
|
def test_custom(self):
|
|
parsers = self.make_parsers()
|
|
self.parse_test(parsers)
|
|
custom_parser = self.get_parser(parsers, "MY_CUSTOM:")
|
|
value = custom_parser.getValue()
|
|
self.assertEqual(value, ["a", "b", "c"])
|
|
|
|
def test_defines(self):
|
|
parsers = self.make_parsers()
|
|
self.parse_test(parsers)
|
|
cmd_parser = self.get_parser(parsers, "MY_DEFINE:")
|
|
value = cmd_parser.getValue()
|
|
self.assertEqual(len(value), 1) # there's only one MY_DEFINE directive
|
|
self.assertEqual(value[0].new_subst, True)
|
|
self.assertEqual(value[0].name, "%{name}")
|
|
self.assertEqual(value[0].value, "value one")
|
|
|
|
def test_redefines(self):
|
|
parsers = self.make_parsers()
|
|
self.parse_test(parsers)
|
|
cmd_parser = self.get_parser(parsers, "MY_REDEFINE:")
|
|
value = cmd_parser.getValue()
|
|
self.assertEqual(len(value), 1) # there's only one MY_REDEFINE directive
|
|
self.assertEqual(value[0].new_subst, False)
|
|
self.assertEqual(value[0].name, "%{name}")
|
|
self.assertEqual(value[0].value, "value two")
|
|
|
|
def test_bad_keywords(self):
|
|
def custom_parse(line_number, line, output):
|
|
return output
|
|
|
|
try:
|
|
IntegratedTestKeywordParser("TAG_NO_SUFFIX", ParserKind.TAG),
|
|
self.fail("TAG_NO_SUFFIX failed to raise an exception")
|
|
except ValueError as e:
|
|
pass
|
|
except BaseException as e:
|
|
self.fail("TAG_NO_SUFFIX raised the wrong exception: %r" % e)
|
|
|
|
try:
|
|
IntegratedTestKeywordParser("TAG_WITH_COLON:", ParserKind.TAG),
|
|
self.fail("TAG_WITH_COLON: failed to raise an exception")
|
|
except ValueError as e:
|
|
pass
|
|
except BaseException as e:
|
|
self.fail("TAG_WITH_COLON: raised the wrong exception: %r" % e)
|
|
|
|
try:
|
|
IntegratedTestKeywordParser("LIST_WITH_DOT.", ParserKind.LIST),
|
|
self.fail("LIST_WITH_DOT. failed to raise an exception")
|
|
except ValueError as e:
|
|
pass
|
|
except BaseException as e:
|
|
self.fail("LIST_WITH_DOT. raised the wrong exception: %r" % e)
|
|
|
|
try:
|
|
IntegratedTestKeywordParser("SPACE_LIST_WITH_DOT.", ParserKind.SPACE_LIST),
|
|
self.fail("SPACE_LIST_WITH_DOT. failed to raise an exception")
|
|
except ValueError as e:
|
|
pass
|
|
except BaseException as e:
|
|
self.fail("SPACE_LIST_WITH_DOT. raised the wrong exception: %r" % e)
|
|
|
|
try:
|
|
IntegratedTestKeywordParser(
|
|
"CUSTOM_NO_SUFFIX", ParserKind.CUSTOM, custom_parse
|
|
),
|
|
self.fail("CUSTOM_NO_SUFFIX failed to raise an exception")
|
|
except ValueError as e:
|
|
pass
|
|
except BaseException as e:
|
|
self.fail("CUSTOM_NO_SUFFIX raised the wrong exception: %r" % e)
|
|
|
|
# Both '.' and ':' are allowed for CUSTOM keywords.
|
|
try:
|
|
IntegratedTestKeywordParser(
|
|
"CUSTOM_WITH_DOT.", ParserKind.CUSTOM, custom_parse
|
|
),
|
|
except BaseException as e:
|
|
self.fail("CUSTOM_WITH_DOT. raised an exception: %r" % e)
|
|
try:
|
|
IntegratedTestKeywordParser(
|
|
"CUSTOM_WITH_COLON:", ParserKind.CUSTOM, custom_parse
|
|
),
|
|
except BaseException as e:
|
|
self.fail("CUSTOM_WITH_COLON: raised an exception: %r" % e)
|
|
|
|
try:
|
|
IntegratedTestKeywordParser("CUSTOM_NO_PARSER:", ParserKind.CUSTOM),
|
|
self.fail("CUSTOM_NO_PARSER: failed to raise an exception")
|
|
except ValueError as e:
|
|
pass
|
|
except BaseException as e:
|
|
self.fail("CUSTOM_NO_PARSER: raised the wrong exception: %r" % e)
|
|
|
|
|
|
class TestApplySubtitutions(unittest.TestCase):
|
|
def test_simple(self):
|
|
script = ["echo %bar"]
|
|
substitutions = [("%bar", "hello")]
|
|
result = lit.TestRunner.applySubstitutions(script, substitutions)
|
|
self.assertEqual(result, ["echo hello"])
|
|
|
|
def test_multiple_substitutions(self):
|
|
script = ["echo %bar %baz"]
|
|
substitutions = [
|
|
("%bar", "hello"),
|
|
("%baz", "world"),
|
|
("%useless", "shouldnt expand"),
|
|
]
|
|
result = lit.TestRunner.applySubstitutions(script, substitutions)
|
|
self.assertEqual(result, ["echo hello world"])
|
|
|
|
def test_multiple_script_lines(self):
|
|
script = ["%cxx %compile_flags -c -o %t.o", "%cxx %link_flags %t.o -o %t.exe"]
|
|
substitutions = [
|
|
("%cxx", "clang++"),
|
|
("%compile_flags", "-std=c++11 -O3"),
|
|
("%link_flags", "-lc++"),
|
|
]
|
|
result = lit.TestRunner.applySubstitutions(script, substitutions)
|
|
self.assertEqual(
|
|
result,
|
|
["clang++ -std=c++11 -O3 -c -o %t.o", "clang++ -lc++ %t.o -o %t.exe"],
|
|
)
|
|
|
|
def test_recursive_substitution_real(self):
|
|
script = ["%build %s"]
|
|
substitutions = [
|
|
("%cxx", "clang++"),
|
|
("%compile_flags", "-std=c++11 -O3"),
|
|
("%link_flags", "-lc++"),
|
|
("%build", "%cxx %compile_flags %link_flags %s -o %t.exe"),
|
|
]
|
|
result = lit.TestRunner.applySubstitutions(
|
|
script, substitutions, recursion_limit=3
|
|
)
|
|
self.assertEqual(result, ["clang++ -std=c++11 -O3 -lc++ %s -o %t.exe %s"])
|
|
|
|
def test_recursive_substitution_limit(self):
|
|
script = ["%rec5"]
|
|
# Make sure the substitutions are not in an order where the global
|
|
# substitution would appear to be recursive just because they are
|
|
# processed in the right order.
|
|
substitutions = [
|
|
("%rec1", "STOP"),
|
|
("%rec2", "%rec1"),
|
|
("%rec3", "%rec2"),
|
|
("%rec4", "%rec3"),
|
|
("%rec5", "%rec4"),
|
|
]
|
|
for limit in [5, 6, 7]:
|
|
result = lit.TestRunner.applySubstitutions(
|
|
script, substitutions, recursion_limit=limit
|
|
)
|
|
self.assertEqual(result, ["STOP"])
|
|
|
|
def test_recursive_substitution_limit_exceeded(self):
|
|
script = ["%rec5"]
|
|
substitutions = [
|
|
("%rec1", "STOP"),
|
|
("%rec2", "%rec1"),
|
|
("%rec3", "%rec2"),
|
|
("%rec4", "%rec3"),
|
|
("%rec5", "%rec4"),
|
|
]
|
|
for limit in [0, 1, 2, 3, 4]:
|
|
try:
|
|
lit.TestRunner.applySubstitutions(
|
|
script, substitutions, recursion_limit=limit
|
|
)
|
|
self.fail("applySubstitutions should have raised an exception")
|
|
except ValueError:
|
|
pass
|
|
|
|
def test_recursive_substitution_invalid_value(self):
|
|
script = ["%rec5"]
|
|
substitutions = [
|
|
("%rec1", "STOP"),
|
|
("%rec2", "%rec1"),
|
|
("%rec3", "%rec2"),
|
|
("%rec4", "%rec3"),
|
|
("%rec5", "%rec4"),
|
|
]
|
|
for limit in [-1, -2, -3, "foo"]:
|
|
try:
|
|
lit.TestRunner.applySubstitutions(
|
|
script, substitutions, recursion_limit=limit
|
|
)
|
|
self.fail("applySubstitutions should have raised an exception")
|
|
except AssertionError:
|
|
pass
|
|
|
|
|
|
if __name__ == "__main__":
|
|
TestIntegratedTestKeywordParser.load_keyword_parser_lit_tests()
|
|
unittest.main(verbosity=2)
|