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