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