17db96d56Sopenharmony_ci'''Test runner and result class for the regression test suite. 27db96d56Sopenharmony_ci 37db96d56Sopenharmony_ci''' 47db96d56Sopenharmony_ci 57db96d56Sopenharmony_ciimport functools 67db96d56Sopenharmony_ciimport io 77db96d56Sopenharmony_ciimport sys 87db96d56Sopenharmony_ciimport time 97db96d56Sopenharmony_ciimport traceback 107db96d56Sopenharmony_ciimport unittest 117db96d56Sopenharmony_ci 127db96d56Sopenharmony_ciclass RegressionTestResult(unittest.TextTestResult): 137db96d56Sopenharmony_ci USE_XML = False 147db96d56Sopenharmony_ci 157db96d56Sopenharmony_ci def __init__(self, stream, descriptions, verbosity): 167db96d56Sopenharmony_ci super().__init__(stream=stream, descriptions=descriptions, 177db96d56Sopenharmony_ci verbosity=2 if verbosity else 0) 187db96d56Sopenharmony_ci self.buffer = True 197db96d56Sopenharmony_ci if self.USE_XML: 207db96d56Sopenharmony_ci from xml.etree import ElementTree as ET 217db96d56Sopenharmony_ci from datetime import datetime 227db96d56Sopenharmony_ci self.__ET = ET 237db96d56Sopenharmony_ci self.__suite = ET.Element('testsuite') 247db96d56Sopenharmony_ci self.__suite.set('start', datetime.utcnow().isoformat(' ')) 257db96d56Sopenharmony_ci self.__e = None 267db96d56Sopenharmony_ci self.__start_time = None 277db96d56Sopenharmony_ci 287db96d56Sopenharmony_ci @classmethod 297db96d56Sopenharmony_ci def __getId(cls, test): 307db96d56Sopenharmony_ci try: 317db96d56Sopenharmony_ci test_id = test.id 327db96d56Sopenharmony_ci except AttributeError: 337db96d56Sopenharmony_ci return str(test) 347db96d56Sopenharmony_ci try: 357db96d56Sopenharmony_ci return test_id() 367db96d56Sopenharmony_ci except TypeError: 377db96d56Sopenharmony_ci return str(test_id) 387db96d56Sopenharmony_ci return repr(test) 397db96d56Sopenharmony_ci 407db96d56Sopenharmony_ci def startTest(self, test): 417db96d56Sopenharmony_ci super().startTest(test) 427db96d56Sopenharmony_ci if self.USE_XML: 437db96d56Sopenharmony_ci self.__e = e = self.__ET.SubElement(self.__suite, 'testcase') 447db96d56Sopenharmony_ci self.__start_time = time.perf_counter() 457db96d56Sopenharmony_ci 467db96d56Sopenharmony_ci def _add_result(self, test, capture=False, **args): 477db96d56Sopenharmony_ci if not self.USE_XML: 487db96d56Sopenharmony_ci return 497db96d56Sopenharmony_ci e = self.__e 507db96d56Sopenharmony_ci self.__e = None 517db96d56Sopenharmony_ci if e is None: 527db96d56Sopenharmony_ci return 537db96d56Sopenharmony_ci ET = self.__ET 547db96d56Sopenharmony_ci 557db96d56Sopenharmony_ci e.set('name', args.pop('name', self.__getId(test))) 567db96d56Sopenharmony_ci e.set('status', args.pop('status', 'run')) 577db96d56Sopenharmony_ci e.set('result', args.pop('result', 'completed')) 587db96d56Sopenharmony_ci if self.__start_time: 597db96d56Sopenharmony_ci e.set('time', f'{time.perf_counter() - self.__start_time:0.6f}') 607db96d56Sopenharmony_ci 617db96d56Sopenharmony_ci if capture: 627db96d56Sopenharmony_ci if self._stdout_buffer is not None: 637db96d56Sopenharmony_ci stdout = self._stdout_buffer.getvalue().rstrip() 647db96d56Sopenharmony_ci ET.SubElement(e, 'system-out').text = stdout 657db96d56Sopenharmony_ci if self._stderr_buffer is not None: 667db96d56Sopenharmony_ci stderr = self._stderr_buffer.getvalue().rstrip() 677db96d56Sopenharmony_ci ET.SubElement(e, 'system-err').text = stderr 687db96d56Sopenharmony_ci 697db96d56Sopenharmony_ci for k, v in args.items(): 707db96d56Sopenharmony_ci if not k or not v: 717db96d56Sopenharmony_ci continue 727db96d56Sopenharmony_ci e2 = ET.SubElement(e, k) 737db96d56Sopenharmony_ci if hasattr(v, 'items'): 747db96d56Sopenharmony_ci for k2, v2 in v.items(): 757db96d56Sopenharmony_ci if k2: 767db96d56Sopenharmony_ci e2.set(k2, str(v2)) 777db96d56Sopenharmony_ci else: 787db96d56Sopenharmony_ci e2.text = str(v2) 797db96d56Sopenharmony_ci else: 807db96d56Sopenharmony_ci e2.text = str(v) 817db96d56Sopenharmony_ci 827db96d56Sopenharmony_ci @classmethod 837db96d56Sopenharmony_ci def __makeErrorDict(cls, err_type, err_value, err_tb): 847db96d56Sopenharmony_ci if isinstance(err_type, type): 857db96d56Sopenharmony_ci if err_type.__module__ == 'builtins': 867db96d56Sopenharmony_ci typename = err_type.__name__ 877db96d56Sopenharmony_ci else: 887db96d56Sopenharmony_ci typename = f'{err_type.__module__}.{err_type.__name__}' 897db96d56Sopenharmony_ci else: 907db96d56Sopenharmony_ci typename = repr(err_type) 917db96d56Sopenharmony_ci 927db96d56Sopenharmony_ci msg = traceback.format_exception(err_type, err_value, None) 937db96d56Sopenharmony_ci tb = traceback.format_exception(err_type, err_value, err_tb) 947db96d56Sopenharmony_ci 957db96d56Sopenharmony_ci return { 967db96d56Sopenharmony_ci 'type': typename, 977db96d56Sopenharmony_ci 'message': ''.join(msg), 987db96d56Sopenharmony_ci '': ''.join(tb), 997db96d56Sopenharmony_ci } 1007db96d56Sopenharmony_ci 1017db96d56Sopenharmony_ci def addError(self, test, err): 1027db96d56Sopenharmony_ci self._add_result(test, True, error=self.__makeErrorDict(*err)) 1037db96d56Sopenharmony_ci super().addError(test, err) 1047db96d56Sopenharmony_ci 1057db96d56Sopenharmony_ci def addExpectedFailure(self, test, err): 1067db96d56Sopenharmony_ci self._add_result(test, True, output=self.__makeErrorDict(*err)) 1077db96d56Sopenharmony_ci super().addExpectedFailure(test, err) 1087db96d56Sopenharmony_ci 1097db96d56Sopenharmony_ci def addFailure(self, test, err): 1107db96d56Sopenharmony_ci self._add_result(test, True, failure=self.__makeErrorDict(*err)) 1117db96d56Sopenharmony_ci super().addFailure(test, err) 1127db96d56Sopenharmony_ci 1137db96d56Sopenharmony_ci def addSkip(self, test, reason): 1147db96d56Sopenharmony_ci self._add_result(test, skipped=reason) 1157db96d56Sopenharmony_ci super().addSkip(test, reason) 1167db96d56Sopenharmony_ci 1177db96d56Sopenharmony_ci def addSuccess(self, test): 1187db96d56Sopenharmony_ci self._add_result(test) 1197db96d56Sopenharmony_ci super().addSuccess(test) 1207db96d56Sopenharmony_ci 1217db96d56Sopenharmony_ci def addUnexpectedSuccess(self, test): 1227db96d56Sopenharmony_ci self._add_result(test, outcome='UNEXPECTED_SUCCESS') 1237db96d56Sopenharmony_ci super().addUnexpectedSuccess(test) 1247db96d56Sopenharmony_ci 1257db96d56Sopenharmony_ci def get_xml_element(self): 1267db96d56Sopenharmony_ci if not self.USE_XML: 1277db96d56Sopenharmony_ci raise ValueError("USE_XML is false") 1287db96d56Sopenharmony_ci e = self.__suite 1297db96d56Sopenharmony_ci e.set('tests', str(self.testsRun)) 1307db96d56Sopenharmony_ci e.set('errors', str(len(self.errors))) 1317db96d56Sopenharmony_ci e.set('failures', str(len(self.failures))) 1327db96d56Sopenharmony_ci return e 1337db96d56Sopenharmony_ci 1347db96d56Sopenharmony_ciclass QuietRegressionTestRunner: 1357db96d56Sopenharmony_ci def __init__(self, stream, buffer=False): 1367db96d56Sopenharmony_ci self.result = RegressionTestResult(stream, None, 0) 1377db96d56Sopenharmony_ci self.result.buffer = buffer 1387db96d56Sopenharmony_ci 1397db96d56Sopenharmony_ci def run(self, test): 1407db96d56Sopenharmony_ci test(self.result) 1417db96d56Sopenharmony_ci return self.result 1427db96d56Sopenharmony_ci 1437db96d56Sopenharmony_cidef get_test_runner_class(verbosity, buffer=False): 1447db96d56Sopenharmony_ci if verbosity: 1457db96d56Sopenharmony_ci return functools.partial(unittest.TextTestRunner, 1467db96d56Sopenharmony_ci resultclass=RegressionTestResult, 1477db96d56Sopenharmony_ci buffer=buffer, 1487db96d56Sopenharmony_ci verbosity=verbosity) 1497db96d56Sopenharmony_ci return functools.partial(QuietRegressionTestRunner, buffer=buffer) 1507db96d56Sopenharmony_ci 1517db96d56Sopenharmony_cidef get_test_runner(stream, verbosity, capture_output=False): 1527db96d56Sopenharmony_ci return get_test_runner_class(verbosity, capture_output)(stream) 1537db96d56Sopenharmony_ci 1547db96d56Sopenharmony_ciif __name__ == '__main__': 1557db96d56Sopenharmony_ci import xml.etree.ElementTree as ET 1567db96d56Sopenharmony_ci RegressionTestResult.USE_XML = True 1577db96d56Sopenharmony_ci 1587db96d56Sopenharmony_ci class TestTests(unittest.TestCase): 1597db96d56Sopenharmony_ci def test_pass(self): 1607db96d56Sopenharmony_ci pass 1617db96d56Sopenharmony_ci 1627db96d56Sopenharmony_ci def test_pass_slow(self): 1637db96d56Sopenharmony_ci time.sleep(1.0) 1647db96d56Sopenharmony_ci 1657db96d56Sopenharmony_ci def test_fail(self): 1667db96d56Sopenharmony_ci print('stdout', file=sys.stdout) 1677db96d56Sopenharmony_ci print('stderr', file=sys.stderr) 1687db96d56Sopenharmony_ci self.fail('failure message') 1697db96d56Sopenharmony_ci 1707db96d56Sopenharmony_ci def test_error(self): 1717db96d56Sopenharmony_ci print('stdout', file=sys.stdout) 1727db96d56Sopenharmony_ci print('stderr', file=sys.stderr) 1737db96d56Sopenharmony_ci raise RuntimeError('error message') 1747db96d56Sopenharmony_ci 1757db96d56Sopenharmony_ci suite = unittest.TestSuite() 1767db96d56Sopenharmony_ci suite.addTest(unittest.TestLoader().loadTestsFromTestCase(TestTests)) 1777db96d56Sopenharmony_ci stream = io.StringIO() 1787db96d56Sopenharmony_ci runner_cls = get_test_runner_class(sum(a == '-v' for a in sys.argv)) 1797db96d56Sopenharmony_ci runner = runner_cls(sys.stdout) 1807db96d56Sopenharmony_ci result = runner.run(suite) 1817db96d56Sopenharmony_ci print('Output:', stream.getvalue()) 1827db96d56Sopenharmony_ci print('XML: ', end='') 1837db96d56Sopenharmony_ci for s in ET.tostringlist(result.get_xml_element()): 1847db96d56Sopenharmony_ci print(s.decode(), end='') 1857db96d56Sopenharmony_ci print() 186