1#!/usr/bin/env python3 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 17from common.archs import archs_list 18from file_format.checker.parser import parse_checker_stream 19from file_format.checker.struct import CheckerFile, TestCase, TestStatement, TestExpression 20 21import io 22import unittest 23 24CheckerException = SystemExit 25 26 27class CheckerParser_PrefixTest(unittest.TestCase): 28 29 def try_parse(self, string): 30 checker_text = "/// CHECK-START: pass\n" + string 31 return parse_checker_stream("<test-file>", "CHECK", io.StringIO(checker_text)) 32 33 def assertParses(self, string): 34 check_file = self.try_parse(string) 35 self.assertEqual(len(check_file.test_cases), 1) 36 self.assertNotEqual(len(check_file.test_cases[0].statements), 0) 37 38 def assertIgnored(self, string): 39 check_file = self.try_parse(string) 40 self.assertEqual(len(check_file.test_cases), 1) 41 self.assertEqual(len(check_file.test_cases[0].statements), 0) 42 43 def assertInvalid(self, string): 44 with self.assertRaises(CheckerException): 45 self.try_parse(string) 46 47 def test_ValidFormat(self): 48 self.assertParses("///CHECK:foo") 49 self.assertParses("##CHECK:bar") 50 51 def test_InvalidFormat(self): 52 self.assertIgnored("CHECK") 53 self.assertIgnored(":CHECK") 54 self.assertIgnored("CHECK:") 55 self.assertIgnored("//CHECK") 56 self.assertIgnored("#CHECK") 57 self.assertInvalid("///CHECK") 58 self.assertInvalid("##CHECK") 59 60 def test_InvalidPrefix(self): 61 self.assertInvalid("///ACHECK:foo") 62 self.assertInvalid("##ACHECK:foo") 63 64 def test_NotFirstOnTheLine(self): 65 self.assertIgnored("A/// CHECK: foo") 66 self.assertIgnored("A # CHECK: foo") 67 self.assertInvalid("/// /// CHECK: foo") 68 self.assertInvalid("## ## CHECK: foo") 69 70 def test_WhitespaceAgnostic(self): 71 self.assertParses(" ///CHECK: foo") 72 self.assertParses("/// CHECK: foo") 73 self.assertParses(" ///CHECK: foo") 74 self.assertParses("/// CHECK: foo") 75 76 77class CheckerParser_TestExpressionTest(unittest.TestCase): 78 def parse_statement(self, string, variant=""): 79 checker_text = ("/// CHECK-START: pass\n" + 80 "/// CHECK" + variant + ": " + string) 81 checker_file = parse_checker_stream("<test-file>", "CHECK", io.StringIO(checker_text)) 82 self.assertEqual(len(checker_file.test_cases), 1) 83 test_case = checker_file.test_cases[0] 84 self.assertEqual(len(test_case.statements), 1) 85 return test_case.statements[0] 86 87 def parse_expression(self, string): 88 line = self.parse_statement(string) 89 self.assertEqual(1, len(line.expressions)) 90 return line.expressions[0] 91 92 def assertEqualsRegex(self, string, expected): 93 self.assertEqual(expected, self.parse_statement(string).to_regex()) 94 95 def assertEqualsText(self, string, text): 96 self.assertEqual(self.parse_expression(string), 97 TestExpression.create_pattern_from_plain_text(text)) 98 99 def assertEqualsPattern(self, string, pattern): 100 self.assertEqual(self.parse_expression(string), TestExpression.create_pattern(pattern)) 101 102 def assertEqualsVarRef(self, string, name): 103 self.assertEqual(self.parse_expression(string), TestExpression.create_variable_reference(name)) 104 105 def assertEqualsVarDef(self, string, name, pattern): 106 self.assertEqual(self.parse_expression(string), 107 TestExpression.create_variable_definition(name, pattern)) 108 109 def assertVariantNotEqual(self, string, variant): 110 self.assertNotEqual(variant, self.parse_expression(string).variant) 111 112 # Test that individual parts of the line are recognized 113 114 def test_TextOnly(self): 115 self.assertEqualsText("foo", "foo") 116 self.assertEqualsText(" foo ", "foo") 117 self.assertEqualsRegex("f$o^o", "(f\\$o\\^o)") 118 119 def test_PatternOnly(self): 120 self.assertEqualsPattern("{{a?b.c}}", "a?b.c") 121 122 def test_VarRefOnly(self): 123 self.assertEqualsVarRef("<<ABC>>", "ABC") 124 125 def test_VarDefOnly(self): 126 self.assertEqualsVarDef("<<ABC:a?b.c>>", "ABC", "a?b.c") 127 128 def test_TextWithWhitespace(self): 129 self.assertEqualsRegex("foo bar", "(foo), (bar)") 130 self.assertEqualsRegex("foo bar", "(foo), (bar)") 131 132 def test_TextWithRegex(self): 133 self.assertEqualsRegex("foo{{abc}}bar", "(foo)(abc)(bar)") 134 135 def test_TextWithVar(self): 136 self.assertEqualsRegex("foo<<ABC:abc>>bar", "(foo)(abc)(bar)") 137 138 def test_PlainWithRegexAndWhitespaces(self): 139 self.assertEqualsRegex("foo {{abc}}bar", "(foo), (abc)(bar)") 140 self.assertEqualsRegex("foo{{abc}} bar", "(foo)(abc), (bar)") 141 self.assertEqualsRegex("foo {{abc}} bar", "(foo), (abc), (bar)") 142 143 def test_PlainWithVarAndWhitespaces(self): 144 self.assertEqualsRegex("foo <<ABC:abc>>bar", "(foo), (abc)(bar)") 145 self.assertEqualsRegex("foo<<ABC:abc>> bar", "(foo)(abc), (bar)") 146 self.assertEqualsRegex("foo <<ABC:abc>> bar", "(foo), (abc), (bar)") 147 148 def test_AllKinds(self): 149 self.assertEqualsRegex("foo <<ABC:abc>>{{def}}bar", "(foo), (abc)(def)(bar)") 150 self.assertEqualsRegex("foo<<ABC:abc>> {{def}}bar", "(foo)(abc), (def)(bar)") 151 self.assertEqualsRegex("foo <<ABC:abc>> {{def}} bar", "(foo), (abc), (def), (bar)") 152 153 # # Test that variables and patterns are parsed correctly 154 155 def test_ValidPattern(self): 156 self.assertEqualsPattern("{{abc}}", "abc") 157 self.assertEqualsPattern("{{a[b]c}}", "a[b]c") 158 self.assertEqualsPattern("{{(a{bc})}}", "(a{bc})") 159 160 def test_ValidRef(self): 161 self.assertEqualsVarRef("<<ABC>>", "ABC") 162 self.assertEqualsVarRef("<<A1BC2>>", "A1BC2") 163 164 def test_ValidDef(self): 165 self.assertEqualsVarDef("<<ABC:abc>>", "ABC", "abc") 166 self.assertEqualsVarDef("<<ABC:ab:c>>", "ABC", "ab:c") 167 self.assertEqualsVarDef("<<ABC:a[b]c>>", "ABC", "a[b]c") 168 self.assertEqualsVarDef("<<ABC:(a[bc])>>", "ABC", "(a[bc])") 169 170 def test_Empty(self): 171 self.assertEqualsText("{{}}", "{{}}") 172 self.assertVariantNotEqual("<<>>", TestExpression.Variant.VAR_REF) 173 self.assertVariantNotEqual("<<:>>", TestExpression.Variant.VAR_DEF) 174 175 def test_InvalidVarName(self): 176 self.assertVariantNotEqual("<<0ABC>>", TestExpression.Variant.VAR_REF) 177 self.assertVariantNotEqual("<<AB=C>>", TestExpression.Variant.VAR_REF) 178 self.assertVariantNotEqual("<<ABC=>>", TestExpression.Variant.VAR_REF) 179 self.assertVariantNotEqual("<<0ABC:abc>>", TestExpression.Variant.VAR_DEF) 180 self.assertVariantNotEqual("<<AB=C:abc>>", TestExpression.Variant.VAR_DEF) 181 self.assertVariantNotEqual("<<ABC=:abc>>", TestExpression.Variant.VAR_DEF) 182 183 def test_BodyMatchNotGreedy(self): 184 self.assertEqualsRegex("{{abc}}{{def}}", "(abc)(def)") 185 self.assertEqualsRegex("<<ABC:abc>><<DEF:def>>", "(abc)(def)") 186 187 def test_NoVarDefsInNotChecks(self): 188 with self.assertRaises(CheckerException): 189 self.parse_statement("<<ABC:abc>>", "-NOT") 190 191 192class CheckerParser_FileLayoutTest(unittest.TestCase): 193 194 # Creates an instance of CheckerFile from provided info. 195 # Data format: [ ( <case-name>, [ ( <text>, <assert-variant> ), ... ] ), ... ] 196 def create_file(self, case_list): 197 test_file = CheckerFile("<test_file>") 198 for caseEntry in case_list: 199 case_name = caseEntry[0] 200 test_case = TestCase(test_file, case_name, 0) 201 statement_list = caseEntry[1] 202 for statementEntry in statement_list: 203 content = statementEntry[0] 204 variant = statementEntry[1] 205 statement = TestStatement(test_case, variant, content, 0) 206 if statement.is_eval_content_statement(): 207 statement.add_expression(TestExpression.create_plain_text(content)) 208 elif statement.is_pattern_match_content_statement(): 209 statement.add_expression(TestExpression.create_pattern_from_plain_text(content)) 210 return test_file 211 212 def assertParsesTo(self, checker_text, expected_data): 213 expected_file = self.create_file(expected_data) 214 actual_file = self.parse(checker_text) 215 return self.assertEqual(expected_file, actual_file) 216 217 def parse(self, checker_text): 218 return parse_checker_stream("<test_file>", "CHECK", io.StringIO(checker_text)) 219 220 def test_EmptyFile(self): 221 self.assertParsesTo("", []) 222 223 def test_SingleGroup(self): 224 self.assertParsesTo( 225 """ 226 /// CHECK-START: Example Group 227 /// CHECK: foo 228 /// CHECK: bar 229 """, 230 [("Example Group", [("foo", TestStatement.Variant.IN_ORDER), 231 ("bar", TestStatement.Variant.IN_ORDER)])]) 232 233 def test_MultipleGroups(self): 234 self.assertParsesTo( 235 """ 236 /// CHECK-START: Example Group1 237 /// CHECK: foo 238 /// CHECK: bar 239 /// CHECK-START: Example Group2 240 /// CHECK: abc 241 /// CHECK: def 242 """, 243 [("Example Group1", [("foo", TestStatement.Variant.IN_ORDER), 244 ("bar", TestStatement.Variant.IN_ORDER)]), 245 ("Example Group2", [("abc", TestStatement.Variant.IN_ORDER), 246 ("def", TestStatement.Variant.IN_ORDER)])]) 247 248 def test_StatementVariants(self): 249 self.assertParsesTo( 250 """ 251 /// CHECK-START: Example Group 252 /// CHECK: foo1 253 /// CHECK: foo2 254 /// CHECK-NEXT: foo3 255 /// CHECK-NEXT: foo4 256 /// CHECK-NOT: bar 257 /// CHECK-DAG: abc 258 /// CHECK-DAG: def 259 /// CHECK-EVAL: x > y 260 /// CHECK-IF: x < y 261 /// CHECK-ELIF: x == y 262 /// CHECK-ELSE: 263 /// CHECK-FI: 264 """, 265 [("Example Group", [("foo1", TestStatement.Variant.IN_ORDER), 266 ("foo2", TestStatement.Variant.IN_ORDER), 267 ("foo3", TestStatement.Variant.NEXT_LINE), 268 ("foo4", TestStatement.Variant.NEXT_LINE), 269 ("bar", TestStatement.Variant.NOT), 270 ("abc", TestStatement.Variant.DAG), 271 ("def", TestStatement.Variant.DAG), 272 ("x > y", TestStatement.Variant.EVAL), 273 ("x < y", TestStatement.Variant.IF), 274 ("x == y", TestStatement.Variant.ELIF), 275 (None, TestStatement.Variant.ELSE), 276 (None, TestStatement.Variant.FI)])]) 277 278 def test_NoContentStatements(self): 279 with self.assertRaises(CheckerException): 280 self.parse( 281 """ 282 /// CHECK-START: Example Group 283 /// CHECK-ELSE: foo 284 """) 285 with self.assertRaises(CheckerException): 286 self.parse( 287 """ 288 /// CHECK-START: Example Group 289 /// CHECK-FI: foo 290 """) 291 292 293class CheckerParser_SuffixTests(unittest.TestCase): 294 NOARCH_BLOCK = """ 295 /// CHECK-START: Group 296 /// CHECK: foo 297 /// CHECK-NEXT: bar 298 /// CHECK-NOT: baz 299 /// CHECK-DAG: yoyo 300 /// CHECK-EVAL: x > y 301 /// CHECK-IF: x < y 302 /// CHECK-ELIF: x == y 303 /// CHECK-ELSE: 304 /// CHECK-FI: 305 """ 306 307 ARCH_BLOCK = """ 308 /// CHECK-START-{test_arch}: Group 309 /// CHECK: foo 310 /// CHECK-NEXT: bar 311 /// CHECK-NOT: baz 312 /// CHECK-DAG: yoyo 313 /// CHECK-EVAL: x > y 314 /// CHECK-IF: x < y 315 /// CHECK-ELIF: x == y 316 /// CHECK-ELSE: 317 /// CHECK-FI: 318 """ 319 320 def parse(self, checker_text): 321 return parse_checker_stream("<test_file>", "CHECK", io.StringIO(checker_text)) 322 323 def test_NonArchTests(self): 324 for arch in [None] + archs_list: 325 checker_file = self.parse(self.NOARCH_BLOCK) 326 self.assertEqual(len(checker_file.test_cases), 1) 327 self.assertEqual(len(checker_file.test_cases[0].statements), 9) 328 329 def test_IgnoreNonTargetArch(self): 330 for target_arch in archs_list: 331 for test_arch in [a for a in archs_list if a != target_arch]: 332 checker_text = self.ARCH_BLOCK.format(test_arch=test_arch) 333 checker_file = self.parse(checker_text) 334 self.assertEqual(len(checker_file.test_cases), 1) 335 self.assertEqual(len(checker_file.test_cases_for_arch(test_arch)), 1) 336 self.assertEqual(len(checker_file.test_cases_for_arch(target_arch)), 0) 337 338 def test_Arch(self): 339 for arch in archs_list: 340 checker_text = self.ARCH_BLOCK.format(test_arch=arch) 341 checker_file = self.parse(checker_text) 342 self.assertEqual(len(checker_file.test_cases), 1) 343 self.assertEqual(len(checker_file.test_cases_for_arch(arch)), 1) 344 self.assertEqual(len(checker_file.test_cases[0].statements), 9) 345 346 def test_NoDebugAndArch(self): 347 test_case = self.parse(""" 348 /// CHECK-START: Group 349 /// CHECK: foo 350 """).test_cases[0] 351 self.assertFalse(test_case.for_debuggable) 352 self.assertEqual(test_case.test_arch, None) 353 354 def test_SetDebugNoArch(self): 355 test_case = self.parse(""" 356 /// CHECK-START-DEBUGGABLE: Group 357 /// CHECK: foo 358 """).test_cases[0] 359 self.assertTrue(test_case.for_debuggable) 360 self.assertEqual(test_case.test_arch, None) 361 362 def test_NoDebugSetArch(self): 363 test_case = self.parse(""" 364 /// CHECK-START-ARM: Group 365 /// CHECK: foo 366 """).test_cases[0] 367 self.assertFalse(test_case.for_debuggable) 368 self.assertEqual(test_case.test_arch, "ARM") 369 370 def test_SetDebugAndArch(self): 371 test_case = self.parse(""" 372 /// CHECK-START-ARM-DEBUGGABLE: Group 373 /// CHECK: foo 374 """).test_cases[0] 375 self.assertTrue(test_case.for_debuggable) 376 self.assertEqual(test_case.test_arch, "ARM") 377 378 379class CheckerParser_EvalTests(unittest.TestCase): 380 def parse_test_case(self, string): 381 checker_text = "/// CHECK-START: pass\n" + string 382 checker_file = parse_checker_stream("<test-file>", "CHECK", io.StringIO(checker_text)) 383 self.assertEqual(len(checker_file.test_cases), 1) 384 return checker_file.test_cases[0] 385 386 def parse_expressions(self, string): 387 test_case = self.parse_test_case("/// CHECK-EVAL: " + string) 388 self.assertEqual(len(test_case.statements), 1) 389 statement = test_case.statements[0] 390 self.assertEqual(statement.variant, TestStatement.Variant.EVAL) 391 self.assertEqual(statement.original_text, string) 392 return statement.expressions 393 394 def assertParsesToPlainText(self, text): 395 test_case = self.parse_test_case("/// CHECK-EVAL: " + text) 396 self.assertEqual(len(test_case.statements), 1) 397 statement = test_case.statements[0] 398 self.assertEqual(statement.variant, TestStatement.Variant.EVAL) 399 self.assertEqual(statement.original_text, text) 400 self.assertEqual(len(statement.expressions), 1) 401 expression = statement.expressions[0] 402 self.assertEqual(expression.variant, TestExpression.Variant.PLAIN_TEXT) 403 self.assertEqual(expression.text, text) 404 405 def test_PlainText(self): 406 self.assertParsesToPlainText("XYZ") 407 self.assertParsesToPlainText("True") 408 self.assertParsesToPlainText("{{abc}}") 409 self.assertParsesToPlainText("<<ABC:abc>>") 410 self.assertParsesToPlainText("<<ABC=>>") 411 412 def test_VariableReference(self): 413 self.assertEqual(self.parse_expressions("<<ABC>>"), 414 [TestExpression.create_variable_reference("ABC")]) 415 self.assertEqual(self.parse_expressions("123<<ABC>>"), 416 [TestExpression.create_plain_text("123"), 417 TestExpression.create_variable_reference("ABC")]) 418 self.assertEqual(self.parse_expressions("123 <<ABC>>"), 419 [TestExpression.create_plain_text("123 "), 420 TestExpression.create_variable_reference("ABC")]) 421 self.assertEqual(self.parse_expressions("<<ABC>>XYZ"), 422 [TestExpression.create_variable_reference("ABC"), 423 TestExpression.create_plain_text("XYZ")]) 424 self.assertEqual(self.parse_expressions("<<ABC>> XYZ"), 425 [TestExpression.create_variable_reference("ABC"), 426 TestExpression.create_plain_text(" XYZ")]) 427 self.assertEqual(self.parse_expressions("123<<ABC>>XYZ"), 428 [TestExpression.create_plain_text("123"), 429 TestExpression.create_variable_reference("ABC"), 430 TestExpression.create_plain_text("XYZ")]) 431 self.assertEqual(self.parse_expressions("123 <<ABC>> XYZ"), 432 [TestExpression.create_plain_text("123 "), 433 TestExpression.create_variable_reference("ABC"), 434 TestExpression.create_plain_text(" XYZ")]) 435