From 05acfa601822fc27d3fb00431130f0f61372eb3b Mon Sep 17 00:00:00 2001 From: Ekaterina Tuzova Date: Mon, 4 Aug 2014 15:30:49 +0400 Subject: [PATCH] fixed PY-12496 Unittest test runner: support subtests --- python/helpers/pycharm/tcunittest.py | 76 +++++++++++++++++----------- 1 file changed, 47 insertions(+), 29 deletions(-) diff --git a/python/helpers/pycharm/tcunittest.py b/python/helpers/pycharm/tcunittest.py index 4f245ba3199a..15e9416b0a84 100644 --- a/python/helpers/pycharm/tcunittest.py +++ b/python/helpers/pycharm/tcunittest.py @@ -6,14 +6,16 @@ from tcmessages import TeamcityServiceMessages PYTHON_VERSION_MAJOR = sys.version_info[0] + def strclass(cls): if not cls.__name__: return cls.__module__ return "%s.%s" % (cls.__module__, cls.__name__) + def smart_str(s): - encoding='utf-8' - errors='strict' + encoding = 'utf-8' + errors = 'strict' if PYTHON_VERSION_MAJOR < 3: is_string = isinstance(s, basestring) else: @@ -33,6 +35,7 @@ def smart_str(s): else: return s + class TeamcityTestResult(TestResult): def __init__(self, stream=sys.stdout, *args, **kwargs): TestResult.__init__(self) @@ -41,6 +44,7 @@ class TeamcityTestResult(TestResult): self.output = stream self.messages = TeamcityServiceMessages(self.output, prepend_linebreak=True) self.messages.testMatrixEntered() + self.current_failed = False self.current_suite = None self.subtest_suite = None @@ -48,29 +52,29 @@ class TeamcityTestResult(TestResult): quot = val[0] count = 1 quote_ind = val[count:].find(quot) - while quote_ind != -1 and val[count+quote_ind-1] == "\\": + while quote_ind != -1 and val[count + quote_ind - 1] == "\\": count = count + quote_ind + 1 quote_ind = val[count:].find(quot) - return val[0:quote_ind+count+1] + return val[0:quote_ind + count + 1] def find_second(self, val): val_index = val.find("!=") if val_index != -1: count = 1 - val = val[val_index+2:].strip() + val = val[val_index + 2:].strip() quot = val[0] quote_ind = val[count:].find(quot) - while quote_ind != -1 and val[count+quote_ind-1] == "\\": + while quote_ind != -1 and val[count + quote_ind - 1] == "\\": count = count + quote_ind + 1 quote_ind = val[count:].find(quot) - return val[0:quote_ind+count+1] + return val[0:quote_ind + count + 1] else: quot = val[-1] - quote_ind = val[:len(val)-1].rfind(quot) - while quote_ind != -1 and val[quote_ind-1] == "\\": - quote_ind = val[:quote_ind-1].rfind(quot) + quote_ind = val[:len(val) - 1].rfind(quot) + while quote_ind != -1 and val[quote_ind - 1] == "\\": + quote_ind = val[:quote_ind - 1].rfind(quot) return val[quote_ind:] def formatErr(self, err): @@ -79,8 +83,8 @@ class TeamcityTestResult(TestResult): def getTestName(self, test, is_subtest=False): if is_subtest: - test_name = self.getTestName(test.test_case) - return "{} {}".format(test_name, test._subDescription()) + test_name = self.getTestName(test.test_case) + return "{} {}".format(test_name, test._subDescription()) if hasattr(test, '_testMethodName'): if test._testMethodName == "runTest": return str(test) @@ -99,10 +103,13 @@ class TeamcityTestResult(TestResult): TestResult.addSuccess(self, test) def addError(self, test, err): + self.init_suite(test) + self.current_failed = True TestResult.addError(self, test, err) err = self._exc_info_to_string(err, test) + self.messages.testStarted(self.getTestName(test)) self.messages.testError(self.getTestName(test), message='Error', details=err) @@ -112,6 +119,8 @@ class TeamcityTestResult(TestResult): return error_value.split('assert')[-1].strip() def addFailure(self, test, err): + self.init_suite(test) + self.current_failed = True TestResult.addFailure(self, test, err) error_value = smart_str(err[1]) @@ -123,7 +132,7 @@ class TeamcityTestResult(TestResult): self_find_second = self.find_second(error_value) quotes = ["'", '"'] if (self_find_first[0] == self_find_first[-1] and self_find_first[0] in quotes and - self_find_second[0] == self_find_second[-1] and self_find_second[0] in quotes): + self_find_second[0] == self_find_second[-1] and self_find_second[0] in quotes): # let's unescape strings to show sexy multiline diff in PyCharm. # By default all caret return chars are escaped by testing framework first = self._unescape(self_find_first) @@ -132,10 +141,12 @@ class TeamcityTestResult(TestResult): first = second = "" err = self._exc_info_to_string(err, test) + self.messages.testStarted(self.getTestName(test)) self.messages.testFailed(self.getTestName(test), message='Failure', details=err, expected=first, actual=second) def addSkip(self, test, reason): + self.init_suite(test) self.messages.testIgnored(self.getTestName(test), message=reason) def __getSuite(self, test): @@ -153,10 +164,10 @@ class TeamcityTestResult(TestResult): try: source_file = inspect.getsourcefile(test.__class__) if source_file: - source_dir_splitted = source_file.split("/")[:-1] - source_dir = "/".join(source_dir_splitted) + "/" + source_dir_splitted = source_file.split("/")[:-1] + source_dir = "/".join(source_dir_splitted) + "/" else: - source_dir = "" + source_dir = "" except TypeError: source_dir = "" @@ -167,19 +178,25 @@ class TeamcityTestResult(TestResult): return (suite, location, suite_location) def startTest(self, test): + self.current_failed = False setattr(test, "startTime", datetime.datetime.now()) + def init_suite(self, test): + suite, location, suite_location = self.__getSuite(test) + if suite != self.current_suite: + if self.current_suite: + self.messages.testSuiteFinished(self.current_suite) + self.current_suite = suite + self.messages.testSuiteStarted(self.current_suite, location=suite_location) + return location + def stopTest(self, test): start = getattr(test, "startTime", datetime.datetime.now()) d = datetime.datetime.now() - start - duration=d.microseconds / 1000 + d.seconds * 1000 + d.days * 86400000 + duration = d.microseconds / 1000 + d.seconds * 1000 + d.days * 86400000 if not self.subtest_suite: - suite, location, suite_location = self.__getSuite(test) - if suite != self.current_suite: - if self.current_suite: - self.messages.testSuiteFinished(self.current_suite) - self.current_suite = suite - self.messages.testSuiteStarted(self.current_suite, location=suite_location) + if not self.current_failed: + location = self.init_suite(test) self.messages.testStarted(self.getTestName(test), location=location) self.messages.testFinished(self.getTestName(test), duration=int(duration)) else: @@ -188,15 +205,15 @@ class TeamcityTestResult(TestResult): def addSubTest(self, test, subtest, err): - suite_name = self.getTestName(test) #+ " (subTests)" + suite_name = self.getTestName(test) # + " (subTests)" if not self.subtest_suite: + self.subtest_suite = suite_name + self.messages.testSuiteStarted(self.subtest_suite) + else: + if suite_name != self.subtest_suite: + self.messages.testSuiteFinished(self.subtest_suite) self.subtest_suite = suite_name self.messages.testSuiteStarted(self.subtest_suite) - else: - if suite_name != self.subtest_suite: - self.messages.testSuiteFinished(self.subtest_suite) - self.subtest_suite = suite_name - self.messages.testSuiteStarted(self.subtest_suite) name = self.getTestName(subtest, True) if err is not None: @@ -217,6 +234,7 @@ class TeamcityTestResult(TestResult): # do not use text.decode('string_escape'), it leads to problems with different string encodings given return text.replace("\\n", "\n") + class TeamcityTestRunner(object): def __init__(self, stream=sys.stdout): self.stream = stream