#============================================================ # Author: John Theofanopoulos # A simple parser. Takes the output files generated during the build process and # extracts information relating to the tests. # # Notes: # To capture an output file under VS builds use the following: # devenv [build instructions] > Output.txt & type Output.txt # # To capture an output file under GCC/Linux builds use the following: # make | tee Output.txt # # To use this parser use the following command # ruby parseOutput.rb [options] [file] # options: -xml : produce a JUnit compatible XML file # file : file to scan for results #============================================================ class ParseOutput # The following flag is set to true when a test is found or false otherwise. @testFlag @xmlOut @arrayList @totalTests @classIndex # Set the flag to indicate if there will be an XML output file or not def setXmlOutput() @xmlOut = true end # if write our output to XML def writeXmlOuput() output = File.open("report.xml", "w") output << "\n" @arrayList.each do |item| output << item << "\n" end output << "\n" end # This function will try and determine when the suite is changed. This is # is the name that gets added to the classname parameter. def testSuiteVerify(testSuiteName) if @testFlag == false @testFlag = true; # Split the path name testName = testSuiteName.split("/") # Remove the extension baseName = testName[testName.size - 1].split(".") @testSuite = "test." + baseName[0] printf "New Test: %s\n", @testSuite end end # Test was flagged as having passed so format the output def testPassed(array) lastItem = array.length - 1 testName = array[lastItem - 1] testSuiteVerify(array[@className]) printf "%-40s PASS\n", testName if @xmlOut == true @arrayList.push " " end end # Test was flagged as having passed so format the output. # This is using the Unity fixture output and not the original Unity output. def testPassedUnityFixture(array) testSuite = array[0].sub("TEST(", "") testSuite = testSuite.sub(",", "") testName = array[1].sub(")", "") if @xmlOut == true @arrayList.push " " end end # Test was flagged as being ingored so format the output def testIgnored(array) lastItem = array.length - 1 testName = array[lastItem - 2] reason = array[lastItem].chomp testSuiteVerify(array[@className]) printf "%-40s IGNORED\n", testName if testName.start_with? "TEST(" array2 = testName.split(" ") @testSuite = array2[0].sub("TEST(", "") @testSuite = @testSuite.sub(",", "") testName = array2[1].sub(")", "") end if @xmlOut == true @arrayList.push " " @arrayList.push " " + reason + " " @arrayList.push " " end end # Test was flagged as having failed so format the line def testFailed(array) lastItem = array.length - 1 testName = array[lastItem - 2] reason = array[lastItem].chomp + " at line: " + array[lastItem - 3] testSuiteVerify(array[@className]) printf "%-40s FAILED\n", testName if testName.start_with? "TEST(" array2 = testName.split(" ") @testSuite = array2[0].sub("TEST(", "") @testSuite = @testSuite.sub(",", "") testName = array2[1].sub(")", "") end if @xmlOut == true @arrayList.push " " @arrayList.push " " + reason + " " @arrayList.push " " end end # Figure out what OS we are running on. For now we are assuming if it's not Windows it must # be Unix based. def detectOS() myOS = RUBY_PLATFORM.split("-") if myOS.size == 2 if myOS[1] == "mingw32" @className = 1 else @className = 0 end else @className = 0 end end # Main function used to parse the file that was captured. def process(name) @testFlag = false @arrayList = Array.new detectOS() puts "Parsing file: " + name testPass = 0 testFail = 0 testIgnore = 0 puts "" puts "=================== RESULTS =====================" puts "" File.open(name).each do |line| # Typical test lines look like this: # /.c:36:test_tc1000_opsys:FAIL: Expected 1 Was 0 # /.c:112:test_tc5004_initCanChannel:IGNORE: Not Yet Implemented # /.c:115:test_tc5100_initCanVoidPtrs:PASS # # where path is different on Unix vs Windows devices (Windows leads with a drive letter) lineArray = line.split(":") lineSize = lineArray.size # If we were able to split the line then we can look to see if any of our target words # were found. Case is important. if ((lineSize >= 4) || (line.start_with? "TEST(")) # Determine if this test passed if line.include? ":PASS" testPassed(lineArray) testPass += 1 elsif line.include? ":FAIL:" testFailed(lineArray) testFail += 1 elsif line.include? ":IGNORE:" testIgnored(lineArray) testIgnore += 1 elsif line.start_with? "TEST(" if line.include? " PASS" lineArray = line.split(" ") testPassedUnityFixture(lineArray) testPass += 1 end # If none of the keywords are found there are no more tests for this suite so clear # the test flag else @testFlag = false end else @testFlag = false end end puts "" puts "=================== SUMMARY =====================" puts "" puts "Tests Passed : " + testPass.to_s puts "Tests Failed : " + testFail.to_s puts "Tests Ignored : " + testIgnore.to_s @totalTests = testPass + testFail + testIgnore if @xmlOut == true heading = "" @arrayList.insert(0, heading) writeXmlOuput() end # return result end end # If the command line has no values in, used a default value of Output.txt parseMyFile = ParseOutput.new if ARGV.size >= 1 ARGV.each do |a| if a == "-xml" parseMyFile.setXmlOutput(); else parseMyFile.process(a) break end end end