#
# Copyright (c) 2009 Nokia Corporation and/or its subsidiary(-ies).
# All rights reserved.
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU Lesser General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU Lesser General Public License for more details.
#
# You should have received a copy of the GNU Lesser General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
# RTestParser represents the results of running an RTest testsuite on the target in terms of RTest
# objects. Each RTest object captures the LineTimeInfo associated with the test and can determine
# whether the test errored, failed or passed. It also provides further information such as the name of
# the test and how long it took to gather the output from the test (which is a crude estimate of how long
# it took to run the test. It can provide various useful bits of information like the line number in the
# raw test data of a given line and the 'context' of a failure (in terms of the lines in the raw data).
import sys
import re
import qemuruntest
startRTestPattern = re.compile('RTEST TITLE:')
bmSuiteFailurePattern = re.compile('Error:')
endRTestPattern = re.compile('RUNTESTS: Test')
failedRTestPattern = re.compile('RUNTESTS: Test .* FAIL')
erroredRTestPattern = re.compile('RUNTESTS: Test .* ERROR')
nameRTestPattern = re.compile('RUNTESTS: Test (\w+)')
testSuiteEndingPattern = re.compile('RUNTESTS: Elapsed')
class NoRTestsFound(Exception):
def __init__(self, parser):
self.parser = parser
def __str__(self):
return "No test results found in output from running '%s' rom image" % (self.parser.GetRomName())
def GetParser(self):
return self.parser
class RTestEndMissing(Exception):
def __init__(self, rtest):
self.rtest = rtest
def __str__(self):
return "Could not find end of test started on line %d: '%s'" % (self.rtest.GetLineNumber(0), self.rtest.GetLine(0))
def GetParser(self):
return self.parser
def GetIndex(self):
return self.index
class RTestNameMissing(Exception):
def __init__(self, rtest, line):
self.rtest = rtest
self.line = line
def GetRTest(self):
return self.rtest
def __str__(self):
return "Could not find RTest name in line '%s'" % (self.line)
def GetParser(self):
return self.parser
def GetLine(self):
return self.line
class RTest(object):
def __init__(self, parser, lineTimeInfo, startLine = 0):
"""return new RTest instance"""
self.parser = parser
self.lineTimeInfoList = []
self.lineTimeInfoList.append(lineTimeInfo)
self.timeTaken = None
self.result = None
self.name = None
self.startLine = startLine
#line = lineTimeInfo.GetLine()
#print >> sys.stdout, line
def __str__(self):
return self.GetName() + " " + self.GetResult()
def Consume(self,lineTimeInfoList, start):
newStart = start;
for i in range(start, len(lineTimeInfoList) - 1):
lineTimeInfo = lineTimeInfoList[i]
self.lineTimeInfoList.append(lineTimeInfo)
line = lineTimeInfo.GetLine()
newStart = newStart + 1
if self.EndOfTestp(line):
break
else:
raise RTestEndMissing(self)
return newStart
def EndOfTestp(self,line):
return re.match(endRTestPattern, line) != None
def FailedTestp(self,line):
return re.match(failedRTestPattern, line) != None
def ErroredTestp(self,line):
return re.match(erroredRTestPattern, line) != None
def GetTimeTaken(self):
if self.timeTaken == None:
self.timeTaken = self.lineTimeInfoList[-1].GetTime() - self.lineTimeInfoList[0].GetTime()
return self.timeTaken
def GetResult(self):
if self.result == None:
line = self.lineTimeInfoList[-1].GetLine()
if self.FailedTestp(line):
self.result = 'Failed'
elif self.ErroredTestp(line):
self.result = 'Errored'
else:
self.result = 'Passed'
return self.result
def Failedp(self):
return self.GetResult() == 'Failed'
def Erroredp(self):
return self.GetResult() == 'Errored'
def Passedp(self):
return self.GetResult() == 'Passed'
def GetName(self):
if self.name == None:
try:
self.name = self.ParseName()
except RTestNameMissing, x:
print >> sys.stderr, "WARNING: ", x
self.name = "RTEST @ line %d" % (x.GetRTest().GetLineNumber(0))
return self.name
def ParseName(self):
line = self.lineTimeInfoList[-1].GetLine()
m = re.match(nameRTestPattern, line)
if m != None:
return m.group(1)
else:
raise RTestNameMissing(self, line)
def GetLineNumber(self, i):
return self.startLine + i
def GetLine(self, index):
return self.lineTimeInfoList[index].GetLine()
def ErrorContext(self):
if self.Failedp():
return map(qemuruntest.LineTimeInfo.GetLine, self.lineTimeInfoList[-5:-1])
else:
return []
class RTestParser(object):
def __init__(self, testRunner, lineTimeInfoList = None):
self.testRunner = testRunner
if lineTimeInfoList == None:
self.lineTimeInfoList = testRunner.GetResults()
else:
self.lineTimeInfoList = lineTimeInfoList
self.rtestList = []
self.result = None
def Parse(self):
index = 0
end = len(self.lineTimeInfoList)
self.rtestList = []
testSuiteComplete = False
testErroredp = False
# find first test
while index < end:
lineTimeInfo = self.lineTimeInfoList[index]
index += 1;
line = lineTimeInfo.GetLine()
if self.StartOfTestp(line):
break
if self.ErroredTestp(line):
self.rtestList.append(RTest(self, lineTimeInfo, index-1))
else:
raise NoRTestsFound(self)
try:
while index < end:
# NB making startLine index means that line number are based at 1 rather than 0
rtest = RTest(self, lineTimeInfo, startLine = index)
self.rtestList.append(rtest)
index = rtest.Consume(self.lineTimeInfoList, index)
if self.TestSuiteEnding(self.lineTimeInfoList[index].GetLine()):
testSuiteComplete = True
break
while index < end:
lineTimeInfo = self.lineTimeInfoList[index]
index += 1;
line = lineTimeInfo.GetLine()
if self.StartOfTestp(line):
break
if self.ErroredTestp(line):
self.rtestList.append(RTest(self, lineTimeInfo, startLine = index))
except RTestEndMissing, x:
print >> sys.stderr, "WARNING: ", x
return testSuiteComplete
def StartOfTestp(self,line):
if re.match(startRTestPattern, line) != None:
return True
if re.match(bmSuiteFailurePattern, line) != None:
return True
return False
def ErroredTestp(self,line):
if re.match(erroredRTestPattern, line) != None:
return True
def TestSuiteEnding(self,line):
return re.match(testSuiteEndingPattern, line) != None
def GetRTests(self):
return self.rtestList
def GetLine(self,index):
return self.lineTimeInfoList[index]
def GetRomName(self):
return self.testRunner.GetRomName()