xref: /openbsd-src/gnu/llvm/llvm/utils/lit/tests/unit/TestRunner.py (revision d415bd752c734aee168c4ee86ff32e8cc249eb16)
109467b48Spatrick# RUN: %{python} %s
209467b48Spatrick#
309467b48Spatrick# END.
409467b48Spatrick
509467b48Spatrick
609467b48Spatrickimport os.path
709467b48Spatrickimport platform
809467b48Spatrickimport unittest
909467b48Spatrick
1009467b48Spatrickimport lit.discovery
1109467b48Spatrickimport lit.LitConfig
1209467b48Spatrickimport lit.Test as Test
1309467b48Spatrickfrom lit.TestRunner import ParserKind, IntegratedTestKeywordParser, \
1409467b48Spatrick                           parseIntegratedTestScript
1509467b48Spatrick
1609467b48Spatrick
1709467b48Spatrickclass TestIntegratedTestKeywordParser(unittest.TestCase):
1809467b48Spatrick    inputTestCase = None
1909467b48Spatrick
2009467b48Spatrick    @staticmethod
2109467b48Spatrick    def load_keyword_parser_lit_tests():
2209467b48Spatrick        """
2309467b48Spatrick        Create and load the LIT test suite and test objects used by
2409467b48Spatrick        TestIntegratedTestKeywordParser
2509467b48Spatrick        """
2609467b48Spatrick        # Create the global config object.
2709467b48Spatrick        lit_config = lit.LitConfig.LitConfig(progname='lit',
2809467b48Spatrick                                             path=[],
2909467b48Spatrick                                             quiet=False,
3009467b48Spatrick                                             useValgrind=False,
3109467b48Spatrick                                             valgrindLeakCheck=False,
3209467b48Spatrick                                             valgrindArgs=[],
3309467b48Spatrick                                             noExecute=False,
3409467b48Spatrick                                             debug=False,
3509467b48Spatrick                                             isWindows=(
3609467b48Spatrick                                               platform.system() == 'Windows'),
37*d415bd75Srobert                                             order='smart',
3809467b48Spatrick                                             params={})
3909467b48Spatrick        TestIntegratedTestKeywordParser.litConfig = lit_config
4009467b48Spatrick        # Perform test discovery.
4109467b48Spatrick        test_path = os.path.dirname(os.path.dirname(__file__))
4209467b48Spatrick        inputs = [os.path.join(test_path, 'Inputs/testrunner-custom-parsers/')]
4309467b48Spatrick        assert os.path.isdir(inputs[0])
4473471bf0Spatrick        tests = lit.discovery.find_tests_for_inputs(lit_config, inputs, False)
4509467b48Spatrick        assert len(tests) == 1 and "there should only be one test"
4609467b48Spatrick        TestIntegratedTestKeywordParser.inputTestCase = tests[0]
4709467b48Spatrick
4809467b48Spatrick    @staticmethod
4909467b48Spatrick    def make_parsers():
5009467b48Spatrick        def custom_parse(line_number, line, output):
5109467b48Spatrick            if output is None:
5209467b48Spatrick                output = []
5309467b48Spatrick            output += [part for part in line.split(' ') if part.strip()]
5409467b48Spatrick            return output
5509467b48Spatrick
5609467b48Spatrick        return [
5709467b48Spatrick            IntegratedTestKeywordParser("MY_TAG.", ParserKind.TAG),
5809467b48Spatrick            IntegratedTestKeywordParser("MY_DNE_TAG.", ParserKind.TAG),
5909467b48Spatrick            IntegratedTestKeywordParser("MY_LIST:", ParserKind.LIST),
6009467b48Spatrick            IntegratedTestKeywordParser("MY_BOOL:", ParserKind.BOOLEAN_EXPR),
61097a140dSpatrick            IntegratedTestKeywordParser("MY_INT:", ParserKind.INTEGER),
6209467b48Spatrick            IntegratedTestKeywordParser("MY_RUN:", ParserKind.COMMAND),
6309467b48Spatrick            IntegratedTestKeywordParser("MY_CUSTOM:", ParserKind.CUSTOM,
6409467b48Spatrick                                        custom_parse),
65*d415bd75Srobert            IntegratedTestKeywordParser("MY_DEFINE:", ParserKind.DEFINE),
66*d415bd75Srobert            IntegratedTestKeywordParser("MY_REDEFINE:", ParserKind.REDEFINE),
6709467b48Spatrick        ]
6809467b48Spatrick
6909467b48Spatrick    @staticmethod
7009467b48Spatrick    def get_parser(parser_list, keyword):
7109467b48Spatrick        for p in parser_list:
7209467b48Spatrick            if p.keyword == keyword:
7309467b48Spatrick                return p
7409467b48Spatrick        assert False and "parser not found"
7509467b48Spatrick
7609467b48Spatrick    @staticmethod
77097a140dSpatrick    def parse_test(parser_list, allow_result=False):
7809467b48Spatrick        script = parseIntegratedTestScript(
7909467b48Spatrick            TestIntegratedTestKeywordParser.inputTestCase,
8009467b48Spatrick            additional_parsers=parser_list, require_script=False)
81097a140dSpatrick        if isinstance(script, lit.Test.Result):
82097a140dSpatrick            assert allow_result
83097a140dSpatrick        else:
8409467b48Spatrick            assert isinstance(script, list)
8509467b48Spatrick            assert len(script) == 0
86097a140dSpatrick        return script
8709467b48Spatrick
8809467b48Spatrick    def test_tags(self):
8909467b48Spatrick        parsers = self.make_parsers()
9009467b48Spatrick        self.parse_test(parsers)
9109467b48Spatrick        tag_parser = self.get_parser(parsers, 'MY_TAG.')
9209467b48Spatrick        dne_tag_parser = self.get_parser(parsers, 'MY_DNE_TAG.')
9309467b48Spatrick        self.assertTrue(tag_parser.getValue())
9409467b48Spatrick        self.assertFalse(dne_tag_parser.getValue())
9509467b48Spatrick
9609467b48Spatrick    def test_lists(self):
9709467b48Spatrick        parsers = self.make_parsers()
9809467b48Spatrick        self.parse_test(parsers)
9909467b48Spatrick        list_parser = self.get_parser(parsers, 'MY_LIST:')
10009467b48Spatrick        self.assertEqual(list_parser.getValue(),
10109467b48Spatrick                              ['one', 'two', 'three', 'four'])
10209467b48Spatrick
10309467b48Spatrick    def test_commands(self):
10409467b48Spatrick        parsers = self.make_parsers()
10509467b48Spatrick        self.parse_test(parsers)
10609467b48Spatrick        cmd_parser = self.get_parser(parsers, 'MY_RUN:')
10709467b48Spatrick        value = cmd_parser.getValue()
10809467b48Spatrick        self.assertEqual(len(value), 2)  # there are only two run lines
109*d415bd75Srobert        self.assertEqual(value[0].command.strip(),
110*d415bd75Srobert                         "%dbg(MY_RUN: at line 4)  baz")
111*d415bd75Srobert        self.assertEqual(value[1].command.strip(),
112*d415bd75Srobert                         "%dbg(MY_RUN: at line 7)  foo  bar")
11309467b48Spatrick
11409467b48Spatrick    def test_boolean(self):
11509467b48Spatrick        parsers = self.make_parsers()
11609467b48Spatrick        self.parse_test(parsers)
11709467b48Spatrick        bool_parser = self.get_parser(parsers, 'MY_BOOL:')
11809467b48Spatrick        value = bool_parser.getValue()
11909467b48Spatrick        self.assertEqual(len(value), 2)  # there are only two run lines
12009467b48Spatrick        self.assertEqual(value[0].strip(), "a && (b)")
12109467b48Spatrick        self.assertEqual(value[1].strip(), "d")
12209467b48Spatrick
123097a140dSpatrick    def test_integer(self):
124097a140dSpatrick        parsers = self.make_parsers()
125097a140dSpatrick        self.parse_test(parsers)
126097a140dSpatrick        int_parser = self.get_parser(parsers, 'MY_INT:')
127097a140dSpatrick        value = int_parser.getValue()
128097a140dSpatrick        self.assertEqual(len(value), 2)  # there are only two MY_INT: lines
129097a140dSpatrick        self.assertEqual(type(value[0]), int)
130097a140dSpatrick        self.assertEqual(value[0], 4)
131097a140dSpatrick        self.assertEqual(type(value[1]), int)
132097a140dSpatrick        self.assertEqual(value[1], 6)
133097a140dSpatrick
134097a140dSpatrick    def test_bad_parser_type(self):
135097a140dSpatrick        parsers = self.make_parsers() + ["BAD_PARSER_TYPE"]
136097a140dSpatrick        script = self.parse_test(parsers, allow_result=True)
137097a140dSpatrick        self.assertTrue(isinstance(script, lit.Test.Result))
138097a140dSpatrick        self.assertEqual(script.code, lit.Test.UNRESOLVED)
139097a140dSpatrick        self.assertEqual('Additional parser must be an instance of '
140097a140dSpatrick                         'IntegratedTestKeywordParser',
141097a140dSpatrick                         script.output)
142097a140dSpatrick
143097a140dSpatrick    def test_duplicate_keyword(self):
144097a140dSpatrick        parsers = self.make_parsers() + \
145097a140dSpatrick            [IntegratedTestKeywordParser("KEY:", ParserKind.BOOLEAN_EXPR),
146097a140dSpatrick             IntegratedTestKeywordParser("KEY:", ParserKind.BOOLEAN_EXPR)]
147097a140dSpatrick        script = self.parse_test(parsers, allow_result=True)
148097a140dSpatrick        self.assertTrue(isinstance(script, lit.Test.Result))
149097a140dSpatrick        self.assertEqual(script.code, lit.Test.UNRESOLVED)
150097a140dSpatrick        self.assertEqual("Parser for keyword 'KEY:' already exists",
151097a140dSpatrick                         script.output)
152097a140dSpatrick
15309467b48Spatrick    def test_boolean_unterminated(self):
15409467b48Spatrick        parsers = self.make_parsers() + \
15509467b48Spatrick            [IntegratedTestKeywordParser("MY_BOOL_UNTERMINATED:", ParserKind.BOOLEAN_EXPR)]
156097a140dSpatrick        script = self.parse_test(parsers, allow_result=True)
157097a140dSpatrick        self.assertTrue(isinstance(script, lit.Test.Result))
158097a140dSpatrick        self.assertEqual(script.code, lit.Test.UNRESOLVED)
159097a140dSpatrick        self.assertEqual("Test has unterminated 'MY_BOOL_UNTERMINATED:' lines "
160097a140dSpatrick                         "(with '\\')",
161097a140dSpatrick                         script.output)
16209467b48Spatrick
16309467b48Spatrick    def test_custom(self):
16409467b48Spatrick        parsers = self.make_parsers()
16509467b48Spatrick        self.parse_test(parsers)
16609467b48Spatrick        custom_parser = self.get_parser(parsers, 'MY_CUSTOM:')
16709467b48Spatrick        value = custom_parser.getValue()
16809467b48Spatrick        self.assertEqual(value, ['a', 'b', 'c'])
16909467b48Spatrick
170*d415bd75Srobert    def test_defines(self):
171*d415bd75Srobert        parsers = self.make_parsers()
172*d415bd75Srobert        self.parse_test(parsers)
173*d415bd75Srobert        cmd_parser = self.get_parser(parsers, 'MY_DEFINE:')
174*d415bd75Srobert        value = cmd_parser.getValue()
175*d415bd75Srobert        self.assertEqual(len(value), 1) # there's only one MY_DEFINE directive
176*d415bd75Srobert        self.assertEqual(value[0].new_subst, True)
177*d415bd75Srobert        self.assertEqual(value[0].name, '%{name}')
178*d415bd75Srobert        self.assertEqual(value[0].value, 'value one')
179*d415bd75Srobert
180*d415bd75Srobert    def test_redefines(self):
181*d415bd75Srobert        parsers = self.make_parsers()
182*d415bd75Srobert        self.parse_test(parsers)
183*d415bd75Srobert        cmd_parser = self.get_parser(parsers, 'MY_REDEFINE:')
184*d415bd75Srobert        value = cmd_parser.getValue()
185*d415bd75Srobert        self.assertEqual(len(value), 1) # there's only one MY_REDEFINE directive
186*d415bd75Srobert        self.assertEqual(value[0].new_subst, False)
187*d415bd75Srobert        self.assertEqual(value[0].name, '%{name}')
188*d415bd75Srobert        self.assertEqual(value[0].value, 'value two')
189*d415bd75Srobert
19009467b48Spatrick    def test_bad_keywords(self):
19109467b48Spatrick        def custom_parse(line_number, line, output):
19209467b48Spatrick            return output
19309467b48Spatrick
19409467b48Spatrick        try:
19509467b48Spatrick            IntegratedTestKeywordParser("TAG_NO_SUFFIX", ParserKind.TAG),
19609467b48Spatrick            self.fail("TAG_NO_SUFFIX failed to raise an exception")
19709467b48Spatrick        except ValueError as e:
19809467b48Spatrick            pass
19909467b48Spatrick        except BaseException as e:
20009467b48Spatrick            self.fail("TAG_NO_SUFFIX raised the wrong exception: %r" % e)
20109467b48Spatrick
20209467b48Spatrick        try:
20309467b48Spatrick            IntegratedTestKeywordParser("TAG_WITH_COLON:", ParserKind.TAG),
20409467b48Spatrick            self.fail("TAG_WITH_COLON: failed to raise an exception")
20509467b48Spatrick        except ValueError as e:
20609467b48Spatrick            pass
20709467b48Spatrick        except BaseException as e:
20809467b48Spatrick            self.fail("TAG_WITH_COLON: raised the wrong exception: %r" % e)
20909467b48Spatrick
21009467b48Spatrick        try:
21109467b48Spatrick            IntegratedTestKeywordParser("LIST_WITH_DOT.", ParserKind.LIST),
21209467b48Spatrick            self.fail("LIST_WITH_DOT. failed to raise an exception")
21309467b48Spatrick        except ValueError as e:
21409467b48Spatrick            pass
21509467b48Spatrick        except BaseException as e:
21609467b48Spatrick            self.fail("LIST_WITH_DOT. raised the wrong exception: %r" % e)
21709467b48Spatrick
21809467b48Spatrick        try:
21909467b48Spatrick            IntegratedTestKeywordParser("CUSTOM_NO_SUFFIX",
22009467b48Spatrick                                        ParserKind.CUSTOM, custom_parse),
22109467b48Spatrick            self.fail("CUSTOM_NO_SUFFIX failed to raise an exception")
22209467b48Spatrick        except ValueError as e:
22309467b48Spatrick            pass
22409467b48Spatrick        except BaseException as e:
22509467b48Spatrick            self.fail("CUSTOM_NO_SUFFIX raised the wrong exception: %r" % e)
22609467b48Spatrick
22709467b48Spatrick        # Both '.' and ':' are allowed for CUSTOM keywords.
22809467b48Spatrick        try:
22909467b48Spatrick            IntegratedTestKeywordParser("CUSTOM_WITH_DOT.",
23009467b48Spatrick                                        ParserKind.CUSTOM, custom_parse),
23109467b48Spatrick        except BaseException as e:
23209467b48Spatrick            self.fail("CUSTOM_WITH_DOT. raised an exception: %r" % e)
23309467b48Spatrick        try:
23409467b48Spatrick            IntegratedTestKeywordParser("CUSTOM_WITH_COLON:",
23509467b48Spatrick                                        ParserKind.CUSTOM, custom_parse),
23609467b48Spatrick        except BaseException as e:
23709467b48Spatrick            self.fail("CUSTOM_WITH_COLON: raised an exception: %r" % e)
23809467b48Spatrick
23909467b48Spatrick        try:
24009467b48Spatrick            IntegratedTestKeywordParser("CUSTOM_NO_PARSER:",
24109467b48Spatrick                                        ParserKind.CUSTOM),
24209467b48Spatrick            self.fail("CUSTOM_NO_PARSER: failed to raise an exception")
24309467b48Spatrick        except ValueError as e:
24409467b48Spatrick            pass
24509467b48Spatrick        except BaseException as e:
24609467b48Spatrick            self.fail("CUSTOM_NO_PARSER: raised the wrong exception: %r" % e)
24709467b48Spatrick
248097a140dSpatrickclass TestApplySubtitutions(unittest.TestCase):
249097a140dSpatrick    def test_simple(self):
250097a140dSpatrick        script = ["echo %bar"]
251097a140dSpatrick        substitutions = [("%bar", "hello")]
252097a140dSpatrick        result = lit.TestRunner.applySubstitutions(script, substitutions)
253097a140dSpatrick        self.assertEqual(result, ["echo hello"])
254097a140dSpatrick
255097a140dSpatrick    def test_multiple_substitutions(self):
256097a140dSpatrick        script = ["echo %bar %baz"]
257097a140dSpatrick        substitutions = [("%bar", "hello"),
258097a140dSpatrick                         ("%baz", "world"),
259097a140dSpatrick                         ("%useless", "shouldnt expand")]
260097a140dSpatrick        result = lit.TestRunner.applySubstitutions(script, substitutions)
261097a140dSpatrick        self.assertEqual(result, ["echo hello world"])
262097a140dSpatrick
263097a140dSpatrick    def test_multiple_script_lines(self):
264097a140dSpatrick        script = ["%cxx %compile_flags -c -o %t.o",
265097a140dSpatrick                  "%cxx %link_flags %t.o -o %t.exe"]
266097a140dSpatrick        substitutions = [("%cxx", "clang++"),
267097a140dSpatrick                         ("%compile_flags", "-std=c++11 -O3"),
268097a140dSpatrick                         ("%link_flags", "-lc++")]
269097a140dSpatrick        result = lit.TestRunner.applySubstitutions(script, substitutions)
270097a140dSpatrick        self.assertEqual(result, ["clang++ -std=c++11 -O3 -c -o %t.o",
271097a140dSpatrick                                  "clang++ -lc++ %t.o -o %t.exe"])
272097a140dSpatrick
273097a140dSpatrick    def test_recursive_substitution_real(self):
274097a140dSpatrick        script = ["%build %s"]
275097a140dSpatrick        substitutions = [("%cxx", "clang++"),
276097a140dSpatrick                         ("%compile_flags", "-std=c++11 -O3"),
277097a140dSpatrick                         ("%link_flags", "-lc++"),
278097a140dSpatrick                         ("%build", "%cxx %compile_flags %link_flags %s -o %t.exe")]
279097a140dSpatrick        result = lit.TestRunner.applySubstitutions(script, substitutions, recursion_limit=3)
280097a140dSpatrick        self.assertEqual(result, ["clang++ -std=c++11 -O3 -lc++ %s -o %t.exe %s"])
281097a140dSpatrick
282097a140dSpatrick    def test_recursive_substitution_limit(self):
283097a140dSpatrick        script = ["%rec5"]
284097a140dSpatrick        # Make sure the substitutions are not in an order where the global
285097a140dSpatrick        # substitution would appear to be recursive just because they are
286097a140dSpatrick        # processed in the right order.
287097a140dSpatrick        substitutions = [("%rec1", "STOP"), ("%rec2", "%rec1"),
288097a140dSpatrick                         ("%rec3", "%rec2"), ("%rec4", "%rec3"), ("%rec5", "%rec4")]
289097a140dSpatrick        for limit in [5, 6, 7]:
290097a140dSpatrick            result = lit.TestRunner.applySubstitutions(script, substitutions, recursion_limit=limit)
291097a140dSpatrick            self.assertEqual(result, ["STOP"])
292097a140dSpatrick
293097a140dSpatrick    def test_recursive_substitution_limit_exceeded(self):
294097a140dSpatrick        script = ["%rec5"]
295097a140dSpatrick        substitutions = [("%rec1", "STOP"), ("%rec2", "%rec1"),
296097a140dSpatrick                         ("%rec3", "%rec2"), ("%rec4", "%rec3"), ("%rec5", "%rec4")]
297097a140dSpatrick        for limit in [0, 1, 2, 3, 4]:
298097a140dSpatrick            try:
299097a140dSpatrick                lit.TestRunner.applySubstitutions(script, substitutions, recursion_limit=limit)
300097a140dSpatrick                self.fail("applySubstitutions should have raised an exception")
301097a140dSpatrick            except ValueError:
302097a140dSpatrick                pass
303097a140dSpatrick
304097a140dSpatrick    def test_recursive_substitution_invalid_value(self):
305097a140dSpatrick        script = ["%rec5"]
306097a140dSpatrick        substitutions = [("%rec1", "STOP"), ("%rec2", "%rec1"),
307097a140dSpatrick                         ("%rec3", "%rec2"), ("%rec4", "%rec3"), ("%rec5", "%rec4")]
308097a140dSpatrick        for limit in [-1, -2, -3, "foo"]:
309097a140dSpatrick            try:
310097a140dSpatrick                lit.TestRunner.applySubstitutions(script, substitutions, recursion_limit=limit)
311097a140dSpatrick                self.fail("applySubstitutions should have raised an exception")
312097a140dSpatrick            except AssertionError:
313097a140dSpatrick                pass
314097a140dSpatrick
315097a140dSpatrick
31609467b48Spatrickif __name__ == '__main__':
31709467b48Spatrick    TestIntegratedTestKeywordParser.load_keyword_parser_lit_tests()
31809467b48Spatrick    unittest.main(verbosity=2)
319