parseOutput.rb revision 290001
1#============================================================
2#  Author:   John Theofanopoulos
3#  A simple parser.   Takes the output files generated during the build process and
4# extracts information relating to the tests.  
5#
6#  Notes:
7#    To capture an output file under VS builds use the following:
8#      devenv [build instructions]  > Output.txt & type Output.txt
9# 
10#    To capture an output file under GCC/Linux builds use the following:
11#      make | tee Output.txt
12#
13#    To use this parser use the following command
14#    ruby parseOutput.rb [options] [file]
15#        options:  -xml  : produce a JUnit compatible XML file
16#        file      :  file to scan for results
17#============================================================
18
19
20class ParseOutput
21# The following flag is set to true when a test is found or false otherwise.
22    @testFlag
23    @xmlOut
24    @arrayList
25    @totalTests
26    @classIndex
27
28#   Set the flag to indicate if there will be an XML output file or not  
29    def setXmlOutput()
30        @xmlOut = true
31    end
32    
33#  if write our output to XML
34    def writeXmlOuput()
35            output = File.open("report.xml", "w")
36            output << "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n"
37            @arrayList.each do |item|
38                output << item << "\n"
39            end
40            output << "</testsuite>\n"
41    end
42    
43#  This function will try and determine when the suite is changed.   This is
44# is the name that gets added to the classname parameter.
45    def  testSuiteVerify(testSuiteName)
46        if @testFlag == false
47            @testFlag = true;
48            # Split the path name 
49            testName = testSuiteName.split("/")
50            # Remove the extension
51            baseName = testName[testName.size - 1].split(".")
52            @testSuite = "test." + baseName[0]
53            printf "New Test: %s\n", @testSuite
54        end
55    end
56    
57
58# Test was flagged as having passed so format the output
59    def testPassed(array)
60        lastItem = array.length - 1
61        testName = array[lastItem - 1]
62        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