1*4882a593Smuzhiyun#!/usr/bin/env python3 2*4882a593Smuzhiyun 3*4882a593Smuzhiyunfrom enum import Enum 4*4882a593Smuzhiyun 5*4882a593Smuzhiyunclass ResultState(Enum): 6*4882a593Smuzhiyun noresult = -1 7*4882a593Smuzhiyun skip = 0 8*4882a593Smuzhiyun success = 1 9*4882a593Smuzhiyun fail = 2 10*4882a593Smuzhiyun 11*4882a593Smuzhiyunclass TestResult: 12*4882a593Smuzhiyun def __init__(self, test_id="", test_name=""): 13*4882a593Smuzhiyun self.test_id = test_id 14*4882a593Smuzhiyun self.test_name = test_name 15*4882a593Smuzhiyun self.result = ResultState.noresult 16*4882a593Smuzhiyun self.failmsg = "" 17*4882a593Smuzhiyun self.errormsg = "" 18*4882a593Smuzhiyun self.steps = [] 19*4882a593Smuzhiyun 20*4882a593Smuzhiyun def set_result(self, result): 21*4882a593Smuzhiyun if (isinstance(result, ResultState)): 22*4882a593Smuzhiyun self.result = result 23*4882a593Smuzhiyun return True 24*4882a593Smuzhiyun else: 25*4882a593Smuzhiyun raise TypeError('Unknown result type, must be type ResultState') 26*4882a593Smuzhiyun 27*4882a593Smuzhiyun def get_result(self): 28*4882a593Smuzhiyun return self.result 29*4882a593Smuzhiyun 30*4882a593Smuzhiyun def set_errormsg(self, errormsg): 31*4882a593Smuzhiyun self.errormsg = errormsg 32*4882a593Smuzhiyun return True 33*4882a593Smuzhiyun 34*4882a593Smuzhiyun def append_errormsg(self, errormsg): 35*4882a593Smuzhiyun self.errormsg = '{}\n{}'.format(self.errormsg, errormsg) 36*4882a593Smuzhiyun 37*4882a593Smuzhiyun def get_errormsg(self): 38*4882a593Smuzhiyun return self.errormsg 39*4882a593Smuzhiyun 40*4882a593Smuzhiyun def set_failmsg(self, failmsg): 41*4882a593Smuzhiyun self.failmsg = failmsg 42*4882a593Smuzhiyun return True 43*4882a593Smuzhiyun 44*4882a593Smuzhiyun def append_failmsg(self, failmsg): 45*4882a593Smuzhiyun self.failmsg = '{}\n{}'.format(self.failmsg, failmsg) 46*4882a593Smuzhiyun 47*4882a593Smuzhiyun def get_failmsg(self): 48*4882a593Smuzhiyun return self.failmsg 49*4882a593Smuzhiyun 50*4882a593Smuzhiyun def add_steps(self, newstep): 51*4882a593Smuzhiyun if type(newstep) == list: 52*4882a593Smuzhiyun self.steps.extend(newstep) 53*4882a593Smuzhiyun elif type(newstep) == str: 54*4882a593Smuzhiyun self.steps.append(step) 55*4882a593Smuzhiyun else: 56*4882a593Smuzhiyun raise TypeError('TdcResults.add_steps() requires a list or str') 57*4882a593Smuzhiyun 58*4882a593Smuzhiyun def get_executed_steps(self): 59*4882a593Smuzhiyun return self.steps 60*4882a593Smuzhiyun 61*4882a593Smuzhiyunclass TestSuiteReport(): 62*4882a593Smuzhiyun _testsuite = [] 63*4882a593Smuzhiyun 64*4882a593Smuzhiyun def add_resultdata(self, result_data): 65*4882a593Smuzhiyun if isinstance(result_data, TestResult): 66*4882a593Smuzhiyun self._testsuite.append(result_data) 67*4882a593Smuzhiyun return True 68*4882a593Smuzhiyun 69*4882a593Smuzhiyun def count_tests(self): 70*4882a593Smuzhiyun return len(self._testsuite) 71*4882a593Smuzhiyun 72*4882a593Smuzhiyun def count_failures(self): 73*4882a593Smuzhiyun return sum(1 for t in self._testsuite if t.result == ResultState.fail) 74*4882a593Smuzhiyun 75*4882a593Smuzhiyun def count_skips(self): 76*4882a593Smuzhiyun return sum(1 for t in self._testsuite if t.result == ResultState.skip) 77*4882a593Smuzhiyun 78*4882a593Smuzhiyun def find_result(self, test_id): 79*4882a593Smuzhiyun return next((tr for tr in self._testsuite if tr.test_id == test_id), None) 80*4882a593Smuzhiyun 81*4882a593Smuzhiyun def update_result(self, result_data): 82*4882a593Smuzhiyun orig = self.find_result(result_data.test_id) 83*4882a593Smuzhiyun if orig != None: 84*4882a593Smuzhiyun idx = self._testsuite.index(orig) 85*4882a593Smuzhiyun self._testsuite[idx] = result_data 86*4882a593Smuzhiyun else: 87*4882a593Smuzhiyun self.add_resultdata(result_data) 88*4882a593Smuzhiyun 89*4882a593Smuzhiyun def format_tap(self): 90*4882a593Smuzhiyun ftap = "" 91*4882a593Smuzhiyun ftap += '1..{}\n'.format(self.count_tests()) 92*4882a593Smuzhiyun index = 1 93*4882a593Smuzhiyun for t in self._testsuite: 94*4882a593Smuzhiyun if t.result == ResultState.fail: 95*4882a593Smuzhiyun ftap += 'not ' 96*4882a593Smuzhiyun ftap += 'ok {} {} - {}'.format(str(index), t.test_id, t.test_name) 97*4882a593Smuzhiyun if t.result == ResultState.skip or t.result == ResultState.noresult: 98*4882a593Smuzhiyun ftap += ' # skipped - {}\n'.format(t.errormsg) 99*4882a593Smuzhiyun elif t.result == ResultState.fail: 100*4882a593Smuzhiyun if len(t.steps) > 0: 101*4882a593Smuzhiyun ftap += '\tCommands executed in this test case:' 102*4882a593Smuzhiyun for step in t.steps: 103*4882a593Smuzhiyun ftap += '\n\t\t{}'.format(step) 104*4882a593Smuzhiyun ftap += '\n\t{}'.format(t.failmsg) 105*4882a593Smuzhiyun ftap += '\n' 106*4882a593Smuzhiyun index += 1 107*4882a593Smuzhiyun return ftap 108*4882a593Smuzhiyun 109*4882a593Smuzhiyun def format_xunit(self): 110*4882a593Smuzhiyun from xml.sax.saxutils import escape 111*4882a593Smuzhiyun xunit = "<testsuites>\n" 112*4882a593Smuzhiyun xunit += '\t<testsuite tests=\"{}\" skips=\"{}\">\n'.format(self.count_tests(), self.count_skips()) 113*4882a593Smuzhiyun for t in self._testsuite: 114*4882a593Smuzhiyun xunit += '\t\t<testcase classname=\"{}\" '.format(escape(t.test_id)) 115*4882a593Smuzhiyun xunit += 'name=\"{}\">\n'.format(escape(t.test_name)) 116*4882a593Smuzhiyun if t.failmsg: 117*4882a593Smuzhiyun xunit += '\t\t\t<failure>\n' 118*4882a593Smuzhiyun if len(t.steps) > 0: 119*4882a593Smuzhiyun xunit += 'Commands executed in this test case:\n' 120*4882a593Smuzhiyun for step in t.steps: 121*4882a593Smuzhiyun xunit += '\t{}\n'.format(escape(step)) 122*4882a593Smuzhiyun xunit += 'FAILURE: {}\n'.format(escape(t.failmsg)) 123*4882a593Smuzhiyun xunit += '\t\t\t</failure>\n' 124*4882a593Smuzhiyun if t.errormsg: 125*4882a593Smuzhiyun xunit += '\t\t\t<error>\n{}\n'.format(escape(t.errormsg)) 126*4882a593Smuzhiyun xunit += '\t\t\t</error>\n' 127*4882a593Smuzhiyun if t.result == ResultState.skip: 128*4882a593Smuzhiyun xunit += '\t\t\t<skipped/>\n' 129*4882a593Smuzhiyun xunit += '\t\t</testcase>\n' 130*4882a593Smuzhiyun xunit += '\t</testsuite>\n' 131*4882a593Smuzhiyun xunit += '</testsuites>\n' 132*4882a593Smuzhiyun return xunit 133