#!/usr/bin/env python3 # # Copyright (C) 2014 The Android Open Source Project # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. from common.archs import archs_list from file_format.checker.parser import parse_checker_stream from file_format.checker.struct import CheckerFile, TestCase, TestStatement, TestExpression import io import unittest CheckerException = SystemExit class CheckerParser_PrefixTest(unittest.TestCase): def try_parse(self, string): checker_text = "/// CHECK-START: pass\n" + string return parse_checker_stream("", "CHECK", io.StringIO(checker_text)) def assertParses(self, string): check_file = self.try_parse(string) self.assertEqual(len(check_file.test_cases), 1) self.assertNotEqual(len(check_file.test_cases[0].statements), 0) def assertIgnored(self, string): check_file = self.try_parse(string) self.assertEqual(len(check_file.test_cases), 1) self.assertEqual(len(check_file.test_cases[0].statements), 0) def assertInvalid(self, string): with self.assertRaises(CheckerException): self.try_parse(string) def test_ValidFormat(self): self.assertParses("///CHECK:foo") self.assertParses("##CHECK:bar") def test_InvalidFormat(self): self.assertIgnored("CHECK") self.assertIgnored(":CHECK") self.assertIgnored("CHECK:") self.assertIgnored("//CHECK") self.assertIgnored("#CHECK") self.assertInvalid("///CHECK") self.assertInvalid("##CHECK") def test_InvalidPrefix(self): self.assertInvalid("///ACHECK:foo") self.assertInvalid("##ACHECK:foo") def test_NotFirstOnTheLine(self): self.assertIgnored("A/// CHECK: foo") self.assertIgnored("A # CHECK: foo") self.assertInvalid("/// /// CHECK: foo") self.assertInvalid("## ## CHECK: foo") def test_WhitespaceAgnostic(self): self.assertParses(" ///CHECK: foo") self.assertParses("/// CHECK: foo") self.assertParses(" ///CHECK: foo") self.assertParses("/// CHECK: foo") class CheckerParser_TestExpressionTest(unittest.TestCase): def parse_statement(self, string, variant=""): checker_text = ("/// CHECK-START: pass\n" + "/// CHECK" + variant + ": " + string) checker_file = parse_checker_stream("", "CHECK", io.StringIO(checker_text)) self.assertEqual(len(checker_file.test_cases), 1) test_case = checker_file.test_cases[0] self.assertEqual(len(test_case.statements), 1) return test_case.statements[0] def parse_expression(self, string): line = self.parse_statement(string) self.assertEqual(1, len(line.expressions)) return line.expressions[0] def assertEqualsRegex(self, string, expected): self.assertEqual(expected, self.parse_statement(string).to_regex()) def assertEqualsText(self, string, text): self.assertEqual(self.parse_expression(string), TestExpression.create_pattern_from_plain_text(text)) def assertEqualsPattern(self, string, pattern): self.assertEqual(self.parse_expression(string), TestExpression.create_pattern(pattern)) def assertEqualsVarRef(self, string, name): self.assertEqual(self.parse_expression(string), TestExpression.create_variable_reference(name)) def assertEqualsVarDef(self, string, name, pattern): self.assertEqual(self.parse_expression(string), TestExpression.create_variable_definition(name, pattern)) def assertVariantNotEqual(self, string, variant): self.assertNotEqual(variant, self.parse_expression(string).variant) # Test that individual parts of the line are recognized def test_TextOnly(self): self.assertEqualsText("foo", "foo") self.assertEqualsText(" foo ", "foo") self.assertEqualsRegex("f$o^o", "(f\\$o\\^o)") def test_PatternOnly(self): self.assertEqualsPattern("{{a?b.c}}", "a?b.c") def test_VarRefOnly(self): self.assertEqualsVarRef("<>", "ABC") def test_VarDefOnly(self): self.assertEqualsVarDef("<>", "ABC", "a?b.c") def test_TextWithWhitespace(self): self.assertEqualsRegex("foo bar", "(foo), (bar)") self.assertEqualsRegex("foo bar", "(foo), (bar)") def test_TextWithRegex(self): self.assertEqualsRegex("foo{{abc}}bar", "(foo)(abc)(bar)") def test_TextWithVar(self): self.assertEqualsRegex("foo<>bar", "(foo)(abc)(bar)") def test_PlainWithRegexAndWhitespaces(self): self.assertEqualsRegex("foo {{abc}}bar", "(foo), (abc)(bar)") self.assertEqualsRegex("foo{{abc}} bar", "(foo)(abc), (bar)") self.assertEqualsRegex("foo {{abc}} bar", "(foo), (abc), (bar)") def test_PlainWithVarAndWhitespaces(self): self.assertEqualsRegex("foo <>bar", "(foo), (abc)(bar)") self.assertEqualsRegex("foo<> bar", "(foo)(abc), (bar)") self.assertEqualsRegex("foo <> bar", "(foo), (abc), (bar)") def test_AllKinds(self): self.assertEqualsRegex("foo <>{{def}}bar", "(foo), (abc)(def)(bar)") self.assertEqualsRegex("foo<> {{def}}bar", "(foo)(abc), (def)(bar)") self.assertEqualsRegex("foo <> {{def}} bar", "(foo), (abc), (def), (bar)") # # Test that variables and patterns are parsed correctly def test_ValidPattern(self): self.assertEqualsPattern("{{abc}}", "abc") self.assertEqualsPattern("{{a[b]c}}", "a[b]c") self.assertEqualsPattern("{{(a{bc})}}", "(a{bc})") def test_ValidRef(self): self.assertEqualsVarRef("<>", "ABC") self.assertEqualsVarRef("<>", "A1BC2") def test_ValidDef(self): self.assertEqualsVarDef("<>", "ABC", "abc") self.assertEqualsVarDef("<>", "ABC", "ab:c") self.assertEqualsVarDef("<>", "ABC", "a[b]c") self.assertEqualsVarDef("<>", "ABC", "(a[bc])") def test_Empty(self): self.assertEqualsText("{{}}", "{{}}") self.assertVariantNotEqual("<<>>", TestExpression.Variant.VAR_REF) self.assertVariantNotEqual("<<:>>", TestExpression.Variant.VAR_DEF) def test_InvalidVarName(self): self.assertVariantNotEqual("<<0ABC>>", TestExpression.Variant.VAR_REF) self.assertVariantNotEqual("<>", TestExpression.Variant.VAR_REF) self.assertVariantNotEqual("<>", TestExpression.Variant.VAR_REF) self.assertVariantNotEqual("<<0ABC:abc>>", TestExpression.Variant.VAR_DEF) self.assertVariantNotEqual("<>", TestExpression.Variant.VAR_DEF) self.assertVariantNotEqual("<>", TestExpression.Variant.VAR_DEF) def test_BodyMatchNotGreedy(self): self.assertEqualsRegex("{{abc}}{{def}}", "(abc)(def)") self.assertEqualsRegex("<><>", "(abc)(def)") def test_NoVarDefsInNotChecks(self): with self.assertRaises(CheckerException): self.parse_statement("<>", "-NOT") class CheckerParser_FileLayoutTest(unittest.TestCase): # Creates an instance of CheckerFile from provided info. # Data format: [ ( , [ ( , ), ... ] ), ... ] def create_file(self, case_list): test_file = CheckerFile("") for caseEntry in case_list: case_name = caseEntry[0] test_case = TestCase(test_file, case_name, 0) statement_list = caseEntry[1] for statementEntry in statement_list: content = statementEntry[0] variant = statementEntry[1] statement = TestStatement(test_case, variant, content, 0) if statement.is_eval_content_statement(): statement.add_expression(TestExpression.create_plain_text(content)) elif statement.is_pattern_match_content_statement(): statement.add_expression(TestExpression.create_pattern_from_plain_text(content)) return test_file def assertParsesTo(self, checker_text, expected_data): expected_file = self.create_file(expected_data) actual_file = self.parse(checker_text) return self.assertEqual(expected_file, actual_file) def parse(self, checker_text): return parse_checker_stream("", "CHECK", io.StringIO(checker_text)) def test_EmptyFile(self): self.assertParsesTo("", []) def test_SingleGroup(self): self.assertParsesTo( """ /// CHECK-START: Example Group /// CHECK: foo /// CHECK: bar """, [("Example Group", [("foo", TestStatement.Variant.IN_ORDER), ("bar", TestStatement.Variant.IN_ORDER)])]) def test_MultipleGroups(self): self.assertParsesTo( """ /// CHECK-START: Example Group1 /// CHECK: foo /// CHECK: bar /// CHECK-START: Example Group2 /// CHECK: abc /// CHECK: def """, [("Example Group1", [("foo", TestStatement.Variant.IN_ORDER), ("bar", TestStatement.Variant.IN_ORDER)]), ("Example Group2", [("abc", TestStatement.Variant.IN_ORDER), ("def", TestStatement.Variant.IN_ORDER)])]) def test_StatementVariants(self): self.assertParsesTo( """ /// CHECK-START: Example Group /// CHECK: foo1 /// CHECK: foo2 /// CHECK-NEXT: foo3 /// CHECK-NEXT: foo4 /// CHECK-NOT: bar /// CHECK-DAG: abc /// CHECK-DAG: def /// CHECK-EVAL: x > y /// CHECK-IF: x < y /// CHECK-ELIF: x == y /// CHECK-ELSE: /// CHECK-FI: """, [("Example Group", [("foo1", TestStatement.Variant.IN_ORDER), ("foo2", TestStatement.Variant.IN_ORDER), ("foo3", TestStatement.Variant.NEXT_LINE), ("foo4", TestStatement.Variant.NEXT_LINE), ("bar", TestStatement.Variant.NOT), ("abc", TestStatement.Variant.DAG), ("def", TestStatement.Variant.DAG), ("x > y", TestStatement.Variant.EVAL), ("x < y", TestStatement.Variant.IF), ("x == y", TestStatement.Variant.ELIF), (None, TestStatement.Variant.ELSE), (None, TestStatement.Variant.FI)])]) def test_NoContentStatements(self): with self.assertRaises(CheckerException): self.parse( """ /// CHECK-START: Example Group /// CHECK-ELSE: foo """) with self.assertRaises(CheckerException): self.parse( """ /// CHECK-START: Example Group /// CHECK-FI: foo """) class CheckerParser_SuffixTests(unittest.TestCase): NOARCH_BLOCK = """ /// CHECK-START: Group /// CHECK: foo /// CHECK-NEXT: bar /// CHECK-NOT: baz /// CHECK-DAG: yoyo /// CHECK-EVAL: x > y /// CHECK-IF: x < y /// CHECK-ELIF: x == y /// CHECK-ELSE: /// CHECK-FI: """ ARCH_BLOCK = """ /// CHECK-START-{test_arch}: Group /// CHECK: foo /// CHECK-NEXT: bar /// CHECK-NOT: baz /// CHECK-DAG: yoyo /// CHECK-EVAL: x > y /// CHECK-IF: x < y /// CHECK-ELIF: x == y /// CHECK-ELSE: /// CHECK-FI: """ def parse(self, checker_text): return parse_checker_stream("", "CHECK", io.StringIO(checker_text)) def test_NonArchTests(self): for arch in [None] + archs_list: checker_file = self.parse(self.NOARCH_BLOCK) self.assertEqual(len(checker_file.test_cases), 1) self.assertEqual(len(checker_file.test_cases[0].statements), 9) def test_IgnoreNonTargetArch(self): for target_arch in archs_list: for test_arch in [a for a in archs_list if a != target_arch]: checker_text = self.ARCH_BLOCK.format(test_arch=test_arch) checker_file = self.parse(checker_text) self.assertEqual(len(checker_file.test_cases), 1) self.assertEqual(len(checker_file.test_cases_for_arch(test_arch)), 1) self.assertEqual(len(checker_file.test_cases_for_arch(target_arch)), 0) def test_Arch(self): for arch in archs_list: checker_text = self.ARCH_BLOCK.format(test_arch=arch) checker_file = self.parse(checker_text) self.assertEqual(len(checker_file.test_cases), 1) self.assertEqual(len(checker_file.test_cases_for_arch(arch)), 1) self.assertEqual(len(checker_file.test_cases[0].statements), 9) def test_NoDebugAndArch(self): test_case = self.parse(""" /// CHECK-START: Group /// CHECK: foo """).test_cases[0] self.assertFalse(test_case.for_debuggable) self.assertEqual(test_case.test_arch, None) def test_SetDebugNoArch(self): test_case = self.parse(""" /// CHECK-START-DEBUGGABLE: Group /// CHECK: foo """).test_cases[0] self.assertTrue(test_case.for_debuggable) self.assertEqual(test_case.test_arch, None) def test_NoDebugSetArch(self): test_case = self.parse(""" /// CHECK-START-ARM: Group /// CHECK: foo """).test_cases[0] self.assertFalse(test_case.for_debuggable) self.assertEqual(test_case.test_arch, "ARM") def test_SetDebugAndArch(self): test_case = self.parse(""" /// CHECK-START-ARM-DEBUGGABLE: Group /// CHECK: foo """).test_cases[0] self.assertTrue(test_case.for_debuggable) self.assertEqual(test_case.test_arch, "ARM") class CheckerParser_EvalTests(unittest.TestCase): def parse_test_case(self, string): checker_text = "/// CHECK-START: pass\n" + string checker_file = parse_checker_stream("", "CHECK", io.StringIO(checker_text)) self.assertEqual(len(checker_file.test_cases), 1) return checker_file.test_cases[0] def parse_expressions(self, string): test_case = self.parse_test_case("/// CHECK-EVAL: " + string) self.assertEqual(len(test_case.statements), 1) statement = test_case.statements[0] self.assertEqual(statement.variant, TestStatement.Variant.EVAL) self.assertEqual(statement.original_text, string) return statement.expressions def assertParsesToPlainText(self, text): test_case = self.parse_test_case("/// CHECK-EVAL: " + text) self.assertEqual(len(test_case.statements), 1) statement = test_case.statements[0] self.assertEqual(statement.variant, TestStatement.Variant.EVAL) self.assertEqual(statement.original_text, text) self.assertEqual(len(statement.expressions), 1) expression = statement.expressions[0] self.assertEqual(expression.variant, TestExpression.Variant.PLAIN_TEXT) self.assertEqual(expression.text, text) def test_PlainText(self): self.assertParsesToPlainText("XYZ") self.assertParsesToPlainText("True") self.assertParsesToPlainText("{{abc}}") self.assertParsesToPlainText("<>") self.assertParsesToPlainText("<>") def test_VariableReference(self): self.assertEqual(self.parse_expressions("<>"), [TestExpression.create_variable_reference("ABC")]) self.assertEqual(self.parse_expressions("123<>"), [TestExpression.create_plain_text("123"), TestExpression.create_variable_reference("ABC")]) self.assertEqual(self.parse_expressions("123 <>"), [TestExpression.create_plain_text("123 "), TestExpression.create_variable_reference("ABC")]) self.assertEqual(self.parse_expressions("<>XYZ"), [TestExpression.create_variable_reference("ABC"), TestExpression.create_plain_text("XYZ")]) self.assertEqual(self.parse_expressions("<> XYZ"), [TestExpression.create_variable_reference("ABC"), TestExpression.create_plain_text(" XYZ")]) self.assertEqual(self.parse_expressions("123<>XYZ"), [TestExpression.create_plain_text("123"), TestExpression.create_variable_reference("ABC"), TestExpression.create_plain_text("XYZ")]) self.assertEqual(self.parse_expressions("123 <> XYZ"), [TestExpression.create_plain_text("123 "), TestExpression.create_variable_reference("ABC"), TestExpression.create_plain_text(" XYZ")])