android13/art/tools/checker/file_format/checker/test.py

435 lines
17 KiB
Python

#!/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("<test-file>", "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("<test-file>", "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>>", "ABC")
def test_VarDefOnly(self):
self.assertEqualsVarDef("<<ABC:a?b.c>>", "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<<ABC:abc>>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 <<ABC:abc>>bar", "(foo), (abc)(bar)")
self.assertEqualsRegex("foo<<ABC:abc>> bar", "(foo)(abc), (bar)")
self.assertEqualsRegex("foo <<ABC:abc>> bar", "(foo), (abc), (bar)")
def test_AllKinds(self):
self.assertEqualsRegex("foo <<ABC:abc>>{{def}}bar", "(foo), (abc)(def)(bar)")
self.assertEqualsRegex("foo<<ABC:abc>> {{def}}bar", "(foo)(abc), (def)(bar)")
self.assertEqualsRegex("foo <<ABC:abc>> {{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>>", "ABC")
self.assertEqualsVarRef("<<A1BC2>>", "A1BC2")
def test_ValidDef(self):
self.assertEqualsVarDef("<<ABC:abc>>", "ABC", "abc")
self.assertEqualsVarDef("<<ABC:ab:c>>", "ABC", "ab:c")
self.assertEqualsVarDef("<<ABC:a[b]c>>", "ABC", "a[b]c")
self.assertEqualsVarDef("<<ABC:(a[bc])>>", "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("<<AB=C>>", TestExpression.Variant.VAR_REF)
self.assertVariantNotEqual("<<ABC=>>", TestExpression.Variant.VAR_REF)
self.assertVariantNotEqual("<<0ABC:abc>>", TestExpression.Variant.VAR_DEF)
self.assertVariantNotEqual("<<AB=C:abc>>", TestExpression.Variant.VAR_DEF)
self.assertVariantNotEqual("<<ABC=:abc>>", TestExpression.Variant.VAR_DEF)
def test_BodyMatchNotGreedy(self):
self.assertEqualsRegex("{{abc}}{{def}}", "(abc)(def)")
self.assertEqualsRegex("<<ABC:abc>><<DEF:def>>", "(abc)(def)")
def test_NoVarDefsInNotChecks(self):
with self.assertRaises(CheckerException):
self.parse_statement("<<ABC:abc>>", "-NOT")
class CheckerParser_FileLayoutTest(unittest.TestCase):
# Creates an instance of CheckerFile from provided info.
# Data format: [ ( <case-name>, [ ( <text>, <assert-variant> ), ... ] ), ... ]
def create_file(self, case_list):
test_file = CheckerFile("<test_file>")
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("<test_file>", "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("<test_file>", "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("<test-file>", "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("<<ABC:abc>>")
self.assertParsesToPlainText("<<ABC=>>")
def test_VariableReference(self):
self.assertEqual(self.parse_expressions("<<ABC>>"),
[TestExpression.create_variable_reference("ABC")])
self.assertEqual(self.parse_expressions("123<<ABC>>"),
[TestExpression.create_plain_text("123"),
TestExpression.create_variable_reference("ABC")])
self.assertEqual(self.parse_expressions("123 <<ABC>>"),
[TestExpression.create_plain_text("123 "),
TestExpression.create_variable_reference("ABC")])
self.assertEqual(self.parse_expressions("<<ABC>>XYZ"),
[TestExpression.create_variable_reference("ABC"),
TestExpression.create_plain_text("XYZ")])
self.assertEqual(self.parse_expressions("<<ABC>> XYZ"),
[TestExpression.create_variable_reference("ABC"),
TestExpression.create_plain_text(" XYZ")])
self.assertEqual(self.parse_expressions("123<<ABC>>XYZ"),
[TestExpression.create_plain_text("123"),
TestExpression.create_variable_reference("ABC"),
TestExpression.create_plain_text("XYZ")])
self.assertEqual(self.parse_expressions("123 <<ABC>> XYZ"),
[TestExpression.create_plain_text("123 "),
TestExpression.create_variable_reference("ABC"),
TestExpression.create_plain_text(" XYZ")])