1# RUN: %{python} %s 2# 3# END. 4 5 6import os.path 7import platform 8import unittest 9 10import lit.discovery 11import lit.LitConfig 12import lit.Test as Test 13from lit.TestRunner import ParserKind, IntegratedTestKeywordParser, \ 14 parseIntegratedTestScript 15 16 17class TestIntegratedTestKeywordParser(unittest.TestCase): 18 inputTestCase = None 19 20 @staticmethod 21 def load_keyword_parser_lit_tests(): 22 """ 23 Create and load the LIT test suite and test objects used by 24 TestIntegratedTestKeywordParser 25 """ 26 # Create the global config object. 27 lit_config = lit.LitConfig.LitConfig(progname='lit', 28 path=[], 29 quiet=False, 30 useValgrind=False, 31 valgrindLeakCheck=False, 32 valgrindArgs=[], 33 noExecute=False, 34 debug=False, 35 isWindows=( 36 platform.system() == 'Windows'), 37 params={}) 38 TestIntegratedTestKeywordParser.litConfig = lit_config 39 # Perform test discovery. 40 test_path = os.path.dirname(os.path.dirname(__file__)) 41 inputs = [os.path.join(test_path, 'Inputs/testrunner-custom-parsers/')] 42 assert os.path.isdir(inputs[0]) 43 tests = lit.discovery.find_tests_for_inputs(lit_config, inputs, False) 44 assert len(tests) == 1 and "there should only be one test" 45 TestIntegratedTestKeywordParser.inputTestCase = tests[0] 46 47 @staticmethod 48 def make_parsers(): 49 def custom_parse(line_number, line, output): 50 if output is None: 51 output = [] 52 output += [part for part in line.split(' ') if part.strip()] 53 return output 54 55 return [ 56 IntegratedTestKeywordParser("MY_TAG.", ParserKind.TAG), 57 IntegratedTestKeywordParser("MY_DNE_TAG.", ParserKind.TAG), 58 IntegratedTestKeywordParser("MY_LIST:", ParserKind.LIST), 59 IntegratedTestKeywordParser("MY_BOOL:", ParserKind.BOOLEAN_EXPR), 60 IntegratedTestKeywordParser("MY_INT:", ParserKind.INTEGER), 61 IntegratedTestKeywordParser("MY_RUN:", ParserKind.COMMAND), 62 IntegratedTestKeywordParser("MY_CUSTOM:", ParserKind.CUSTOM, 63 custom_parse), 64 65 ] 66 67 @staticmethod 68 def get_parser(parser_list, keyword): 69 for p in parser_list: 70 if p.keyword == keyword: 71 return p 72 assert False and "parser not found" 73 74 @staticmethod 75 def parse_test(parser_list, allow_result=False): 76 script = parseIntegratedTestScript( 77 TestIntegratedTestKeywordParser.inputTestCase, 78 additional_parsers=parser_list, require_script=False) 79 if isinstance(script, lit.Test.Result): 80 assert allow_result 81 else: 82 assert isinstance(script, list) 83 assert len(script) == 0 84 return script 85 86 def test_tags(self): 87 parsers = self.make_parsers() 88 self.parse_test(parsers) 89 tag_parser = self.get_parser(parsers, 'MY_TAG.') 90 dne_tag_parser = self.get_parser(parsers, 'MY_DNE_TAG.') 91 self.assertTrue(tag_parser.getValue()) 92 self.assertFalse(dne_tag_parser.getValue()) 93 94 def test_lists(self): 95 parsers = self.make_parsers() 96 self.parse_test(parsers) 97 list_parser = self.get_parser(parsers, 'MY_LIST:') 98 self.assertEqual(list_parser.getValue(), 99 ['one', 'two', 'three', 'four']) 100 101 def test_commands(self): 102 parsers = self.make_parsers() 103 self.parse_test(parsers) 104 cmd_parser = self.get_parser(parsers, 'MY_RUN:') 105 value = cmd_parser.getValue() 106 self.assertEqual(len(value), 2) # there are only two run lines 107 self.assertEqual(value[0].strip(), "%dbg(MY_RUN: at line 4) baz") 108 self.assertEqual(value[1].strip(), "%dbg(MY_RUN: at line 7) foo bar") 109 110 def test_boolean(self): 111 parsers = self.make_parsers() 112 self.parse_test(parsers) 113 bool_parser = self.get_parser(parsers, 'MY_BOOL:') 114 value = bool_parser.getValue() 115 self.assertEqual(len(value), 2) # there are only two run lines 116 self.assertEqual(value[0].strip(), "a && (b)") 117 self.assertEqual(value[1].strip(), "d") 118 119 def test_integer(self): 120 parsers = self.make_parsers() 121 self.parse_test(parsers) 122 int_parser = self.get_parser(parsers, 'MY_INT:') 123 value = int_parser.getValue() 124 self.assertEqual(len(value), 2) # there are only two MY_INT: lines 125 self.assertEqual(type(value[0]), int) 126 self.assertEqual(value[0], 4) 127 self.assertEqual(type(value[1]), int) 128 self.assertEqual(value[1], 6) 129 130 def test_bad_parser_type(self): 131 parsers = self.make_parsers() + ["BAD_PARSER_TYPE"] 132 script = self.parse_test(parsers, allow_result=True) 133 self.assertTrue(isinstance(script, lit.Test.Result)) 134 self.assertEqual(script.code, lit.Test.UNRESOLVED) 135 self.assertEqual('Additional parser must be an instance of ' 136 'IntegratedTestKeywordParser', 137 script.output) 138 139 def test_duplicate_keyword(self): 140 parsers = self.make_parsers() + \ 141 [IntegratedTestKeywordParser("KEY:", ParserKind.BOOLEAN_EXPR), 142 IntegratedTestKeywordParser("KEY:", ParserKind.BOOLEAN_EXPR)] 143 script = self.parse_test(parsers, allow_result=True) 144 self.assertTrue(isinstance(script, lit.Test.Result)) 145 self.assertEqual(script.code, lit.Test.UNRESOLVED) 146 self.assertEqual("Parser for keyword 'KEY:' already exists", 147 script.output) 148 149 def test_boolean_unterminated(self): 150 parsers = self.make_parsers() + \ 151 [IntegratedTestKeywordParser("MY_BOOL_UNTERMINATED:", ParserKind.BOOLEAN_EXPR)] 152 script = self.parse_test(parsers, allow_result=True) 153 self.assertTrue(isinstance(script, lit.Test.Result)) 154 self.assertEqual(script.code, lit.Test.UNRESOLVED) 155 self.assertEqual("Test has unterminated 'MY_BOOL_UNTERMINATED:' lines " 156 "(with '\\')", 157 script.output) 158 159 def test_custom(self): 160 parsers = self.make_parsers() 161 self.parse_test(parsers) 162 custom_parser = self.get_parser(parsers, 'MY_CUSTOM:') 163 value = custom_parser.getValue() 164 self.assertEqual(value, ['a', 'b', 'c']) 165 166 def test_bad_keywords(self): 167 def custom_parse(line_number, line, output): 168 return output 169 170 try: 171 IntegratedTestKeywordParser("TAG_NO_SUFFIX", ParserKind.TAG), 172 self.fail("TAG_NO_SUFFIX failed to raise an exception") 173 except ValueError as e: 174 pass 175 except BaseException as e: 176 self.fail("TAG_NO_SUFFIX raised the wrong exception: %r" % e) 177 178 try: 179 IntegratedTestKeywordParser("TAG_WITH_COLON:", ParserKind.TAG), 180 self.fail("TAG_WITH_COLON: failed to raise an exception") 181 except ValueError as e: 182 pass 183 except BaseException as e: 184 self.fail("TAG_WITH_COLON: raised the wrong exception: %r" % e) 185 186 try: 187 IntegratedTestKeywordParser("LIST_WITH_DOT.", ParserKind.LIST), 188 self.fail("LIST_WITH_DOT. failed to raise an exception") 189 except ValueError as e: 190 pass 191 except BaseException as e: 192 self.fail("LIST_WITH_DOT. raised the wrong exception: %r" % e) 193 194 try: 195 IntegratedTestKeywordParser("CUSTOM_NO_SUFFIX", 196 ParserKind.CUSTOM, custom_parse), 197 self.fail("CUSTOM_NO_SUFFIX failed to raise an exception") 198 except ValueError as e: 199 pass 200 except BaseException as e: 201 self.fail("CUSTOM_NO_SUFFIX raised the wrong exception: %r" % e) 202 203 # Both '.' and ':' are allowed for CUSTOM keywords. 204 try: 205 IntegratedTestKeywordParser("CUSTOM_WITH_DOT.", 206 ParserKind.CUSTOM, custom_parse), 207 except BaseException as e: 208 self.fail("CUSTOM_WITH_DOT. raised an exception: %r" % e) 209 try: 210 IntegratedTestKeywordParser("CUSTOM_WITH_COLON:", 211 ParserKind.CUSTOM, custom_parse), 212 except BaseException as e: 213 self.fail("CUSTOM_WITH_COLON: raised an exception: %r" % e) 214 215 try: 216 IntegratedTestKeywordParser("CUSTOM_NO_PARSER:", 217 ParserKind.CUSTOM), 218 self.fail("CUSTOM_NO_PARSER: failed to raise an exception") 219 except ValueError as e: 220 pass 221 except BaseException as e: 222 self.fail("CUSTOM_NO_PARSER: raised the wrong exception: %r" % e) 223 224class TestApplySubtitutions(unittest.TestCase): 225 def test_simple(self): 226 script = ["echo %bar"] 227 substitutions = [("%bar", "hello")] 228 result = lit.TestRunner.applySubstitutions(script, substitutions) 229 self.assertEqual(result, ["echo hello"]) 230 231 def test_multiple_substitutions(self): 232 script = ["echo %bar %baz"] 233 substitutions = [("%bar", "hello"), 234 ("%baz", "world"), 235 ("%useless", "shouldnt expand")] 236 result = lit.TestRunner.applySubstitutions(script, substitutions) 237 self.assertEqual(result, ["echo hello world"]) 238 239 def test_multiple_script_lines(self): 240 script = ["%cxx %compile_flags -c -o %t.o", 241 "%cxx %link_flags %t.o -o %t.exe"] 242 substitutions = [("%cxx", "clang++"), 243 ("%compile_flags", "-std=c++11 -O3"), 244 ("%link_flags", "-lc++")] 245 result = lit.TestRunner.applySubstitutions(script, substitutions) 246 self.assertEqual(result, ["clang++ -std=c++11 -O3 -c -o %t.o", 247 "clang++ -lc++ %t.o -o %t.exe"]) 248 249 def test_recursive_substitution_real(self): 250 script = ["%build %s"] 251 substitutions = [("%cxx", "clang++"), 252 ("%compile_flags", "-std=c++11 -O3"), 253 ("%link_flags", "-lc++"), 254 ("%build", "%cxx %compile_flags %link_flags %s -o %t.exe")] 255 result = lit.TestRunner.applySubstitutions(script, substitutions, recursion_limit=3) 256 self.assertEqual(result, ["clang++ -std=c++11 -O3 -lc++ %s -o %t.exe %s"]) 257 258 def test_recursive_substitution_limit(self): 259 script = ["%rec5"] 260 # Make sure the substitutions are not in an order where the global 261 # substitution would appear to be recursive just because they are 262 # processed in the right order. 263 substitutions = [("%rec1", "STOP"), ("%rec2", "%rec1"), 264 ("%rec3", "%rec2"), ("%rec4", "%rec3"), ("%rec5", "%rec4")] 265 for limit in [5, 6, 7]: 266 result = lit.TestRunner.applySubstitutions(script, substitutions, recursion_limit=limit) 267 self.assertEqual(result, ["STOP"]) 268 269 def test_recursive_substitution_limit_exceeded(self): 270 script = ["%rec5"] 271 substitutions = [("%rec1", "STOP"), ("%rec2", "%rec1"), 272 ("%rec3", "%rec2"), ("%rec4", "%rec3"), ("%rec5", "%rec4")] 273 for limit in [0, 1, 2, 3, 4]: 274 try: 275 lit.TestRunner.applySubstitutions(script, substitutions, recursion_limit=limit) 276 self.fail("applySubstitutions should have raised an exception") 277 except ValueError: 278 pass 279 280 def test_recursive_substitution_invalid_value(self): 281 script = ["%rec5"] 282 substitutions = [("%rec1", "STOP"), ("%rec2", "%rec1"), 283 ("%rec3", "%rec2"), ("%rec4", "%rec3"), ("%rec5", "%rec4")] 284 for limit in [-1, -2, -3, "foo"]: 285 try: 286 lit.TestRunner.applySubstitutions(script, substitutions, recursion_limit=limit) 287 self.fail("applySubstitutions should have raised an exception") 288 except AssertionError: 289 pass 290 291 292if __name__ == '__main__': 293 TestIntegratedTestKeywordParser.load_keyword_parser_lit_tests() 294 unittest.main(verbosity=2) 295