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