diff options
author | 2020-10-15 00:46:06 +0000 | |
---|---|---|
committer | 2020-10-22 17:22:18 +0000 | |
commit | 4a128a1d33758b5c7b7179dd6779ae120453a94c (patch) | |
tree | 07e8c8c823b7f6dc7a49fb0408984612b50d0d46 | |
parent | 463d03e93071be1efe6c5b65dbf7cbbe1b793eee (diff) |
Reformat Checker according to recent Google styleguide
Test: art/tools/checker/run_unit_tests.py
Test: Run any Checker test with atest or mts
Change-Id: I0452429fa43356d93ca748879bad14ef23609f40
-rwxr-xr-x | tools/checker/checker.py | 75 | ||||
-rw-r--r-- | tools/checker/common/archs.py | 2 | ||||
-rw-r--r-- | tools/checker/common/immutables.py | 9 | ||||
-rw-r--r-- | tools/checker/common/logger.py | 73 | ||||
-rw-r--r-- | tools/checker/common/mixins.py | 6 | ||||
-rw-r--r-- | tools/checker/file_format/c1visualizer/parser.py | 111 | ||||
-rw-r--r-- | tools/checker/file_format/c1visualizer/struct.py | 49 | ||||
-rw-r--r-- | tools/checker/file_format/c1visualizer/test.py | 57 | ||||
-rw-r--r-- | tools/checker/file_format/checker/parser.py | 239 | ||||
-rw-r--r-- | tools/checker/file_format/checker/struct.py | 173 | ||||
-rw-r--r-- | tools/checker/file_format/checker/test.py | 311 | ||||
-rw-r--r-- | tools/checker/file_format/common.py | 31 | ||||
-rw-r--r-- | tools/checker/match/file.py | 316 | ||||
-rw-r--r-- | tools/checker/match/line.py | 103 | ||||
-rw-r--r-- | tools/checker/match/test.py | 1298 | ||||
-rwxr-xr-x | tools/checker/run_unit_tests.py | 18 |
16 files changed, 1452 insertions, 1419 deletions
diff --git a/tools/checker/checker.py b/tools/checker/checker.py index 78bd58567f..1e0314199a 100755 --- a/tools/checker/checker.py +++ b/tools/checker/checker.py @@ -17,13 +17,14 @@ import argparse import os -from common.archs import archs_list -from common.logger import Logger -from file_format.c1visualizer.parser import ParseC1visualizerStream -from file_format.checker.parser import ParseCheckerStream -from match.file import MatchFiles +from common.archs import archs_list +from common.logger import Logger +from file_format.c1visualizer.parser import parse_c1_visualizer_stream +from file_format.checker.parser import parse_checker_stream +from match.file import match_files -def ParseArguments(): + +def parse_arguments(): parser = argparse.ArgumentParser() parser.add_argument("tested_file", help="text file the checks should be verified against") @@ -48,27 +49,27 @@ def ParseArguments(): return parser.parse_args() -def ListPasses(outputFilename): - c1File = ParseC1visualizerStream(outputFilename, open(outputFilename, "r")) - for compiler_pass in c1File.passes: +def list_passes(output_filename): + c1_file = parse_c1_visualizer_stream(output_filename, open(output_filename, "r")) + for compiler_pass in c1_file.passes: Logger.log(compiler_pass.name) -def DumpPass(outputFilename, passName): - c1File = ParseC1visualizerStream(outputFilename, open(outputFilename, "r")) - compiler_pass = c1File.findPass(passName) +def dump_pass(output_filename, pass_name): + c1_file = parse_c1_visualizer_stream(output_filename, open(output_filename, "r")) + compiler_pass = c1_file.find_pass(pass_name) if compiler_pass: - maxLineNo = compiler_pass.startLineNo + len(compiler_pass.body) - lenLineNo = len(str(maxLineNo)) + 2 - curLineNo = compiler_pass.startLineNo + max_line_no = compiler_pass.start_line_no + len(compiler_pass.body) + len_line_no = len(str(max_line_no)) + 2 + cur_line_no = compiler_pass.start_line_no for line in compiler_pass.body: - Logger.log((str(curLineNo) + ":").ljust(lenLineNo) + line) - curLineNo += 1 + Logger.log((str(cur_line_no) + ":").ljust(len_line_no) + line) + cur_line_no += 1 else: - Logger.fail("Pass \"" + passName + "\" not found in the output") + Logger.fail('Pass "{}" not found in the output'.format(pass_name)) -def FindCheckerFiles(path): +def find_checker_files(path): """ Returns a list of files to scan for check annotations in the given path. Path to a file is returned as a single-element list, directories are recursively traversed and all '.java' and '.smali' files returned. @@ -76,39 +77,39 @@ def FindCheckerFiles(path): if not path: Logger.fail("No source path provided") elif os.path.isfile(path): - return [ path ] + return [path] elif os.path.isdir(path): - foundFiles = [] + found_files = [] for root, dirs, files in os.walk(path): for file in files: extension = os.path.splitext(file)[1] if extension in [".java", ".smali"]: - foundFiles.append(os.path.join(root, file)) - return foundFiles + found_files.append(os.path.join(root, file)) + return found_files else: - Logger.fail("Source path \"" + path + "\" not found") + Logger.fail('Source path "{}" not found'.format(path)) -def RunTests(checkPrefix, checkPath, outputFilename, targetArch, debuggableMode, printCfg): - c1File = ParseC1visualizerStream(outputFilename, open(outputFilename, "r")) - for checkFilename in FindCheckerFiles(checkPath): - checkerFile = ParseCheckerStream(os.path.basename(checkFilename), - checkPrefix, - open(checkFilename, "r"), - targetArch) - MatchFiles(checkerFile, c1File, targetArch, debuggableMode, printCfg) +def run_tests(check_prefix, check_path, output_filename, target_arch, debuggable_mode, print_cfg): + c1_file = parse_c1_visualizer_stream(output_filename, open(output_filename, "r")) + for check_filename in find_checker_files(check_path): + checker_file = parse_checker_stream(os.path.basename(check_filename), + check_prefix, + open(check_filename, "r"), + target_arch) + match_files(checker_file, c1_file, target_arch, debuggable_mode, print_cfg) if __name__ == "__main__": - args = ParseArguments() + args = parse_arguments() if args.quiet: Logger.Verbosity = Logger.Level.ERROR if args.list_passes: - ListPasses(args.tested_file) + list_passes(args.tested_file) elif args.dump_pass: - DumpPass(args.tested_file, args.dump_pass) + dump_pass(args.tested_file, args.dump_pass) else: - RunTests(args.check_prefix, args.source_path, args.tested_file, args.arch, args.debuggable, - args.print_cfg) + run_tests(args.check_prefix, args.source_path, args.tested_file, args.arch, args.debuggable, + args.print_cfg) diff --git a/tools/checker/common/archs.py b/tools/checker/common/archs.py index 9628c888aa..6781fbfda2 100644 --- a/tools/checker/common/archs.py +++ b/tools/checker/common/archs.py @@ -12,4 +12,4 @@ # See the License for the specific language governing permissions and # limitations under the License. -archs_list = ['ARM', 'ARM64', 'X86', 'X86_64'] +archs_list = ["ARM", "ARM64", "X86", "X86_64"] diff --git a/tools/checker/common/immutables.py b/tools/checker/common/immutables.py index e016867c23..3a29ce3c0d 100644 --- a/tools/checker/common/immutables.py +++ b/tools/checker/common/immutables.py @@ -12,6 +12,7 @@ # See the License for the specific language governing permissions and # limitations under the License. + class ImmutableDict(dict): def __setitem__(self, key, value): raise RuntimeError("Cannot modify ImmutableDict") @@ -19,7 +20,7 @@ class ImmutableDict(dict): def __delitem__(self, key): raise RuntimeError("Cannot modify ImmutableDict") - def copyWith(self, key, value): - newDict = ImmutableDict(self) - dict.__setitem__(newDict, key, value) - return newDict + def copy_with(self, key, value): + new_dict = ImmutableDict(self) + dict.__setitem__(new_dict, key, value) + return new_dict diff --git a/tools/checker/common/logger.py b/tools/checker/common/logger.py index 67bb67413d..1a65c7315b 100644 --- a/tools/checker/common/logger.py +++ b/tools/checker/common/logger.py @@ -18,56 +18,49 @@ import sys class Logger: - class Level(enum.IntEnum): - NO_OUTPUT = 0 - ERROR = 1 - INFO = 2 + NO_OUTPUT, ERROR, INFO = range(3) class Color(enum.Enum): - DEFAULT = 0 - BLUE = 1 - GRAY = 2 - PURPLE = 3 - RED = 4 - GREEN = 5 + DEFAULT, BLUE, GRAY, PURPLE, RED, GREEN = range(6) @staticmethod - def terminalCode(color, out=sys.stdout): + def terminal_code(color, out=sys.stdout): if not out.isatty(): - return '' + return "" elif color == Logger.Color.BLUE: - return '\033[94m' + return "\033[94m" elif color == Logger.Color.GRAY: - return '\033[37m' + return "\033[37m" elif color == Logger.Color.PURPLE: - return '\033[95m' + return "\033[95m" elif color == Logger.Color.RED: - return '\033[91m' + return "\033[91m" elif color == Logger.Color.GREEN: - return '\033[32m' + return "\033[32m" else: - return '\033[0m' + return "\033[0m" Verbosity = Level.INFO @staticmethod - def log(content, level=Level.INFO, color=Color.DEFAULT, newLine=True, out=sys.stdout): + def log(content, level=Level.INFO, color=Color.DEFAULT, new_line=True, out=sys.stdout): if level <= Logger.Verbosity: - content = Logger.Color.terminalCode(color, out) + str(content) + \ - Logger.Color.terminalCode(Logger.Color.DEFAULT, out) - if newLine: + content = "{}{}{}".format(Logger.Color.terminal_code(color, out), content, + Logger.Color.terminal_code(Logger.Color.DEFAULT, out)) + if new_line: print(content, file=out) else: print(content, end="", file=out) out.flush() @staticmethod - def fail(msg, file=None, line=-1, lineText=None, variables=None): - Logger.log("error: ", Logger.Level.ERROR, color=Logger.Color.RED, newLine=False, out=sys.stderr) + def fail(msg, file=None, line=-1, line_text=None, variables=None): + Logger.log("error: ", Logger.Level.ERROR, color=Logger.Color.RED, new_line=False, + out=sys.stderr) Logger.log(msg, Logger.Level.ERROR, out=sys.stderr) - if lineText: + if line_text: loc = "" if file: loc += file + ":" @@ -75,33 +68,33 @@ class Logger: loc += str(line) + ":" if loc: loc += " " - Logger.log(loc, Logger.Level.ERROR, color=Logger.Color.GRAY, newLine=False, out=sys.stderr) - Logger.log(lineText, Logger.Level.ERROR, out=sys.stderr) + Logger.log(loc, Logger.Level.ERROR, color=Logger.Color.GRAY, new_line=False, + out=sys.stderr) + Logger.log(line_text, Logger.Level.ERROR, out=sys.stderr) if variables: - longestName = 0 - for var in variables: - longestName = max(longestName, len(var)) + longest_name = max(len(var) for var in variables) for var in collections.OrderedDict(sorted(variables.items())): - padding = ' ' * (longestName - len(var)) - Logger.log(var, Logger.Level.ERROR, color=Logger.Color.GREEN, newLine=False, out=sys.stderr) - Logger.log(padding, Logger.Level.ERROR, newLine=False, out=sys.stderr) - Logger.log(" = ", Logger.Level.ERROR, newLine=False, out=sys.stderr) + padding = " " * (longest_name - len(var)) + Logger.log(var, Logger.Level.ERROR, color=Logger.Color.GREEN, new_line=False, + out=sys.stderr) + Logger.log(padding, Logger.Level.ERROR, new_line=False, out=sys.stderr) + Logger.log(" = ", Logger.Level.ERROR, new_line=False, out=sys.stderr) Logger.log(variables[var], Logger.Level.ERROR, out=sys.stderr) sys.exit(1) @staticmethod - def startTest(name): - Logger.log("TEST ", color=Logger.Color.PURPLE, newLine=False) - Logger.log(name + "... ", newLine=False) + def start_test(name): + Logger.log("TEST ", color=Logger.Color.PURPLE, new_line=False) + Logger.log(name + "... ", new_line=False) @staticmethod - def testPassed(): + def test_passed(): Logger.log("PASS", color=Logger.Color.BLUE) @staticmethod - def testFailed(msg, statement, variables): + def test_failed(msg, statement, variables): Logger.log("FAIL", color=Logger.Color.RED) - Logger.fail(msg, statement.fileName, statement.lineNo, statement.originalText, variables) + Logger.fail(msg, statement.filename, statement.line_no, statement.original_text, variables) diff --git a/tools/checker/common/mixins.py b/tools/checker/common/mixins.py index e44c84d531..81bd2a8d83 100644 --- a/tools/checker/common/mixins.py +++ b/tools/checker/common/mixins.py @@ -16,11 +16,11 @@ class EqualityMixin: """ Object equality via equality of dictionaries. """ def __eq__(self, other): - return isinstance(other, self.__class__) \ - and self.__dict__ == other.__dict__ + return isinstance(other, self.__class__) and self.__dict__ == other.__dict__ + class PrintableMixin: """ Prints object as name-dictionary pair. """ def __repr__(self): - return '<{}: {}>'.format(type(self).__name__, str(self.__dict__)) + return "<{}: {}>".format(type(self).__name__, str(self.__dict__)) diff --git a/tools/checker/file_format/c1visualizer/parser.py b/tools/checker/file_format/c1visualizer/parser.py index e8a6ac8978..55efbd74ea 100644 --- a/tools/checker/file_format/c1visualizer/parser.py +++ b/tools/checker/file_format/c1visualizer/parser.py @@ -12,20 +12,22 @@ # See the License for the specific language governing permissions and # limitations under the License. -from common.logger import Logger -from file_format.common import SplitStream +from common.logger import Logger +from file_format.common import split_stream from file_format.c1visualizer.struct import C1visualizerFile, C1visualizerPass import re + class C1ParserState: - OutsideBlock, InsideCompilationBlock, StartingCfgBlock, InsideCfgBlock = range(4) + OUTSIDE_BLOCK, INSIDE_COMPILATION_BLOCK, STARTING_CFG_BLOCK, INSIDE_CFG_BLOCK = range(4) def __init__(self): - self.currentState = C1ParserState.OutsideBlock - self.lastMethodName = None + self.current_state = C1ParserState.OUTSIDE_BLOCK + self.last_method_name = None + -def __parseC1Line(c1File, line, lineNo, state, fileName): +def _parse_c1_line(c1_file, line, line_no, state, filename): """ This function is invoked on each line of the output file and returns a triplet which instructs the parser how the line should be handled. If the line is to be included in the current group, it is returned in the first @@ -34,79 +36,80 @@ def __parseC1Line(c1File, line, lineNo, state, fileName): function prototype compatible with `SplitStream` and is always set to `None` here. """ - if state.currentState == C1ParserState.StartingCfgBlock: + if state.current_state == C1ParserState.STARTING_CFG_BLOCK: # Previous line started a new 'cfg' block which means that this one must # contain the name of the pass (this is enforced by C1visualizer). - if re.match(r"name\s+\"[^\"]+\"", line): + if re.match(r'name\s+"[^"]+"', line): # Extract the pass name, prepend it with the name of the method and # return as the beginning of a new group. - state.currentState = C1ParserState.InsideCfgBlock - return (None, state.lastMethodName + " " + line.split("\"")[1], None) + state.current_state = C1ParserState.INSIDE_CFG_BLOCK + return None, state.last_method_name + " " + line.split('"')[1], None else: - Logger.fail("Expected output group name", fileName, lineNo) + Logger.fail("Expected output group name", filename, line_no) - elif state.currentState == C1ParserState.InsideCfgBlock: + elif state.current_state == C1ParserState.INSIDE_CFG_BLOCK: if line == "end_cfg": - state.currentState = C1ParserState.OutsideBlock - return (None, None, None) + state.current_state = C1ParserState.OUTSIDE_BLOCK + return None, None, None else: - return (line, None, None) + return line, None, None - elif state.currentState == C1ParserState.InsideCompilationBlock: + elif state.current_state == C1ParserState.INSIDE_COMPILATION_BLOCK: # Search for the method's name. Format: method "<name>" - if re.match(r"method\s+\"[^\"]*\"", line): - methodName = line.split("\"")[1].strip() - if not methodName: - Logger.fail("Empty method name in output", fileName, lineNo) - - m = re.search(r"isa_features:([\w,-]+)", methodName) - if (m): - rawFeatures = m.group(1).split(",") - # Create a map of features in the form {featureName: isEnabled}. + if re.match(r'method\s+"[^"]*"', line): + method_name = line.split('"')[1].strip() + if not method_name: + Logger.fail("Empty method name in output", filename, line_no) + + match = re.search(r"isa_features:([\w,-]+)", method_name) + if match: + raw_features = match.group(1).split(",") + # Create a map of features in the form {feature_name: is_enabled}. features = {} - for rf in rawFeatures: - featureName = rf - isEnabled = True + for rf in raw_features: + feature_name = rf + is_enabled = True # A '-' in front of the feature name indicates that the feature wasn't enabled at compile # time. - if rf[0] == '-': - featureName = rf[1:] - isEnabled = False - features[featureName] = isEnabled + if rf[0] == "-": + feature_name = rf[1:] + is_enabled = False + features[feature_name] = is_enabled - c1File.setISAFeatures(features) + c1_file.set_isa_features(features) else: - state.lastMethodName = methodName + state.last_method_name = method_name elif line == "end_compilation": - state.currentState = C1ParserState.OutsideBlock - return (None, None, None) + state.current_state = C1ParserState.OUTSIDE_BLOCK + return None, None, None else: - assert state.currentState == C1ParserState.OutsideBlock + assert state.current_state == C1ParserState.OUTSIDE_BLOCK if line == "begin_cfg": # The line starts a new group but we'll wait until the next line from # which we can extract the name of the pass. - if state.lastMethodName is None: - Logger.fail("Expected method header", fileName, lineNo) - state.currentState = C1ParserState.StartingCfgBlock - return (None, None, None) + if state.last_method_name is None: + Logger.fail("Expected method header", filename, line_no) + state.current_state = C1ParserState.STARTING_CFG_BLOCK + return None, None, None elif line == "begin_compilation": - state.currentState = C1ParserState.InsideCompilationBlock - return (None, None, None) + state.current_state = C1ParserState.INSIDE_COMPILATION_BLOCK + return None, None, None else: - Logger.fail("C1visualizer line not inside a group", fileName, lineNo) + Logger.fail("C1visualizer line not inside a group", filename, line_no) -def ParseC1visualizerStream(fileName, stream): - c1File = C1visualizerFile(fileName) +def parse_c1_visualizer_stream(filename, stream): + c1_file = C1visualizerFile(filename) state = C1ParserState() - def fnProcessLine(line, lineNo): - return __parseC1Line(c1File, line, lineNo, state, c1File.baseFileName) + def fn_process_line(line, line_no): + return _parse_c1_line(c1_file, line, line_no, state, c1_file.base_file_name) + + def fn_line_outside_chunk(line, line_no): + Logger.fail("C1visualizer line not inside a group", c1_file.base_file_name, line_no) - def fnLineOutsideChunk(line, lineNo): - Logger.fail("C1visualizer line not inside a group", c1File.baseFileName, lineNo) - for passName, passLines, startLineNo, testArch in \ - SplitStream(stream, fnProcessLine, fnLineOutsideChunk): - C1visualizerPass(c1File, passName, passLines, startLineNo + 1) - return c1File + for pass_name, pass_lines, start_line_no, test_arch in split_stream(stream, fn_process_line, + fn_line_outside_chunk): + C1visualizerPass(c1_file, pass_name, pass_lines, start_line_no + 1) + return c1_file diff --git a/tools/checker/file_format/c1visualizer/struct.py b/tools/checker/file_format/c1visualizer/struct.py index 5925da96c5..9428a0e5f6 100644 --- a/tools/checker/file_format/c1visualizer/struct.py +++ b/tools/checker/file_format/c1visualizer/struct.py @@ -15,55 +15,54 @@ import os from common.immutables import ImmutableDict -from common.logger import Logger -from common.mixins import PrintableMixin +from common.logger import Logger +from common.mixins import PrintableMixin -class C1visualizerFile(PrintableMixin): - def __init__(self, fileName): - self.baseFileName = os.path.basename(fileName) - self.fullFileName = fileName +class C1visualizerFile(PrintableMixin): + def __init__(self, filename): + self.base_file_name = os.path.basename(filename) + self.full_file_name = filename self.passes = [] - self.instructionSetFeatures = ImmutableDict() + self.instruction_set_features = ImmutableDict() - def setISAFeatures(self, features): - self.instructionSetFeatures = ImmutableDict(features) + def set_isa_features(self, features): + self.instruction_set_features = ImmutableDict(features) - def addPass(self, new_pass): + def add_pass(self, new_pass): self.passes.append(new_pass) - def findPass(self, name): + def find_pass(self, name): for entry in self.passes: if entry.name == name: return entry return None def __eq__(self, other): - return isinstance(other, self.__class__) \ - and self.passes == other.passes \ - and self.instructionSetFeatures == other.instructionSetFeatures + return (isinstance(other, self.__class__) + and self.passes == other.passes + and self.instruction_set_features == other.instruction_set_features) class C1visualizerPass(PrintableMixin): - - def __init__(self, parent, name, body, startLineNo): + def __init__(self, parent, name, body, start_line_no): self.parent = parent self.name = name self.body = body - self.startLineNo = startLineNo + self.start_line_no = start_line_no if not self.name: - Logger.fail("C1visualizer pass does not have a name", self.fileName, self.startLineNo) + Logger.fail("C1visualizer pass does not have a name", self.filename, self.start_line_no) if not self.body: - Logger.fail("C1visualizer pass does not have a body", self.fileName, self.startLineNo) + Logger.fail("C1visualizer pass does not have a body", self.filename, self.start_line_no) - self.parent.addPass(self) + self.parent.add_pass(self) @property - def fileName(self): - return self.parent.baseFileName + def filename(self): + return self.parent.base_file_name def __eq__(self, other): - return isinstance(other, self.__class__) \ - and self.name == other.name \ - and self.body == other.body + return (isinstance(other, self.__class__) + and self.name == other.name + and self.body == other.body) diff --git a/tools/checker/file_format/c1visualizer/test.py b/tools/checker/file_format/c1visualizer/test.py index a118a92b04..8c3cce4a4c 100644 --- a/tools/checker/file_format/c1visualizer/test.py +++ b/tools/checker/file_format/c1visualizer/test.py @@ -14,34 +14,35 @@ # See the License for the specific language governing permissions and # limitations under the License. -from common.immutables import ImmutableDict -from file_format.c1visualizer.parser import ParseC1visualizerStream +from common.immutables import ImmutableDict +from file_format.c1visualizer.parser import parse_c1_visualizer_stream from file_format.c1visualizer.struct import C1visualizerFile, C1visualizerPass import io import unittest + class C1visualizerParser_Test(unittest.TestCase): - def createFile(self, data): + def create_file(self, data): """ Creates an instance of CheckerFile from provided info. Data format: ( [ <isa-feature>, ... ], [ ( <case-name>, [ ( <text>, <assert-variant> ), ... ] ), ... ] ) """ - c1File = C1visualizerFile("<c1_file>") - c1File.instructionSetFeatures = data[0] - for passEntry in data[1]: - passName = passEntry[0] - passBody = passEntry[1] - c1Pass = C1visualizerPass(c1File, passName, passBody, 0) - return c1File + c1_file = C1visualizerFile("<c1_file>") + c1_file.instruction_set_features = data[0] + for pass_entry in data[1]: + pass_name = pass_entry[0] + pass_body = pass_entry[1] + c1_pass = C1visualizerPass(c1_file, pass_name, pass_body, 0) + return c1_file - def assertParsesTo(self, c1Text, expectedData): - expectedFile = self.createFile(expectedData) - actualFile = ParseC1visualizerStream("<c1_file>", io.StringIO(c1Text)) - return self.assertEqual(expectedFile, actualFile) + def assertParsesTo(self, c1_text, expected_data): + expected_file = self.create_file(expected_data) + actual_file = parse_c1_visualizer_stream("<c1_file>", io.StringIO(c1_text)) + return self.assertEqual(expected_file, actual_file) def test_EmptyFile(self): self.assertParsesTo("", (ImmutableDict(), [])) @@ -58,8 +59,8 @@ class C1visualizerParser_Test(unittest.TestCase): bar end_cfg """, - ( ImmutableDict(), [ - ( "MyMethod pass1", [ "foo", "bar" ] ) + (ImmutableDict(), [ + ("MyMethod pass1", ["foo", "bar"]) ])) def test_MultipleGroups(self): @@ -81,9 +82,9 @@ class C1visualizerParser_Test(unittest.TestCase): def end_cfg """, - ( ImmutableDict(), [ - ( "MyMethod1 pass1", [ "foo", "bar" ] ), - ( "MyMethod1 pass2", [ "abc", "def" ] ) + (ImmutableDict(), [ + ("MyMethod1 pass1", ["foo", "bar"]), + ("MyMethod1 pass2", ["abc", "def"]) ])) self.assertParsesTo( """ @@ -108,9 +109,9 @@ class C1visualizerParser_Test(unittest.TestCase): def end_cfg """, - ( ImmutableDict(), [ - ( "MyMethod1 pass1", [ "foo", "bar" ] ), - ( "MyMethod2 pass2", [ "abc", "def" ] ) + (ImmutableDict(), [ + ("MyMethod1 pass1", ["foo", "bar"]), + ("MyMethod2 pass2", ["abc", "def"]) ])) def test_InstructionSetFeatures(self): @@ -122,7 +123,7 @@ class C1visualizerParser_Test(unittest.TestCase): date 1234 end_compilation """, - ( ImmutableDict({"feature1": True, "feature2": False}), [])) + (ImmutableDict({"feature1": True, "feature2": False}), [])) self.assertParsesTo( """ begin_compilation @@ -141,8 +142,8 @@ class C1visualizerParser_Test(unittest.TestCase): bar end_cfg """, - ( ImmutableDict({"feature1": True, "feature2": False}), [ - ( "MyMethod1 pass1", [ "foo", "bar" ] ) + (ImmutableDict({"feature1": True, "feature2": False}), [ + ("MyMethod1 pass1", ["foo", "bar"]) ])) self.assertParsesTo( """ @@ -152,7 +153,7 @@ class C1visualizerParser_Test(unittest.TestCase): date 1234 end_compilation """, - ( ImmutableDict({"feature1": True, "feature2": False}), [])) + (ImmutableDict({"feature1": True, "feature2": False}), [])) self.assertParsesTo( """ begin_compilation @@ -171,6 +172,6 @@ class C1visualizerParser_Test(unittest.TestCase): bar end_cfg """, - ( ImmutableDict({"feature1": True, "feature2": False}), [ - ( "MyMethod1 pass1", [ "foo", "bar" ] ) + (ImmutableDict({"feature1": True, "feature2": False}), [ + ("MyMethod1 pass1", ["foo", "bar"]) ])) diff --git a/tools/checker/file_format/checker/parser.py b/tools/checker/file_format/checker/parser.py index c42d7de613..a2c52d3870 100644 --- a/tools/checker/file_format/checker/parser.py +++ b/tools/checker/file_format/checker/parser.py @@ -12,65 +12,68 @@ # See the License for the specific language governing permissions and # limitations under the License. -from common.archs import archs_list -from common.logger import Logger -from file_format.common import SplitStream +from common.archs import archs_list +from common.logger import Logger +from file_format.common import split_stream from file_format.checker.struct import CheckerFile, TestCase, TestStatement, TestExpression import re -def __isCheckerLine(line): + +def _is_checker_line(line): return line.startswith("///") or line.startswith("##") -def __extractLine(prefix, line, arch = None, debuggable = False): + +def _extract_line(prefix, line, arch=None, debuggable=False): """ Attempts to parse a check line. The regex searches for a comment symbol followed by the CHECK keyword, given attribute and a colon at the very beginning of the line. Whitespaces are ignored. """ - rIgnoreWhitespace = r"\s*" - rCommentSymbols = [r"///", r"##"] - arch_specifier = r"-%s" % arch if arch is not None else r"" - dbg_specifier = r"-DEBUGGABLE" if debuggable else r"" - regexPrefix = rIgnoreWhitespace + \ - r"(" + r"|".join(rCommentSymbols) + r")" + \ - rIgnoreWhitespace + \ - prefix + arch_specifier + dbg_specifier + r":" + r_ignore_whitespace = r"\s*" + r_comment_symbols = ["///", "##"] + arch_specifier = "-{}".format(arch) if arch is not None else "" + dbg_specifier = "-DEBUGGABLE" if debuggable else "" + regex_prefix = (r_ignore_whitespace + + "(" + "|".join(r_comment_symbols) + ")" + + r_ignore_whitespace + prefix + arch_specifier + dbg_specifier + ":") # The 'match' function succeeds only if the pattern is matched at the # beginning of the line. - match = re.match(regexPrefix, line) + match = re.match(regex_prefix, line) if match is not None: return line[match.end():].strip() else: return None -def __preprocessLineForStart(prefix, line, targetArch): + +def _preprocess_line_for_start(prefix, line, target_arch): """ This function modifies a CHECK-START-{x,y,z} into a matching CHECK-START-y line for matching targetArch y. If no matching architecture is found, CHECK-START-x is returned arbitrarily to ensure all following check lines are put into a test that is skipped. Any other line is left unmodified. """ - if targetArch is not None: + if target_arch is not None: if prefix in line: # Find { } on the line and assume that defines the set. - s = line.find('{') - e = line.find('}') - if 0 < s and s < e: - archs = line[s+1:e].split(',') + s = line.find("{") + e = line.find("}") + if 0 < s < e: + archs = line[s + 1:e].split(",") # First verify that every archs is valid. Return the # full line on failure to prompt error back to user. for arch in archs: - if not arch in archs_list: + if arch not in archs_list: return line # Now accept matching arch or arbitrarily return first. - if targetArch in archs: - return line[:s] + targetArch + line[e + 1:] + if target_arch in archs: + return line[:s] + target_arch + line[e + 1:] else: return line[:s] + archs[0] + line[e + 1:] return line -def __processLine(line, lineNo, prefix, fileName, targetArch): + +def _process_line(line, line_no, prefix, filename, target_arch): """ This function is invoked on each line of the check file and returns a triplet which instructs the parser how the line should be handled. If the line is to be included in the current check group, it is returned in the first @@ -78,152 +81,160 @@ def __processLine(line, lineNo, prefix, fileName, targetArch): returned in the second value. The third value indicates whether the line contained an architecture-specific suffix. """ - if not __isCheckerLine(line): + if not _is_checker_line(line): return None, None, None # Lines beginning with 'CHECK-START' start a new test case. # We currently only consider the architecture suffix(es) in "CHECK-START" lines. for debuggable in [True, False]: - sline = __preprocessLineForStart(prefix + "-START", line, targetArch) + sline = _preprocess_line_for_start(prefix + "-START", line, target_arch) for arch in [None] + archs_list: - startLine = __extractLine(prefix + "-START", sline, arch, debuggable) - if startLine is not None: - return None, startLine, (arch, debuggable) + start_line = _extract_line(prefix + "-START", sline, arch, debuggable) + if start_line is not None: + return None, start_line, (arch, debuggable) # Lines starting only with 'CHECK' are matched in order. - plainLine = __extractLine(prefix, line) - if plainLine is not None: - return (plainLine, TestStatement.Variant.InOrder, lineNo), None, None + plain_line = _extract_line(prefix, line) + if plain_line is not None: + return (plain_line, TestStatement.Variant.IN_ORDER, line_no), None, None # 'CHECK-NEXT' lines are in-order but must match the very next line. - nextLine = __extractLine(prefix + "-NEXT", line) - if nextLine is not None: - return (nextLine, TestStatement.Variant.NextLine, lineNo), None, None + next_line = _extract_line(prefix + "-NEXT", line) + if next_line is not None: + return (next_line, TestStatement.Variant.NEXT_LINE, line_no), None, None # 'CHECK-DAG' lines are no-order statements. - dagLine = __extractLine(prefix + "-DAG", line) - if dagLine is not None: - return (dagLine, TestStatement.Variant.DAG, lineNo), None, None + dag_line = _extract_line(prefix + "-DAG", line) + if dag_line is not None: + return (dag_line, TestStatement.Variant.DAG, line_no), None, None # 'CHECK-NOT' lines are no-order negative statements. - notLine = __extractLine(prefix + "-NOT", line) - if notLine is not None: - return (notLine, TestStatement.Variant.Not, lineNo), None, None + not_line = _extract_line(prefix + "-NOT", line) + if not_line is not None: + return (not_line, TestStatement.Variant.NOT, line_no), None, None # 'CHECK-EVAL' lines evaluate a Python expression. - evalLine = __extractLine(prefix + "-EVAL", line) - if evalLine is not None: - return (evalLine, TestStatement.Variant.Eval, lineNo), None, None + eval_line = _extract_line(prefix + "-EVAL", line) + if eval_line is not None: + return (eval_line, TestStatement.Variant.EVAL, line_no), None, None # 'CHECK-IF' lines mark the beginning of a block that will be executed # only if the Python expression that follows evaluates to true. - ifLine = __extractLine(prefix + "-IF", line) - if ifLine is not None: - return (ifLine, TestStatement.Variant.If, lineNo), None, None + if_line = _extract_line(prefix + "-IF", line) + if if_line is not None: + return (if_line, TestStatement.Variant.IF, line_no), None, None # 'CHECK-ELIF' lines mark the beginning of an `else if` branch of a CHECK-IF block. - elifLine = __extractLine(prefix + "-ELIF", line) - if elifLine is not None: - return (elifLine, TestStatement.Variant.Elif, lineNo), None, None + elif_line = _extract_line(prefix + "-ELIF", line) + if elif_line is not None: + return (elif_line, TestStatement.Variant.ELIF, line_no), None, None # 'CHECK-ELSE' lines mark the beginning of the `else` branch of a CHECK-IF block. - elseLine = __extractLine(prefix + "-ELSE", line) - if elseLine is not None: - return (elseLine, TestStatement.Variant.Else, lineNo), None, None + else_line = _extract_line(prefix + "-ELSE", line) + if else_line is not None: + return (else_line, TestStatement.Variant.ELSE, line_no), None, None # 'CHECK-FI' lines mark the end of a CHECK-IF block. - fiLine = __extractLine(prefix + "-FI", line) - if fiLine is not None: - return (fiLine, TestStatement.Variant.Fi, lineNo), None, None + fi_line = _extract_line(prefix + "-FI", line) + if fi_line is not None: + return (fi_line, TestStatement.Variant.FI, line_no), None, None + + Logger.fail("Checker statement could not be parsed: '" + line + "'", filename, line_no) - Logger.fail("Checker statement could not be parsed: '" + line + "'", fileName, lineNo) -def __isMatchAtStart(match): +def _is_match_at_start(match): """ Tests if the given Match occurred at the beginning of the line. """ return (match is not None) and (match.start() == 0) -def __firstMatch(matches, string): + +def _first_match(matches, string): """ Takes in a list of Match objects and returns the minimal start point among them. If there aren't any successful matches it returns the length of the searched string. """ - starts = map(lambda m: len(string) if m is None else m.start(), matches) - return min(starts) + return min(len(string) if m is None else m.start() for m in matches) -def ParseCheckerStatement(parent, line, variant, lineNo): + +def parse_checker_statement(parent, line, variant, line_no): """ This method parses the content of a check line stripped of the initial comment symbol and the CHECK-* keyword. """ - statement = TestStatement(parent, variant, line, lineNo) + statement = TestStatement(parent, variant, line, line_no) - if statement.isNoContentStatement() and line: - Logger.fail("Expected empty statement: '" + line + "'", statement.fileName, statement.lineNo) + if statement.is_no_content_statement() and line: + Logger.fail("Expected empty statement: '{}'".format(line), statement.filename, + statement.line_no) # Loop as long as there is something to parse. while line: # Search for the nearest occurrence of the special markers. - if statement.isEvalContentStatement(): + if statement.is_eval_content_statement(): # The following constructs are not supported in CHECK-EVAL, -IF and -ELIF lines - matchWhitespace = None - matchPattern = None - matchVariableDefinition = None + match_whitespace = None + match_pattern = None + match_variable_definition = None else: - matchWhitespace = re.search(r"\s+", line) - matchPattern = re.search(TestExpression.Regex.regexPattern, line) - matchVariableDefinition = re.search(TestExpression.Regex.regexVariableDefinition, line) - matchVariableReference = re.search(TestExpression.Regex.regexVariableReference, line) + match_whitespace = re.search(r"\s+", line) + match_pattern = re.search(TestExpression.Regex.REGEX_PATTERN, line) + match_variable_definition = re.search(TestExpression.Regex.REGEX_VARIABLE_DEFINITION, line) + match_variable_reference = re.search(TestExpression.Regex.REGEX_VARIABLE_REFERENCE, line) # If one of the above was identified at the current position, extract them # from the line, parse them and add to the list of line parts. - if __isMatchAtStart(matchWhitespace): + if _is_match_at_start(match_whitespace): # A whitespace in the check line creates a new separator of line parts. # This allows for ignored output between the previous and next parts. - line = line[matchWhitespace.end():] - statement.addExpression(TestExpression.createSeparator()) - elif __isMatchAtStart(matchPattern): - pattern = line[0:matchPattern.end()] + line = line[match_whitespace.end():] + statement.add_expression(TestExpression.create_separator()) + elif _is_match_at_start(match_pattern): + pattern = line[0:match_pattern.end()] pattern = pattern[2:-2] - line = line[matchPattern.end():] - statement.addExpression(TestExpression.createPattern(pattern)) - elif __isMatchAtStart(matchVariableReference): - var = line[0:matchVariableReference.end()] - line = line[matchVariableReference.end():] + line = line[match_pattern.end():] + statement.add_expression(TestExpression.create_pattern(pattern)) + elif _is_match_at_start(match_variable_reference): + var = line[0:match_variable_reference.end()] + line = line[match_variable_reference.end():] name = var[2:-2] - statement.addExpression(TestExpression.createVariableReference(name)) - elif __isMatchAtStart(matchVariableDefinition): - var = line[0:matchVariableDefinition.end()] - line = line[matchVariableDefinition.end():] - colonPos = var.find(":") - name = var[2:colonPos] - body = var[colonPos+1:-2] - statement.addExpression(TestExpression.createVariableDefinition(name, body)) + statement.add_expression(TestExpression.create_variable_reference(name)) + elif _is_match_at_start(match_variable_definition): + var = line[0:match_variable_definition.end()] + line = line[match_variable_definition.end():] + colon_pos = var.find(":") + name = var[2:colon_pos] + body = var[colon_pos + 1:-2] + statement.add_expression(TestExpression.create_variable_definition(name, body)) else: # If we're not currently looking at a special marker, this is a plain # text match all the way until the first special marker (or the end # of the line). - firstMatch = __firstMatch([ matchWhitespace, - matchPattern, - matchVariableReference, - matchVariableDefinition ], - line) - text = line[0:firstMatch] - line = line[firstMatch:] - if statement.isEvalContentStatement(): - statement.addExpression(TestExpression.createPlainText(text)) + first_match = _first_match([match_whitespace, + match_pattern, + match_variable_reference, + match_variable_definition], + line) + text = line[0:first_match] + line = line[first_match:] + if statement.is_eval_content_statement(): + statement.add_expression(TestExpression.create_plain_text(text)) else: - statement.addExpression(TestExpression.createPatternFromPlainText(text)) + statement.add_expression(TestExpression.create_pattern_from_plain_text(text)) return statement -def ParseCheckerStream(fileName, prefix, stream, targetArch = None): - checkerFile = CheckerFile(fileName) - fnProcessLine = lambda line, lineNo: __processLine(line, lineNo, prefix, fileName, targetArch) - fnLineOutsideChunk = lambda line, lineNo: \ - Logger.fail("Checker line not inside a group", fileName, lineNo) - for caseName, caseLines, startLineNo, testData in \ - SplitStream(stream, fnProcessLine, fnLineOutsideChunk): - testArch = testData[0] - forDebuggable = testData[1] - testCase = TestCase(checkerFile, caseName, startLineNo, testArch, forDebuggable) - for caseLine in caseLines: - ParseCheckerStatement(testCase, caseLine[0], caseLine[1], caseLine[2]) - return checkerFile + +def parse_checker_stream(file_name, prefix, stream, target_arch=None): + checker_file = CheckerFile(file_name) + + def fn_process_line(line, line_no): + return _process_line(line, line_no, prefix, file_name, target_arch) + + def fn_line_outside_chunk(line, line_no): + Logger.fail("Checker line not inside a group", file_name, line_no) + + for case_name, case_lines, start_line_no, test_data in split_stream(stream, fn_process_line, + fn_line_outside_chunk): + test_arch = test_data[0] + for_debuggable = test_data[1] + test_case = TestCase(checker_file, case_name, start_line_no, test_arch, for_debuggable) + for case_line in case_lines: + parse_checker_statement(test_case, case_line[0], case_line[1], case_line[2]) + return checker_file diff --git a/tools/checker/file_format/checker/struct.py b/tools/checker/file_format/checker/struct.py index 540badc440..f9242c4d71 100644 --- a/tools/checker/file_format/checker/struct.py +++ b/tools/checker/file_format/checker/struct.py @@ -12,136 +12,137 @@ # See the License for the specific language governing permissions and # limitations under the License. +import enum + from common.logger import Logger from common.mixins import EqualityMixin, PrintableMixin import re + class CheckerFile(PrintableMixin): - def __init__(self, fileName): - self.fileName = fileName - self.testCases = [] + def __init__(self, filename): + self.file_name = filename + self.test_cases = [] - def addTestCase(self, new_test_case): - self.testCases.append(new_test_case) + def add_test_case(self, new_test_case): + self.test_cases.append(new_test_case) - def testCasesForArch(self, targetArch): - return [t for t in self.testCases if t.testArch == targetArch] + def test_cases_for_arch(self, target_arch): + return [t for t in self.test_cases if t.test_arch == target_arch] def __eq__(self, other): - return isinstance(other, self.__class__) \ - and self.testCases == other.testCases + return isinstance(other, self.__class__) and self.test_cases == other.test_cases class TestCase(PrintableMixin): - def __init__(self, parent, name, startLineNo, testArch = None, forDebuggable = False): + def __init__(self, parent, name, start_line_no, test_arch=None, for_debuggable=False): assert isinstance(parent, CheckerFile) self.parent = parent self.name = name self.statements = [] - self.startLineNo = startLineNo - self.testArch = testArch - self.forDebuggable = forDebuggable + self.start_line_no = start_line_no + self.test_arch = test_arch + self.for_debuggable = for_debuggable if not self.name: - Logger.fail("Test case does not have a name", self.fileName, self.startLineNo) + Logger.fail("Test case does not have a name", self.filename, self.start_line_no) - self.parent.addTestCase(self) + self.parent.add_test_case(self) @property - def fileName(self): - return self.parent.fileName + def filename(self): + return self.parent.file_name - def addStatement(self, new_statement): + def add_statement(self, new_statement): self.statements.append(new_statement) def __eq__(self, other): - return isinstance(other, self.__class__) \ - and self.name == other.name \ - and self.statements == other.statements + return (isinstance(other, self.__class__) + and self.name == other.name + and self.statements == other.statements) class TestStatement(PrintableMixin): - - class Variant(object): + class Variant(enum.IntEnum): """Supported types of statements.""" - InOrder, NextLine, DAG, Not, Eval, If, Elif, Else, Fi = range(9) + IN_ORDER, NEXT_LINE, DAG, NOT, EVAL, IF, ELIF, ELSE, FI = range(9) - def __init__(self, parent, variant, originalText, lineNo): + def __init__(self, parent, variant, original_text, line_no): assert isinstance(parent, TestCase) self.parent = parent self.variant = variant self.expressions = [] - self.lineNo = lineNo - self.originalText = originalText + self.line_no = line_no + self.original_text = original_text - self.parent.addStatement(self) + self.parent.add_statement(self) @property - def fileName(self): - return self.parent.fileName + def filename(self): + return self.parent.filename - def isPatternMatchContentStatement(self): - return self.variant in [ TestStatement.Variant.InOrder, - TestStatement.Variant.NextLine, - TestStatement.Variant.DAG, - TestStatement.Variant.Not ] + def is_pattern_match_content_statement(self): + return self.variant in [TestStatement.Variant.IN_ORDER, + TestStatement.Variant.NEXT_LINE, + TestStatement.Variant.DAG, + TestStatement.Variant.NOT] - def isEvalContentStatement(self): - return self.variant in [ TestStatement.Variant.Eval, - TestStatement.Variant.If, - TestStatement.Variant.Elif ] + def is_eval_content_statement(self): + return self.variant in [TestStatement.Variant.EVAL, + TestStatement.Variant.IF, + TestStatement.Variant.ELIF] - def isNoContentStatement(self): - return self.variant in [ TestStatement.Variant.Else, - TestStatement.Variant.Fi ] + def is_no_content_statement(self): + return self.variant in [TestStatement.Variant.ELSE, + TestStatement.Variant.FI] - def addExpression(self, new_expression): + def add_expression(self, new_expression): assert isinstance(new_expression, TestExpression) - if self.variant == TestStatement.Variant.Not: - if new_expression.variant == TestExpression.Variant.VarDef: - Logger.fail("CHECK-NOT lines cannot define variables", self.fileName, self.lineNo) + if self.variant == TestStatement.Variant.NOT: + if new_expression.variant == TestExpression.Variant.VAR_DEF: + Logger.fail("CHECK-NOT lines cannot define variables", self.filename, self.line_no) self.expressions.append(new_expression) - def toRegex(self): + def to_regex(self): """ Returns a regex pattern for this entire statement. Only used in tests. """ regex = "" for expression in self.expressions: - if expression.variant == TestExpression.Variant.Separator: + if expression.variant == TestExpression.Variant.SEPARATOR: regex = regex + ", " else: regex = regex + "(" + expression.text + ")" return regex def __eq__(self, other): - return isinstance(other, self.__class__) \ - and self.variant == other.variant \ - and self.expressions == other.expressions + return (isinstance(other, self.__class__) + and self.variant == other.variant + and self.expressions == other.expressions) class TestExpression(EqualityMixin, PrintableMixin): - - class Variant(object): + class Variant: """Supported language constructs.""" - PlainText, Pattern, VarRef, VarDef, Separator = range(5) - - class Regex(object): - rName = r"([a-zA-Z][a-zA-Z0-9]*)" - rRegex = r"(.+?)" - rPatternStartSym = r"(\{\{)" - rPatternEndSym = r"(\}\})" - rVariableStartSym = r"(<<)" - rVariableEndSym = r"(>>)" - rVariableSeparator = r"(:)" - rVariableDefinitionBody = rName + rVariableSeparator + rRegex - - regexPattern = rPatternStartSym + rRegex + rPatternEndSym - regexVariableReference = rVariableStartSym + rName + rVariableEndSym - regexVariableDefinition = rVariableStartSym + rVariableDefinitionBody + rVariableEndSym + PLAIN_TEXT, PATTERN, VAR_REF, VAR_DEF, SEPARATOR = range(5) + + class Regex: + R_NAME = r"([a-zA-Z][a-zA-Z0-9]*)" + R_REGEX = r"(.+?)" + R_PATTERN_START_SYM = r"(\{\{)" + R_PATTERN_END_SYM = r"(\}\})" + R_VARIABLE_START_SYM = r"(<<)" + R_VARIABLE_END_SYM = r"(>>)" + R_VARIABLE_SEPARATOR = r"(:)" + R_VARIABLE_DEFINITION_BODY = R_NAME + R_VARIABLE_SEPARATOR + R_REGEX + + REGEX_PATTERN = R_PATTERN_START_SYM + R_REGEX + R_PATTERN_END_SYM + REGEX_VARIABLE_REFERENCE = R_VARIABLE_START_SYM + R_NAME + R_VARIABLE_END_SYM + REGEX_VARIABLE_DEFINITION = (R_VARIABLE_START_SYM + R_VARIABLE_DEFINITION_BODY + + R_VARIABLE_END_SYM) def __init__(self, variant, name, text): self.variant = variant @@ -149,33 +150,33 @@ class TestExpression(EqualityMixin, PrintableMixin): self.text = text def __eq__(self, other): - return isinstance(other, self.__class__) \ - and self.variant == other.variant \ - and self.name == other.name \ - and self.text == other.text + return (isinstance(other, self.__class__) + and self.variant == other.variant + and self.name == other.name + and self.text == other.text) @staticmethod - def createSeparator(): - return TestExpression(TestExpression.Variant.Separator, None, None) + def create_separator(): + return TestExpression(TestExpression.Variant.SEPARATOR, None, None) @staticmethod - def createPlainText(text): - return TestExpression(TestExpression.Variant.PlainText, None, text) + def create_plain_text(text): + return TestExpression(TestExpression.Variant.PLAIN_TEXT, None, text) @staticmethod - def createPatternFromPlainText(text): - return TestExpression(TestExpression.Variant.Pattern, None, re.escape(text)) + def create_pattern_from_plain_text(text): + return TestExpression(TestExpression.Variant.PATTERN, None, re.escape(text)) @staticmethod - def createPattern(pattern): - return TestExpression(TestExpression.Variant.Pattern, None, pattern) + def create_pattern(pattern): + return TestExpression(TestExpression.Variant.PATTERN, None, pattern) @staticmethod - def createVariableReference(name): - assert re.match(TestExpression.Regex.rName, name) - return TestExpression(TestExpression.Variant.VarRef, name, None) + def create_variable_reference(name): + assert re.match(TestExpression.Regex.R_NAME, name) + return TestExpression(TestExpression.Variant.VAR_REF, name, None) @staticmethod - def createVariableDefinition(name, pattern): - assert re.match(TestExpression.Regex.rName, name) - return TestExpression(TestExpression.Variant.VarDef, name, pattern) + def create_variable_definition(name, pattern): + assert re.match(TestExpression.Regex.R_NAME, name) + return TestExpression(TestExpression.Variant.VAR_DEF, name, pattern) diff --git a/tools/checker/file_format/checker/test.py b/tools/checker/file_format/checker/test.py index 4c61664874..dd440d6eab 100644 --- a/tools/checker/file_format/checker/test.py +++ b/tools/checker/file_format/checker/test.py @@ -14,8 +14,8 @@ # 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 ParseCheckerStream +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 @@ -23,25 +23,26 @@ import unittest CheckerException = SystemExit + class CheckerParser_PrefixTest(unittest.TestCase): - def tryParse(self, string): - checkerText = "/// CHECK-START: pass\n" + string - return ParseCheckerStream("<test-file>", "CHECK", io.StringIO(checkerText)) + 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): - checkFile = self.tryParse(string) - self.assertEqual(len(checkFile.testCases), 1) - self.assertNotEqual(len(checkFile.testCases[0].statements), 0) + 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): - checkFile = self.tryParse(string) - self.assertEqual(len(checkFile.testCases), 1) - self.assertEqual(len(checkFile.testCases[0].statements), 0) + 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.tryParse(string) + self.try_parse(string) def test_ValidFormat(self): self.assertParses("///CHECK:foo") @@ -72,47 +73,48 @@ class CheckerParser_PrefixTest(unittest.TestCase): self.assertParses(" ///CHECK: foo") self.assertParses("/// CHECK: foo") -class CheckerParser_TestExpressionTest(unittest.TestCase): - def parseStatement(self, string, variant=""): - checkerText = ("/// CHECK-START: pass\n" + - "/// CHECK" + variant + ": " + string) - checkerFile = ParseCheckerStream("<test-file>", "CHECK", io.StringIO(checkerText)) - self.assertEqual(len(checkerFile.testCases), 1) - testCase = checkerFile.testCases[0] - self.assertEqual(len(testCase.statements), 1) - return testCase.statements[0] - - def parseExpression(self, string): - line = self.parseStatement(string) +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.parseStatement(string).toRegex()) + self.assertEqual(expected, self.parse_statement(string).to_regex()) def assertEqualsText(self, string, text): - self.assertEqual(self.parseExpression(string), TestExpression.createPatternFromPlainText(text)) + self.assertEqual(self.parse_expression(string), + TestExpression.create_pattern_from_plain_text(text)) def assertEqualsPattern(self, string, pattern): - self.assertEqual(self.parseExpression(string), TestExpression.createPattern(pattern)) + self.assertEqual(self.parse_expression(string), TestExpression.create_pattern(pattern)) def assertEqualsVarRef(self, string, name): - self.assertEqual(self.parseExpression(string), TestExpression.createVariableReference(name)) + self.assertEqual(self.parse_expression(string), TestExpression.create_variable_reference(name)) def assertEqualsVarDef(self, string, name, pattern): - self.assertEqual(self.parseExpression(string), - TestExpression.createVariableDefinition(name, pattern)) + self.assertEqual(self.parse_expression(string), + TestExpression.create_variable_definition(name, pattern)) def assertVariantNotEqual(self, string, variant): - self.assertNotEqual(variant, self.parseExpression(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)") + self.assertEqualsRegex("f$o^o", "(f\\$o\\^o)") def test_PatternOnly(self): self.assertEqualsPattern("{{a?b.c}}", "a?b.c") @@ -167,16 +169,16 @@ class CheckerParser_TestExpressionTest(unittest.TestCase): def test_Empty(self): self.assertEqualsText("{{}}", "{{}}") - self.assertVariantNotEqual("<<>>", TestExpression.Variant.VarRef) - self.assertVariantNotEqual("<<:>>", TestExpression.Variant.VarDef) + self.assertVariantNotEqual("<<>>", TestExpression.Variant.VAR_REF) + self.assertVariantNotEqual("<<:>>", TestExpression.Variant.VAR_DEF) def test_InvalidVarName(self): - self.assertVariantNotEqual("<<0ABC>>", TestExpression.Variant.VarRef) - self.assertVariantNotEqual("<<AB=C>>", TestExpression.Variant.VarRef) - self.assertVariantNotEqual("<<ABC=>>", TestExpression.Variant.VarRef) - self.assertVariantNotEqual("<<0ABC:abc>>", TestExpression.Variant.VarDef) - self.assertVariantNotEqual("<<AB=C:abc>>", TestExpression.Variant.VarDef) - self.assertVariantNotEqual("<<ABC=:abc>>", TestExpression.Variant.VarDef) + 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)") @@ -184,36 +186,36 @@ class CheckerParser_TestExpressionTest(unittest.TestCase): def test_NoVarDefsInNotChecks(self): with self.assertRaises(CheckerException): - self.parseStatement("<<ABC:abc>>", "-NOT") + 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 createFile(self, caseList): - testFile = CheckerFile("<test_file>") - for caseEntry in caseList: - caseName = caseEntry[0] - testCase = TestCase(testFile, caseName, 0) - statementList = caseEntry[1] - for statementEntry in statementList: + 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(testCase, variant, content, 0) - if statement.isEvalContentStatement(): - statement.addExpression(TestExpression.createPlainText(content)) - elif statement.isPatternMatchContentStatement(): - statement.addExpression(TestExpression.createPatternFromPlainText(content)) - return testFile + 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, checkerText, expectedData): - expectedFile = self.createFile(expectedData) - actualFile = self.parse(checkerText) - return self.assertEqual(expectedFile, actualFile) + 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, checkerText): - return ParseCheckerStream("<test_file>", "CHECK", io.StringIO(checkerText)) + def parse(self, checker_text): + return parse_checker_stream("<test_file>", "CHECK", io.StringIO(checker_text)) def test_EmptyFile(self): self.assertParsesTo("", []) @@ -225,8 +227,8 @@ class CheckerParser_FileLayoutTest(unittest.TestCase): /// CHECK: foo /// CHECK: bar """, - [ ( "Example Group", [ ("foo", TestStatement.Variant.InOrder), - ("bar", TestStatement.Variant.InOrder) ] ) ]) + [("Example Group", [("foo", TestStatement.Variant.IN_ORDER), + ("bar", TestStatement.Variant.IN_ORDER)])]) def test_MultipleGroups(self): self.assertParsesTo( @@ -238,10 +240,10 @@ class CheckerParser_FileLayoutTest(unittest.TestCase): /// CHECK: abc /// CHECK: def """, - [ ( "Example Group1", [ ("foo", TestStatement.Variant.InOrder), - ("bar", TestStatement.Variant.InOrder) ] ), - ( "Example Group2", [ ("abc", TestStatement.Variant.InOrder), - ("def", TestStatement.Variant.InOrder) ] ) ]) + [("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( @@ -260,18 +262,18 @@ class CheckerParser_FileLayoutTest(unittest.TestCase): /// CHECK-ELSE: /// CHECK-FI: """, - [ ( "Example Group", [ ("foo1", TestStatement.Variant.InOrder), - ("foo2", TestStatement.Variant.InOrder), - ("foo3", TestStatement.Variant.NextLine), - ("foo4", TestStatement.Variant.NextLine), - ("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) ] ) ]) + [("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): @@ -287,9 +289,9 @@ class CheckerParser_FileLayoutTest(unittest.TestCase): /// CHECK-FI: foo """) -class CheckerParser_SuffixTests(unittest.TestCase): - noarch_block = """ +class CheckerParser_SuffixTests(unittest.TestCase): + NOARCH_BLOCK = """ /// CHECK-START: Group /// CHECK: foo /// CHECK-NEXT: bar @@ -302,7 +304,7 @@ class CheckerParser_SuffixTests(unittest.TestCase): /// CHECK-FI: """ - arch_block = """ + ARCH_BLOCK = """ /// CHECK-START-{test_arch}: Group /// CHECK: foo /// CHECK-NEXT: bar @@ -315,88 +317,89 @@ class CheckerParser_SuffixTests(unittest.TestCase): /// CHECK-FI: """ - def parse(self, checkerText): - return ParseCheckerStream("<test_file>", "CHECK", io.StringIO(checkerText)) + 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: - checkerFile = self.parse(self.noarch_block) - self.assertEqual(len(checkerFile.testCases), 1) - self.assertEqual(len(checkerFile.testCases[0].statements), 9) + 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 targetArch in archs_list: - for testArch in [a for a in archs_list if a != targetArch]: - checkerText = self.arch_block.format(test_arch = testArch) - checkerFile = self.parse(checkerText) - self.assertEqual(len(checkerFile.testCases), 1) - self.assertEqual(len(checkerFile.testCasesForArch(testArch)), 1) - self.assertEqual(len(checkerFile.testCasesForArch(targetArch)), 0) + 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: - checkerText = self.arch_block.format(test_arch = arch) - checkerFile = self.parse(checkerText) - self.assertEqual(len(checkerFile.testCases), 1) - self.assertEqual(len(checkerFile.testCasesForArch(arch)), 1) - self.assertEqual(len(checkerFile.testCases[0].statements), 9) + 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): - testCase = self.parse(""" + test_case = self.parse(""" /// CHECK-START: Group /// CHECK: foo - """).testCases[0] - self.assertFalse(testCase.forDebuggable) - self.assertEqual(testCase.testArch, None) + """).test_cases[0] + self.assertFalse(test_case.for_debuggable) + self.assertEqual(test_case.test_arch, None) def test_SetDebugNoArch(self): - testCase = self.parse(""" + test_case = self.parse(""" /// CHECK-START-DEBUGGABLE: Group /// CHECK: foo - """).testCases[0] - self.assertTrue(testCase.forDebuggable) - self.assertEqual(testCase.testArch, None) + """).test_cases[0] + self.assertTrue(test_case.for_debuggable) + self.assertEqual(test_case.test_arch, None) def test_NoDebugSetArch(self): - testCase = self.parse(""" + test_case = self.parse(""" /// CHECK-START-ARM: Group /// CHECK: foo - """).testCases[0] - self.assertFalse(testCase.forDebuggable) - self.assertEqual(testCase.testArch, "ARM") + """).test_cases[0] + self.assertFalse(test_case.for_debuggable) + self.assertEqual(test_case.test_arch, "ARM") def test_SetDebugAndArch(self): - testCase = self.parse(""" + test_case = self.parse(""" /// CHECK-START-ARM-DEBUGGABLE: Group /// CHECK: foo - """).testCases[0] - self.assertTrue(testCase.forDebuggable) - self.assertEqual(testCase.testArch, "ARM") + """).test_cases[0] + self.assertTrue(test_case.for_debuggable) + self.assertEqual(test_case.test_arch, "ARM") + class CheckerParser_EvalTests(unittest.TestCase): - def parseTestCase(self, string): - checkerText = "/// CHECK-START: pass\n" + string - checkerFile = ParseCheckerStream("<test-file>", "CHECK", io.StringIO(checkerText)) - self.assertEqual(len(checkerFile.testCases), 1) - return checkerFile.testCases[0] - - def parseExpressions(self, string): - testCase = self.parseTestCase("/// CHECK-EVAL: " + string) - self.assertEqual(len(testCase.statements), 1) - statement = testCase.statements[0] - self.assertEqual(statement.variant, TestStatement.Variant.Eval) - self.assertEqual(statement.originalText, string) + 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): - testCase = self.parseTestCase("/// CHECK-EVAL: " + text) - self.assertEqual(len(testCase.statements), 1) - statement = testCase.statements[0] - self.assertEqual(statement.variant, TestStatement.Variant.Eval) - self.assertEqual(statement.originalText, 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.PlainText) + self.assertEqual(expression.variant, TestExpression.Variant.PLAIN_TEXT) self.assertEqual(expression.text, text) def test_PlainText(self): @@ -407,25 +410,25 @@ class CheckerParser_EvalTests(unittest.TestCase): self.assertParsesToPlainText("<<ABC=>>") def test_VariableReference(self): - self.assertEqual(self.parseExpressions("<<ABC>>"), - [ TestExpression.createVariableReference("ABC") ]) - self.assertEqual(self.parseExpressions("123<<ABC>>"), - [ TestExpression.createPlainText("123"), - TestExpression.createVariableReference("ABC") ]) - self.assertEqual(self.parseExpressions("123 <<ABC>>"), - [ TestExpression.createPlainText("123 "), - TestExpression.createVariableReference("ABC") ]) - self.assertEqual(self.parseExpressions("<<ABC>>XYZ"), - [ TestExpression.createVariableReference("ABC"), - TestExpression.createPlainText("XYZ") ]) - self.assertEqual(self.parseExpressions("<<ABC>> XYZ"), - [ TestExpression.createVariableReference("ABC"), - TestExpression.createPlainText(" XYZ") ]) - self.assertEqual(self.parseExpressions("123<<ABC>>XYZ"), - [ TestExpression.createPlainText("123"), - TestExpression.createVariableReference("ABC"), - TestExpression.createPlainText("XYZ") ]) - self.assertEqual(self.parseExpressions("123 <<ABC>> XYZ"), - [ TestExpression.createPlainText("123 "), - TestExpression.createVariableReference("ABC"), - TestExpression.createPlainText(" XYZ") ]) + 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")]) diff --git a/tools/checker/file_format/common.py b/tools/checker/file_format/common.py index 4931550355..3127321552 100644 --- a/tools/checker/file_format/common.py +++ b/tools/checker/file_format/common.py @@ -12,7 +12,8 @@ # See the License for the specific language governing permissions and # limitations under the License. -def SplitStream(stream, fnProcessLine, fnLineOutsideChunk): + +def split_stream(stream, fn_process_line, fn_line_outside_chunk): """ Reads the given input stream and splits it into chunks based on information extracted from individual lines. @@ -24,12 +25,12 @@ def SplitStream(stream, fnProcessLine, fnLineOutsideChunk): - fnLineOutsideChunk: Called on attempt to attach data prior to creating a chunk. """ - lineNo = 0 - allChunks = [] - currentChunk = None + line_no = 0 + all_chunks = [] + current_chunk = None for line in stream: - lineNo += 1 + line_no += 1 line = line.strip() if not line: continue @@ -37,15 +38,15 @@ def SplitStream(stream, fnProcessLine, fnLineOutsideChunk): # Let the child class process the line and return information about it. # The _processLine method can modify the content of the line (or delete it # entirely) and specify whether it starts a new group. - processedLine, newChunkName, testArch = fnProcessLine(line, lineNo) + processed_line, new_chunk_name, test_arch = fn_process_line(line, line_no) # Currently, only a full chunk can be specified as architecture-specific. - assert testArch is None or newChunkName is not None - if newChunkName is not None: - currentChunk = (newChunkName, [], lineNo, testArch) - allChunks.append(currentChunk) - if processedLine is not None: - if currentChunk is not None: - currentChunk[1].append(processedLine) + assert test_arch is None or new_chunk_name is not None + if new_chunk_name is not None: + current_chunk = (new_chunk_name, [], line_no, test_arch) + all_chunks.append(current_chunk) + if processed_line is not None: + if current_chunk is not None: + current_chunk[1].append(processed_line) else: - fnLineOutsideChunk(line, lineNo) - return allChunks + fn_line_outside_chunk(line, line_no) + return all_chunks diff --git a/tools/checker/match/file.py b/tools/checker/match/file.py index 6f3631353a..1df83246e7 100644 --- a/tools/checker/match/file.py +++ b/tools/checker/match/file.py @@ -17,21 +17,24 @@ from collections import namedtuple from common.immutables import ImmutableDict from common.logger import Logger from file_format.checker.struct import TestStatement -from match.line import MatchLines, EvaluateLine +from match.line import match_lines, evaluate_line MatchScope = namedtuple("MatchScope", ["start", "end"]) MatchInfo = namedtuple("MatchInfo", ["scope", "variables"]) + class MatchFailedException(Exception): - def __init__(self, statement, lineNo, variables): + def __init__(self, statement, line_no, variables): self.statement = statement - self.lineNo = lineNo + self.line_no = line_no self.variables = variables + class BadStructureException(Exception): - def __init__(self, msg, lineNo): + def __init__(self, msg, line_no): self.msg = msg - self.lineNo = lineNo + self.line_no = line_no + class IfStack: """ @@ -41,11 +44,11 @@ class IfStack: statements, and consequently update the stack with new information. The following elements can appear on the stack: - - BranchTaken: a branch is taken if its condition evaluates to true and + - BRANCH_TAKEN: a branch is taken if its condition evaluates to true and its parent branch was also previously taken. - - BranchNotTakenYet: the branch's parent was taken, but this branch wasn't as its + - BRANCH_NOT_TAKEN_YET: the branch's parent was taken, but this branch wasn't as its condition did not evaluate to true. - - BranchNotTaken: a branch is not taken when its parent was either NotTaken or NotTakenYet. + - BRANCH_NOT_TAKEN: a branch is not taken when its parent was either NotTaken or NotTakenYet. It doesn't matter if the condition would evaluate to true, that's not even checked. CHECK-IF is the only instruction that pushes a new element on the stack. CHECK-ELIF @@ -54,110 +57,111 @@ class IfStack: processed just by looking at the top of the stack. CHECK-FI will pop the last element. - `BranchTaken`, `BranchNotTaken`, `BranchNotTakenYet` are implemented as positive integers. - Negated values of `BranchTaken` and `BranchNotTaken` may be appear; `-BranchTaken` and - `-BranchNotTaken` have the same meaning as `BranchTaken` and `BranchNotTaken` + `BRANCH_TAKEN`, `BRANCH_NOT_TAKEN`, `BRANCH_NOT_TAKEN_YET` are implemented as positive integers. + Negated values of `BRANCH_TAKEN` and `BRANCH_NOT_TAKEN` may be appear; `-BRANCH_TAKEN` and + `-BRANCH_NOT_TAKEN` have the same meaning as `BRANCH_TAKEN` and `BRANCH_NOT_TAKEN` (respectively), but they indicate that we went past the ELSE branch. Knowing that, we can output a precise error message if the user creates a malformed branching structure. """ - BranchTaken, BranchNotTaken, BranchNotTakenYet = range(1, 4) + BRANCH_TAKEN, BRANCH_NOT_TAKEN, BRANCH_NOT_TAKEN_YET = range(1, 4) def __init__(self): self.stack = [] - def CanExecute(self): + def can_execute(self): """ Returns true if we're not in any branch, or the branch we're currently in was taken. """ - if self.__isEmpty(): + if self._is_empty(): return True - return abs(self.__peek()) == IfStack.BranchTaken + return abs(self._peek()) == IfStack.BRANCH_TAKEN - def Handle(self, statement, variables): + def handle(self, statement, variables): """ This function is invoked if the cursor is pointing to a CHECK-[IF, ELIF, ELSE, FI] line. """ variant = statement.variant - if variant is TestStatement.Variant.If: - self.__if(statement, variables) - elif variant is TestStatement.Variant.Elif: - self.__elif(statement, variables) - elif variant is TestStatement.Variant.Else: - self.__else(statement) + if variant is TestStatement.Variant.IF: + self._if(statement, variables) + elif variant is TestStatement.Variant.ELIF: + self._elif(statement, variables) + elif variant is TestStatement.Variant.ELSE: + self._else(statement) else: - assert variant is TestStatement.Variant.Fi - self.__fi(statement) + assert variant is TestStatement.Variant.FI + self._fi(statement) - def Eof(self): + def eof(self): """ The last line the cursor points to is always EOF. """ - if not self.__isEmpty(): + if not self._is_empty(): raise BadStructureException("Missing CHECK-FI", -1) - def __isEmpty(self): - return len(self.stack) == 0 + def _is_empty(self): + return not self.stack - def __if(self, statement, variables): - if not self.__isEmpty() and abs(self.__peek()) in [ IfStack.BranchNotTaken, - IfStack.BranchNotTakenYet ]: - self.__push(IfStack.BranchNotTaken) - elif EvaluateLine(statement, variables): - self.__push(IfStack.BranchTaken) + def _if(self, statement, variables): + if not self._is_empty() and abs(self._peek()) in [IfStack.BRANCH_NOT_TAKEN, + IfStack.BRANCH_NOT_TAKEN_YET]: + self._push(IfStack.BRANCH_NOT_TAKEN) + elif evaluate_line(statement, variables): + self._push(IfStack.BRANCH_TAKEN) else: - self.__push(IfStack.BranchNotTakenYet) + self._push(IfStack.BRANCH_NOT_TAKEN_YET) - def __elif(self, statement, variables): - if self.__isEmpty(): + def _elif(self, statement, variables): + if self._is_empty(): raise BadStructureException("CHECK-ELIF must be after CHECK-IF or CHECK-ELIF", - statement.lineNo) - if self.__peek() < 0: - raise BadStructureException("CHECK-ELIF cannot be after CHECK-ELSE", statement.lineNo) - if self.__peek() == IfStack.BranchTaken: - self.__setLast(IfStack.BranchNotTaken) - elif self.__peek() == IfStack.BranchNotTakenYet: - if EvaluateLine(statement, variables): - self.__setLast(IfStack.BranchTaken) + statement.line_no) + if self._peek() < 0: + raise BadStructureException("CHECK-ELIF cannot be after CHECK-ELSE", statement.line_no) + if self._peek() == IfStack.BRANCH_TAKEN: + self._set_last(IfStack.BRANCH_NOT_TAKEN) + elif self._peek() == IfStack.BRANCH_NOT_TAKEN_YET: + if evaluate_line(statement, variables): + self._set_last(IfStack.BRANCH_TAKEN) # else, the CHECK-ELIF condition is False, so do nothing: the last element on the stack is - # already set to BranchNotTakenYet. + # already set to BRANCH_NOT_TAKEN_YET. else: - assert self.__peek() == IfStack.BranchNotTaken + assert self._peek() == IfStack.BRANCH_NOT_TAKEN - def __else(self, statement): - if self.__isEmpty(): + def _else(self, statement): + if self._is_empty(): raise BadStructureException("CHECK-ELSE must be after CHECK-IF or CHECK-ELIF", - statement.lineNo) - if self.__peek() < 0: - raise BadStructureException("Consecutive CHECK-ELSE statements", statement.lineNo) - if self.__peek() in [ IfStack.BranchTaken, IfStack.BranchNotTaken ]: - # Notice that we're setting -BranchNotTaken rather that BranchNotTaken as we went past the + statement.line_no) + if self._peek() < 0: + raise BadStructureException("Consecutive CHECK-ELSE statements", statement.line_no) + if self._peek() in [IfStack.BRANCH_TAKEN, IfStack.BRANCH_NOT_TAKEN]: + # Notice that we're setting -BRANCH_NOT_TAKEN rather that BRANCH_NOT_TAKEN as we went past the # ELSE branch. - self.__setLast(-IfStack.BranchNotTaken) + self._set_last(-IfStack.BRANCH_NOT_TAKEN) else: - assert self.__peek() == IfStack.BranchNotTakenYet - # Setting -BranchTaken rather BranchTaken for the same reason. - self.__setLast(-IfStack.BranchTaken) + assert self._peek() == IfStack.BRANCH_NOT_TAKEN_YET + # Setting -BRANCH_TAKEN rather BRANCH_TAKEN for the same reason. + self._set_last(-IfStack.BRANCH_TAKEN) - def __fi(self, statement): - if self.__isEmpty(): - raise BadStructureException("CHECK-FI does not have a matching CHECK-IF", statement.lineNo) + def _fi(self, statement): + if self._is_empty(): + raise BadStructureException("CHECK-FI does not have a matching CHECK-IF", statement.line_no) self.stack.pop() - def __peek(self): - assert not self.__isEmpty() + def _peek(self): + assert not self._is_empty() return self.stack[-1] - def __push(self, element): + def _push(self, element): self.stack.append(element) - def __setLast(self, element): + def _set_last(self, element): self.stack[-1] = element -def findMatchingLine(statement, c1Pass, scope, variables, excludeLines=[]): - """ Finds the first line in `c1Pass` which matches `statement`. + +def find_matching_line(statement, c1_pass, scope, variables, exclude_lines=[]): + """ Finds the first line in `c1_pass` which matches `statement`. Scan only lines numbered between `scope.start` and `scope.end` and not on the `excludeLines` list. @@ -168,33 +172,35 @@ def findMatchingLine(statement, c1Pass, scope, variables, excludeLines=[]): Raises MatchFailedException if no such `c1Pass` line can be found. """ for i in range(scope.start, scope.end): - if i in excludeLines: continue - newVariables = MatchLines(statement, c1Pass.body[i], variables) - if newVariables is not None: - return MatchInfo(MatchScope(i, i), newVariables) + if i in exclude_lines: + continue + new_variables = match_lines(statement, c1_pass.body[i], variables) + if new_variables is not None: + return MatchInfo(MatchScope(i, i), new_variables) raise MatchFailedException(statement, scope.start, variables) + class ExecutionState(object): - def __init__(self, c1Pass, variables={}): + def __init__(self, c1_pass, variables={}): self.cursor = 0 - self.c1Pass = c1Pass - self.c1Length = len(c1Pass.body) + self.c1_pass = c1_pass + self.c1_length = len(c1_pass.body) self.variables = ImmutableDict(variables) - self.dagQueue = [] - self.notQueue = [] - self.ifStack = IfStack() - self.lastVariant = None + self.dag_queue = [] + self.not_queue = [] + self.if_stack = IfStack() + self.last_variant = None - def moveCursor(self, match): + def move_cursor(self, match): assert self.cursor <= match.scope.end # Handle any pending NOT statements before moving the cursor - self.handleNotQueue(MatchScope(self.cursor, match.scope.start)) + self.handle_not_queue(MatchScope(self.cursor, match.scope.start)) self.cursor = match.scope.end + 1 self.variables = match.variables - def handleDagQueue(self, scope): + def handle_dag_queue(self, scope): """ Attempts to find matching `c1Pass` lines for a group of DAG statements. Statements are matched in the list order and variable values propagated. Only @@ -205,154 +211,156 @@ class ExecutionState(object): Raises MatchFailedException when a statement cannot be satisfied. """ - if not self.dagQueue: + if not self.dag_queue: return - matchedLines = [] + matched_lines = [] variables = self.variables - for statement in self.dagQueue: + for statement in self.dag_queue: assert statement.variant == TestStatement.Variant.DAG - match = findMatchingLine(statement, self.c1Pass, scope, variables, matchedLines) + match = find_matching_line(statement, self.c1_pass, scope, variables, matched_lines) variables = match.variables assert match.scope.start == match.scope.end - assert match.scope.start not in matchedLines - matchedLines.append(match.scope.start) + assert match.scope.start not in matched_lines + matched_lines.append(match.scope.start) - match = MatchInfo(MatchScope(min(matchedLines), max(matchedLines)), variables) - self.dagQueue = [] - self.moveCursor(match) + match = MatchInfo(MatchScope(min(matched_lines), max(matched_lines)), variables) + self.dag_queue = [] + self.move_cursor(match) - def handleNotQueue(self, scope): + def handle_not_queue(self, scope): """ Verifies that none of the given NOT statements matches a line inside the given `scope` of `c1Pass` lines. Raises MatchFailedException if a statement matches a line in the scope. """ - for statement in self.notQueue: - assert statement.variant == TestStatement.Variant.Not + for statement in self.not_queue: + assert statement.variant == TestStatement.Variant.NOT for i in range(scope.start, scope.end): - if MatchLines(statement, self.c1Pass.body[i], self.variables) is not None: + if match_lines(statement, self.c1_pass.body[i], self.variables) is not None: raise MatchFailedException(statement, i, self.variables) - self.notQueue = [] + self.not_queue = [] - def handleEOF(self): + def handle_eof(self): """ EOF marker always moves the cursor to the end of the file.""" - match = MatchInfo(MatchScope(self.c1Length, self.c1Length), None) - self.moveCursor(match) + match = MatchInfo(MatchScope(self.c1_length, self.c1_length), None) + self.move_cursor(match) - def handleInOrder(self, statement): + def handle_in_order(self, statement): """ Single in-order statement. Find the first line that matches and move the cursor to the subsequent line. Raises MatchFailedException if no such line can be found. """ - scope = MatchScope(self.cursor, self.c1Length) - match = findMatchingLine(statement, self.c1Pass, scope, self.variables) - self.moveCursor(match) + scope = MatchScope(self.cursor, self.c1_length) + match = find_matching_line(statement, self.c1_pass, scope, self.variables) + self.move_cursor(match) - def handleNextLine(self, statement): + def handle_next_line(self, statement): """ Single next-line statement. Test if the current line matches and move the cursor to the next line if it does. Raises MatchFailedException if the current line does not match. """ - if self.lastVariant not in [ TestStatement.Variant.InOrder, TestStatement.Variant.NextLine ]: + if self.last_variant not in [TestStatement.Variant.IN_ORDER, TestStatement.Variant.NEXT_LINE]: raise BadStructureException("A next-line statement can only be placed " - "after an in-order statement or another next-line statement.", - statement.lineNo) + "after an in-order statement or another next-line statement.", + statement.line_no) scope = MatchScope(self.cursor, self.cursor + 1) - match = findMatchingLine(statement, self.c1Pass, scope, self.variables) - self.moveCursor(match) + match = find_matching_line(statement, self.c1_pass, scope, self.variables) + self.move_cursor(match) - def handleEval(self, statement): + def handle_eval(self, statement): """ Evaluates the statement in the current context. Raises MatchFailedException if the expression evaluates to False. """ - if not EvaluateLine(statement, self.variables): + if not evaluate_line(statement, self.variables): raise MatchFailedException(statement, self.cursor, self.variables) def handle(self, statement): variant = None if statement is None else statement.variant - if variant in [ TestStatement.Variant.If, - TestStatement.Variant.Elif, - TestStatement.Variant.Else, - TestStatement.Variant.Fi ]: - self.ifStack.Handle(statement, self.variables) + if variant in [TestStatement.Variant.IF, + TestStatement.Variant.ELIF, + TestStatement.Variant.ELSE, + TestStatement.Variant.FI]: + self.if_stack.handle(statement, self.variables) return if variant is None: - self.ifStack.Eof() + self.if_stack.eof() - if not self.ifStack.CanExecute(): + if not self.if_stack.can_execute(): return # First non-DAG statement always triggers execution of any preceding # DAG statements. if variant is not TestStatement.Variant.DAG: - self.handleDagQueue(MatchScope(self.cursor, self.c1Length)) + self.handle_dag_queue(MatchScope(self.cursor, self.c1_length)) if variant is None: - self.handleEOF() - elif variant is TestStatement.Variant.InOrder: - self.handleInOrder(statement) - elif variant is TestStatement.Variant.NextLine: - self.handleNextLine(statement) + self.handle_eof() + elif variant is TestStatement.Variant.IN_ORDER: + self.handle_in_order(statement) + elif variant is TestStatement.Variant.NEXT_LINE: + self.handle_next_line(statement) elif variant is TestStatement.Variant.DAG: - self.dagQueue.append(statement) - elif variant is TestStatement.Variant.Not: - self.notQueue.append(statement) + self.dag_queue.append(statement) + elif variant is TestStatement.Variant.NOT: + self.not_queue.append(statement) else: - assert variant is TestStatement.Variant.Eval - self.handleEval(statement) + assert variant is TestStatement.Variant.EVAL + self.handle_eval(statement) - self.lastVariant = variant + self.last_variant = variant -def MatchTestCase(testCase, c1Pass, instructionSetFeatures): + +def match_test_case(test_case, c1_pass, instruction_set_features): """ Runs a test case against a C1visualizer graph dump. Raises MatchFailedException when a statement cannot be satisfied. """ - assert testCase.name == c1Pass.name + assert test_case.name == c1_pass.name - initialVariables = {"ISA_FEATURES": instructionSetFeatures} - state = ExecutionState(c1Pass, initialVariables) - testStatements = testCase.statements + [ None ] - for statement in testStatements: + initial_variables = {"ISA_FEATURES": instruction_set_features} + state = ExecutionState(c1_pass, initial_variables) + test_statements = test_case.statements + [None] + for statement in test_statements: state.handle(statement) -def MatchFiles(checkerFile, c1File, targetArch, debuggableMode, printCfg): - for testCase in checkerFile.testCases: - if testCase.testArch not in [None, targetArch]: + +def match_files(checker_file, c1_file, target_arch, debuggable_mode, print_cfg): + for test_case in checker_file.test_cases: + if test_case.test_arch not in [None, target_arch]: continue - if testCase.forDebuggable != debuggableMode: + if test_case.for_debuggable != debuggable_mode: continue # TODO: Currently does not handle multiple occurrences of the same group # name, e.g. when a pass is run multiple times. It will always try to # match a check group against the first output group of the same name. - c1Pass = c1File.findPass(testCase.name) - if c1Pass is None: - with open(c1File.fullFileName) as cfgFile: - Logger.log(''.join(cfgFile), Logger.Level.ERROR) + c1_pass = c1_file.find_pass(test_case.name) + if c1_pass is None: + with open(c1_file.full_file_name) as cfg_file: + Logger.log("".join(cfg_file), Logger.Level.ERROR) Logger.fail("Test case not found in the CFG file", - testCase.fullFileName, testCase.startLineNo, testCase.name) + test_case.full_file_name, test_case.start_line_no, test_case.name) - Logger.startTest(testCase.name) + Logger.start_test(test_case.name) try: - MatchTestCase(testCase, c1Pass, c1File.instructionSetFeatures) - Logger.testPassed() + match_test_case(test_case, c1_pass, c1_file.instruction_set_features) + Logger.test_passed() except MatchFailedException as e: - lineNo = c1Pass.startLineNo + e.lineNo - if e.statement.variant == TestStatement.Variant.Not: + line_no = c1_pass.start_line_no + e.line_no + if e.statement.variant == TestStatement.Variant.NOT: msg = "NOT statement matched line {}" else: msg = "Statement could not be matched starting from line {}" - msg = msg.format(lineNo) - if printCfg: - with open(c1File.fullFileName) as cfgFile: - Logger.log(''.join(cfgFile), Logger.Level.Error) - Logger.testFailed(msg, e.statement, e.variables) + msg = msg.format(line_no) + if print_cfg: + with open(c1_file.full_file_name) as cfg_file: + Logger.log("".join(cfg_file), Logger.Level.ERROR) + Logger.test_failed(msg, e.statement, e.variables) diff --git a/tools/checker/match/line.py b/tools/checker/match/line.py index 91450a56f7..f6fa92fa94 100644 --- a/tools/checker/match/line.py +++ b/tools/checker/match/line.py @@ -12,106 +12,117 @@ # See the License for the specific language governing permissions and # limitations under the License. -from common.logger import Logger +from common.logger import Logger from file_format.checker.struct import TestExpression, TestStatement +# Required for eval. import os import re -def headAndTail(list): + +def head_and_tail(list): return list[0], list[1:] -def splitAtSeparators(expressions): + +def split_at_separators(expressions): """ Splits a list of TestExpressions at separators. """ - splitExpressions = [] - wordStart = 0 + split_expressions = [] + word_start = 0 for index, expression in enumerate(expressions): - if expression.variant == TestExpression.Variant.Separator: - splitExpressions.append(expressions[wordStart:index]) - wordStart = index + 1 - splitExpressions.append(expressions[wordStart:]) - return splitExpressions + if expression.variant == TestExpression.Variant.SEPARATOR: + split_expressions.append(expressions[word_start:index]) + word_start = index + 1 + split_expressions.append(expressions[word_start:]) + return split_expressions -def getVariable(name, variables, pos): + +def get_variable(name, variables, pos): if name in variables: return variables[name] else: - Logger.testFailed("Missing definition of variable \"{}\"".format(name), pos, variables) + Logger.test_failed('Missing definition of variable "{}"'.format(name), pos, variables) + -def setVariable(name, value, variables, pos): +def set_variable(name, value, variables, pos): if name not in variables: - return variables.copyWith(name, value) + return variables.copy_with(name, value) else: - Logger.testFailed("Multiple definitions of variable \"{}\"".format(name), pos, variables) + Logger.test_failed('Multiple definitions of variable "{}"'.format(name), pos, variables) -def matchWords(checkerWord, stringWord, variables, pos): + +def match_words(checker_word, string_word, variables, pos): """ Attempts to match a list of TestExpressions against a string. Returns updated variable dictionary if successful and None otherwise. """ - for expression in checkerWord: + for expression in checker_word: # If `expression` is a variable reference, replace it with the value. - if expression.variant == TestExpression.Variant.VarRef: - pattern = re.escape(getVariable(expression.name, variables, pos)) + if expression.variant == TestExpression.Variant.VAR_REF: + pattern = re.escape(get_variable(expression.name, variables, pos)) else: pattern = expression.text # Match the expression's regex pattern against the remainder of the word. # Note: re.match will succeed only if matched from the beginning. - match = re.match(pattern, stringWord) + match = re.match(pattern, string_word) if not match: return None # If `expression` was a variable definition, set the variable's value. - if expression.variant == TestExpression.Variant.VarDef: - variables = setVariable(expression.name, stringWord[:match.end()], variables, pos) + if expression.variant == TestExpression.Variant.VAR_DEF: + variables = set_variable(expression.name, string_word[:match.end()], variables, pos) # Move cursor by deleting the matched characters. - stringWord = stringWord[match.end():] + string_word = string_word[match.end():] # Make sure the entire word matched, i.e. `stringWord` is empty. - if stringWord: + if string_word: return None return variables -def MatchLines(checkerLine, stringLine, variables): + +def match_lines(checker_line, string_line, variables): """ Attempts to match a CHECK line against a string. Returns variable state after the match if successful and None otherwise. """ - assert checkerLine.variant != TestStatement.Variant.Eval + assert checker_line.variant != TestStatement.Variant.EVAL - checkerWords = splitAtSeparators(checkerLine.expressions) - stringWords = stringLine.split() + checker_words = split_at_separators(checker_line.expressions) + string_words = string_line.split() - while checkerWords: + while checker_words: # Get the next run of TestExpressions which must match one string word. - checkerWord, checkerWords = headAndTail(checkerWords) + checker_word, checker_words = head_and_tail(checker_words) # Keep reading words until a match is found. - wordMatched = False - while stringWords: - stringWord, stringWords = headAndTail(stringWords) - newVariables = matchWords(checkerWord, stringWord, variables, checkerLine) - if newVariables is not None: - wordMatched = True - variables = newVariables + word_matched = False + while string_words: + string_word, string_words = head_and_tail(string_words) + new_variables = match_words(checker_word, string_word, variables, checker_line) + if new_variables is not None: + word_matched = True + variables = new_variables break - if not wordMatched: + if not word_matched: return None # All TestExpressions matched. Return new variable state. return variables -def getEvalText(expression, variables, pos): - if expression.variant == TestExpression.Variant.PlainText: + +def get_eval_text(expression, variables, pos): + if expression.variant == TestExpression.Variant.PLAIN_TEXT: return expression.text else: - assert expression.variant == TestExpression.Variant.VarRef - return getVariable(expression.name, variables, pos) + assert expression.variant == TestExpression.Variant.VAR_REF + return get_variable(expression.name, variables, pos) + -def EvaluateLine(checkerLine, variables): - assert checkerLine.isEvalContentStatement() +def evaluate_line(checker_line, variables): + assert checker_line.is_eval_content_statement() + # Required for eval. hasIsaFeature = lambda feature: variables["ISA_FEATURES"].get(feature, False) - eval_string = "".join(map(lambda expr: getEvalText(expr, variables, checkerLine), - checkerLine.expressions)) + eval_string = "".join(get_eval_text(expr, + variables, + checker_line) for expr in checker_line.expressions) return eval(eval_string) diff --git a/tools/checker/match/test.py b/tools/checker/match/test.py index 5e43fa0e7b..adebd6da61 100644 --- a/tools/checker/match/test.py +++ b/tools/checker/match/test.py @@ -12,34 +12,36 @@ # See the License for the specific language governing permissions and # limitations under the License. -from common.immutables import ImmutableDict -from file_format.c1visualizer.parser import ParseC1visualizerStream -from file_format.checker.parser import ParseCheckerStream, ParseCheckerStatement -from file_format.checker.struct import CheckerFile, TestCase, TestStatement -from match.file import MatchTestCase, MatchFailedException, \ - BadStructureException -from match.line import MatchLines +from common.immutables import ImmutableDict +from file_format.c1visualizer.parser import parse_c1_visualizer_stream +from file_format.checker.parser import parse_checker_stream, parse_checker_statement +from file_format.checker.struct import CheckerFile, TestCase, TestStatement +from match.file import match_test_case, MatchFailedException, BadStructureException +from match.line import match_lines import io import unittest CheckerException = SystemExit + class MatchLines_Test(unittest.TestCase): - def createTestStatement(self, checkerString): - checkerFile = CheckerFile("<checker-file>") - testCase = TestCase(checkerFile, "TestMethod TestPass", 0) - return ParseCheckerStatement(testCase, checkerString, TestStatement.Variant.InOrder, 0) + def create_test_statement(self, checker_string): + checker_file = CheckerFile("<checker-file>") + test_case = TestCase(checker_file, "TestMethod TestPass", 0) + return parse_checker_statement(test_case, checker_string, TestStatement.Variant.IN_ORDER, 0) - def tryMatch(self, checkerString, c1String, varState={}): - return MatchLines(self.createTestStatement(checkerString), c1String, ImmutableDict(varState)) + def try_match(self, checker_string, c1_string, var_state={}): + return match_lines(self.create_test_statement(checker_string), + c1_string, + ImmutableDict(var_state)) - def assertMatches(self, checkerString, c1String, varState={}): - self.assertIsNotNone(self.tryMatch(checkerString, c1String, varState)) + def assertMatches(self, checker_string, c1_string, var_state={}): + self.assertIsNotNone(self.try_match(checker_string, c1_string, var_state)) - def assertDoesNotMatch(self, checkerString, c1String, varState={}): - self.assertIsNone(self.tryMatch(checkerString, c1String, varState)) + def assertDoesNotMatch(self, checker_string, c1_string, var_state={}): + self.assertIsNone(self.try_match(checker_string, c1_string, var_state)) def test_TextAndWhitespace(self): self.assertMatches("foo", "foo") @@ -67,16 +69,16 @@ class MatchLines_Test(unittest.TestCase): self.assertDoesNotMatch("foo<<X>>bar", "foobar", {"X": "A"}) self.assertDoesNotMatch("foo<<X>>bar", "foo bar", {"X": "A"}) with self.assertRaises(CheckerException): - self.tryMatch("foo<<X>>bar", "foobar", {}) + self.try_match("foo<<X>>bar", "foobar", {}) def test_VariableDefinition(self): self.assertMatches("foo<<X:A|B>>bar", "fooAbar") self.assertMatches("foo<<X:A|B>>bar", "fooBbar") self.assertDoesNotMatch("foo<<X:A|B>>bar", "fooCbar") - env = self.tryMatch("foo<<X:A.*B>>bar", "fooABbar", {}) + env = self.try_match("foo<<X:A.*B>>bar", "fooABbar", {}) self.assertEqual(env, {"X": "AB"}) - env = self.tryMatch("foo<<X:A.*B>>bar", "fooAxxBbar", {}) + env = self.try_match("foo<<X:A.*B>>bar", "fooAxxBbar", {}) self.assertEqual(env, {"X": "AxxB"}) self.assertMatches("foo<<X:A|B>>bar<<X>>baz", "fooAbarAbaz") @@ -85,7 +87,7 @@ class MatchLines_Test(unittest.TestCase): def test_NoVariableRedefinition(self): with self.assertRaises(CheckerException): - self.tryMatch("<<X:...>><<X>><<X:...>><<X>>", "foofoobarbar") + self.try_match("<<X:...>><<X>><<X:...>><<X>>", "foofoobarbar") def test_EnvNotChangedOnPartialMatch(self): env = {"Y": "foo"} @@ -99,61 +101,59 @@ class MatchLines_Test(unittest.TestCase): class MatchFiles_Test(unittest.TestCase): - def assertMatches(self, checkerString, c1String, isa=None, instructionSetFeatures=None): - checkerString = \ + def assertMatches(self, checker_string, c1_string, isa=None, instruction_set_features=None): + checker_string = \ """ /// CHECK-START: MyMethod MyPass - """ + checkerString - metaData = "" + """ + checker_string + meta_data = "" if isa: - metaData += "isa:" + isa + meta_data += "isa:" + isa - if instructionSetFeatures: - if metaData: - metaData += " " + if instruction_set_features: + if meta_data: + meta_data += " " - joinedFeatures = ",".join(map(lambda feature: feature - if instructionSetFeatures[feature] - else "-" + feature, - instructionSetFeatures)) - metaData += "isa_features:" + joinedFeatures + joined_features = ",".join( + name if present else "-" + name for name, present in instruction_set_features.items()) + meta_data += "isa_features:" + joined_features - metaDataString = "" - if metaData: - metaDataString = \ + meta_data_string = "" + if meta_data: + meta_data_string = \ """ begin_compilation name "%s" method "%s" date 1234 end_compilation - """ % (metaData, metaData) - c1String = metaDataString + \ - """ - begin_compilation - name "MyMethod" - method "MyMethod" - date 1234 - end_compilation - begin_cfg - name "MyPass" - """ + c1String + \ - """ - end_cfg - """ - checkerFile = ParseCheckerStream("<test-file>", "CHECK", io.StringIO(checkerString)) - c1File = ParseC1visualizerStream("<c1-file>", io.StringIO(c1String)) - assert len(checkerFile.testCases) == 1 - assert len(c1File.passes) == 1 - MatchTestCase(checkerFile.testCases[0], c1File.passes[0], c1File.instructionSetFeatures) - - def assertDoesNotMatch(self, checkerString, c1String, isa=None, instructionSetFeatures=None): + """ % (meta_data, meta_data) + c1_string = meta_data_string + \ + """ + begin_compilation + name "MyMethod" + method "MyMethod" + date 1234 + end_compilation + begin_cfg + name "MyPass" + """ + c1_string + \ + """ + end_cfg + """ + checker_file = parse_checker_stream("<test-file>", "CHECK", io.StringIO(checker_string)) + c1_file = parse_c1_visualizer_stream("<c1-file>", io.StringIO(c1_string)) + assert len(checker_file.test_cases) == 1 + assert len(c1_file.passes) == 1 + match_test_case(checker_file.test_cases[0], c1_file.passes[0], c1_file.instruction_set_features) + + def assertDoesNotMatch(self, checker_string, c1_string, isa=None, instruction_set_features=None): with self.assertRaises(MatchFailedException): - self.assertMatches(checkerString, c1String, isa, instructionSetFeatures) + self.assertMatches(checker_string, c1_string, isa, instruction_set_features) - def assertBadStructure(self, checkerString, c1String): + def assertBadStructure(self, checker_string, c1_string): with self.assertRaises(BadStructureException): - self.assertMatches(checkerString, c1String) + self.assertMatches(checker_string, c1_string) def test_Text(self): self.assertMatches("/// CHECK: foo bar", "foo bar") @@ -165,34 +165,34 @@ class MatchFiles_Test(unittest.TestCase): def test_Variables(self): self.assertMatches( - """ - /// CHECK: foo<<X:.>>bar - /// CHECK: abc<<X>>def - """, - """ - foo0bar - abc0def - """) - self.assertMatches( - """ - /// CHECK: foo<<X:([0-9]+)>>bar - /// CHECK: abc<<X>>def - /// CHECK: ### <<X>> ### - """, - """ - foo1234bar - abc1234def - ### 1234 ### - """) + """ + /// CHECK: foo<<X:.>>bar + /// CHECK: abc<<X>>def + """, + """ + foo0bar + abc0def + """) + self.assertMatches( + """ + /// CHECK: foo<<X:([0-9]+)>>bar + /// CHECK: abc<<X>>def + /// CHECK: ### <<X>> ### + """, + """ + foo1234bar + abc1234def + ### 1234 ### + """) self.assertDoesNotMatch( - """ - /// CHECK: foo<<X:([0-9]+)>>bar - /// CHECK: abc<<X>>def - """, - """ - foo1234bar - abc1235def - """) + """ + /// CHECK: foo<<X:([0-9]+)>>bar + /// CHECK: abc<<X>>def + """, + """ + foo1234bar + abc1235def + """) def test_WholeWordMustMatch(self): self.assertMatches("/// CHECK: b{{.}}r", "abc bar def") @@ -202,248 +202,248 @@ class MatchFiles_Test(unittest.TestCase): def test_InOrderStatements(self): self.assertMatches( - """ - /// CHECK: foo - /// CHECK: bar - """, - """ - foo - bar - """) + """ + /// CHECK: foo + /// CHECK: bar + """, + """ + foo + bar + """) self.assertDoesNotMatch( - """ - /// CHECK: foo - /// CHECK: bar - """, - """ - bar - foo - """) + """ + /// CHECK: foo + /// CHECK: bar + """, + """ + bar + foo + """) def test_NextLineStatements(self): self.assertMatches( - """ - /// CHECK: foo - /// CHECK-NEXT: bar - /// CHECK-NEXT: abc - /// CHECK: def - """, - """ - foo - bar - abc - def - """) - self.assertMatches( - """ - /// CHECK: foo - /// CHECK-NEXT: bar - /// CHECK: def - """, - """ - foo - bar - abc - def - """) + """ + /// CHECK: foo + /// CHECK-NEXT: bar + /// CHECK-NEXT: abc + /// CHECK: def + """, + """ + foo + bar + abc + def + """) + self.assertMatches( + """ + /// CHECK: foo + /// CHECK-NEXT: bar + /// CHECK: def + """, + """ + foo + bar + abc + def + """) self.assertDoesNotMatch( - """ - /// CHECK: foo - /// CHECK-NEXT: bar - """, - """ - foo - abc - bar - """) + """ + /// CHECK: foo + /// CHECK-NEXT: bar + """, + """ + foo + abc + bar + """) self.assertDoesNotMatch( - """ - /// CHECK: foo - /// CHECK-NEXT: bar - """, - """ - bar - foo - abc - """) + """ + /// CHECK: foo + /// CHECK-NEXT: bar + """, + """ + bar + foo + abc + """) def test_DagStatements(self): self.assertMatches( - """ - /// CHECK-DAG: foo - /// CHECK-DAG: bar - """, - """ - foo - bar - """) + """ + /// CHECK-DAG: foo + /// CHECK-DAG: bar + """, + """ + foo + bar + """) self.assertMatches( - """ - /// CHECK-DAG: foo - /// CHECK-DAG: bar - """, - """ - bar - foo - """) + """ + /// CHECK-DAG: foo + /// CHECK-DAG: bar + """, + """ + bar + foo + """) def test_DagStatementsScope(self): self.assertMatches( - """ - /// CHECK: foo - /// CHECK-DAG: abc - /// CHECK-DAG: def - /// CHECK: bar - """, - """ - foo - def - abc - bar - """) + """ + /// CHECK: foo + /// CHECK-DAG: abc + /// CHECK-DAG: def + /// CHECK: bar + """, + """ + foo + def + abc + bar + """) self.assertDoesNotMatch( - """ - /// CHECK: foo - /// CHECK-DAG: abc - /// CHECK-DAG: def - /// CHECK: bar - """, - """ - foo - abc - bar - def - """) + """ + /// CHECK: foo + /// CHECK-DAG: abc + /// CHECK-DAG: def + /// CHECK: bar + """, + """ + foo + abc + bar + def + """) self.assertDoesNotMatch( - """ - /// CHECK: foo - /// CHECK-DAG: abc - /// CHECK-DAG: def - /// CHECK: bar - """, - """ - foo - def - bar - abc - """) + """ + /// CHECK: foo + /// CHECK-DAG: abc + /// CHECK-DAG: def + /// CHECK: bar + """, + """ + foo + def + bar + abc + """) def test_NotStatements(self): self.assertMatches( - """ - /// CHECK-NOT: foo - """, - """ - abc - def - """) + """ + /// CHECK-NOT: foo + """, + """ + abc + def + """) self.assertDoesNotMatch( - """ - /// CHECK-NOT: foo - """, - """ - abc foo - def - """) + """ + /// CHECK-NOT: foo + """, + """ + abc foo + def + """) self.assertDoesNotMatch( - """ - /// CHECK-NOT: foo - /// CHECK-NOT: bar - """, - """ - abc - def bar - """) + """ + /// CHECK-NOT: foo + /// CHECK-NOT: bar + """, + """ + abc + def bar + """) def test_NotStatementsScope(self): self.assertMatches( - """ - /// CHECK: abc - /// CHECK-NOT: foo - /// CHECK: def - """, - """ - abc - def - """) - self.assertMatches( - """ - /// CHECK: abc - /// CHECK-NOT: foo - /// CHECK: def - """, - """ - abc - def - foo - """) + """ + /// CHECK: abc + /// CHECK-NOT: foo + /// CHECK: def + """, + """ + abc + def + """) + self.assertMatches( + """ + /// CHECK: abc + /// CHECK-NOT: foo + /// CHECK: def + """, + """ + abc + def + foo + """) self.assertDoesNotMatch( - """ - /// CHECK: abc - /// CHECK-NOT: foo - /// CHECK: def - """, - """ - abc - foo - def - """) + """ + /// CHECK: abc + /// CHECK-NOT: foo + /// CHECK: def + """, + """ + abc + foo + def + """) self.assertDoesNotMatch( - """ - /// CHECK-NOT: foo - /// CHECK-EVAL: 1 + 1 == 2 - /// CHECK: bar - """, - """ - foo - abc - bar - """); - self.assertMatches( - """ - /// CHECK-DAG: bar - /// CHECK-DAG: abc - /// CHECK-NOT: foo - """, - """ - foo - abc - bar - """); + """ + /// CHECK-NOT: foo + /// CHECK-EVAL: 1 + 1 == 2 + /// CHECK: bar + """, + """ + foo + abc + bar + """) + self.assertMatches( + """ + /// CHECK-DAG: bar + /// CHECK-DAG: abc + /// CHECK-NOT: foo + """, + """ + foo + abc + bar + """) self.assertDoesNotMatch( - """ - /// CHECK-DAG: abc - /// CHECK-DAG: foo - /// CHECK-NOT: bar - """, - """ - foo - abc - bar - """); + """ + /// CHECK-DAG: abc + /// CHECK-DAG: foo + /// CHECK-NOT: bar + """, + """ + foo + abc + bar + """) def test_LineOnlyMatchesOnce(self): self.assertMatches( - """ - /// CHECK-DAG: foo - /// CHECK-DAG: foo - """, - """ - foo - abc - foo - """) + """ + /// CHECK-DAG: foo + /// CHECK-DAG: foo + """, + """ + foo + abc + foo + """) self.assertDoesNotMatch( - """ - /// CHECK-DAG: foo - /// CHECK-DAG: foo - """, - """ - foo - abc - bar - """) + """ + /// CHECK-DAG: foo + /// CHECK-DAG: foo + """, + """ + foo + abc + bar + """) def test_EvalStatements(self): self.assertMatches("/// CHECK-EVAL: True", "foo") @@ -456,7 +456,7 @@ class MatchFiles_Test(unittest.TestCase): /// CHECK-DAG: <<X:\d+>> <<Y:\d+>> /// CHECK-EVAL: <<X>> > <<Y>> """ - self.assertMatches(twoVarTestCase, "42 41"); + self.assertMatches(twoVarTestCase, "42 41") self.assertDoesNotMatch(twoVarTestCase, "42 43") def test_MisplacedNext(self): @@ -498,378 +498,378 @@ class MatchFiles_Test(unittest.TestCase): def test_EnvVariableEval(self): self.assertMatches( - """ - /// CHECK-IF: os.environ.get('MARTY_MCFLY') != '89mph!' - /// CHECK-FI: - """, - """ - foo - """ + """ + /// CHECK-IF: os.environ.get('MARTY_MCFLY') != '89mph!' + /// CHECK-FI: + """, + """ + foo + """ ) self.assertMatches( - """ - /// CHECK-EVAL: os.environ.get('MARTY_MCFLY') != '89mph!' - """, - """ - foo - """ + """ + /// CHECK-EVAL: os.environ.get('MARTY_MCFLY') != '89mph!' + """, + """ + foo + """ ) def test_IfStatements(self): self.assertMatches( - """ - /// CHECK: foo1 - /// CHECK-IF: True - /// CHECK-NEXT: foo2 - /// CHECK-FI: - /// CHECK-NEXT: foo3 - /// CHECK-NEXT: bar - """, - """ - foo1 - foo2 - foo3 - bar - """) - self.assertMatches( - """ - /// CHECK: foo1 - /// CHECK-IF: False - /// CHECK-NEXT: foo2 - /// CHECK-FI: - /// CHECK-NEXT: bar - """, - """ - foo1 - bar - """) - self.assertMatches( - """ - /// CHECK: foo1 - /// CHECK-IF: True - /// CHECK-DAG: foo2 - /// CHECK-FI: - /// CHECK-DAG: bar - /// CHECK: foo3 - """, - """ - foo1 - bar - foo2 - foo3 - """) + """ + /// CHECK: foo1 + /// CHECK-IF: True + /// CHECK-NEXT: foo2 + /// CHECK-FI: + /// CHECK-NEXT: foo3 + /// CHECK-NEXT: bar + """, + """ + foo1 + foo2 + foo3 + bar + """) + self.assertMatches( + """ + /// CHECK: foo1 + /// CHECK-IF: False + /// CHECK-NEXT: foo2 + /// CHECK-FI: + /// CHECK-NEXT: bar + """, + """ + foo1 + bar + """) + self.assertMatches( + """ + /// CHECK: foo1 + /// CHECK-IF: True + /// CHECK-DAG: foo2 + /// CHECK-FI: + /// CHECK-DAG: bar + /// CHECK: foo3 + """, + """ + foo1 + bar + foo2 + foo3 + """) self.assertDoesNotMatch( - """ - /// CHECK: foo1 - /// CHECK-IF: False - /// CHECK-NEXT: foo2 - /// CHECK-FI: - /// CHECK-NEXT: foo3 - """, - """ - foo1 - foo2 - foo3 - """) + """ + /// CHECK: foo1 + /// CHECK-IF: False + /// CHECK-NEXT: foo2 + /// CHECK-FI: + /// CHECK-NEXT: foo3 + """, + """ + foo1 + foo2 + foo3 + """) def test_IfElseStatements(self): self.assertMatches( - """ - /// CHECK: foo1 - /// CHECK-IF: True - /// CHECK-NEXT: foo2 - /// CHECK-ELSE: - /// CHECK-NEXT: foo3 - /// CHECK-FI: - /// CHECK-NEXT: bar - """, - """ - foo1 - foo2 - bar - """) - self.assertMatches( - """ - /// CHECK: foo1 - /// CHECK-IF: False - /// CHECK-NEXT: foo2 - /// CHECK-ELSE: - /// CHECK-NEXT: foo3 - /// CHECK-FI: - /// CHECK-NEXT: bar - """, - """ - foo1 - foo3 - bar - """) - self.assertMatches( - """ - /// CHECK: foo1 - /// CHECK-IF: False - /// CHECK-NEXT: foo2 - /// CHECK-ELSE: - /// CHECK-DAG: bar - /// CHECK-FI: - /// CHECK-DAG: foo3 - /// CHECK: foo4 - """, - """ - foo1 - foo3 - bar - foo4 - """) + """ + /// CHECK: foo1 + /// CHECK-IF: True + /// CHECK-NEXT: foo2 + /// CHECK-ELSE: + /// CHECK-NEXT: foo3 + /// CHECK-FI: + /// CHECK-NEXT: bar + """, + """ + foo1 + foo2 + bar + """) + self.assertMatches( + """ + /// CHECK: foo1 + /// CHECK-IF: False + /// CHECK-NEXT: foo2 + /// CHECK-ELSE: + /// CHECK-NEXT: foo3 + /// CHECK-FI: + /// CHECK-NEXT: bar + """, + """ + foo1 + foo3 + bar + """) + self.assertMatches( + """ + /// CHECK: foo1 + /// CHECK-IF: False + /// CHECK-NEXT: foo2 + /// CHECK-ELSE: + /// CHECK-DAG: bar + /// CHECK-FI: + /// CHECK-DAG: foo3 + /// CHECK: foo4 + """, + """ + foo1 + foo3 + bar + foo4 + """) self.assertDoesNotMatch( - """ - /// CHECK: foo1 - /// CHECK-IF: False - /// CHECK-NEXT: foo2 - /// CHECK-ELSE: - /// CHECK-NEXT: foo3 - /// CHECK-FI: - /// CHECK-NEXT: bar - """, - """ - foo1 - foo2 - bar - """) + """ + /// CHECK: foo1 + /// CHECK-IF: False + /// CHECK-NEXT: foo2 + /// CHECK-ELSE: + /// CHECK-NEXT: foo3 + /// CHECK-FI: + /// CHECK-NEXT: bar + """, + """ + foo1 + foo2 + bar + """) def test_IfElifElseStatements(self): self.assertMatches( - """ - /// CHECK: foo1 - /// CHECK-IF: True - /// CHECK-NEXT: foo2 - /// CHECK-ELIF: True - /// CHECK-NEXT: foo3 - /// CHECK-ELIF: True - /// CHECK-NEXT: foo4 - /// CHECK-FI: - /// CHECK-NEXT: bar - """, - """ - foo1 - foo2 - bar - """) - self.assertMatches( - """ - /// CHECK: foo1 - /// CHECK-IF: False - /// CHECK-NEXT: foo2 - /// CHECK-ELIF: False - /// CHECK-NEXT: foo3 - /// CHECK-ELIF: True - /// CHECK-NEXT: foo4 - /// CHECK-FI: - /// CHECK-NEXT: bar - """, - """ - foo1 - foo4 - bar - """) - self.assertMatches( - """ - /// CHECK: foo1 - /// CHECK-IF: False - /// CHECK-NEXT: foo2 - /// CHECK-ELIF: True - /// CHECK-NEXT: foo3 - /// CHECK-ELIF: True - /// CHECK-NEXT: foo4 - /// CHECK-FI: - /// CHECK-NEXT: bar - """, - """ - foo1 - foo3 - bar - """) - self.assertMatches( - """ - /// CHECK: foo1 - /// CHECK-IF: False - /// CHECK-NEXT: foo2 - /// CHECK-ELIF: False - /// CHECK-NEXT: foo3 - /// CHECK-ELIF: False - /// CHECK-NEXT: foo4 - /// CHECK-FI: - /// CHECK-NEXT: bar - """, - """ - foo1 - bar - """) + """ + /// CHECK: foo1 + /// CHECK-IF: True + /// CHECK-NEXT: foo2 + /// CHECK-ELIF: True + /// CHECK-NEXT: foo3 + /// CHECK-ELIF: True + /// CHECK-NEXT: foo4 + /// CHECK-FI: + /// CHECK-NEXT: bar + """, + """ + foo1 + foo2 + bar + """) + self.assertMatches( + """ + /// CHECK: foo1 + /// CHECK-IF: False + /// CHECK-NEXT: foo2 + /// CHECK-ELIF: False + /// CHECK-NEXT: foo3 + /// CHECK-ELIF: True + /// CHECK-NEXT: foo4 + /// CHECK-FI: + /// CHECK-NEXT: bar + """, + """ + foo1 + foo4 + bar + """) + self.assertMatches( + """ + /// CHECK: foo1 + /// CHECK-IF: False + /// CHECK-NEXT: foo2 + /// CHECK-ELIF: True + /// CHECK-NEXT: foo3 + /// CHECK-ELIF: True + /// CHECK-NEXT: foo4 + /// CHECK-FI: + /// CHECK-NEXT: bar + """, + """ + foo1 + foo3 + bar + """) + self.assertMatches( + """ + /// CHECK: foo1 + /// CHECK-IF: False + /// CHECK-NEXT: foo2 + /// CHECK-ELIF: False + /// CHECK-NEXT: foo3 + /// CHECK-ELIF: False + /// CHECK-NEXT: foo4 + /// CHECK-FI: + /// CHECK-NEXT: bar + """, + """ + foo1 + bar + """) self.assertDoesNotMatch( - """ - /// CHECK: foo1 - /// CHECK-IF: False - /// CHECK-NEXT: foo2 - /// CHECK-ELIF: True - /// CHECK-NEXT: foo3 - /// CHECK-ELSE: - /// CHECK-NEXT: foo4 - /// CHECK-FI: - /// CHECK-NEXT: bar - """, - """ - foo1 - foo2 - bar - """) + """ + /// CHECK: foo1 + /// CHECK-IF: False + /// CHECK-NEXT: foo2 + /// CHECK-ELIF: True + /// CHECK-NEXT: foo3 + /// CHECK-ELSE: + /// CHECK-NEXT: foo4 + /// CHECK-FI: + /// CHECK-NEXT: bar + """, + """ + foo1 + foo2 + bar + """) def test_NestedBranching(self): self.assertMatches( - """ - /// CHECK: foo1 - /// CHECK-IF: True - /// CHECK-IF: True - /// CHECK-NEXT: foo2 - /// CHECK-ELSE: - /// CHECK-NEXT: foo3 - /// CHECK-FI: - /// CHECK-ELSE: - /// CHECK-IF: True - /// CHECK-NEXT: foo4 - /// CHECK-ELSE: - /// CHECK-NEXT: foo5 - /// CHECK-FI: - /// CHECK-FI: - /// CHECK-NEXT: foo6 - """, - """ - foo1 - foo2 - foo6 - """) - self.assertMatches( - """ - /// CHECK-IF: True - /// CHECK-IF: False - /// CHECK: foo1 - /// CHECK-ELSE: - /// CHECK: foo2 - /// CHECK-FI: - /// CHECK-ELSE: - /// CHECK-IF: True - /// CHECK: foo3 - /// CHECK-ELSE: - /// CHECK: foo4 - /// CHECK-FI: - /// CHECK-FI: - """, - """ - foo2 - """) - self.assertMatches( - """ - /// CHECK-IF: False - /// CHECK-IF: True - /// CHECK: foo1 - /// CHECK-ELSE: - /// CHECK: foo2 - /// CHECK-FI: - /// CHECK-ELSE: - /// CHECK-IF: False - /// CHECK: foo3 - /// CHECK-ELSE: - /// CHECK-IF: False - /// CHECK: foo4 - /// CHECK-ELSE: - /// CHECK: foo5 - /// CHECK-FI: - /// CHECK-FI: - /// CHECK-FI: - """, - """ - foo5 - """) + """ + /// CHECK: foo1 + /// CHECK-IF: True + /// CHECK-IF: True + /// CHECK-NEXT: foo2 + /// CHECK-ELSE: + /// CHECK-NEXT: foo3 + /// CHECK-FI: + /// CHECK-ELSE: + /// CHECK-IF: True + /// CHECK-NEXT: foo4 + /// CHECK-ELSE: + /// CHECK-NEXT: foo5 + /// CHECK-FI: + /// CHECK-FI: + /// CHECK-NEXT: foo6 + """, + """ + foo1 + foo2 + foo6 + """) + self.assertMatches( + """ + /// CHECK-IF: True + /// CHECK-IF: False + /// CHECK: foo1 + /// CHECK-ELSE: + /// CHECK: foo2 + /// CHECK-FI: + /// CHECK-ELSE: + /// CHECK-IF: True + /// CHECK: foo3 + /// CHECK-ELSE: + /// CHECK: foo4 + /// CHECK-FI: + /// CHECK-FI: + """, + """ + foo2 + """) + self.assertMatches( + """ + /// CHECK-IF: False + /// CHECK-IF: True + /// CHECK: foo1 + /// CHECK-ELSE: + /// CHECK: foo2 + /// CHECK-FI: + /// CHECK-ELSE: + /// CHECK-IF: False + /// CHECK: foo3 + /// CHECK-ELSE: + /// CHECK-IF: False + /// CHECK: foo4 + /// CHECK-ELSE: + /// CHECK: foo5 + /// CHECK-FI: + /// CHECK-FI: + /// CHECK-FI: + """, + """ + foo5 + """) self.assertDoesNotMatch( - """ - /// CHECK: foo1 - /// CHECK-IF: True - /// CHECK-IF: False - /// CHECK-NEXT: foo2 - /// CHECK-ELSE: - /// CHECK-NEXT: foo3 - /// CHECK-FI: - /// CHECK-NEXT: foo6 - """, - """ - foo1 - foo2 - foo6 - """) + """ + /// CHECK: foo1 + /// CHECK-IF: True + /// CHECK-IF: False + /// CHECK-NEXT: foo2 + /// CHECK-ELSE: + /// CHECK-NEXT: foo3 + /// CHECK-FI: + /// CHECK-NEXT: foo6 + """, + """ + foo1 + foo2 + foo6 + """) def test_VariablesInBranches(self): self.assertMatches( - """ - /// CHECK-IF: True - /// CHECK: foo<<VarA:\d+>> - /// CHECK-FI: - /// CHECK-EVAL: <<VarA>> == 12 - """, - """ - foo12 - """) + """ + /// CHECK-IF: True + /// CHECK: foo<<VarA:\d+>> + /// CHECK-FI: + /// CHECK-EVAL: <<VarA>> == 12 + """, + """ + foo12 + """) self.assertDoesNotMatch( - """ - /// CHECK-IF: True - /// CHECK: foo<<VarA:\d+>> - /// CHECK-FI: - /// CHECK-EVAL: <<VarA>> == 99 - """, - """ - foo12 - """) - self.assertMatches( - """ - /// CHECK-IF: True - /// CHECK: foo<<VarA:\d+>> - /// CHECK-IF: <<VarA>> == 12 - /// CHECK: bar<<VarB:M|N>> - /// CHECK-FI: - /// CHECK-FI: - /// CHECK-EVAL: "<<VarB>>" == "M" - """, - """ - foo12 - barM - """) - self.assertMatches( - """ - /// CHECK-IF: False - /// CHECK: foo<<VarA:\d+>> - /// CHECK-ELIF: True - /// CHECK: foo<<VarA:M|N>> - /// CHECK-FI: - /// CHECK-EVAL: "<<VarA>>" == "M" - """, - """ - fooM - """) - self.assertMatches( - """ - /// CHECK-IF: False - /// CHECK: foo<<VarA:A|B>> - /// CHECK-ELIF: False - /// CHECK: foo<<VarA:A|B>> - /// CHECK-ELSE: - /// CHECK-IF: False - /// CHECK: foo<<VarA:A|B>> - /// CHECK-ELSE: - /// CHECK: foo<<VarA:M|N>> - /// CHECK-FI: - /// CHECK-FI: - /// CHECK-EVAL: "<<VarA>>" == "N" - """, - """ - fooN - """) + """ + /// CHECK-IF: True + /// CHECK: foo<<VarA:\d+>> + /// CHECK-FI: + /// CHECK-EVAL: <<VarA>> == 99 + """, + """ + foo12 + """) + self.assertMatches( + """ + /// CHECK-IF: True + /// CHECK: foo<<VarA:\d+>> + /// CHECK-IF: <<VarA>> == 12 + /// CHECK: bar<<VarB:M|N>> + /// CHECK-FI: + /// CHECK-FI: + /// CHECK-EVAL: "<<VarB>>" == "M" + """, + """ + foo12 + barM + """) + self.assertMatches( + """ + /// CHECK-IF: False + /// CHECK: foo<<VarA:\d+>> + /// CHECK-ELIF: True + /// CHECK: foo<<VarA:M|N>> + /// CHECK-FI: + /// CHECK-EVAL: "<<VarA>>" == "M" + """, + """ + fooM + """) + self.assertMatches( + """ + /// CHECK-IF: False + /// CHECK: foo<<VarA:A|B>> + /// CHECK-ELIF: False + /// CHECK: foo<<VarA:A|B>> + /// CHECK-ELSE: + /// CHECK-IF: False + /// CHECK: foo<<VarA:A|B>> + /// CHECK-ELSE: + /// CHECK: foo<<VarA:M|N>> + /// CHECK-FI: + /// CHECK-FI: + /// CHECK-EVAL: "<<VarA>>" == "N" + """, + """ + fooN + """) def test_MalformedBranching(self): self.assertBadStructure( diff --git a/tools/checker/run_unit_tests.py b/tools/checker/run_unit_tests.py index 9bd3f53021..7611c2e553 100755 --- a/tools/checker/run_unit_tests.py +++ b/tools/checker/run_unit_tests.py @@ -14,18 +14,18 @@ # See the License for the specific language governing permissions and # limitations under the License. -from common.logger import Logger +from common.logger import Logger from file_format.c1visualizer.test import C1visualizerParser_Test -from file_format.checker.test import CheckerParser_PrefixTest, \ - CheckerParser_TestExpressionTest, \ - CheckerParser_FileLayoutTest, \ - CheckerParser_SuffixTests, \ - CheckerParser_EvalTests -from match.test import MatchLines_Test, \ - MatchFiles_Test +from file_format.checker.test import CheckerParser_PrefixTest, \ + CheckerParser_TestExpressionTest, \ + CheckerParser_FileLayoutTest, \ + CheckerParser_SuffixTests, \ + CheckerParser_EvalTests +from match.test import MatchLines_Test, \ + MatchFiles_Test import unittest -if __name__ == '__main__': +if __name__ == "__main__": Logger.Verbosity = Logger.Level.NO_OUTPUT unittest.main(verbosity=2) |