parseOutput.rb 7.6 KB

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