xref: /aosp_15_r20/prebuilts/build-tools/common/py3-stdlib/unittest/result.py (revision cda5da8d549138a6648c5ee6d7a49cf8f4a657be)
1*cda5da8dSAndroid Build Coastguard Worker"""Test result object"""
2*cda5da8dSAndroid Build Coastguard Worker
3*cda5da8dSAndroid Build Coastguard Workerimport io
4*cda5da8dSAndroid Build Coastguard Workerimport sys
5*cda5da8dSAndroid Build Coastguard Workerimport traceback
6*cda5da8dSAndroid Build Coastguard Worker
7*cda5da8dSAndroid Build Coastguard Workerfrom . import util
8*cda5da8dSAndroid Build Coastguard Workerfrom functools import wraps
9*cda5da8dSAndroid Build Coastguard Worker
10*cda5da8dSAndroid Build Coastguard Worker__unittest = True
11*cda5da8dSAndroid Build Coastguard Worker
12*cda5da8dSAndroid Build Coastguard Workerdef failfast(method):
13*cda5da8dSAndroid Build Coastguard Worker    @wraps(method)
14*cda5da8dSAndroid Build Coastguard Worker    def inner(self, *args, **kw):
15*cda5da8dSAndroid Build Coastguard Worker        if getattr(self, 'failfast', False):
16*cda5da8dSAndroid Build Coastguard Worker            self.stop()
17*cda5da8dSAndroid Build Coastguard Worker        return method(self, *args, **kw)
18*cda5da8dSAndroid Build Coastguard Worker    return inner
19*cda5da8dSAndroid Build Coastguard Worker
20*cda5da8dSAndroid Build Coastguard WorkerSTDOUT_LINE = '\nStdout:\n%s'
21*cda5da8dSAndroid Build Coastguard WorkerSTDERR_LINE = '\nStderr:\n%s'
22*cda5da8dSAndroid Build Coastguard Worker
23*cda5da8dSAndroid Build Coastguard Worker
24*cda5da8dSAndroid Build Coastguard Workerclass TestResult(object):
25*cda5da8dSAndroid Build Coastguard Worker    """Holder for test result information.
26*cda5da8dSAndroid Build Coastguard Worker
27*cda5da8dSAndroid Build Coastguard Worker    Test results are automatically managed by the TestCase and TestSuite
28*cda5da8dSAndroid Build Coastguard Worker    classes, and do not need to be explicitly manipulated by writers of tests.
29*cda5da8dSAndroid Build Coastguard Worker
30*cda5da8dSAndroid Build Coastguard Worker    Each instance holds the total number of tests run, and collections of
31*cda5da8dSAndroid Build Coastguard Worker    failures and errors that occurred among those test runs. The collections
32*cda5da8dSAndroid Build Coastguard Worker    contain tuples of (testcase, exceptioninfo), where exceptioninfo is the
33*cda5da8dSAndroid Build Coastguard Worker    formatted traceback of the error that occurred.
34*cda5da8dSAndroid Build Coastguard Worker    """
35*cda5da8dSAndroid Build Coastguard Worker    _previousTestClass = None
36*cda5da8dSAndroid Build Coastguard Worker    _testRunEntered = False
37*cda5da8dSAndroid Build Coastguard Worker    _moduleSetUpFailed = False
38*cda5da8dSAndroid Build Coastguard Worker    def __init__(self, stream=None, descriptions=None, verbosity=None):
39*cda5da8dSAndroid Build Coastguard Worker        self.failfast = False
40*cda5da8dSAndroid Build Coastguard Worker        self.failures = []
41*cda5da8dSAndroid Build Coastguard Worker        self.errors = []
42*cda5da8dSAndroid Build Coastguard Worker        self.testsRun = 0
43*cda5da8dSAndroid Build Coastguard Worker        self.skipped = []
44*cda5da8dSAndroid Build Coastguard Worker        self.expectedFailures = []
45*cda5da8dSAndroid Build Coastguard Worker        self.unexpectedSuccesses = []
46*cda5da8dSAndroid Build Coastguard Worker        self.shouldStop = False
47*cda5da8dSAndroid Build Coastguard Worker        self.buffer = False
48*cda5da8dSAndroid Build Coastguard Worker        self.tb_locals = False
49*cda5da8dSAndroid Build Coastguard Worker        self._stdout_buffer = None
50*cda5da8dSAndroid Build Coastguard Worker        self._stderr_buffer = None
51*cda5da8dSAndroid Build Coastguard Worker        self._original_stdout = sys.stdout
52*cda5da8dSAndroid Build Coastguard Worker        self._original_stderr = sys.stderr
53*cda5da8dSAndroid Build Coastguard Worker        self._mirrorOutput = False
54*cda5da8dSAndroid Build Coastguard Worker
55*cda5da8dSAndroid Build Coastguard Worker    def printErrors(self):
56*cda5da8dSAndroid Build Coastguard Worker        "Called by TestRunner after test run"
57*cda5da8dSAndroid Build Coastguard Worker
58*cda5da8dSAndroid Build Coastguard Worker    def startTest(self, test):
59*cda5da8dSAndroid Build Coastguard Worker        "Called when the given test is about to be run"
60*cda5da8dSAndroid Build Coastguard Worker        self.testsRun += 1
61*cda5da8dSAndroid Build Coastguard Worker        self._mirrorOutput = False
62*cda5da8dSAndroid Build Coastguard Worker        self._setupStdout()
63*cda5da8dSAndroid Build Coastguard Worker
64*cda5da8dSAndroid Build Coastguard Worker    def _setupStdout(self):
65*cda5da8dSAndroid Build Coastguard Worker        if self.buffer:
66*cda5da8dSAndroid Build Coastguard Worker            if self._stderr_buffer is None:
67*cda5da8dSAndroid Build Coastguard Worker                self._stderr_buffer = io.StringIO()
68*cda5da8dSAndroid Build Coastguard Worker                self._stdout_buffer = io.StringIO()
69*cda5da8dSAndroid Build Coastguard Worker            sys.stdout = self._stdout_buffer
70*cda5da8dSAndroid Build Coastguard Worker            sys.stderr = self._stderr_buffer
71*cda5da8dSAndroid Build Coastguard Worker
72*cda5da8dSAndroid Build Coastguard Worker    def startTestRun(self):
73*cda5da8dSAndroid Build Coastguard Worker        """Called once before any tests are executed.
74*cda5da8dSAndroid Build Coastguard Worker
75*cda5da8dSAndroid Build Coastguard Worker        See startTest for a method called before each test.
76*cda5da8dSAndroid Build Coastguard Worker        """
77*cda5da8dSAndroid Build Coastguard Worker
78*cda5da8dSAndroid Build Coastguard Worker    def stopTest(self, test):
79*cda5da8dSAndroid Build Coastguard Worker        """Called when the given test has been run"""
80*cda5da8dSAndroid Build Coastguard Worker        self._restoreStdout()
81*cda5da8dSAndroid Build Coastguard Worker        self._mirrorOutput = False
82*cda5da8dSAndroid Build Coastguard Worker
83*cda5da8dSAndroid Build Coastguard Worker    def _restoreStdout(self):
84*cda5da8dSAndroid Build Coastguard Worker        if self.buffer:
85*cda5da8dSAndroid Build Coastguard Worker            if self._mirrorOutput:
86*cda5da8dSAndroid Build Coastguard Worker                output = sys.stdout.getvalue()
87*cda5da8dSAndroid Build Coastguard Worker                error = sys.stderr.getvalue()
88*cda5da8dSAndroid Build Coastguard Worker                if output:
89*cda5da8dSAndroid Build Coastguard Worker                    if not output.endswith('\n'):
90*cda5da8dSAndroid Build Coastguard Worker                        output += '\n'
91*cda5da8dSAndroid Build Coastguard Worker                    self._original_stdout.write(STDOUT_LINE % output)
92*cda5da8dSAndroid Build Coastguard Worker                if error:
93*cda5da8dSAndroid Build Coastguard Worker                    if not error.endswith('\n'):
94*cda5da8dSAndroid Build Coastguard Worker                        error += '\n'
95*cda5da8dSAndroid Build Coastguard Worker                    self._original_stderr.write(STDERR_LINE % error)
96*cda5da8dSAndroid Build Coastguard Worker
97*cda5da8dSAndroid Build Coastguard Worker            sys.stdout = self._original_stdout
98*cda5da8dSAndroid Build Coastguard Worker            sys.stderr = self._original_stderr
99*cda5da8dSAndroid Build Coastguard Worker            self._stdout_buffer.seek(0)
100*cda5da8dSAndroid Build Coastguard Worker            self._stdout_buffer.truncate()
101*cda5da8dSAndroid Build Coastguard Worker            self._stderr_buffer.seek(0)
102*cda5da8dSAndroid Build Coastguard Worker            self._stderr_buffer.truncate()
103*cda5da8dSAndroid Build Coastguard Worker
104*cda5da8dSAndroid Build Coastguard Worker    def stopTestRun(self):
105*cda5da8dSAndroid Build Coastguard Worker        """Called once after all tests are executed.
106*cda5da8dSAndroid Build Coastguard Worker
107*cda5da8dSAndroid Build Coastguard Worker        See stopTest for a method called after each test.
108*cda5da8dSAndroid Build Coastguard Worker        """
109*cda5da8dSAndroid Build Coastguard Worker
110*cda5da8dSAndroid Build Coastguard Worker    @failfast
111*cda5da8dSAndroid Build Coastguard Worker    def addError(self, test, err):
112*cda5da8dSAndroid Build Coastguard Worker        """Called when an error has occurred. 'err' is a tuple of values as
113*cda5da8dSAndroid Build Coastguard Worker        returned by sys.exc_info().
114*cda5da8dSAndroid Build Coastguard Worker        """
115*cda5da8dSAndroid Build Coastguard Worker        self.errors.append((test, self._exc_info_to_string(err, test)))
116*cda5da8dSAndroid Build Coastguard Worker        self._mirrorOutput = True
117*cda5da8dSAndroid Build Coastguard Worker
118*cda5da8dSAndroid Build Coastguard Worker    @failfast
119*cda5da8dSAndroid Build Coastguard Worker    def addFailure(self, test, err):
120*cda5da8dSAndroid Build Coastguard Worker        """Called when an error has occurred. 'err' is a tuple of values as
121*cda5da8dSAndroid Build Coastguard Worker        returned by sys.exc_info()."""
122*cda5da8dSAndroid Build Coastguard Worker        self.failures.append((test, self._exc_info_to_string(err, test)))
123*cda5da8dSAndroid Build Coastguard Worker        self._mirrorOutput = True
124*cda5da8dSAndroid Build Coastguard Worker
125*cda5da8dSAndroid Build Coastguard Worker    def addSubTest(self, test, subtest, err):
126*cda5da8dSAndroid Build Coastguard Worker        """Called at the end of a subtest.
127*cda5da8dSAndroid Build Coastguard Worker        'err' is None if the subtest ended successfully, otherwise it's a
128*cda5da8dSAndroid Build Coastguard Worker        tuple of values as returned by sys.exc_info().
129*cda5da8dSAndroid Build Coastguard Worker        """
130*cda5da8dSAndroid Build Coastguard Worker        # By default, we don't do anything with successful subtests, but
131*cda5da8dSAndroid Build Coastguard Worker        # more sophisticated test results might want to record them.
132*cda5da8dSAndroid Build Coastguard Worker        if err is not None:
133*cda5da8dSAndroid Build Coastguard Worker            if getattr(self, 'failfast', False):
134*cda5da8dSAndroid Build Coastguard Worker                self.stop()
135*cda5da8dSAndroid Build Coastguard Worker            if issubclass(err[0], test.failureException):
136*cda5da8dSAndroid Build Coastguard Worker                errors = self.failures
137*cda5da8dSAndroid Build Coastguard Worker            else:
138*cda5da8dSAndroid Build Coastguard Worker                errors = self.errors
139*cda5da8dSAndroid Build Coastguard Worker            errors.append((subtest, self._exc_info_to_string(err, test)))
140*cda5da8dSAndroid Build Coastguard Worker            self._mirrorOutput = True
141*cda5da8dSAndroid Build Coastguard Worker
142*cda5da8dSAndroid Build Coastguard Worker    def addSuccess(self, test):
143*cda5da8dSAndroid Build Coastguard Worker        "Called when a test has completed successfully"
144*cda5da8dSAndroid Build Coastguard Worker        pass
145*cda5da8dSAndroid Build Coastguard Worker
146*cda5da8dSAndroid Build Coastguard Worker    def addSkip(self, test, reason):
147*cda5da8dSAndroid Build Coastguard Worker        """Called when a test is skipped."""
148*cda5da8dSAndroid Build Coastguard Worker        self.skipped.append((test, reason))
149*cda5da8dSAndroid Build Coastguard Worker
150*cda5da8dSAndroid Build Coastguard Worker    def addExpectedFailure(self, test, err):
151*cda5da8dSAndroid Build Coastguard Worker        """Called when an expected failure/error occurred."""
152*cda5da8dSAndroid Build Coastguard Worker        self.expectedFailures.append(
153*cda5da8dSAndroid Build Coastguard Worker            (test, self._exc_info_to_string(err, test)))
154*cda5da8dSAndroid Build Coastguard Worker
155*cda5da8dSAndroid Build Coastguard Worker    @failfast
156*cda5da8dSAndroid Build Coastguard Worker    def addUnexpectedSuccess(self, test):
157*cda5da8dSAndroid Build Coastguard Worker        """Called when a test was expected to fail, but succeed."""
158*cda5da8dSAndroid Build Coastguard Worker        self.unexpectedSuccesses.append(test)
159*cda5da8dSAndroid Build Coastguard Worker
160*cda5da8dSAndroid Build Coastguard Worker    def wasSuccessful(self):
161*cda5da8dSAndroid Build Coastguard Worker        """Tells whether or not this result was a success."""
162*cda5da8dSAndroid Build Coastguard Worker        # The hasattr check is for test_result's OldResult test.  That
163*cda5da8dSAndroid Build Coastguard Worker        # way this method works on objects that lack the attribute.
164*cda5da8dSAndroid Build Coastguard Worker        # (where would such result instances come from? old stored pickles?)
165*cda5da8dSAndroid Build Coastguard Worker        return ((len(self.failures) == len(self.errors) == 0) and
166*cda5da8dSAndroid Build Coastguard Worker                (not hasattr(self, 'unexpectedSuccesses') or
167*cda5da8dSAndroid Build Coastguard Worker                 len(self.unexpectedSuccesses) == 0))
168*cda5da8dSAndroid Build Coastguard Worker
169*cda5da8dSAndroid Build Coastguard Worker    def stop(self):
170*cda5da8dSAndroid Build Coastguard Worker        """Indicates that the tests should be aborted."""
171*cda5da8dSAndroid Build Coastguard Worker        self.shouldStop = True
172*cda5da8dSAndroid Build Coastguard Worker
173*cda5da8dSAndroid Build Coastguard Worker    def _exc_info_to_string(self, err, test):
174*cda5da8dSAndroid Build Coastguard Worker        """Converts a sys.exc_info()-style tuple of values into a string."""
175*cda5da8dSAndroid Build Coastguard Worker        exctype, value, tb = err
176*cda5da8dSAndroid Build Coastguard Worker        tb = self._clean_tracebacks(exctype, value, tb, test)
177*cda5da8dSAndroid Build Coastguard Worker        tb_e = traceback.TracebackException(
178*cda5da8dSAndroid Build Coastguard Worker            exctype, value, tb,
179*cda5da8dSAndroid Build Coastguard Worker            capture_locals=self.tb_locals, compact=True)
180*cda5da8dSAndroid Build Coastguard Worker        msgLines = list(tb_e.format())
181*cda5da8dSAndroid Build Coastguard Worker
182*cda5da8dSAndroid Build Coastguard Worker        if self.buffer:
183*cda5da8dSAndroid Build Coastguard Worker            output = sys.stdout.getvalue()
184*cda5da8dSAndroid Build Coastguard Worker            error = sys.stderr.getvalue()
185*cda5da8dSAndroid Build Coastguard Worker            if output:
186*cda5da8dSAndroid Build Coastguard Worker                if not output.endswith('\n'):
187*cda5da8dSAndroid Build Coastguard Worker                    output += '\n'
188*cda5da8dSAndroid Build Coastguard Worker                msgLines.append(STDOUT_LINE % output)
189*cda5da8dSAndroid Build Coastguard Worker            if error:
190*cda5da8dSAndroid Build Coastguard Worker                if not error.endswith('\n'):
191*cda5da8dSAndroid Build Coastguard Worker                    error += '\n'
192*cda5da8dSAndroid Build Coastguard Worker                msgLines.append(STDERR_LINE % error)
193*cda5da8dSAndroid Build Coastguard Worker        return ''.join(msgLines)
194*cda5da8dSAndroid Build Coastguard Worker
195*cda5da8dSAndroid Build Coastguard Worker    def _clean_tracebacks(self, exctype, value, tb, test):
196*cda5da8dSAndroid Build Coastguard Worker        ret = None
197*cda5da8dSAndroid Build Coastguard Worker        first = True
198*cda5da8dSAndroid Build Coastguard Worker        excs = [(exctype, value, tb)]
199*cda5da8dSAndroid Build Coastguard Worker        seen = {id(value)}  # Detect loops in chained exceptions.
200*cda5da8dSAndroid Build Coastguard Worker        while excs:
201*cda5da8dSAndroid Build Coastguard Worker            (exctype, value, tb) = excs.pop()
202*cda5da8dSAndroid Build Coastguard Worker            # Skip test runner traceback levels
203*cda5da8dSAndroid Build Coastguard Worker            while tb and self._is_relevant_tb_level(tb):
204*cda5da8dSAndroid Build Coastguard Worker                tb = tb.tb_next
205*cda5da8dSAndroid Build Coastguard Worker
206*cda5da8dSAndroid Build Coastguard Worker            # Skip assert*() traceback levels
207*cda5da8dSAndroid Build Coastguard Worker            if exctype is test.failureException:
208*cda5da8dSAndroid Build Coastguard Worker                self._remove_unittest_tb_frames(tb)
209*cda5da8dSAndroid Build Coastguard Worker
210*cda5da8dSAndroid Build Coastguard Worker            if first:
211*cda5da8dSAndroid Build Coastguard Worker                ret = tb
212*cda5da8dSAndroid Build Coastguard Worker                first = False
213*cda5da8dSAndroid Build Coastguard Worker            else:
214*cda5da8dSAndroid Build Coastguard Worker                value.__traceback__ = tb
215*cda5da8dSAndroid Build Coastguard Worker
216*cda5da8dSAndroid Build Coastguard Worker            if value is not None:
217*cda5da8dSAndroid Build Coastguard Worker                for c in (value.__cause__, value.__context__):
218*cda5da8dSAndroid Build Coastguard Worker                    if c is not None and id(c) not in seen:
219*cda5da8dSAndroid Build Coastguard Worker                        excs.append((type(c), c, c.__traceback__))
220*cda5da8dSAndroid Build Coastguard Worker                        seen.add(id(c))
221*cda5da8dSAndroid Build Coastguard Worker        return ret
222*cda5da8dSAndroid Build Coastguard Worker
223*cda5da8dSAndroid Build Coastguard Worker    def _is_relevant_tb_level(self, tb):
224*cda5da8dSAndroid Build Coastguard Worker        return '__unittest' in tb.tb_frame.f_globals
225*cda5da8dSAndroid Build Coastguard Worker
226*cda5da8dSAndroid Build Coastguard Worker    def _remove_unittest_tb_frames(self, tb):
227*cda5da8dSAndroid Build Coastguard Worker        '''Truncates usercode tb at the first unittest frame.
228*cda5da8dSAndroid Build Coastguard Worker
229*cda5da8dSAndroid Build Coastguard Worker        If the first frame of the traceback is in user code,
230*cda5da8dSAndroid Build Coastguard Worker        the prefix up to the first unittest frame is returned.
231*cda5da8dSAndroid Build Coastguard Worker        If the first frame is already in the unittest module,
232*cda5da8dSAndroid Build Coastguard Worker        the traceback is not modified.
233*cda5da8dSAndroid Build Coastguard Worker        '''
234*cda5da8dSAndroid Build Coastguard Worker        prev = None
235*cda5da8dSAndroid Build Coastguard Worker        while tb and not self._is_relevant_tb_level(tb):
236*cda5da8dSAndroid Build Coastguard Worker            prev = tb
237*cda5da8dSAndroid Build Coastguard Worker            tb = tb.tb_next
238*cda5da8dSAndroid Build Coastguard Worker        if prev is not None:
239*cda5da8dSAndroid Build Coastguard Worker            prev.tb_next = None
240*cda5da8dSAndroid Build Coastguard Worker
241*cda5da8dSAndroid Build Coastguard Worker    def __repr__(self):
242*cda5da8dSAndroid Build Coastguard Worker        return ("<%s run=%i errors=%i failures=%i>" %
243*cda5da8dSAndroid Build Coastguard Worker               (util.strclass(self.__class__), self.testsRun, len(self.errors),
244*cda5da8dSAndroid Build Coastguard Worker                len(self.failures)))
245