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
395cc343d7239f9b1faf3ddf592cd5172a1371d276David Brazdil  def __init__(self, parent, name, startLineNo, testArch = None, forDebuggable = False):
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
475cc343d7239f9b1faf3ddf592cd5172a1371d276David Brazdil    self.forDebuggable = forDebuggable
482c27f2ccf316aebf96cf365d33d2834a8206444dDavid Brazdil
492c27f2ccf316aebf96cf365d33d2834a8206444dDavid Brazdil    if not self.name:
50711411957a433555eda4bcf8d1f05aabf04425e8David Brazdil      Logger.fail("Test case does not have a name", self.fileName, self.startLineNo)
512c27f2ccf316aebf96cf365d33d2834a8206444dDavid Brazdil
522c27f2ccf316aebf96cf365d33d2834a8206444dDavid Brazdil    self.parent.addTestCase(self)
532c27f2ccf316aebf96cf365d33d2834a8206444dDavid Brazdil
542c27f2ccf316aebf96cf365d33d2834a8206444dDavid Brazdil  @property
552c27f2ccf316aebf96cf365d33d2834a8206444dDavid Brazdil  def fileName(self):
562c27f2ccf316aebf96cf365d33d2834a8206444dDavid Brazdil    return self.parent.fileName
572c27f2ccf316aebf96cf365d33d2834a8206444dDavid Brazdil
582c27f2ccf316aebf96cf365d33d2834a8206444dDavid Brazdil  def addAssertion(self, new_assertion):
59711411957a433555eda4bcf8d1f05aabf04425e8David Brazdil    if new_assertion.variant == TestAssertion.Variant.NextLine:
60711411957a433555eda4bcf8d1f05aabf04425e8David Brazdil      if not self.assertions or \
61711411957a433555eda4bcf8d1f05aabf04425e8David Brazdil         (self.assertions[-1].variant != TestAssertion.Variant.InOrder and \
62711411957a433555eda4bcf8d1f05aabf04425e8David Brazdil          self.assertions[-1].variant != TestAssertion.Variant.NextLine):
63711411957a433555eda4bcf8d1f05aabf04425e8David Brazdil        Logger.fail("A next-line assertion can only be placed after an "
64711411957a433555eda4bcf8d1f05aabf04425e8David Brazdil                    "in-order assertion or another next-line assertion.",
65711411957a433555eda4bcf8d1f05aabf04425e8David Brazdil                    new_assertion.fileName, new_assertion.lineNo)
662c27f2ccf316aebf96cf365d33d2834a8206444dDavid Brazdil    self.assertions.append(new_assertion)
672c27f2ccf316aebf96cf365d33d2834a8206444dDavid Brazdil
682c27f2ccf316aebf96cf365d33d2834a8206444dDavid Brazdil  def __eq__(self, other):
692c27f2ccf316aebf96cf365d33d2834a8206444dDavid Brazdil    return isinstance(other, self.__class__) \
702c27f2ccf316aebf96cf365d33d2834a8206444dDavid Brazdil       and self.name == other.name \
712c27f2ccf316aebf96cf365d33d2834a8206444dDavid Brazdil       and self.assertions == other.assertions
722c27f2ccf316aebf96cf365d33d2834a8206444dDavid Brazdil
732c27f2ccf316aebf96cf365d33d2834a8206444dDavid Brazdil
742c27f2ccf316aebf96cf365d33d2834a8206444dDavid Brazdilclass TestAssertion(PrintableMixin):
752c27f2ccf316aebf96cf365d33d2834a8206444dDavid Brazdil
762c27f2ccf316aebf96cf365d33d2834a8206444dDavid Brazdil  class Variant(object):
772c27f2ccf316aebf96cf365d33d2834a8206444dDavid Brazdil    """Supported types of assertions."""
78b34c35ee8fe1516118d1d172a5e05b263ccbd93dDavid Brazdil    InOrder, NextLine, DAG, Not, Eval = range(5)
792c27f2ccf316aebf96cf365d33d2834a8206444dDavid Brazdil
802c27f2ccf316aebf96cf365d33d2834a8206444dDavid Brazdil  def __init__(self, parent, variant, originalText, lineNo):
812c27f2ccf316aebf96cf365d33d2834a8206444dDavid Brazdil    assert isinstance(parent, TestCase)
822c27f2ccf316aebf96cf365d33d2834a8206444dDavid Brazdil
832c27f2ccf316aebf96cf365d33d2834a8206444dDavid Brazdil    self.parent = parent
842c27f2ccf316aebf96cf365d33d2834a8206444dDavid Brazdil    self.variant = variant
852c27f2ccf316aebf96cf365d33d2834a8206444dDavid Brazdil    self.expressions = []
862c27f2ccf316aebf96cf365d33d2834a8206444dDavid Brazdil    self.lineNo = lineNo
872c27f2ccf316aebf96cf365d33d2834a8206444dDavid Brazdil    self.originalText = originalText
882c27f2ccf316aebf96cf365d33d2834a8206444dDavid Brazdil
892c27f2ccf316aebf96cf365d33d2834a8206444dDavid Brazdil    self.parent.addAssertion(self)
902c27f2ccf316aebf96cf365d33d2834a8206444dDavid Brazdil
912c27f2ccf316aebf96cf365d33d2834a8206444dDavid Brazdil  @property
922c27f2ccf316aebf96cf365d33d2834a8206444dDavid Brazdil  def fileName(self):
932c27f2ccf316aebf96cf365d33d2834a8206444dDavid Brazdil    return self.parent.fileName
942c27f2ccf316aebf96cf365d33d2834a8206444dDavid Brazdil
952c27f2ccf316aebf96cf365d33d2834a8206444dDavid Brazdil  def addExpression(self, new_expression):
96b34c35ee8fe1516118d1d172a5e05b263ccbd93dDavid Brazdil    assert isinstance(new_expression, TestExpression)
972c27f2ccf316aebf96cf365d33d2834a8206444dDavid Brazdil    if self.variant == TestAssertion.Variant.Not:
98b34c35ee8fe1516118d1d172a5e05b263ccbd93dDavid Brazdil      if new_expression.variant == TestExpression.Variant.VarDef:
992c27f2ccf316aebf96cf365d33d2834a8206444dDavid Brazdil        Logger.fail("CHECK-NOT lines cannot define variables", self.fileName, self.lineNo)
1002c27f2ccf316aebf96cf365d33d2834a8206444dDavid Brazdil    self.expressions.append(new_expression)
1012c27f2ccf316aebf96cf365d33d2834a8206444dDavid Brazdil
1022c27f2ccf316aebf96cf365d33d2834a8206444dDavid Brazdil  def toRegex(self):
1032c27f2ccf316aebf96cf365d33d2834a8206444dDavid Brazdil    """ Returns a regex pattern for this entire assertion. Only used in tests. """
1042c27f2ccf316aebf96cf365d33d2834a8206444dDavid Brazdil    regex = ""
1052c27f2ccf316aebf96cf365d33d2834a8206444dDavid Brazdil    for expression in self.expressions:
106b34c35ee8fe1516118d1d172a5e05b263ccbd93dDavid Brazdil      if expression.variant == TestExpression.Variant.Separator:
1072c27f2ccf316aebf96cf365d33d2834a8206444dDavid Brazdil        regex = regex + ", "
1082c27f2ccf316aebf96cf365d33d2834a8206444dDavid Brazdil      else:
109b34c35ee8fe1516118d1d172a5e05b263ccbd93dDavid Brazdil        regex = regex + "(" + expression.text + ")"
1102c27f2ccf316aebf96cf365d33d2834a8206444dDavid Brazdil    return regex
1112c27f2ccf316aebf96cf365d33d2834a8206444dDavid Brazdil
1122c27f2ccf316aebf96cf365d33d2834a8206444dDavid Brazdil  def __eq__(self, other):
1132c27f2ccf316aebf96cf365d33d2834a8206444dDavid Brazdil    return isinstance(other, self.__class__) \
1142c27f2ccf316aebf96cf365d33d2834a8206444dDavid Brazdil       and self.variant == other.variant \
1152c27f2ccf316aebf96cf365d33d2834a8206444dDavid Brazdil       and self.expressions == other.expressions
1162c27f2ccf316aebf96cf365d33d2834a8206444dDavid Brazdil
1172c27f2ccf316aebf96cf365d33d2834a8206444dDavid Brazdil
118b34c35ee8fe1516118d1d172a5e05b263ccbd93dDavid Brazdilclass TestExpression(EqualityMixin, PrintableMixin):
1192c27f2ccf316aebf96cf365d33d2834a8206444dDavid Brazdil
1202c27f2ccf316aebf96cf365d33d2834a8206444dDavid Brazdil  class Variant(object):
1212c27f2ccf316aebf96cf365d33d2834a8206444dDavid Brazdil    """Supported language constructs."""
122b34c35ee8fe1516118d1d172a5e05b263ccbd93dDavid Brazdil    PlainText, Pattern, VarRef, VarDef, Separator = range(5)
1232c27f2ccf316aebf96cf365d33d2834a8206444dDavid Brazdil
1242c27f2ccf316aebf96cf365d33d2834a8206444dDavid Brazdil  class Regex(object):
1252c27f2ccf316aebf96cf365d33d2834a8206444dDavid Brazdil    rName = r"([a-zA-Z][a-zA-Z0-9]*)"
1262c27f2ccf316aebf96cf365d33d2834a8206444dDavid Brazdil    rRegex = r"(.+?)"
1272c27f2ccf316aebf96cf365d33d2834a8206444dDavid Brazdil    rPatternStartSym = r"(\{\{)"
1282c27f2ccf316aebf96cf365d33d2834a8206444dDavid Brazdil    rPatternEndSym = r"(\}\})"
129c2c48ffdd623b4e58b34115d1521b0988a42b217David Brazdil    rVariableStartSym = r"(<<)"
130c2c48ffdd623b4e58b34115d1521b0988a42b217David Brazdil    rVariableEndSym = r"(>>)"
1312c27f2ccf316aebf96cf365d33d2834a8206444dDavid Brazdil    rVariableSeparator = r"(:)"
1328ff495e15074d621371b4e9d46ba399563315819David Brazdil    rVariableDefinitionBody = rName + rVariableSeparator + rRegex
1332c27f2ccf316aebf96cf365d33d2834a8206444dDavid Brazdil
1342c27f2ccf316aebf96cf365d33d2834a8206444dDavid Brazdil    regexPattern = rPatternStartSym + rRegex + rPatternEndSym
1352c27f2ccf316aebf96cf365d33d2834a8206444dDavid Brazdil    regexVariableReference = rVariableStartSym + rName + rVariableEndSym
1368ff495e15074d621371b4e9d46ba399563315819David Brazdil    regexVariableDefinition = rVariableStartSym + rVariableDefinitionBody + rVariableEndSym
1372c27f2ccf316aebf96cf365d33d2834a8206444dDavid Brazdil
138b34c35ee8fe1516118d1d172a5e05b263ccbd93dDavid Brazdil  def __init__(self, variant, name, text):
1392c27f2ccf316aebf96cf365d33d2834a8206444dDavid Brazdil    self.variant = variant
1402c27f2ccf316aebf96cf365d33d2834a8206444dDavid Brazdil    self.name = name
141b34c35ee8fe1516118d1d172a5e05b263ccbd93dDavid Brazdil    self.text = text
1422c27f2ccf316aebf96cf365d33d2834a8206444dDavid Brazdil
1432c27f2ccf316aebf96cf365d33d2834a8206444dDavid Brazdil  def __eq__(self, other):
1442c27f2ccf316aebf96cf365d33d2834a8206444dDavid Brazdil    return isinstance(other, self.__class__) \
1452c27f2ccf316aebf96cf365d33d2834a8206444dDavid Brazdil       and self.variant == other.variant \
1462c27f2ccf316aebf96cf365d33d2834a8206444dDavid Brazdil       and self.name == other.name \
147b34c35ee8fe1516118d1d172a5e05b263ccbd93dDavid Brazdil       and self.text == other.text
1482c27f2ccf316aebf96cf365d33d2834a8206444dDavid Brazdil
1492c27f2ccf316aebf96cf365d33d2834a8206444dDavid Brazdil  @staticmethod
1502c27f2ccf316aebf96cf365d33d2834a8206444dDavid Brazdil  def createSeparator():
151b34c35ee8fe1516118d1d172a5e05b263ccbd93dDavid Brazdil    return TestExpression(TestExpression.Variant.Separator, None, None)
1522c27f2ccf316aebf96cf365d33d2834a8206444dDavid Brazdil
1532c27f2ccf316aebf96cf365d33d2834a8206444dDavid Brazdil  @staticmethod
154b34c35ee8fe1516118d1d172a5e05b263ccbd93dDavid Brazdil  def createPlainText(text):
155b34c35ee8fe1516118d1d172a5e05b263ccbd93dDavid Brazdil    return TestExpression(TestExpression.Variant.PlainText, None, text)
156b34c35ee8fe1516118d1d172a5e05b263ccbd93dDavid Brazdil
157b34c35ee8fe1516118d1d172a5e05b263ccbd93dDavid Brazdil  @staticmethod
158b34c35ee8fe1516118d1d172a5e05b263ccbd93dDavid Brazdil  def createPatternFromPlainText(text):
159b34c35ee8fe1516118d1d172a5e05b263ccbd93dDavid Brazdil    return TestExpression(TestExpression.Variant.Pattern, None, re.escape(text))
1602c27f2ccf316aebf96cf365d33d2834a8206444dDavid Brazdil
1612c27f2ccf316aebf96cf365d33d2834a8206444dDavid Brazdil  @staticmethod
1622c27f2ccf316aebf96cf365d33d2834a8206444dDavid Brazdil  def createPattern(pattern):
163b34c35ee8fe1516118d1d172a5e05b263ccbd93dDavid Brazdil    return TestExpression(TestExpression.Variant.Pattern, None, pattern)
1642c27f2ccf316aebf96cf365d33d2834a8206444dDavid Brazdil
1652c27f2ccf316aebf96cf365d33d2834a8206444dDavid Brazdil  @staticmethod
1662c27f2ccf316aebf96cf365d33d2834a8206444dDavid Brazdil  def createVariableReference(name):
167b34c35ee8fe1516118d1d172a5e05b263ccbd93dDavid Brazdil    assert re.match(TestExpression.Regex.rName, name)
168b34c35ee8fe1516118d1d172a5e05b263ccbd93dDavid Brazdil    return TestExpression(TestExpression.Variant.VarRef, name, None)
1692c27f2ccf316aebf96cf365d33d2834a8206444dDavid Brazdil
1702c27f2ccf316aebf96cf365d33d2834a8206444dDavid Brazdil  @staticmethod
1712c27f2ccf316aebf96cf365d33d2834a8206444dDavid Brazdil  def createVariableDefinition(name, pattern):
172b34c35ee8fe1516118d1d172a5e05b263ccbd93dDavid Brazdil    assert re.match(TestExpression.Regex.rName, name)
173b34c35ee8fe1516118d1d172a5e05b263ccbd93dDavid Brazdil    return TestExpression(TestExpression.Variant.VarDef, name, pattern)
174