#============================================================ # 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('-') @className = if myOS.size == 2 if myOS[1] == 'mingw32' 1 else 0 end else 0 end end # Main function used to parse the file that was captured. def process(name) @testFlag = false @arrayList = [] 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