parseOutput.rb revision 289997
1174199Srwatson#============================================================
2174199Srwatson#  Author:   John Theofanopoulos
3174199Srwatson#  A simple parser.   Takes the output files generated during the build process and
4174199Srwatson# extracts information relating to the tests.  
5174199Srwatson#
6174199Srwatson#  Notes:
7174199Srwatson#    To capture an output file under VS builds use the following:
8174199Srwatson#      devenv [build instructions]  > Output.txt & type Output.txt
9174199Srwatson# 
10174199Srwatson#    To capture an output file under GCC/Linux builds use the following:
11174199Srwatson#      make | tee Output.txt
12174199Srwatson#
13174199Srwatson#    To use this parser use the following command
14174199Srwatson#    ruby parseOutput.rb [options] [file]
15174199Srwatson#        options:  -xml  : produce a JUnit compatible XML file
16174199Srwatson#        file      :  file to scan for results
17174199Srwatson#============================================================
18174199Srwatson
19174199Srwatson
20174199Srwatsonclass ParseOutput
21174199Srwatson# The following flag is set to true when a test is found or false otherwise.
22174199Srwatson    @testFlag
23174199Srwatson    @xmlOut
24174199Srwatson    @arrayList
25174199Srwatson    @totalTests
26174199Srwatson    @classIndex
27174199Srwatson
28174199Srwatson#   Set the flag to indicate if there will be an XML output file or not  
29186567Srwatson    def setXmlOutput()
30174199Srwatson        @xmlOut = true
31174530Srwatson    end
32174199Srwatson    
33174199Srwatson#  if write our output to XML
34174199Srwatson    def writeXmlOuput()
35221807Sstas            output = File.open("report.xml", "w")
36174199Srwatson            output << "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n"
37174199Srwatson            @arrayList.each do |item|
38174199Srwatson                output << item << "\n"
39174199Srwatson            end
40174199Srwatson            output << "</testsuite>\n"
41174199Srwatson    end
42174199Srwatson    
43249678Strociny#  This function will try and determine when the suite is changed.   This is
44174199Srwatson# is the name that gets added to the classname parameter.
45249678Strociny    def  testSuiteVerify(testSuiteName)
46249678Strociny        if @testFlag == false
47174199Srwatson            @testFlag = true;
48174199Srwatson            # Split the path name 
49233390Strociny            testName = testSuiteName.split("/")
50174199Srwatson            # Remove the extension
51249678Strociny            baseName = testName[testName.size - 1].split(".")
52174199Srwatson            @testSuite = "test." + baseName[0]
53249678Strociny            printf "New Test: %s\n", @testSuite
54174199Srwatson        end
55249678Strociny    end
56233390Strociny    
57233390Strociny
58221807Sstas# Test was flagged as having passed so format the output
59174530Srwatson    def testPassed(array)
60233390Strociny        lastItem = array.length - 1
61174199Srwatson        testName = array[lastItem - 1]
62174199Srwatson        testSuiteVerify(array[@className])
63        printf "%-40s PASS\n", testName
64        if @xmlOut == true
65            @arrayList.push "     <testcase classname=\"" + @testSuite + "\" name=\"" + testName + "\"/>"
66        end          
67    end
68
69# Test was flagged as being ingored so format the output
70    def testIgnored(array)
71        lastItem = array.length - 1
72        testName = array[lastItem - 2]
73        reason = array[lastItem].chomp
74        testSuiteVerify(array[@className])
75        printf "%-40s IGNORED\n", testName
76        if @xmlOut == true
77            @arrayList.push "     <testcase classname=\"" + @testSuite + "\" name=\"" + testName + "\">"
78            @arrayList.push "            <skipped type=\"TEST IGNORED\"> " + reason + " </skipped>"
79            @arrayList.push "     </testcase>"
80        end          
81    end
82
83# Test was flagged as having failed  so format the line
84    def testFailed(array)
85        lastItem = array.length - 1
86        testName = array[lastItem - 2]
87        reason = array[lastItem].chomp + " at line: " + array[lastItem - 3]
88        testSuiteVerify(array[@className])
89        printf "%-40s FAILED\n", testName
90        if @xmlOut == true
91            @arrayList.push "     <testcase classname=\"" + @testSuite + "\" name=\"" + testName + "\">"
92            @arrayList.push "            <failure type=\"ASSERT FAILED\"> " + reason + " </failure>"
93            @arrayList.push "     </testcase>"
94        end          
95    end
96
97    
98# Figure out what OS we are running on.   For now we are assuming if it's not Windows it must
99# be Unix based.  
100    def detectOS()
101        myOS = RUBY_PLATFORM.split("-")
102        if myOS.size == 2
103            if myOS[1] == "mingw32"
104                @className = 1
105            else
106                @className = 0
107            end
108	else
109                @className = 0
110        end
111        
112    end
113
114# Main function used to parse the file that was captured.
115    def process(name)
116        @testFlag = false
117        @arrayList = Array.new
118
119        detectOS()
120
121        puts "Parsing file: " + name
122    
123      
124        testPass = 0
125        testFail = 0
126        testIgnore = 0
127        puts ""
128        puts "=================== RESULTS ====================="
129        puts ""
130        File.open(name).each do |line|
131        # Typical test lines look like this:
132        # <path>/<test_file>.c:36:test_tc1000_opsys:FAIL: Expected 1 Was 0
133        # <path>/<test_file>.c:112:test_tc5004_initCanChannel:IGNORE: Not Yet Implemented
134        # <path>/<test_file>.c:115:test_tc5100_initCanVoidPtrs:PASS
135        #
136        # where path is different on Unix vs Windows devices (Windows leads with a drive letter)
137            lineArray = line.split(":")
138            lineSize = lineArray.size
139            # If we were able to split the line then we can look to see if any of our target words
140            # were found.  Case is important.
141            if lineSize >= 4
142                # Determine if this test passed
143                if  line.include? ":PASS"
144                    testPassed(lineArray)
145                    testPass += 1
146                elsif line.include? ":FAIL:"
147                    testFailed(lineArray)
148                    testFail += 1
149                elsif line.include? ":IGNORE:"
150                    testIgnored(lineArray)
151                    testIgnore += 1
152                # If none of the keywords are found there are no more tests for this suite so clear
153                # the test flag
154                else
155                    @testFlag = false
156                end
157            else
158                @testFlag = false
159                end
160            end
161        puts ""
162        puts "=================== SUMMARY ====================="
163        puts ""
164        puts "Tests Passed  : " + testPass.to_s
165        puts "Tests Failed  : " + testFail.to_s
166        puts "Tests Ignored : " + testIgnore.to_s
167        @totalTests = testPass + testFail + testIgnore
168        if @xmlOut == true
169            heading = "<testsuite tests=\"" +  @totalTests.to_s  + "\" failures=\"" + testFail.to_s + "\""  + " skips=\"" +  testIgnore.to_s + "\">" 
170            @arrayList.insert(0, heading) 
171            writeXmlOuput()
172        end
173
174    #  return result
175    end
176
177 end
178
179# If the command line has no values in, used a default value of Output.txt
180parseMyFile = ParseOutput.new
181
182if ARGV.size >= 1 
183    ARGV.each do |a|
184        if a == "-xml"
185            parseMyFile.setXmlOutput();
186        else
187            parseMyFile.process(a)
188            break
189        end
190    end
191end
192