struct.py revision c2c48ffdd623b4e58b34115d1521b0988a42b217
1# Copyright (C) 2014 The Android Open Source Project 2# 3# Licensed under the Apache License, Version 2.0 (the "License"); 4# you may not use this file except in compliance with the License. 5# You may obtain a copy of the License at 6# 7# http://www.apache.org/licenses/LICENSE-2.0 8# 9# Unless required by applicable law or agreed to in writing, software 10# distributed under the License is distributed on an "AS IS" BASIS, 11# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12# See the License for the specific language governing permissions and 13# limitations under the License. 14 15from common.logger import Logger 16from common.mixins import EqualityMixin, PrintableMixin 17 18import re 19 20class CheckerFile(PrintableMixin): 21 22 def __init__(self, fileName): 23 self.fileName = fileName 24 self.testCases = [] 25 26 def addTestCase(self, new_test_case): 27 self.testCases.append(new_test_case) 28 29 def __eq__(self, other): 30 return isinstance(other, self.__class__) \ 31 and self.testCases == other.testCases 32 33 34class TestCase(PrintableMixin): 35 36 def __init__(self, parent, name, startLineNo): 37 assert isinstance(parent, CheckerFile) 38 39 self.parent = parent 40 self.name = name 41 self.assertions = [] 42 self.startLineNo = startLineNo 43 44 if not self.name: 45 Logger.fail("Test case does not have a name", self.parent.fileName, self.startLineNo) 46 47 self.parent.addTestCase(self) 48 49 @property 50 def fileName(self): 51 return self.parent.fileName 52 53 def addAssertion(self, new_assertion): 54 self.assertions.append(new_assertion) 55 56 def __eq__(self, other): 57 return isinstance(other, self.__class__) \ 58 and self.name == other.name \ 59 and self.assertions == other.assertions 60 61 62class TestAssertion(PrintableMixin): 63 64 class Variant(object): 65 """Supported types of assertions.""" 66 InOrder, DAG, Not = range(3) 67 68 def __init__(self, parent, variant, originalText, lineNo): 69 assert isinstance(parent, TestCase) 70 71 self.parent = parent 72 self.variant = variant 73 self.expressions = [] 74 self.lineNo = lineNo 75 self.originalText = originalText 76 77 self.parent.addAssertion(self) 78 79 @property 80 def fileName(self): 81 return self.parent.fileName 82 83 def addExpression(self, new_expression): 84 assert isinstance(new_expression, RegexExpression) 85 if self.variant == TestAssertion.Variant.Not: 86 if new_expression.variant == RegexExpression.Variant.VarDef: 87 Logger.fail("CHECK-NOT lines cannot define variables", self.fileName, self.lineNo) 88 self.expressions.append(new_expression) 89 90 def toRegex(self): 91 """ Returns a regex pattern for this entire assertion. Only used in tests. """ 92 regex = "" 93 for expression in self.expressions: 94 if expression.variant == RegexExpression.Variant.Separator: 95 regex = regex + ", " 96 else: 97 regex = regex + "(" + expression.pattern + ")" 98 return regex 99 100 def __eq__(self, other): 101 return isinstance(other, self.__class__) \ 102 and self.variant == other.variant \ 103 and self.expressions == other.expressions 104 105 106class RegexExpression(EqualityMixin, PrintableMixin): 107 108 class Variant(object): 109 """Supported language constructs.""" 110 Text, Pattern, VarRef, VarDef, Separator = range(5) 111 112 class Regex(object): 113 rName = r"([a-zA-Z][a-zA-Z0-9]*)" 114 rRegex = r"(.+?)" 115 rPatternStartSym = r"(\{\{)" 116 rPatternEndSym = r"(\}\})" 117 rVariableStartSym = r"(<<)" 118 rVariableEndSym = r"(>>)" 119 rVariableSeparator = r"(:)" 120 121 regexPattern = rPatternStartSym + rRegex + rPatternEndSym 122 regexVariableReference = rVariableStartSym + rName + rVariableEndSym 123 regexVariableDefinition = rVariableStartSym + rName + rVariableSeparator + rRegex + rVariableEndSym 124 125 def __init__(self, variant, name, pattern): 126 self.variant = variant 127 self.name = name 128 self.pattern = pattern 129 130 def __eq__(self, other): 131 return isinstance(other, self.__class__) \ 132 and self.variant == other.variant \ 133 and self.name == other.name \ 134 and self.pattern == other.pattern 135 136 @staticmethod 137 def createSeparator(): 138 return RegexExpression(RegexExpression.Variant.Separator, None, None) 139 140 @staticmethod 141 def createText(text): 142 return RegexExpression(RegexExpression.Variant.Text, None, re.escape(text)) 143 144 @staticmethod 145 def createPattern(pattern): 146 return RegexExpression(RegexExpression.Variant.Pattern, None, pattern) 147 148 @staticmethod 149 def createVariableReference(name): 150 assert re.match(RegexExpression.Regex.rName, name) 151 return RegexExpression(RegexExpression.Variant.VarRef, name, None) 152 153 @staticmethod 154 def createVariableDefinition(name, pattern): 155 assert re.match(RegexExpression.Regex.rName, name) 156 return RegexExpression(RegexExpression.Variant.VarDef, name, pattern) 157