tools/e32test-driver/rtest.py
changeset 34 92d87f2e53c2
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/tools/e32test-driver/rtest.py	Fri Jan 15 09:07:44 2010 +0000
@@ -0,0 +1,246 @@
+#
+# 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()