1*9034852cSGleb Smirnoff#============================================================ 2*9034852cSGleb Smirnoff# Author: John Theofanopoulos 3*9034852cSGleb Smirnoff# A simple parser. Takes the output files generated during the build process and 4*9034852cSGleb Smirnoff# extracts information relating to the tests. 5*9034852cSGleb Smirnoff# 6*9034852cSGleb Smirnoff# Notes: 7*9034852cSGleb Smirnoff# To capture an output file under VS builds use the following: 8*9034852cSGleb Smirnoff# devenv [build instructions] > Output.txt & type Output.txt 9*9034852cSGleb Smirnoff# 10*9034852cSGleb Smirnoff# To capture an output file under GCC/Linux builds use the following: 11*9034852cSGleb Smirnoff# make | tee Output.txt 12*9034852cSGleb Smirnoff# 13*9034852cSGleb Smirnoff# To use this parser use the following command 14*9034852cSGleb Smirnoff# ruby parseOutput.rb [options] [file] 15*9034852cSGleb Smirnoff# options: -xml : produce a JUnit compatible XML file 16*9034852cSGleb Smirnoff# file : file to scan for results 17*9034852cSGleb Smirnoff#============================================================ 18*9034852cSGleb Smirnoff 19*9034852cSGleb Smirnoff 20*9034852cSGleb Smirnoffclass ParseOutput 21*9034852cSGleb Smirnoff# The following flag is set to true when a test is found or false otherwise. 22*9034852cSGleb Smirnoff @testFlag 23*9034852cSGleb Smirnoff @xmlOut 24*9034852cSGleb Smirnoff @arrayList 25*9034852cSGleb Smirnoff @totalTests 26*9034852cSGleb Smirnoff @classIndex 27*9034852cSGleb Smirnoff 28*9034852cSGleb Smirnoff# Set the flag to indicate if there will be an XML output file or not 29*9034852cSGleb Smirnoff def setXmlOutput() 30*9034852cSGleb Smirnoff @xmlOut = true 31*9034852cSGleb Smirnoff end 32*9034852cSGleb Smirnoff 33*9034852cSGleb Smirnoff# if write our output to XML 34*9034852cSGleb Smirnoff def writeXmlOuput() 35*9034852cSGleb Smirnoff output = File.open("report.xml", "w") 36*9034852cSGleb Smirnoff output << "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n" 37*9034852cSGleb Smirnoff @arrayList.each do |item| 38*9034852cSGleb Smirnoff output << item << "\n" 39*9034852cSGleb Smirnoff end 40*9034852cSGleb Smirnoff output << "</testsuite>\n" 41*9034852cSGleb Smirnoff end 42*9034852cSGleb Smirnoff 43*9034852cSGleb Smirnoff# This function will try and determine when the suite is changed. This is 44*9034852cSGleb Smirnoff# is the name that gets added to the classname parameter. 45*9034852cSGleb Smirnoff def testSuiteVerify(testSuiteName) 46*9034852cSGleb Smirnoff if @testFlag == false 47*9034852cSGleb Smirnoff @testFlag = true; 48*9034852cSGleb Smirnoff # Split the path name 49*9034852cSGleb Smirnoff testName = testSuiteName.split("/") 50*9034852cSGleb Smirnoff # Remove the extension 51*9034852cSGleb Smirnoff baseName = testName[testName.size - 1].split(".") 52*9034852cSGleb Smirnoff @testSuite = "test." + baseName[0] 53*9034852cSGleb Smirnoff printf "New Test: %s\n", @testSuite 54*9034852cSGleb Smirnoff end 55*9034852cSGleb Smirnoff end 56*9034852cSGleb Smirnoff 57*9034852cSGleb Smirnoff 58*9034852cSGleb Smirnoff# Test was flagged as having passed so format the output 59*9034852cSGleb Smirnoff def testPassed(array) 60*9034852cSGleb Smirnoff lastItem = array.length - 1 61*9034852cSGleb Smirnoff testName = array[lastItem - 1] 62*9034852cSGleb Smirnoff testSuiteVerify(array[@className]) 63*9034852cSGleb Smirnoff printf "%-40s PASS\n", testName 64*9034852cSGleb Smirnoff if @xmlOut == true 65*9034852cSGleb Smirnoff @arrayList.push " <testcase classname=\"" + @testSuite + "\" name=\"" + testName + "\"/>" 66*9034852cSGleb Smirnoff end 67*9034852cSGleb Smirnoff end 68*9034852cSGleb Smirnoff 69*9034852cSGleb Smirnoff# Test was flagged as being ingored so format the output 70*9034852cSGleb Smirnoff def testIgnored(array) 71*9034852cSGleb Smirnoff lastItem = array.length - 1 72*9034852cSGleb Smirnoff testName = array[lastItem - 2] 73*9034852cSGleb Smirnoff reason = array[lastItem].chomp 74*9034852cSGleb Smirnoff testSuiteVerify(array[@className]) 75*9034852cSGleb Smirnoff printf "%-40s IGNORED\n", testName 76*9034852cSGleb Smirnoff if @xmlOut == true 77*9034852cSGleb Smirnoff @arrayList.push " <testcase classname=\"" + @testSuite + "\" name=\"" + testName + "\">" 78*9034852cSGleb Smirnoff @arrayList.push " <skipped type=\"TEST IGNORED\"> " + reason + " </skipped>" 79*9034852cSGleb Smirnoff @arrayList.push " </testcase>" 80*9034852cSGleb Smirnoff end 81*9034852cSGleb Smirnoff end 82*9034852cSGleb Smirnoff 83*9034852cSGleb Smirnoff# Test was flagged as having failed so format the line 84*9034852cSGleb Smirnoff def testFailed(array) 85*9034852cSGleb Smirnoff lastItem = array.length - 1 86*9034852cSGleb Smirnoff testName = array[lastItem - 2] 87*9034852cSGleb Smirnoff reason = array[lastItem].chomp + " at line: " + array[lastItem - 3] 88*9034852cSGleb Smirnoff testSuiteVerify(array[@className]) 89*9034852cSGleb Smirnoff printf "%-40s FAILED\n", testName 90*9034852cSGleb Smirnoff if @xmlOut == true 91*9034852cSGleb Smirnoff @arrayList.push " <testcase classname=\"" + @testSuite + "\" name=\"" + testName + "\">" 92*9034852cSGleb Smirnoff @arrayList.push " <failure type=\"ASSERT FAILED\"> " + reason + " </failure>" 93*9034852cSGleb Smirnoff @arrayList.push " </testcase>" 94*9034852cSGleb Smirnoff end 95*9034852cSGleb Smirnoff end 96*9034852cSGleb Smirnoff 97*9034852cSGleb Smirnoff 98*9034852cSGleb Smirnoff# Figure out what OS we are running on. For now we are assuming if it's not Windows it must 99*9034852cSGleb Smirnoff# be Unix based. 100*9034852cSGleb Smirnoff def detectOS() 101*9034852cSGleb Smirnoff myOS = RUBY_PLATFORM.split("-") 102*9034852cSGleb Smirnoff if myOS.size == 2 103*9034852cSGleb Smirnoff if myOS[1] == "mingw32" 104*9034852cSGleb Smirnoff @className = 1 105*9034852cSGleb Smirnoff else 106*9034852cSGleb Smirnoff @className = 0 107*9034852cSGleb Smirnoff end 108*9034852cSGleb Smirnoff else 109*9034852cSGleb Smirnoff @className = 0 110*9034852cSGleb Smirnoff end 111*9034852cSGleb Smirnoff 112*9034852cSGleb Smirnoff end 113*9034852cSGleb Smirnoff 114*9034852cSGleb Smirnoff# Main function used to parse the file that was captured. 115*9034852cSGleb Smirnoff def process(name) 116*9034852cSGleb Smirnoff @testFlag = false 117*9034852cSGleb Smirnoff @arrayList = Array.new 118*9034852cSGleb Smirnoff 119*9034852cSGleb Smirnoff detectOS() 120*9034852cSGleb Smirnoff 121*9034852cSGleb Smirnoff puts "Parsing file: " + name 122*9034852cSGleb Smirnoff 123*9034852cSGleb Smirnoff 124*9034852cSGleb Smirnoff testPass = 0 125*9034852cSGleb Smirnoff testFail = 0 126*9034852cSGleb Smirnoff testIgnore = 0 127*9034852cSGleb Smirnoff puts "" 128*9034852cSGleb Smirnoff puts "=================== RESULTS =====================" 129*9034852cSGleb Smirnoff puts "" 130*9034852cSGleb Smirnoff File.open(name).each do |line| 131*9034852cSGleb Smirnoff # Typical test lines look like this: 132*9034852cSGleb Smirnoff # <path>/<test_file>.c:36:test_tc1000_opsys:FAIL: Expected 1 Was 0 133*9034852cSGleb Smirnoff # <path>/<test_file>.c:112:test_tc5004_initCanChannel:IGNORE: Not Yet Implemented 134*9034852cSGleb Smirnoff # <path>/<test_file>.c:115:test_tc5100_initCanVoidPtrs:PASS 135*9034852cSGleb Smirnoff # 136*9034852cSGleb Smirnoff # where path is different on Unix vs Windows devices (Windows leads with a drive letter) 137*9034852cSGleb Smirnoff lineArray = line.split(":") 138*9034852cSGleb Smirnoff lineSize = lineArray.size 139*9034852cSGleb Smirnoff # If we were able to split the line then we can look to see if any of our target words 140*9034852cSGleb Smirnoff # were found. Case is important. 141*9034852cSGleb Smirnoff if lineSize >= 4 142*9034852cSGleb Smirnoff # Determine if this test passed 143*9034852cSGleb Smirnoff if line.include? ":PASS" 144*9034852cSGleb Smirnoff testPassed(lineArray) 145*9034852cSGleb Smirnoff testPass += 1 146*9034852cSGleb Smirnoff elsif line.include? ":FAIL:" 147*9034852cSGleb Smirnoff testFailed(lineArray) 148*9034852cSGleb Smirnoff testFail += 1 149*9034852cSGleb Smirnoff elsif line.include? ":IGNORE:" 150*9034852cSGleb Smirnoff testIgnored(lineArray) 151*9034852cSGleb Smirnoff testIgnore += 1 152*9034852cSGleb Smirnoff # If none of the keywords are found there are no more tests for this suite so clear 153*9034852cSGleb Smirnoff # the test flag 154*9034852cSGleb Smirnoff else 155*9034852cSGleb Smirnoff @testFlag = false 156*9034852cSGleb Smirnoff end 157*9034852cSGleb Smirnoff else 158*9034852cSGleb Smirnoff @testFlag = false 159*9034852cSGleb Smirnoff end 160*9034852cSGleb Smirnoff end 161*9034852cSGleb Smirnoff puts "" 162*9034852cSGleb Smirnoff puts "=================== SUMMARY =====================" 163*9034852cSGleb Smirnoff puts "" 164*9034852cSGleb Smirnoff puts "Tests Passed : " + testPass.to_s 165*9034852cSGleb Smirnoff puts "Tests Failed : " + testFail.to_s 166*9034852cSGleb Smirnoff puts "Tests Ignored : " + testIgnore.to_s 167*9034852cSGleb Smirnoff @totalTests = testPass + testFail + testIgnore 168*9034852cSGleb Smirnoff if @xmlOut == true 169*9034852cSGleb Smirnoff heading = "<testsuite tests=\"" + @totalTests.to_s + "\" failures=\"" + testFail.to_s + "\"" + " skips=\"" + testIgnore.to_s + "\">" 170*9034852cSGleb Smirnoff @arrayList.insert(0, heading) 171*9034852cSGleb Smirnoff writeXmlOuput() 172*9034852cSGleb Smirnoff end 173*9034852cSGleb Smirnoff 174*9034852cSGleb Smirnoff # return result 175*9034852cSGleb Smirnoff end 176*9034852cSGleb Smirnoff 177*9034852cSGleb Smirnoff end 178*9034852cSGleb Smirnoff 179*9034852cSGleb Smirnoff# If the command line has no values in, used a default value of Output.txt 180*9034852cSGleb SmirnoffparseMyFile = ParseOutput.new 181*9034852cSGleb Smirnoff 182*9034852cSGleb Smirnoffif ARGV.size >= 1 183*9034852cSGleb Smirnoff ARGV.each do |a| 184*9034852cSGleb Smirnoff if a == "-xml" 185*9034852cSGleb Smirnoff parseMyFile.setXmlOutput(); 186*9034852cSGleb Smirnoff else 187*9034852cSGleb Smirnoff parseMyFile.process(a) 188*9034852cSGleb Smirnoff break 189*9034852cSGleb Smirnoff end 190*9034852cSGleb Smirnoff end 191*9034852cSGleb Smirnoffend 192