unity_test_summary.py 5.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139
  1. #! python3
  2. # ==========================================
  3. # Unity Project - A Test Framework for C
  4. # Copyright (c) 2015 Alexander Mueller / XelaRellum@web.de
  5. # [Released under MIT License. Please refer to license.txt for details]
  6. # Based on the ruby script by Mike Karlesky, Mark VanderVoord, Greg Williams
  7. # ==========================================
  8. import sys
  9. import os
  10. import re
  11. from glob import glob
  12. class UnityTestSummary:
  13. def __init__(self):
  14. self.report = ''
  15. self.total_tests = 0
  16. self.failures = 0
  17. self.ignored = 0
  18. def run(self):
  19. # Clean up result file names
  20. results = []
  21. for target in self.targets:
  22. results.append(target.replace('\\', '/'))
  23. # Dig through each result file, looking for details on pass/fail:
  24. failure_output = []
  25. ignore_output = []
  26. for result_file in results:
  27. lines = list(map(lambda line: line.rstrip(), open(result_file, "r").read().split('\n')))
  28. if len(lines) == 0:
  29. raise Exception("Empty test result file: %s" % result_file)
  30. details = self.get_details(result_file, lines)
  31. failures = details['failures']
  32. ignores = details['ignores']
  33. if len(failures) > 0: failure_output.append('\n'.join(failures))
  34. if len(ignores) > 0: ignore_output.append('n'.join(ignores))
  35. tests,failures,ignored = self.parse_test_summary('\n'.join(lines))
  36. self.total_tests += tests
  37. self.failures += failures
  38. self.ignored += ignored
  39. if self.ignored > 0:
  40. self.report += "\n"
  41. self.report += "--------------------------\n"
  42. self.report += "UNITY IGNORED TEST SUMMARY\n"
  43. self.report += "--------------------------\n"
  44. self.report += "\n".join(ignore_output)
  45. if self.failures > 0:
  46. self.report += "\n"
  47. self.report += "--------------------------\n"
  48. self.report += "UNITY FAILED TEST SUMMARY\n"
  49. self.report += "--------------------------\n"
  50. self.report += '\n'.join(failure_output)
  51. self.report += "\n"
  52. self.report += "--------------------------\n"
  53. self.report += "OVERALL UNITY TEST SUMMARY\n"
  54. self.report += "--------------------------\n"
  55. self.report += "{total_tests} TOTAL TESTS {failures} TOTAL FAILURES {ignored} IGNORED\n".format(total_tests = self.total_tests, failures=self.failures, ignored=self.ignored)
  56. self.report += "\n"
  57. return self.report
  58. def set_targets(self, target_array):
  59. self.targets = target_array
  60. def set_root_path(self, path):
  61. self.root = path
  62. def usage(self, err_msg=None):
  63. print("\nERROR: ")
  64. if err_msg:
  65. print(err_msg)
  66. print("\nUsage: unity_test_summary.py result_file_directory/ root_path/")
  67. print(" result_file_directory - The location of your results files.")
  68. print(" Defaults to current directory if not specified.")
  69. print(" Should end in / if specified.")
  70. print(" root_path - Helpful for producing more verbose output if using relative paths.")
  71. sys.exit(1)
  72. def get_details(self, result_file, lines):
  73. results = { 'failures': [], 'ignores': [], 'successes': [] }
  74. for line in lines:
  75. parts = line.split(':')
  76. if len(parts) == 5:
  77. src_file,src_line,test_name,status,msg = parts
  78. elif len(parts) == 4:
  79. src_file,src_line,test_name,status = parts
  80. msg = ''
  81. else:
  82. continue
  83. if len(self.root) > 0:
  84. line_out = "%s%s" % (self.root, line)
  85. else:
  86. line_out = line
  87. if status == 'IGNORE':
  88. results['ignores'].append(line_out)
  89. elif status == 'FAIL':
  90. results['failures'].append(line_out)
  91. elif status == 'PASS':
  92. results['successes'].append(line_out)
  93. return results
  94. def parse_test_summary(self, summary):
  95. m = re.search(r"([0-9]+) Tests ([0-9]+) Failures ([0-9]+) Ignored", summary)
  96. if not m:
  97. raise Exception("Couldn't parse test results: %s" % summary)
  98. return int(m.group(1)), int(m.group(2)), int(m.group(3))
  99. if __name__ == '__main__':
  100. uts = UnityTestSummary()
  101. try:
  102. #look in the specified or current directory for result files
  103. if len(sys.argv) > 1:
  104. targets_dir = sys.argv[1]
  105. else:
  106. targets_dir = './'
  107. targets = list(map(lambda x: x.replace('\\', '/'), glob(targets_dir + '*.test*')))
  108. if len(targets) == 0:
  109. raise Exception("No *.testpass or *.testfail files found in '%s'" % targets_dir)
  110. uts.set_targets(targets)
  111. #set the root path
  112. if len(sys.argv) > 2:
  113. root_path = sys.argv[2]
  114. else:
  115. root_path = os.path.split(__file__)[0]
  116. uts.set_root_path(root_path)
  117. #run the summarizer
  118. print(uts.run())
  119. except Exception as e:
  120. uts.usage(e)