1#!/usr/bin/env python2 2# 3# Copyright (C) 2014 The Android Open Source Project 4# 5# Licensed under the Apache License, Version 2.0 (the "License"); 6# you may not use this file except in compliance with the License. 7# You may obtain a copy of the License at 8# 9# http://www.apache.org/licenses/LICENSE-2.0 10# 11# Unless required by applicable law or agreed to in writing, software 12# distributed under the License is distributed on an "AS IS" BASIS, 13# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14# See the License for the specific language governing permissions and 15# limitations under the License. 16 17# This is a test file which exercises all feautres supported by the domain- 18# specific markup language implemented by Checker. 19 20import checker 21import io 22import unittest 23 24# The parent type of exception expected to be thrown by Checker during tests. 25# It must be specific enough to not cover exceptions thrown due to actual flaws 26# in Checker. 27CheckerException = SystemExit 28 29 30class TestCheckFile_PrefixExtraction(unittest.TestCase): 31 def __tryParse(self, string): 32 checkFile = checker.CheckFile(None, []) 33 return checkFile._extractLine("CHECK", string) 34 35 def test_InvalidFormat(self): 36 self.assertIsNone(self.__tryParse("CHECK")) 37 self.assertIsNone(self.__tryParse(":CHECK")) 38 self.assertIsNone(self.__tryParse("CHECK:")) 39 self.assertIsNone(self.__tryParse("//CHECK")) 40 self.assertIsNone(self.__tryParse("#CHECK")) 41 42 self.assertIsNotNone(self.__tryParse("//CHECK:foo")) 43 self.assertIsNotNone(self.__tryParse("#CHECK:bar")) 44 45 def test_InvalidLabel(self): 46 self.assertIsNone(self.__tryParse("//ACHECK:foo")) 47 self.assertIsNone(self.__tryParse("#ACHECK:foo")) 48 49 def test_NotFirstOnTheLine(self): 50 self.assertIsNone(self.__tryParse("A// CHECK: foo")) 51 self.assertIsNone(self.__tryParse("A # CHECK: foo")) 52 self.assertIsNone(self.__tryParse("// // CHECK: foo")) 53 self.assertIsNone(self.__tryParse("# # CHECK: foo")) 54 55 def test_WhitespaceAgnostic(self): 56 self.assertIsNotNone(self.__tryParse(" //CHECK: foo")) 57 self.assertIsNotNone(self.__tryParse("// CHECK: foo")) 58 self.assertIsNotNone(self.__tryParse(" //CHECK: foo")) 59 self.assertIsNotNone(self.__tryParse("// CHECK: foo")) 60 61 62class TestCheckLine_Parse(unittest.TestCase): 63 def __getPartPattern(self, linePart): 64 if linePart.variant == checker.CheckElement.Variant.Separator: 65 return "\s+" 66 else: 67 return linePart.pattern 68 69 def __getRegex(self, checkLine): 70 return "".join(map(lambda x: "(" + self.__getPartPattern(x) + ")", checkLine.lineParts)) 71 72 def __tryParse(self, string): 73 return checker.CheckLine(string) 74 75 def __parsesTo(self, string, expected): 76 self.assertEqual(expected, self.__getRegex(self.__tryParse(string))) 77 78 def __tryParseNot(self, string): 79 return checker.CheckLine(string, checker.CheckLine.Variant.Not) 80 81 def __parsesPattern(self, string, pattern): 82 line = self.__tryParse(string) 83 self.assertEqual(1, len(line.lineParts)) 84 self.assertEqual(checker.CheckElement.Variant.Pattern, line.lineParts[0].variant) 85 self.assertEqual(pattern, line.lineParts[0].pattern) 86 87 def __parsesVarRef(self, string, name): 88 line = self.__tryParse(string) 89 self.assertEqual(1, len(line.lineParts)) 90 self.assertEqual(checker.CheckElement.Variant.VarRef, line.lineParts[0].variant) 91 self.assertEqual(name, line.lineParts[0].name) 92 93 def __parsesVarDef(self, string, name, body): 94 line = self.__tryParse(string) 95 self.assertEqual(1, len(line.lineParts)) 96 self.assertEqual(checker.CheckElement.Variant.VarDef, line.lineParts[0].variant) 97 self.assertEqual(name, line.lineParts[0].name) 98 self.assertEqual(body, line.lineParts[0].pattern) 99 100 def __doesNotParse(self, string, partType): 101 line = self.__tryParse(string) 102 self.assertEqual(1, len(line.lineParts)) 103 self.assertNotEqual(partType, line.lineParts[0].variant) 104 105 # Test that individual parts of the line are recognized 106 107 def test_TextOnly(self): 108 self.__parsesTo("foo", "(foo)") 109 self.__parsesTo(" foo ", "(foo)") 110 self.__parsesTo("f$o^o", "(f\$o\^o)") 111 112 def test_TextWithWhitespace(self): 113 self.__parsesTo("foo bar", "(foo)(\s+)(bar)") 114 self.__parsesTo("foo bar", "(foo)(\s+)(bar)") 115 116 def test_RegexOnly(self): 117 self.__parsesPattern("{{a?b.c}}", "a?b.c") 118 119 def test_VarRefOnly(self): 120 self.__parsesVarRef("[[ABC]]", "ABC") 121 122 def test_VarDefOnly(self): 123 self.__parsesVarDef("[[ABC:a?b.c]]", "ABC", "a?b.c") 124 125 def test_TextWithRegex(self): 126 self.__parsesTo("foo{{abc}}bar", "(foo)(abc)(bar)") 127 128 def test_TextWithVar(self): 129 self.__parsesTo("foo[[ABC:abc]]bar", "(foo)(abc)(bar)") 130 131 def test_PlainWithRegexAndWhitespaces(self): 132 self.__parsesTo("foo {{abc}}bar", "(foo)(\s+)(abc)(bar)") 133 self.__parsesTo("foo{{abc}} bar", "(foo)(abc)(\s+)(bar)") 134 self.__parsesTo("foo {{abc}} bar", "(foo)(\s+)(abc)(\s+)(bar)") 135 136 def test_PlainWithVarAndWhitespaces(self): 137 self.__parsesTo("foo [[ABC:abc]]bar", "(foo)(\s+)(abc)(bar)") 138 self.__parsesTo("foo[[ABC:abc]] bar", "(foo)(abc)(\s+)(bar)") 139 self.__parsesTo("foo [[ABC:abc]] bar", "(foo)(\s+)(abc)(\s+)(bar)") 140 141 def test_AllKinds(self): 142 self.__parsesTo("foo [[ABC:abc]]{{def}}bar", "(foo)(\s+)(abc)(def)(bar)") 143 self.__parsesTo("foo[[ABC:abc]] {{def}}bar", "(foo)(abc)(\s+)(def)(bar)") 144 self.__parsesTo("foo [[ABC:abc]] {{def}} bar", "(foo)(\s+)(abc)(\s+)(def)(\s+)(bar)") 145 146 # Test that variables and patterns are parsed correctly 147 148 def test_ValidPattern(self): 149 self.__parsesPattern("{{abc}}", "abc") 150 self.__parsesPattern("{{a[b]c}}", "a[b]c") 151 self.__parsesPattern("{{(a{bc})}}", "(a{bc})") 152 153 def test_ValidRef(self): 154 self.__parsesVarRef("[[ABC]]", "ABC") 155 self.__parsesVarRef("[[A1BC2]]", "A1BC2") 156 157 def test_ValidDef(self): 158 self.__parsesVarDef("[[ABC:abc]]", "ABC", "abc") 159 self.__parsesVarDef("[[ABC:ab:c]]", "ABC", "ab:c") 160 self.__parsesVarDef("[[ABC:a[b]c]]", "ABC", "a[b]c") 161 self.__parsesVarDef("[[ABC:(a[bc])]]", "ABC", "(a[bc])") 162 163 def test_Empty(self): 164 self.__doesNotParse("{{}}", checker.CheckElement.Variant.Pattern) 165 self.__doesNotParse("[[]]", checker.CheckElement.Variant.VarRef) 166 self.__doesNotParse("[[:]]", checker.CheckElement.Variant.VarDef) 167 168 def test_InvalidVarName(self): 169 self.__doesNotParse("[[0ABC]]", checker.CheckElement.Variant.VarRef) 170 self.__doesNotParse("[[AB=C]]", checker.CheckElement.Variant.VarRef) 171 self.__doesNotParse("[[ABC=]]", checker.CheckElement.Variant.VarRef) 172 self.__doesNotParse("[[0ABC:abc]]", checker.CheckElement.Variant.VarDef) 173 self.__doesNotParse("[[AB=C:abc]]", checker.CheckElement.Variant.VarDef) 174 self.__doesNotParse("[[ABC=:abc]]", checker.CheckElement.Variant.VarDef) 175 176 def test_BodyMatchNotGreedy(self): 177 self.__parsesTo("{{abc}}{{def}}", "(abc)(def)") 178 self.__parsesTo("[[ABC:abc]][[DEF:def]]", "(abc)(def)") 179 180 def test_NoVarDefsInNotChecks(self): 181 with self.assertRaises(CheckerException): 182 self.__tryParseNot("[[ABC:abc]]") 183 184class TestCheckLine_Match(unittest.TestCase): 185 def __matchSingle(self, checkString, outputString, varState={}): 186 checkLine = checker.CheckLine(checkString) 187 newVarState = checkLine.match(outputString, varState) 188 self.assertIsNotNone(newVarState) 189 return newVarState 190 191 def __notMatchSingle(self, checkString, outputString, varState={}): 192 checkLine = checker.CheckLine(checkString) 193 self.assertIsNone(checkLine.match(outputString, varState)) 194 195 def test_TextAndWhitespace(self): 196 self.__matchSingle("foo", "foo") 197 self.__matchSingle("foo", " foo ") 198 self.__matchSingle("foo", "foo bar") 199 self.__notMatchSingle("foo", "XfooX") 200 self.__notMatchSingle("foo", "zoo") 201 202 self.__matchSingle("foo bar", "foo bar") 203 self.__matchSingle("foo bar", "abc foo bar def") 204 self.__matchSingle("foo bar", "foo foo bar bar") 205 206 self.__matchSingle("foo bar", "foo X bar") 207 self.__notMatchSingle("foo bar", "foo Xbar") 208 209 def test_Pattern(self): 210 self.__matchSingle("foo{{A|B}}bar", "fooAbar") 211 self.__matchSingle("foo{{A|B}}bar", "fooBbar") 212 self.__notMatchSingle("foo{{A|B}}bar", "fooCbar") 213 214 def test_VariableReference(self): 215 self.__matchSingle("foo[[X]]bar", "foobar", {"X": ""}) 216 self.__matchSingle("foo[[X]]bar", "fooAbar", {"X": "A"}) 217 self.__matchSingle("foo[[X]]bar", "fooBbar", {"X": "B"}) 218 self.__notMatchSingle("foo[[X]]bar", "foobar", {"X": "A"}) 219 self.__notMatchSingle("foo[[X]]bar", "foo bar", {"X": "A"}) 220 with self.assertRaises(CheckerException): 221 self.__matchSingle("foo[[X]]bar", "foobar", {}) 222 223 def test_VariableDefinition(self): 224 self.__matchSingle("foo[[X:A|B]]bar", "fooAbar") 225 self.__matchSingle("foo[[X:A|B]]bar", "fooBbar") 226 self.__notMatchSingle("foo[[X:A|B]]bar", "fooCbar") 227 228 env = self.__matchSingle("foo[[X:A.*B]]bar", "fooABbar", {}) 229 self.assertEqual(env, {"X": "AB"}) 230 env = self.__matchSingle("foo[[X:A.*B]]bar", "fooAxxBbar", {}) 231 self.assertEqual(env, {"X": "AxxB"}) 232 233 self.__matchSingle("foo[[X:A|B]]bar[[X]]baz", "fooAbarAbaz") 234 self.__matchSingle("foo[[X:A|B]]bar[[X]]baz", "fooBbarBbaz") 235 self.__notMatchSingle("foo[[X:A|B]]bar[[X]]baz", "fooAbarBbaz") 236 237 def test_NoVariableRedefinition(self): 238 with self.assertRaises(CheckerException): 239 self.__matchSingle("[[X:...]][[X]][[X:...]][[X]]", "foofoobarbar") 240 241 def test_EnvNotChangedOnPartialMatch(self): 242 env = {"Y": "foo"} 243 self.__notMatchSingle("[[X:A]]bar", "Abaz", env) 244 self.assertFalse("X" in env.keys()) 245 246 def test_VariableContentEscaped(self): 247 self.__matchSingle("[[X:..]]foo[[X]]", ".*foo.*") 248 self.__notMatchSingle("[[X:..]]foo[[X]]", ".*fooAAAA") 249 250 251CheckVariant = checker.CheckLine.Variant 252 253def prepareSingleCheck(line): 254 if isinstance(line, str): 255 return checker.CheckLine(line) 256 else: 257 return checker.CheckLine(line[0], line[1]) 258 259def prepareChecks(lines): 260 if isinstance(lines, str): 261 lines = lines.splitlines() 262 return list(map(lambda line: prepareSingleCheck(line), lines)) 263 264 265class TestCheckGroup_Match(unittest.TestCase): 266 def __matchMulti(self, checkLines, outputString): 267 checkGroup = checker.CheckGroup("MyGroup", prepareChecks(checkLines)) 268 outputGroup = checker.OutputGroup("MyGroup", outputString.splitlines()) 269 return checkGroup.match(outputGroup) 270 271 def __notMatchMulti(self, checkString, outputString): 272 with self.assertRaises(CheckerException): 273 self.__matchMulti(checkString, outputString) 274 275 def test_TextAndPattern(self): 276 self.__matchMulti("""foo bar 277 abc {{def}}""", 278 """foo bar 279 abc def"""); 280 self.__matchMulti("""foo bar 281 abc {{de.}}""", 282 """======= 283 foo bar 284 ======= 285 abc de# 286 ======="""); 287 self.__notMatchMulti("""//XYZ: foo bar 288 //XYZ: abc {{def}}""", 289 """======= 290 foo bar 291 ======= 292 abc de# 293 ======="""); 294 295 def test_Variables(self): 296 self.__matchMulti("""foo[[X:.]]bar 297 abc[[X]]def""", 298 """foo bar 299 abc def"""); 300 self.__matchMulti("""foo[[X:([0-9]+)]]bar 301 abc[[X]]def 302 ### [[X]] ###""", 303 """foo1234bar 304 abc1234def 305 ### 1234 ###"""); 306 307 def test_Ordering(self): 308 self.__matchMulti([("foo", CheckVariant.InOrder), 309 ("bar", CheckVariant.InOrder)], 310 """foo 311 bar""") 312 self.__notMatchMulti([("foo", CheckVariant.InOrder), 313 ("bar", CheckVariant.InOrder)], 314 """bar 315 foo""") 316 self.__matchMulti([("abc", CheckVariant.DAG), 317 ("def", CheckVariant.DAG)], 318 """abc 319 def""") 320 self.__matchMulti([("abc", CheckVariant.DAG), 321 ("def", CheckVariant.DAG)], 322 """def 323 abc""") 324 self.__matchMulti([("foo", CheckVariant.InOrder), 325 ("abc", CheckVariant.DAG), 326 ("def", CheckVariant.DAG), 327 ("bar", CheckVariant.InOrder)], 328 """foo 329 def 330 abc 331 bar""") 332 self.__notMatchMulti([("foo", CheckVariant.InOrder), 333 ("abc", CheckVariant.DAG), 334 ("def", CheckVariant.DAG), 335 ("bar", CheckVariant.InOrder)], 336 """foo 337 abc 338 bar""") 339 self.__notMatchMulti([("foo", CheckVariant.InOrder), 340 ("abc", CheckVariant.DAG), 341 ("def", CheckVariant.DAG), 342 ("bar", CheckVariant.InOrder)], 343 """foo 344 def 345 bar""") 346 347 def test_NotAssertions(self): 348 self.__matchMulti([("foo", CheckVariant.Not)], 349 """abc 350 def""") 351 self.__notMatchMulti([("foo", CheckVariant.Not)], 352 """abc foo 353 def""") 354 self.__notMatchMulti([("foo", CheckVariant.Not), 355 ("bar", CheckVariant.Not)], 356 """abc 357 def bar""") 358 359 def test_LineOnlyMatchesOnce(self): 360 self.__matchMulti([("foo", CheckVariant.DAG), 361 ("foo", CheckVariant.DAG)], 362 """foo 363 foo""") 364 self.__notMatchMulti([("foo", CheckVariant.DAG), 365 ("foo", CheckVariant.DAG)], 366 """foo 367 bar""") 368 369class TestOutputFile_Parse(unittest.TestCase): 370 def __parsesTo(self, string, expected): 371 if isinstance(string, str): 372 string = unicode(string) 373 outputStream = io.StringIO(string) 374 return self.assertEqual(checker.OutputFile(outputStream).groups, expected) 375 376 def test_NoInput(self): 377 self.__parsesTo(None, []) 378 self.__parsesTo("", []) 379 380 def test_SingleGroup(self): 381 self.__parsesTo("""begin_compilation 382 method "MyMethod" 383 end_compilation 384 begin_cfg 385 name "pass1" 386 foo 387 bar 388 end_cfg""", 389 [ checker.OutputGroup("MyMethod pass1", [ "foo", "bar" ]) ]) 390 391 def test_MultipleGroups(self): 392 self.__parsesTo("""begin_compilation 393 name "xyz1" 394 method "MyMethod1" 395 date 1234 396 end_compilation 397 begin_cfg 398 name "pass1" 399 foo 400 bar 401 end_cfg 402 begin_cfg 403 name "pass2" 404 abc 405 def 406 end_cfg""", 407 [ checker.OutputGroup("MyMethod1 pass1", [ "foo", "bar" ]), 408 checker.OutputGroup("MyMethod1 pass2", [ "abc", "def" ]) ]) 409 410 self.__parsesTo("""begin_compilation 411 name "xyz1" 412 method "MyMethod1" 413 date 1234 414 end_compilation 415 begin_cfg 416 name "pass1" 417 foo 418 bar 419 end_cfg 420 begin_compilation 421 name "xyz2" 422 method "MyMethod2" 423 date 5678 424 end_compilation 425 begin_cfg 426 name "pass2" 427 abc 428 def 429 end_cfg""", 430 [ checker.OutputGroup("MyMethod1 pass1", [ "foo", "bar" ]), 431 checker.OutputGroup("MyMethod2 pass2", [ "abc", "def" ]) ]) 432 433class TestCheckFile_Parse(unittest.TestCase): 434 def __parsesTo(self, string, expected): 435 if isinstance(string, str): 436 string = unicode(string) 437 checkStream = io.StringIO(string) 438 return self.assertEqual(checker.CheckFile("CHECK", checkStream).groups, expected) 439 440 def test_NoInput(self): 441 self.__parsesTo(None, []) 442 self.__parsesTo("", []) 443 444 def test_SingleGroup(self): 445 self.__parsesTo("""// CHECK-START: Example Group 446 // CHECK: foo 447 // CHECK: bar""", 448 [ checker.CheckGroup("Example Group", prepareChecks([ "foo", "bar" ])) ]) 449 450 def test_MultipleGroups(self): 451 self.__parsesTo("""// CHECK-START: Example Group1 452 // CHECK: foo 453 // CHECK: bar 454 // CHECK-START: Example Group2 455 // CHECK: abc 456 // CHECK: def""", 457 [ checker.CheckGroup("Example Group1", prepareChecks([ "foo", "bar" ])), 458 checker.CheckGroup("Example Group2", prepareChecks([ "abc", "def" ])) ]) 459 460 def test_CheckVariants(self): 461 self.__parsesTo("""// CHECK-START: Example Group 462 // CHECK: foo 463 // CHECK-NOT: bar 464 // CHECK-DAG: abc 465 // CHECK-DAG: def""", 466 [ checker.CheckGroup("Example Group", 467 prepareChecks([ ("foo", CheckVariant.InOrder), 468 ("bar", CheckVariant.Not), 469 ("abc", CheckVariant.DAG), 470 ("def", CheckVariant.DAG) ])) ]) 471 472if __name__ == '__main__': 473 checker.Logger.Verbosity = checker.Logger.Level.NoOutput 474 unittest.main() 475