1# -*- coding: utf-8 -*- 2 3import shlex 4import xml.dom.minidom 5 6class StatusCode: 7 PASS = 'Pass' 8 FAIL = 'Fail' 9 QUALITY_WARNING = 'QualityWarning' 10 COMPATIBILITY_WARNING = 'CompatibilityWarning' 11 PENDING = 'Pending' 12 NOT_SUPPORTED = 'NotSupported' 13 RESOURCE_ERROR = 'ResourceError' 14 INTERNAL_ERROR = 'InternalError' 15 CRASH = 'Crash' 16 TIMEOUT = 'Timeout' 17 18 STATUS_CODES = [ 19 PASS, 20 FAIL, 21 QUALITY_WARNING, 22 COMPATIBILITY_WARNING, 23 PENDING, 24 NOT_SUPPORTED, 25 RESOURCE_ERROR, 26 INTERNAL_ERROR, 27 CRASH, 28 TIMEOUT 29 ] 30 STATUS_CODE_SET = set(STATUS_CODES) 31 32 @staticmethod 33 def isValid (code): 34 return code in StatusCode.STATUS_CODE_SET 35 36class TestCaseResult: 37 def __init__ (self, name, statusCode, statusDetails, log): 38 self.name = name 39 self.statusCode = statusCode 40 self.statusDetails = statusDetails 41 self.log = log 42 43 def __str__ (self): 44 return "%s: %s (%s)" % (self.name, self.statusCode, self.statusDetails) 45 46class ParseError(Exception): 47 def __init__ (self, filename, line, message): 48 self.filename = filename 49 self.line = line 50 self.message = message 51 52 def __str__ (self): 53 return "%s:%d: %s" % (self.filename, self.line, self.message) 54 55def splitContainerLine (line): 56 return shlex.split(line) 57 58def getNodeText (node): 59 rc = [] 60 for node in node.childNodes: 61 if node.nodeType == node.TEXT_NODE: 62 rc.append(node.data) 63 return ''.join(rc) 64 65class BatchResultParser: 66 def __init__ (self): 67 pass 68 69 def parseFile (self, filename): 70 self.init(filename) 71 72 f = open(filename, 'rb') 73 for line in f: 74 self.parseLine(line) 75 self.curLine += 1 76 f.close() 77 78 return self.testCaseResults 79 80 def init (self, filename): 81 # Results 82 self.sessionInfo = [] 83 self.testCaseResults = [] 84 85 # State 86 self.curResultText = None 87 self.curCaseName = None 88 89 # Error context 90 self.curLine = 1 91 self.filename = filename 92 93 def parseLine (self, line): 94 if len(line) > 0 and line[0] == '#': 95 self.parseContainerLine(line) 96 elif self.curResultText != None: 97 self.curResultText += line 98 # else: just ignored 99 100 def parseContainerLine (self, line): 101 args = splitContainerLine(line) 102 if args[0] == "#sessionInfo": 103 if len(args) < 3: 104 print args 105 self.parseError("Invalid #sessionInfo") 106 self.sessionInfo.append((args[1], ' '.join(args[2:]))) 107 elif args[0] == "#beginSession" or args[0] == "#endSession": 108 pass # \todo [pyry] Validate 109 elif args[0] == "#beginTestCaseResult": 110 if len(args) != 2 or self.curCaseName != None: 111 self.parseError("Invalid #beginTestCaseResult") 112 self.curCaseName = args[1] 113 self.curResultText = "" 114 elif args[0] == "#endTestCaseResult": 115 if len(args) != 1 or self.curCaseName == None: 116 self.parseError("Invalid #endTestCaseResult") 117 self.parseTestCaseResult(self.curCaseName, self.curResultText) 118 self.curCaseName = None 119 self.curResultText = None 120 elif args[0] == "#terminateTestCaseResult": 121 if len(args) < 2 or self.curCaseName == None: 122 self.parseError("Invalid #terminateTestCaseResult") 123 statusCode = ' '.join(args[1:]) 124 statusDetails = statusCode 125 126 if not StatusCode.isValid(statusCode): 127 # Legacy format 128 if statusCode == "Watchdog timeout occurred.": 129 statusCode = StatusCode.TIMEOUT 130 else: 131 statusCode = StatusCode.CRASH 132 133 # Do not try to parse at all since XML is likely broken 134 self.testCaseResults.append(TestCaseResult(self.curCaseName, statusCode, statusDetails, self.curResultText)) 135 136 self.curCaseName = None 137 self.curResultText = None 138 else: 139 # Assume this is result text 140 if self.curResultText != None: 141 self.curResultText += line 142 143 def parseTestCaseResult (self, name, log): 144 try: 145 doc = xml.dom.minidom.parseString(log) 146 resultItems = doc.getElementsByTagName('Result') 147 if len(resultItems) != 1: 148 self.parseError("Expected 1 <Result>, found %d" % len(resultItems)) 149 150 statusCode = resultItems[0].getAttributeNode('StatusCode').nodeValue 151 statusDetails = getNodeText(resultItems[0]) 152 except Exception as e: 153 statusCode = TestStatusCode.INTERNAL_ERROR 154 statusDetails = "XML parsing failed: %s" % str(e) 155 156 self.testCaseResults.append(TestCaseResult(name, statusCode, statusDetails, log)) 157 158 def parseError (self, message): 159 raise ParseError(self.filename, self.curLine, message) 160