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