xref: /aosp_15_r20/prebuilts/build-tools/common/py3-stdlib/unittest/runner.py (revision cda5da8d549138a6648c5ee6d7a49cf8f4a657be)
1*cda5da8dSAndroid Build Coastguard Worker"""Running tests"""
2*cda5da8dSAndroid Build Coastguard Worker
3*cda5da8dSAndroid Build Coastguard Workerimport sys
4*cda5da8dSAndroid Build Coastguard Workerimport time
5*cda5da8dSAndroid Build Coastguard Workerimport warnings
6*cda5da8dSAndroid Build Coastguard Worker
7*cda5da8dSAndroid Build Coastguard Workerfrom . import result
8*cda5da8dSAndroid Build Coastguard Workerfrom .case import _SubTest
9*cda5da8dSAndroid Build Coastguard Workerfrom .signals import registerResult
10*cda5da8dSAndroid Build Coastguard Worker
11*cda5da8dSAndroid Build Coastguard Worker__unittest = True
12*cda5da8dSAndroid Build Coastguard Worker
13*cda5da8dSAndroid Build Coastguard Worker
14*cda5da8dSAndroid Build Coastguard Workerclass _WritelnDecorator(object):
15*cda5da8dSAndroid Build Coastguard Worker    """Used to decorate file-like objects with a handy 'writeln' method"""
16*cda5da8dSAndroid Build Coastguard Worker    def __init__(self,stream):
17*cda5da8dSAndroid Build Coastguard Worker        self.stream = stream
18*cda5da8dSAndroid Build Coastguard Worker
19*cda5da8dSAndroid Build Coastguard Worker    def __getattr__(self, attr):
20*cda5da8dSAndroid Build Coastguard Worker        if attr in ('stream', '__getstate__'):
21*cda5da8dSAndroid Build Coastguard Worker            raise AttributeError(attr)
22*cda5da8dSAndroid Build Coastguard Worker        return getattr(self.stream,attr)
23*cda5da8dSAndroid Build Coastguard Worker
24*cda5da8dSAndroid Build Coastguard Worker    def writeln(self, arg=None):
25*cda5da8dSAndroid Build Coastguard Worker        if arg:
26*cda5da8dSAndroid Build Coastguard Worker            self.write(arg)
27*cda5da8dSAndroid Build Coastguard Worker        self.write('\n') # text-mode streams translate to \r\n if needed
28*cda5da8dSAndroid Build Coastguard Worker
29*cda5da8dSAndroid Build Coastguard Worker
30*cda5da8dSAndroid Build Coastguard Workerclass TextTestResult(result.TestResult):
31*cda5da8dSAndroid Build Coastguard Worker    """A test result class that can print formatted text results to a stream.
32*cda5da8dSAndroid Build Coastguard Worker
33*cda5da8dSAndroid Build Coastguard Worker    Used by TextTestRunner.
34*cda5da8dSAndroid Build Coastguard Worker    """
35*cda5da8dSAndroid Build Coastguard Worker    separator1 = '=' * 70
36*cda5da8dSAndroid Build Coastguard Worker    separator2 = '-' * 70
37*cda5da8dSAndroid Build Coastguard Worker
38*cda5da8dSAndroid Build Coastguard Worker    def __init__(self, stream, descriptions, verbosity):
39*cda5da8dSAndroid Build Coastguard Worker        super(TextTestResult, self).__init__(stream, descriptions, verbosity)
40*cda5da8dSAndroid Build Coastguard Worker        self.stream = stream
41*cda5da8dSAndroid Build Coastguard Worker        self.showAll = verbosity > 1
42*cda5da8dSAndroid Build Coastguard Worker        self.dots = verbosity == 1
43*cda5da8dSAndroid Build Coastguard Worker        self.descriptions = descriptions
44*cda5da8dSAndroid Build Coastguard Worker        self._newline = True
45*cda5da8dSAndroid Build Coastguard Worker
46*cda5da8dSAndroid Build Coastguard Worker    def getDescription(self, test):
47*cda5da8dSAndroid Build Coastguard Worker        doc_first_line = test.shortDescription()
48*cda5da8dSAndroid Build Coastguard Worker        if self.descriptions and doc_first_line:
49*cda5da8dSAndroid Build Coastguard Worker            return '\n'.join((str(test), doc_first_line))
50*cda5da8dSAndroid Build Coastguard Worker        else:
51*cda5da8dSAndroid Build Coastguard Worker            return str(test)
52*cda5da8dSAndroid Build Coastguard Worker
53*cda5da8dSAndroid Build Coastguard Worker    def startTest(self, test):
54*cda5da8dSAndroid Build Coastguard Worker        super(TextTestResult, self).startTest(test)
55*cda5da8dSAndroid Build Coastguard Worker        if self.showAll:
56*cda5da8dSAndroid Build Coastguard Worker            self.stream.write(self.getDescription(test))
57*cda5da8dSAndroid Build Coastguard Worker            self.stream.write(" ... ")
58*cda5da8dSAndroid Build Coastguard Worker            self.stream.flush()
59*cda5da8dSAndroid Build Coastguard Worker            self._newline = False
60*cda5da8dSAndroid Build Coastguard Worker
61*cda5da8dSAndroid Build Coastguard Worker    def _write_status(self, test, status):
62*cda5da8dSAndroid Build Coastguard Worker        is_subtest = isinstance(test, _SubTest)
63*cda5da8dSAndroid Build Coastguard Worker        if is_subtest or self._newline:
64*cda5da8dSAndroid Build Coastguard Worker            if not self._newline:
65*cda5da8dSAndroid Build Coastguard Worker                self.stream.writeln()
66*cda5da8dSAndroid Build Coastguard Worker            if is_subtest:
67*cda5da8dSAndroid Build Coastguard Worker                self.stream.write("  ")
68*cda5da8dSAndroid Build Coastguard Worker            self.stream.write(self.getDescription(test))
69*cda5da8dSAndroid Build Coastguard Worker            self.stream.write(" ... ")
70*cda5da8dSAndroid Build Coastguard Worker        self.stream.writeln(status)
71*cda5da8dSAndroid Build Coastguard Worker        self.stream.flush()
72*cda5da8dSAndroid Build Coastguard Worker        self._newline = True
73*cda5da8dSAndroid Build Coastguard Worker
74*cda5da8dSAndroid Build Coastguard Worker    def addSubTest(self, test, subtest, err):
75*cda5da8dSAndroid Build Coastguard Worker        if err is not None:
76*cda5da8dSAndroid Build Coastguard Worker            if self.showAll:
77*cda5da8dSAndroid Build Coastguard Worker                if issubclass(err[0], subtest.failureException):
78*cda5da8dSAndroid Build Coastguard Worker                    self._write_status(subtest, "FAIL")
79*cda5da8dSAndroid Build Coastguard Worker                else:
80*cda5da8dSAndroid Build Coastguard Worker                    self._write_status(subtest, "ERROR")
81*cda5da8dSAndroid Build Coastguard Worker            elif self.dots:
82*cda5da8dSAndroid Build Coastguard Worker                if issubclass(err[0], subtest.failureException):
83*cda5da8dSAndroid Build Coastguard Worker                    self.stream.write('F')
84*cda5da8dSAndroid Build Coastguard Worker                else:
85*cda5da8dSAndroid Build Coastguard Worker                    self.stream.write('E')
86*cda5da8dSAndroid Build Coastguard Worker                self.stream.flush()
87*cda5da8dSAndroid Build Coastguard Worker        super(TextTestResult, self).addSubTest(test, subtest, err)
88*cda5da8dSAndroid Build Coastguard Worker
89*cda5da8dSAndroid Build Coastguard Worker    def addSuccess(self, test):
90*cda5da8dSAndroid Build Coastguard Worker        super(TextTestResult, self).addSuccess(test)
91*cda5da8dSAndroid Build Coastguard Worker        if self.showAll:
92*cda5da8dSAndroid Build Coastguard Worker            self._write_status(test, "ok")
93*cda5da8dSAndroid Build Coastguard Worker        elif self.dots:
94*cda5da8dSAndroid Build Coastguard Worker            self.stream.write('.')
95*cda5da8dSAndroid Build Coastguard Worker            self.stream.flush()
96*cda5da8dSAndroid Build Coastguard Worker
97*cda5da8dSAndroid Build Coastguard Worker    def addError(self, test, err):
98*cda5da8dSAndroid Build Coastguard Worker        super(TextTestResult, self).addError(test, err)
99*cda5da8dSAndroid Build Coastguard Worker        if self.showAll:
100*cda5da8dSAndroid Build Coastguard Worker            self._write_status(test, "ERROR")
101*cda5da8dSAndroid Build Coastguard Worker        elif self.dots:
102*cda5da8dSAndroid Build Coastguard Worker            self.stream.write('E')
103*cda5da8dSAndroid Build Coastguard Worker            self.stream.flush()
104*cda5da8dSAndroid Build Coastguard Worker
105*cda5da8dSAndroid Build Coastguard Worker    def addFailure(self, test, err):
106*cda5da8dSAndroid Build Coastguard Worker        super(TextTestResult, self).addFailure(test, err)
107*cda5da8dSAndroid Build Coastguard Worker        if self.showAll:
108*cda5da8dSAndroid Build Coastguard Worker            self._write_status(test, "FAIL")
109*cda5da8dSAndroid Build Coastguard Worker        elif self.dots:
110*cda5da8dSAndroid Build Coastguard Worker            self.stream.write('F')
111*cda5da8dSAndroid Build Coastguard Worker            self.stream.flush()
112*cda5da8dSAndroid Build Coastguard Worker
113*cda5da8dSAndroid Build Coastguard Worker    def addSkip(self, test, reason):
114*cda5da8dSAndroid Build Coastguard Worker        super(TextTestResult, self).addSkip(test, reason)
115*cda5da8dSAndroid Build Coastguard Worker        if self.showAll:
116*cda5da8dSAndroid Build Coastguard Worker            self._write_status(test, "skipped {0!r}".format(reason))
117*cda5da8dSAndroid Build Coastguard Worker        elif self.dots:
118*cda5da8dSAndroid Build Coastguard Worker            self.stream.write("s")
119*cda5da8dSAndroid Build Coastguard Worker            self.stream.flush()
120*cda5da8dSAndroid Build Coastguard Worker
121*cda5da8dSAndroid Build Coastguard Worker    def addExpectedFailure(self, test, err):
122*cda5da8dSAndroid Build Coastguard Worker        super(TextTestResult, self).addExpectedFailure(test, err)
123*cda5da8dSAndroid Build Coastguard Worker        if self.showAll:
124*cda5da8dSAndroid Build Coastguard Worker            self.stream.writeln("expected failure")
125*cda5da8dSAndroid Build Coastguard Worker            self.stream.flush()
126*cda5da8dSAndroid Build Coastguard Worker        elif self.dots:
127*cda5da8dSAndroid Build Coastguard Worker            self.stream.write("x")
128*cda5da8dSAndroid Build Coastguard Worker            self.stream.flush()
129*cda5da8dSAndroid Build Coastguard Worker
130*cda5da8dSAndroid Build Coastguard Worker    def addUnexpectedSuccess(self, test):
131*cda5da8dSAndroid Build Coastguard Worker        super(TextTestResult, self).addUnexpectedSuccess(test)
132*cda5da8dSAndroid Build Coastguard Worker        if self.showAll:
133*cda5da8dSAndroid Build Coastguard Worker            self.stream.writeln("unexpected success")
134*cda5da8dSAndroid Build Coastguard Worker            self.stream.flush()
135*cda5da8dSAndroid Build Coastguard Worker        elif self.dots:
136*cda5da8dSAndroid Build Coastguard Worker            self.stream.write("u")
137*cda5da8dSAndroid Build Coastguard Worker            self.stream.flush()
138*cda5da8dSAndroid Build Coastguard Worker
139*cda5da8dSAndroid Build Coastguard Worker    def printErrors(self):
140*cda5da8dSAndroid Build Coastguard Worker        if self.dots or self.showAll:
141*cda5da8dSAndroid Build Coastguard Worker            self.stream.writeln()
142*cda5da8dSAndroid Build Coastguard Worker            self.stream.flush()
143*cda5da8dSAndroid Build Coastguard Worker        self.printErrorList('ERROR', self.errors)
144*cda5da8dSAndroid Build Coastguard Worker        self.printErrorList('FAIL', self.failures)
145*cda5da8dSAndroid Build Coastguard Worker        unexpectedSuccesses = getattr(self, 'unexpectedSuccesses', ())
146*cda5da8dSAndroid Build Coastguard Worker        if unexpectedSuccesses:
147*cda5da8dSAndroid Build Coastguard Worker            self.stream.writeln(self.separator1)
148*cda5da8dSAndroid Build Coastguard Worker            for test in unexpectedSuccesses:
149*cda5da8dSAndroid Build Coastguard Worker                self.stream.writeln(f"UNEXPECTED SUCCESS: {self.getDescription(test)}")
150*cda5da8dSAndroid Build Coastguard Worker            self.stream.flush()
151*cda5da8dSAndroid Build Coastguard Worker
152*cda5da8dSAndroid Build Coastguard Worker    def printErrorList(self, flavour, errors):
153*cda5da8dSAndroid Build Coastguard Worker        for test, err in errors:
154*cda5da8dSAndroid Build Coastguard Worker            self.stream.writeln(self.separator1)
155*cda5da8dSAndroid Build Coastguard Worker            self.stream.writeln("%s: %s" % (flavour,self.getDescription(test)))
156*cda5da8dSAndroid Build Coastguard Worker            self.stream.writeln(self.separator2)
157*cda5da8dSAndroid Build Coastguard Worker            self.stream.writeln("%s" % err)
158*cda5da8dSAndroid Build Coastguard Worker            self.stream.flush()
159*cda5da8dSAndroid Build Coastguard Worker
160*cda5da8dSAndroid Build Coastguard Worker
161*cda5da8dSAndroid Build Coastguard Workerclass TextTestRunner(object):
162*cda5da8dSAndroid Build Coastguard Worker    """A test runner class that displays results in textual form.
163*cda5da8dSAndroid Build Coastguard Worker
164*cda5da8dSAndroid Build Coastguard Worker    It prints out the names of tests as they are run, errors as they
165*cda5da8dSAndroid Build Coastguard Worker    occur, and a summary of the results at the end of the test run.
166*cda5da8dSAndroid Build Coastguard Worker    """
167*cda5da8dSAndroid Build Coastguard Worker    resultclass = TextTestResult
168*cda5da8dSAndroid Build Coastguard Worker
169*cda5da8dSAndroid Build Coastguard Worker    def __init__(self, stream=None, descriptions=True, verbosity=1,
170*cda5da8dSAndroid Build Coastguard Worker                 failfast=False, buffer=False, resultclass=None, warnings=None,
171*cda5da8dSAndroid Build Coastguard Worker                 *, tb_locals=False):
172*cda5da8dSAndroid Build Coastguard Worker        """Construct a TextTestRunner.
173*cda5da8dSAndroid Build Coastguard Worker
174*cda5da8dSAndroid Build Coastguard Worker        Subclasses should accept **kwargs to ensure compatibility as the
175*cda5da8dSAndroid Build Coastguard Worker        interface changes.
176*cda5da8dSAndroid Build Coastguard Worker        """
177*cda5da8dSAndroid Build Coastguard Worker        if stream is None:
178*cda5da8dSAndroid Build Coastguard Worker            stream = sys.stderr
179*cda5da8dSAndroid Build Coastguard Worker        self.stream = _WritelnDecorator(stream)
180*cda5da8dSAndroid Build Coastguard Worker        self.descriptions = descriptions
181*cda5da8dSAndroid Build Coastguard Worker        self.verbosity = verbosity
182*cda5da8dSAndroid Build Coastguard Worker        self.failfast = failfast
183*cda5da8dSAndroid Build Coastguard Worker        self.buffer = buffer
184*cda5da8dSAndroid Build Coastguard Worker        self.tb_locals = tb_locals
185*cda5da8dSAndroid Build Coastguard Worker        self.warnings = warnings
186*cda5da8dSAndroid Build Coastguard Worker        if resultclass is not None:
187*cda5da8dSAndroid Build Coastguard Worker            self.resultclass = resultclass
188*cda5da8dSAndroid Build Coastguard Worker
189*cda5da8dSAndroid Build Coastguard Worker    def _makeResult(self):
190*cda5da8dSAndroid Build Coastguard Worker        return self.resultclass(self.stream, self.descriptions, self.verbosity)
191*cda5da8dSAndroid Build Coastguard Worker
192*cda5da8dSAndroid Build Coastguard Worker    def run(self, test):
193*cda5da8dSAndroid Build Coastguard Worker        "Run the given test case or test suite."
194*cda5da8dSAndroid Build Coastguard Worker        result = self._makeResult()
195*cda5da8dSAndroid Build Coastguard Worker        registerResult(result)
196*cda5da8dSAndroid Build Coastguard Worker        result.failfast = self.failfast
197*cda5da8dSAndroid Build Coastguard Worker        result.buffer = self.buffer
198*cda5da8dSAndroid Build Coastguard Worker        result.tb_locals = self.tb_locals
199*cda5da8dSAndroid Build Coastguard Worker        with warnings.catch_warnings():
200*cda5da8dSAndroid Build Coastguard Worker            if self.warnings:
201*cda5da8dSAndroid Build Coastguard Worker                # if self.warnings is set, use it to filter all the warnings
202*cda5da8dSAndroid Build Coastguard Worker                warnings.simplefilter(self.warnings)
203*cda5da8dSAndroid Build Coastguard Worker                # if the filter is 'default' or 'always', special-case the
204*cda5da8dSAndroid Build Coastguard Worker                # warnings from the deprecated unittest methods to show them
205*cda5da8dSAndroid Build Coastguard Worker                # no more than once per module, because they can be fairly
206*cda5da8dSAndroid Build Coastguard Worker                # noisy.  The -Wd and -Wa flags can be used to bypass this
207*cda5da8dSAndroid Build Coastguard Worker                # only when self.warnings is None.
208*cda5da8dSAndroid Build Coastguard Worker                if self.warnings in ['default', 'always']:
209*cda5da8dSAndroid Build Coastguard Worker                    warnings.filterwarnings('module',
210*cda5da8dSAndroid Build Coastguard Worker                            category=DeprecationWarning,
211*cda5da8dSAndroid Build Coastguard Worker                            message=r'Please use assert\w+ instead.')
212*cda5da8dSAndroid Build Coastguard Worker            startTime = time.perf_counter()
213*cda5da8dSAndroid Build Coastguard Worker            startTestRun = getattr(result, 'startTestRun', None)
214*cda5da8dSAndroid Build Coastguard Worker            if startTestRun is not None:
215*cda5da8dSAndroid Build Coastguard Worker                startTestRun()
216*cda5da8dSAndroid Build Coastguard Worker            try:
217*cda5da8dSAndroid Build Coastguard Worker                test(result)
218*cda5da8dSAndroid Build Coastguard Worker            finally:
219*cda5da8dSAndroid Build Coastguard Worker                stopTestRun = getattr(result, 'stopTestRun', None)
220*cda5da8dSAndroid Build Coastguard Worker                if stopTestRun is not None:
221*cda5da8dSAndroid Build Coastguard Worker                    stopTestRun()
222*cda5da8dSAndroid Build Coastguard Worker            stopTime = time.perf_counter()
223*cda5da8dSAndroid Build Coastguard Worker        timeTaken = stopTime - startTime
224*cda5da8dSAndroid Build Coastguard Worker        result.printErrors()
225*cda5da8dSAndroid Build Coastguard Worker        if hasattr(result, 'separator2'):
226*cda5da8dSAndroid Build Coastguard Worker            self.stream.writeln(result.separator2)
227*cda5da8dSAndroid Build Coastguard Worker        run = result.testsRun
228*cda5da8dSAndroid Build Coastguard Worker        self.stream.writeln("Ran %d test%s in %.3fs" %
229*cda5da8dSAndroid Build Coastguard Worker                            (run, run != 1 and "s" or "", timeTaken))
230*cda5da8dSAndroid Build Coastguard Worker        self.stream.writeln()
231*cda5da8dSAndroid Build Coastguard Worker
232*cda5da8dSAndroid Build Coastguard Worker        expectedFails = unexpectedSuccesses = skipped = 0
233*cda5da8dSAndroid Build Coastguard Worker        try:
234*cda5da8dSAndroid Build Coastguard Worker            results = map(len, (result.expectedFailures,
235*cda5da8dSAndroid Build Coastguard Worker                                result.unexpectedSuccesses,
236*cda5da8dSAndroid Build Coastguard Worker                                result.skipped))
237*cda5da8dSAndroid Build Coastguard Worker        except AttributeError:
238*cda5da8dSAndroid Build Coastguard Worker            pass
239*cda5da8dSAndroid Build Coastguard Worker        else:
240*cda5da8dSAndroid Build Coastguard Worker            expectedFails, unexpectedSuccesses, skipped = results
241*cda5da8dSAndroid Build Coastguard Worker
242*cda5da8dSAndroid Build Coastguard Worker        infos = []
243*cda5da8dSAndroid Build Coastguard Worker        if not result.wasSuccessful():
244*cda5da8dSAndroid Build Coastguard Worker            self.stream.write("FAILED")
245*cda5da8dSAndroid Build Coastguard Worker            failed, errored = len(result.failures), len(result.errors)
246*cda5da8dSAndroid Build Coastguard Worker            if failed:
247*cda5da8dSAndroid Build Coastguard Worker                infos.append("failures=%d" % failed)
248*cda5da8dSAndroid Build Coastguard Worker            if errored:
249*cda5da8dSAndroid Build Coastguard Worker                infos.append("errors=%d" % errored)
250*cda5da8dSAndroid Build Coastguard Worker        else:
251*cda5da8dSAndroid Build Coastguard Worker            self.stream.write("OK")
252*cda5da8dSAndroid Build Coastguard Worker        if skipped:
253*cda5da8dSAndroid Build Coastguard Worker            infos.append("skipped=%d" % skipped)
254*cda5da8dSAndroid Build Coastguard Worker        if expectedFails:
255*cda5da8dSAndroid Build Coastguard Worker            infos.append("expected failures=%d" % expectedFails)
256*cda5da8dSAndroid Build Coastguard Worker        if unexpectedSuccesses:
257*cda5da8dSAndroid Build Coastguard Worker            infos.append("unexpected successes=%d" % unexpectedSuccesses)
258*cda5da8dSAndroid Build Coastguard Worker        if infos:
259*cda5da8dSAndroid Build Coastguard Worker            self.stream.writeln(" (%s)" % (", ".join(infos),))
260*cda5da8dSAndroid Build Coastguard Worker        else:
261*cda5da8dSAndroid Build Coastguard Worker            self.stream.write("\n")
262*cda5da8dSAndroid Build Coastguard Worker        self.stream.flush()
263*cda5da8dSAndroid Build Coastguard Worker        return result
264