struct.py revision 5e2c8d323fbab4db8a71041ff94b6baf3953bca9
12c27f2ccf316aebf96cf365d33d2834a8206444dDavid Brazdil# Copyright (C) 2014 The Android Open Source Project
22c27f2ccf316aebf96cf365d33d2834a8206444dDavid Brazdil#
32c27f2ccf316aebf96cf365d33d2834a8206444dDavid Brazdil# Licensed under the Apache License, Version 2.0 (the "License");
42c27f2ccf316aebf96cf365d33d2834a8206444dDavid Brazdil# you may not use this file except in compliance with the License.
52c27f2ccf316aebf96cf365d33d2834a8206444dDavid Brazdil# You may obtain a copy of the License at
62c27f2ccf316aebf96cf365d33d2834a8206444dDavid Brazdil#
72c27f2ccf316aebf96cf365d33d2834a8206444dDavid Brazdil#   http://www.apache.org/licenses/LICENSE-2.0
82c27f2ccf316aebf96cf365d33d2834a8206444dDavid Brazdil#
92c27f2ccf316aebf96cf365d33d2834a8206444dDavid Brazdil# Unless required by applicable law or agreed to in writing, software
102c27f2ccf316aebf96cf365d33d2834a8206444dDavid Brazdil# distributed under the License is distributed on an "AS IS" BASIS,
112c27f2ccf316aebf96cf365d33d2834a8206444dDavid Brazdil# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
122c27f2ccf316aebf96cf365d33d2834a8206444dDavid Brazdil# See the License for the specific language governing permissions and
132c27f2ccf316aebf96cf365d33d2834a8206444dDavid Brazdil# limitations under the License.
142c27f2ccf316aebf96cf365d33d2834a8206444dDavid Brazdil
152c27f2ccf316aebf96cf365d33d2834a8206444dDavid Brazdilfrom common.logger import Logger
162c27f2ccf316aebf96cf365d33d2834a8206444dDavid Brazdilfrom common.mixins import EqualityMixin, PrintableMixin
172c27f2ccf316aebf96cf365d33d2834a8206444dDavid Brazdil
182c27f2ccf316aebf96cf365d33d2834a8206444dDavid Brazdilimport re
192c27f2ccf316aebf96cf365d33d2834a8206444dDavid Brazdil
202c27f2ccf316aebf96cf365d33d2834a8206444dDavid Brazdilclass CheckerFile(PrintableMixin):
212c27f2ccf316aebf96cf365d33d2834a8206444dDavid Brazdil
222c27f2ccf316aebf96cf365d33d2834a8206444dDavid Brazdil  def __init__(self, fileName):
232c27f2ccf316aebf96cf365d33d2834a8206444dDavid Brazdil    self.fileName = fileName
242c27f2ccf316aebf96cf365d33d2834a8206444dDavid Brazdil    self.testCases = []
252c27f2ccf316aebf96cf365d33d2834a8206444dDavid Brazdil
262c27f2ccf316aebf96cf365d33d2834a8206444dDavid Brazdil  def addTestCase(self, new_test_case):
272c27f2ccf316aebf96cf365d33d2834a8206444dDavid Brazdil    self.testCases.append(new_test_case)
282c27f2ccf316aebf96cf365d33d2834a8206444dDavid Brazdil
295e2c8d323fbab4db8a71041ff94b6baf3953bca9Alexandre Rames  def testCasesForArch(self, targetArch):
305e2c8d323fbab4db8a71041ff94b6baf3953bca9Alexandre Rames    return [t for t in self.testCases if t.testArch == targetArch]
315e2c8d323fbab4db8a71041ff94b6baf3953bca9Alexandre Rames
322c27f2ccf316aebf96cf365d33d2834a8206444dDavid Brazdil  def __eq__(self, other):
332c27f2ccf316aebf96cf365d33d2834a8206444dDavid Brazdil    return isinstance(other, self.__class__) \
342c27f2ccf316aebf96cf365d33d2834a8206444dDavid Brazdil       and self.testCases == other.testCases
352c27f2ccf316aebf96cf365d33d2834a8206444dDavid Brazdil
362c27f2ccf316aebf96cf365d33d2834a8206444dDavid Brazdil
372c27f2ccf316aebf96cf365d33d2834a8206444dDavid Brazdilclass TestCase(PrintableMixin):
382c27f2ccf316aebf96cf365d33d2834a8206444dDavid Brazdil
395e2c8d323fbab4db8a71041ff94b6baf3953bca9Alexandre Rames  def __init__(self, parent, name, startLineNo, testArch = None):
402c27f2ccf316aebf96cf365d33d2834a8206444dDavid Brazdil    assert isinstance(parent, CheckerFile)
412c27f2ccf316aebf96cf365d33d2834a8206444dDavid Brazdil
422c27f2ccf316aebf96cf365d33d2834a8206444dDavid Brazdil    self.parent = parent
432c27f2ccf316aebf96cf365d33d2834a8206444dDavid Brazdil    self.name = name
442c27f2ccf316aebf96cf365d33d2834a8206444dDavid Brazdil    self.assertions = []
452c27f2ccf316aebf96cf365d33d2834a8206444dDavid Brazdil    self.startLineNo = startLineNo
465e2c8d323fbab4db8a71041ff94b6baf3953bca9Alexandre Rames    self.testArch = testArch
472c27f2ccf316aebf96cf365d33d2834a8206444dDavid Brazdil
482c27f2ccf316aebf96cf365d33d2834a8206444dDavid Brazdil    if not self.name:
49711411957a433555eda4bcf8d1f05aabf04425e8David Brazdil      Logger.fail("Test case does not have a name", self.fileName, self.startLineNo)
502c27f2ccf316aebf96cf365d33d2834a8206444dDavid Brazdil
512c27f2ccf316aebf96cf365d33d2834a8206444dDavid Brazdil    self.parent.addTestCase(self)
522c27f2ccf316aebf96cf365d33d2834a8206444dDavid Brazdil
532c27f2ccf316aebf96cf365d33d2834a8206444dDavid Brazdil  @property
542c27f2ccf316aebf96cf365d33d2834a8206444dDavid Brazdil  def fileName(self):
552c27f2ccf316aebf96cf365d33d2834a8206444dDavid Brazdil    return self.parent.fileName
562c27f2ccf316aebf96cf365d33d2834a8206444dDavid Brazdil
572c27f2ccf316aebf96cf365d33d2834a8206444dDavid Brazdil  def addAssertion(self, new_assertion):
58711411957a433555eda4bcf8d1f05aabf04425e8David Brazdil    if new_assertion.variant == TestAssertion.Variant.NextLine:
59711411957a433555eda4bcf8d1f05aabf04425e8David Brazdil      if not self.assertions or \
60711411957a433555eda4bcf8d1f05aabf04425e8David Brazdil         (self.assertions[-1].variant != TestAssertion.Variant.InOrder and \
61711411957a433555eda4bcf8d1f05aabf04425e8David Brazdil          self.assertions[-1].variant != TestAssertion.Variant.NextLine):
62711411957a433555eda4bcf8d1f05aabf04425e8David Brazdil        Logger.fail("A next-line assertion can only be placed after an "
63711411957a433555eda4bcf8d1f05aabf04425e8David Brazdil                    "in-order assertion or another next-line assertion.",
64711411957a433555eda4bcf8d1f05aabf04425e8David Brazdil                    new_assertion.fileName, new_assertion.lineNo)
652c27f2ccf316aebf96cf365d33d2834a8206444dDavid Brazdil    self.assertions.append(new_assertion)
662c27f2ccf316aebf96cf365d33d2834a8206444dDavid Brazdil
672c27f2ccf316aebf96cf365d33d2834a8206444dDavid Brazdil  def __eq__(self, other):
682c27f2ccf316aebf96cf365d33d2834a8206444dDavid Brazdil    return isinstance(other, self.__class__) \
692c27f2ccf316aebf96cf365d33d2834a8206444dDavid Brazdil       and self.name == other.name \
702c27f2ccf316aebf96cf365d33d2834a8206444dDavid Brazdil       and self.assertions == other.assertions
712c27f2ccf316aebf96cf365d33d2834a8206444dDavid Brazdil
722c27f2ccf316aebf96cf365d33d2834a8206444dDavid Brazdil
732c27f2ccf316aebf96cf365d33d2834a8206444dDavid Brazdilclass TestAssertion(PrintableMixin):
742c27f2ccf316aebf96cf365d33d2834a8206444dDavid Brazdil
752c27f2ccf316aebf96cf365d33d2834a8206444dDavid Brazdil  class Variant(object):
762c27f2ccf316aebf96cf365d33d2834a8206444dDavid Brazdil    """Supported types of assertions."""
77711411957a433555eda4bcf8d1f05aabf04425e8David Brazdil    InOrder, NextLine, DAG, Not = range(4)
782c27f2ccf316aebf96cf365d33d2834a8206444dDavid Brazdil
792c27f2ccf316aebf96cf365d33d2834a8206444dDavid Brazdil  def __init__(self, parent, variant, originalText, lineNo):
802c27f2ccf316aebf96cf365d33d2834a8206444dDavid Brazdil    assert isinstance(parent, TestCase)
812c27f2ccf316aebf96cf365d33d2834a8206444dDavid Brazdil
822c27f2ccf316aebf96cf365d33d2834a8206444dDavid Brazdil    self.parent = parent
832c27f2ccf316aebf96cf365d33d2834a8206444dDavid Brazdil    self.variant = variant
842c27f2ccf316aebf96cf365d33d2834a8206444dDavid Brazdil    self.expressions = []
852c27f2ccf316aebf96cf365d33d2834a8206444dDavid Brazdil    self.lineNo = lineNo
862c27f2ccf316aebf96cf365d33d2834a8206444dDavid Brazdil    self.originalText = originalText
872c27f2ccf316aebf96cf365d33d2834a8206444dDavid Brazdil
882c27f2ccf316aebf96cf365d33d2834a8206444dDavid Brazdil    self.parent.addAssertion(self)
892c27f2ccf316aebf96cf365d33d2834a8206444dDavid Brazdil
902c27f2ccf316aebf96cf365d33d2834a8206444dDavid Brazdil  @property
912c27f2ccf316aebf96cf365d33d2834a8206444dDavid Brazdil  def fileName(self):
922c27f2ccf316aebf96cf365d33d2834a8206444dDavid Brazdil    return self.parent.fileName
932c27f2ccf316aebf96cf365d33d2834a8206444dDavid Brazdil
942c27f2ccf316aebf96cf365d33d2834a8206444dDavid Brazdil  def addExpression(self, new_expression):
952c27f2ccf316aebf96cf365d33d2834a8206444dDavid Brazdil    assert isinstance(new_expression, RegexExpression)
962c27f2ccf316aebf96cf365d33d2834a8206444dDavid Brazdil    if self.variant == TestAssertion.Variant.Not:
972c27f2ccf316aebf96cf365d33d2834a8206444dDavid Brazdil      if new_expression.variant == RegexExpression.Variant.VarDef:
982c27f2ccf316aebf96cf365d33d2834a8206444dDavid Brazdil        Logger.fail("CHECK-NOT lines cannot define variables", self.fileName, self.lineNo)
992c27f2ccf316aebf96cf365d33d2834a8206444dDavid Brazdil    self.expressions.append(new_expression)
1002c27f2ccf316aebf96cf365d33d2834a8206444dDavid Brazdil
1012c27f2ccf316aebf96cf365d33d2834a8206444dDavid Brazdil  def toRegex(self):
1022c27f2ccf316aebf96cf365d33d2834a8206444dDavid Brazdil    """ Returns a regex pattern for this entire assertion. Only used in tests. """
1032c27f2ccf316aebf96cf365d33d2834a8206444dDavid Brazdil    regex = ""
1042c27f2ccf316aebf96cf365d33d2834a8206444dDavid Brazdil    for expression in self.expressions:
1052c27f2ccf316aebf96cf365d33d2834a8206444dDavid Brazdil      if expression.variant == RegexExpression.Variant.Separator:
1062c27f2ccf316aebf96cf365d33d2834a8206444dDavid Brazdil        regex = regex + ", "
1072c27f2ccf316aebf96cf365d33d2834a8206444dDavid Brazdil      else:
1082c27f2ccf316aebf96cf365d33d2834a8206444dDavid Brazdil        regex = regex + "(" + expression.pattern + ")"
1092c27f2ccf316aebf96cf365d33d2834a8206444dDavid Brazdil    return regex
1102c27f2ccf316aebf96cf365d33d2834a8206444dDavid Brazdil
1112c27f2ccf316aebf96cf365d33d2834a8206444dDavid Brazdil  def __eq__(self, other):
1122c27f2ccf316aebf96cf365d33d2834a8206444dDavid Brazdil    return isinstance(other, self.__class__) \
1132c27f2ccf316aebf96cf365d33d2834a8206444dDavid Brazdil       and self.variant == other.variant \
1142c27f2ccf316aebf96cf365d33d2834a8206444dDavid Brazdil       and self.expressions == other.expressions
1152c27f2ccf316aebf96cf365d33d2834a8206444dDavid Brazdil
1162c27f2ccf316aebf96cf365d33d2834a8206444dDavid Brazdil
1172c27f2ccf316aebf96cf365d33d2834a8206444dDavid Brazdilclass RegexExpression(EqualityMixin, PrintableMixin):
1182c27f2ccf316aebf96cf365d33d2834a8206444dDavid Brazdil
1192c27f2ccf316aebf96cf365d33d2834a8206444dDavid Brazdil  class Variant(object):
1202c27f2ccf316aebf96cf365d33d2834a8206444dDavid Brazdil    """Supported language constructs."""
1212c27f2ccf316aebf96cf365d33d2834a8206444dDavid Brazdil    Text, Pattern, VarRef, VarDef, Separator = range(5)
1222c27f2ccf316aebf96cf365d33d2834a8206444dDavid Brazdil
1232c27f2ccf316aebf96cf365d33d2834a8206444dDavid Brazdil  class Regex(object):
1242c27f2ccf316aebf96cf365d33d2834a8206444dDavid Brazdil    rName = r"([a-zA-Z][a-zA-Z0-9]*)"
1252c27f2ccf316aebf96cf365d33d2834a8206444dDavid Brazdil    rRegex = r"(.+?)"
1262c27f2ccf316aebf96cf365d33d2834a8206444dDavid Brazdil    rPatternStartSym = r"(\{\{)"
1272c27f2ccf316aebf96cf365d33d2834a8206444dDavid Brazdil    rPatternEndSym = r"(\}\})"
128c2c48ffdd623b4e58b34115d1521b0988a42b217David Brazdil    rVariableStartSym = r"(<<)"
129c2c48ffdd623b4e58b34115d1521b0988a42b217David Brazdil    rVariableEndSym = r"(>>)"
1302c27f2ccf316aebf96cf365d33d2834a8206444dDavid Brazdil    rVariableSeparator = r"(:)"
1312c27f2ccf316aebf96cf365d33d2834a8206444dDavid Brazdil
1322c27f2ccf316aebf96cf365d33d2834a8206444dDavid Brazdil    regexPattern = rPatternStartSym + rRegex + rPatternEndSym
1332c27f2ccf316aebf96cf365d33d2834a8206444dDavid Brazdil    regexVariableReference = rVariableStartSym + rName + rVariableEndSym
1342c27f2ccf316aebf96cf365d33d2834a8206444dDavid Brazdil    regexVariableDefinition = rVariableStartSym + rName + rVariableSeparator + rRegex + rVariableEndSym
1352c27f2ccf316aebf96cf365d33d2834a8206444dDavid Brazdil
1362c27f2ccf316aebf96cf365d33d2834a8206444dDavid Brazdil  def __init__(self, variant, name, pattern):
1372c27f2ccf316aebf96cf365d33d2834a8206444dDavid Brazdil    self.variant = variant
1382c27f2ccf316aebf96cf365d33d2834a8206444dDavid Brazdil    self.name = name
1392c27f2ccf316aebf96cf365d33d2834a8206444dDavid Brazdil    self.pattern = pattern
1402c27f2ccf316aebf96cf365d33d2834a8206444dDavid Brazdil
1412c27f2ccf316aebf96cf365d33d2834a8206444dDavid Brazdil  def __eq__(self, other):
1422c27f2ccf316aebf96cf365d33d2834a8206444dDavid Brazdil    return isinstance(other, self.__class__) \
1432c27f2ccf316aebf96cf365d33d2834a8206444dDavid Brazdil       and self.variant == other.variant \
1442c27f2ccf316aebf96cf365d33d2834a8206444dDavid Brazdil       and self.name == other.name \
1452c27f2ccf316aebf96cf365d33d2834a8206444dDavid Brazdil       and self.pattern == other.pattern
1462c27f2ccf316aebf96cf365d33d2834a8206444dDavid Brazdil
1472c27f2ccf316aebf96cf365d33d2834a8206444dDavid Brazdil  @staticmethod
1482c27f2ccf316aebf96cf365d33d2834a8206444dDavid Brazdil  def createSeparator():
1492c27f2ccf316aebf96cf365d33d2834a8206444dDavid Brazdil    return RegexExpression(RegexExpression.Variant.Separator, None, None)
1502c27f2ccf316aebf96cf365d33d2834a8206444dDavid Brazdil
1512c27f2ccf316aebf96cf365d33d2834a8206444dDavid Brazdil  @staticmethod
1522c27f2ccf316aebf96cf365d33d2834a8206444dDavid Brazdil  def createText(text):
1532c27f2ccf316aebf96cf365d33d2834a8206444dDavid Brazdil    return RegexExpression(RegexExpression.Variant.Text, None, re.escape(text))
1542c27f2ccf316aebf96cf365d33d2834a8206444dDavid Brazdil
1552c27f2ccf316aebf96cf365d33d2834a8206444dDavid Brazdil  @staticmethod
1562c27f2ccf316aebf96cf365d33d2834a8206444dDavid Brazdil  def createPattern(pattern):
1572c27f2ccf316aebf96cf365d33d2834a8206444dDavid Brazdil    return RegexExpression(RegexExpression.Variant.Pattern, None, pattern)
1582c27f2ccf316aebf96cf365d33d2834a8206444dDavid Brazdil
1592c27f2ccf316aebf96cf365d33d2834a8206444dDavid Brazdil  @staticmethod
1602c27f2ccf316aebf96cf365d33d2834a8206444dDavid Brazdil  def createVariableReference(name):
1612c27f2ccf316aebf96cf365d33d2834a8206444dDavid Brazdil    assert re.match(RegexExpression.Regex.rName, name)
1622c27f2ccf316aebf96cf365d33d2834a8206444dDavid Brazdil    return RegexExpression(RegexExpression.Variant.VarRef, name, None)
1632c27f2ccf316aebf96cf365d33d2834a8206444dDavid Brazdil
1642c27f2ccf316aebf96cf365d33d2834a8206444dDavid Brazdil  @staticmethod
1652c27f2ccf316aebf96cf365d33d2834a8206444dDavid Brazdil  def createVariableDefinition(name, pattern):
1662c27f2ccf316aebf96cf365d33d2834a8206444dDavid Brazdil    assert re.match(RegexExpression.Regex.rName, name)
1672c27f2ccf316aebf96cf365d33d2834a8206444dDavid Brazdil    return RegexExpression(RegexExpression.Variant.VarDef, name, pattern)
168