| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146 | import sysimport osfrom glob import globfrom pyparsing import *from junit_xml import TestSuite, TestCaseclass UnityTestSummary:    def __init__(self):        self.report = ''        self.total_tests = 0        self.failures = 0        self.ignored = 0        self.targets = 0        self.root = None        self.test_suites = dict()    def run(self):        # Clean up result file names        results = []        for target in self.targets:            results.append(target.replace('\\', '/'))        # Dig through each result file, looking for details on pass/fail:        for result_file in results:            lines = list(map(lambda line: line.rstrip(), open(result_file, "r").read().split('\n')))            if len(lines) == 0:                raise Exception("Empty test result file: %s" % result_file)            # define an expression for your file reference            entry_one = Combine(                oneOf(list(alphas)) + ':/' +                Word(alphanums + '_-./'))            entry_two = Word(printables + ' ', excludeChars=':')            entry = entry_one | entry_two            delimiter = Literal(':').suppress()            tc_result_line = Group(entry.setResultsName('tc_file_name') + delimiter + entry.setResultsName(                'tc_line_nr') + delimiter + entry.setResultsName('tc_name') + delimiter + entry.setResultsName(                'tc_status') + Optional(                delimiter + entry.setResultsName('tc_msg'))).setResultsName("tc_line")            eol = LineEnd().suppress()            sol = LineStart().suppress()            blank_line = sol + eol            tc_summary_line = Group(Word(nums).setResultsName("num_of_tests") + "Tests" + Word(nums).setResultsName(                "num_of_fail") + "Failures" + Word(nums).setResultsName("num_of_ignore") + "Ignored").setResultsName(                "tc_summary")            tc_end_line = Or(Literal("FAIL"), Literal('Ok')).setResultsName("tc_result")            # run it and see...            pp1 = tc_result_line | Optional(tc_summary_line | tc_end_line)            pp1.ignore(blank_line | OneOrMore("-"))            result = list()            for l in lines:                result.append((pp1.parseString(l)).asDict())            # delete empty results            result = filter(None, result)            tc_list = list()            for r in result:                if 'tc_line' in r:                    tmp_tc_line = r['tc_line']                    # get only the file name which will be used as the classname                    file_name = tmp_tc_line['tc_file_name'].split('\\').pop().split('/').pop().rsplit('.', 1)[0]                    tmp_tc = TestCase(name=tmp_tc_line['tc_name'], classname=file_name)                    if 'tc_status' in tmp_tc_line:                        if str(tmp_tc_line['tc_status']) == 'IGNORE':                            if 'tc_msg' in tmp_tc_line:                                tmp_tc.add_skipped_info(message=tmp_tc_line['tc_msg'],                                                        output=r'[File]={0}, [Line]={1}'.format(                                                            tmp_tc_line['tc_file_name'], tmp_tc_line['tc_line_nr']))                            else:                                tmp_tc.add_skipped_info(message=" ")                        elif str(tmp_tc_line['tc_status']) == 'FAIL':                            if 'tc_msg' in tmp_tc_line:                                tmp_tc.add_failure_info(message=tmp_tc_line['tc_msg'],                                                        output=r'[File]={0}, [Line]={1}'.format(                                                            tmp_tc_line['tc_file_name'], tmp_tc_line['tc_line_nr']))                            else:                                tmp_tc.add_failure_info(message=" ")                    tc_list.append((str(result_file), tmp_tc))            for k, v in tc_list:                try:                    self.test_suites[k].append(v)                except KeyError:                    self.test_suites[k] = [v]        ts = []        for suite_name in self.test_suites:            ts.append(TestSuite(suite_name, self.test_suites[suite_name]))        with open('result.xml', 'w') as f:            TestSuite.to_file(f, ts, prettyprint='True', encoding='utf-8')        return self.report    def set_targets(self, target_array):        self.targets = target_array    def set_root_path(self, path):        self.root = path    @staticmethod    def usage(err_msg=None):        print("\nERROR: ")        if err_msg:            print(err_msg)        print("\nUsage: unity_test_summary.py result_file_directory/ root_path/")        print("     result_file_directory - The location of your results files.")        print("                             Defaults to current directory if not specified.")        print("                             Should end in / if specified.")        print("     root_path - Helpful for producing more verbose output if using relative paths.")        sys.exit(1)if __name__ == '__main__':    uts = UnityTestSummary()    try:        # look in the specified or current directory for result files        if len(sys.argv) > 1:            targets_dir = sys.argv[1]        else:            targets_dir = './'        targets = list(map(lambda x: x.replace('\\', '/'), glob(targets_dir + '*.test*')))        if len(targets) == 0:            raise Exception("No *.testpass or *.testfail files found in '%s'" % targets_dir)        uts.set_targets(targets)        # set the root path        if len(sys.argv) > 2:            root_path = sys.argv[2]        else:            root_path = os.path.split(__file__)[0]        uts.set_root_path(root_path)        # run the summarizer        print(uts.run())    except Exception as e:        UnityTestSummary.usage(e)
 |