• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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