14710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm"""Test result object"""
24710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm
34710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylmimport os
44710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylmimport sys
54710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylmimport traceback
64710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm
74710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylmfrom StringIO import StringIO
84710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm
94710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylmfrom . import util
104710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylmfrom functools import wraps
114710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm
124710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm__unittest = True
134710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm
144710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylmdef failfast(method):
154710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm    @wraps(method)
164710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm    def inner(self, *args, **kw):
174710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm        if getattr(self, 'failfast', False):
184710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm            self.stop()
194710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm        return method(self, *args, **kw)
204710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm    return inner
214710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm
224710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylmSTDOUT_LINE = '\nStdout:\n%s'
234710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylmSTDERR_LINE = '\nStderr:\n%s'
244710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm
254710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm
264710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylmclass TestResult(object):
274710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm    """Holder for test result information.
284710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm
294710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm    Test results are automatically managed by the TestCase and TestSuite
304710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm    classes, and do not need to be explicitly manipulated by writers of tests.
314710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm
324710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm    Each instance holds the total number of tests run, and collections of
334710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm    failures and errors that occurred among those test runs. The collections
344710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm    contain tuples of (testcase, exceptioninfo), where exceptioninfo is the
354710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm    formatted traceback of the error that occurred.
364710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm    """
374710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm    _previousTestClass = None
384710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm    _testRunEntered = False
394710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm    _moduleSetUpFailed = False
404710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm    def __init__(self, stream=None, descriptions=None, verbosity=None):
414710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm        self.failfast = False
424710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm        self.failures = []
434710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm        self.errors = []
444710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm        self.testsRun = 0
454710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm        self.skipped = []
464710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm        self.expectedFailures = []
474710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm        self.unexpectedSuccesses = []
484710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm        self.shouldStop = False
494710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm        self.buffer = False
504710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm        self._stdout_buffer = None
514710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm        self._stderr_buffer = None
524710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm        self._original_stdout = sys.stdout
534710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm        self._original_stderr = sys.stderr
544710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm        self._mirrorOutput = False
554710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm
564710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm    def printErrors(self):
574710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm        "Called by TestRunner after test run"
584710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm
594710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm    def startTest(self, test):
604710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm        "Called when the given test is about to be run"
614710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm        self.testsRun += 1
624710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm        self._mirrorOutput = False
634710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm        self._setupStdout()
644710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm
654710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm    def _setupStdout(self):
664710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm        if self.buffer:
674710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm            if self._stderr_buffer is None:
684710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm                self._stderr_buffer = StringIO()
694710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm                self._stdout_buffer = StringIO()
704710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm            sys.stdout = self._stdout_buffer
714710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm            sys.stderr = self._stderr_buffer
724710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm
734710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm    def startTestRun(self):
744710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm        """Called once before any tests are executed.
754710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm
764710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm        See startTest for a method called before each test.
774710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm        """
784710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm
794710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm    def stopTest(self, test):
804710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm        """Called when the given test has been run"""
814710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm        self._restoreStdout()
824710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm        self._mirrorOutput = False
834710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm
844710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm    def _restoreStdout(self):
854710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm        if self.buffer:
864710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm            if self._mirrorOutput:
874710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm                output = sys.stdout.getvalue()
884710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm                error = sys.stderr.getvalue()
894710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm                if output:
904710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm                    if not output.endswith('\n'):
914710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm                        output += '\n'
924710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm                    self._original_stdout.write(STDOUT_LINE % output)
934710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm                if error:
944710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm                    if not error.endswith('\n'):
954710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm                        error += '\n'
964710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm                    self._original_stderr.write(STDERR_LINE % error)
974710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm
984710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm            sys.stdout = self._original_stdout
994710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm            sys.stderr = self._original_stderr
1004710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm            self._stdout_buffer.seek(0)
1014710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm            self._stdout_buffer.truncate()
1024710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm            self._stderr_buffer.seek(0)
1034710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm            self._stderr_buffer.truncate()
1044710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm
1054710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm    def stopTestRun(self):
1064710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm        """Called once after all tests are executed.
1074710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm
1084710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm        See stopTest for a method called after each test.
1094710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm        """
1104710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm
1114710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm    @failfast
1124710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm    def addError(self, test, err):
1134710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm        """Called when an error has occurred. 'err' is a tuple of values as
1144710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm        returned by sys.exc_info().
1154710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm        """
1164710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm        self.errors.append((test, self._exc_info_to_string(err, test)))
1174710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm        self._mirrorOutput = True
1184710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm
1194710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm    @failfast
1204710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm    def addFailure(self, test, err):
1214710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm        """Called when an error has occurred. 'err' is a tuple of values as
1224710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm        returned by sys.exc_info()."""
1234710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm        self.failures.append((test, self._exc_info_to_string(err, test)))
1244710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm        self._mirrorOutput = True
1254710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm
1264710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm    def addSuccess(self, test):
1274710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm        "Called when a test has completed successfully"
1284710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm        pass
1294710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm
1304710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm    def addSkip(self, test, reason):
1314710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm        """Called when a test is skipped."""
1324710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm        self.skipped.append((test, reason))
1334710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm
1344710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm    def addExpectedFailure(self, test, err):
1354710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm        """Called when an expected failure/error occured."""
1364710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm        self.expectedFailures.append(
1374710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm            (test, self._exc_info_to_string(err, test)))
1384710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm
1394710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm    @failfast
1404710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm    def addUnexpectedSuccess(self, test):
1414710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm        """Called when a test was expected to fail, but succeed."""
1424710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm        self.unexpectedSuccesses.append(test)
1434710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm
1444710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm    def wasSuccessful(self):
1454710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm        "Tells whether or not this result was a success"
1464710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm        return len(self.failures) == len(self.errors) == 0
1474710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm
1484710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm    def stop(self):
1494710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm        "Indicates that the tests should be aborted"
1504710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm        self.shouldStop = True
1514710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm
1524710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm    def _exc_info_to_string(self, err, test):
1534710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm        """Converts a sys.exc_info()-style tuple of values into a string."""
1544710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm        exctype, value, tb = err
1554710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm        # Skip test runner traceback levels
1564710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm        while tb and self._is_relevant_tb_level(tb):
1574710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm            tb = tb.tb_next
1584710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm
1594710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm        if exctype is test.failureException:
1604710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm            # Skip assert*() traceback levels
1614710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm            length = self._count_relevant_tb_levels(tb)
1624710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm            msgLines = traceback.format_exception(exctype, value, tb, length)
1634710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm        else:
1644710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm            msgLines = traceback.format_exception(exctype, value, tb)
1654710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm
1664710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm        if self.buffer:
1674710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm            output = sys.stdout.getvalue()
1684710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm            error = sys.stderr.getvalue()
1694710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm            if output:
1704710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm                if not output.endswith('\n'):
1714710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm                    output += '\n'
1724710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm                msgLines.append(STDOUT_LINE % output)
1734710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm            if error:
1744710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm                if not error.endswith('\n'):
1754710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm                    error += '\n'
1764710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm                msgLines.append(STDERR_LINE % error)
1774710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm        return ''.join(msgLines)
1784710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm
1794710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm
1804710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm    def _is_relevant_tb_level(self, tb):
1814710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm        return '__unittest' in tb.tb_frame.f_globals
1824710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm
1834710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm    def _count_relevant_tb_levels(self, tb):
1844710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm        length = 0
1854710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm        while tb and not self._is_relevant_tb_level(tb):
1864710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm            length += 1
1874710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm            tb = tb.tb_next
1884710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm        return length
1894710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm
1904710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm    def __repr__(self):
1914710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm        return ("<%s run=%i errors=%i failures=%i>" %
1924710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm               (util.strclass(self.__class__), self.testsRun, len(self.errors),
1934710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm                len(self.failures)))
194