#============================================================
# 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