~bzr-pqm/bzr/bzr.dev

« back to all changes in this revision

Viewing changes to bzrlib/tests/__init__.py

'bzr selftest' now shows a progress bar with the number of tests, and 
progress made. 'make check' shows tests in -v mode, to be more useful
for the PQM status window. (Robert Collins).

Show diffs side-by-side

added added

removed removed

Lines of Context:
52
52
import bzrlib.osutils
53
53
import bzrlib.osutils as osutils
54
54
import bzrlib.plugin
 
55
import bzrlib.progress as progress
55
56
from bzrlib.revision import common_ancestor
56
57
import bzrlib.store
57
58
import bzrlib.trace
113
114
    Shows output in a different format, including displaying runtime for tests.
114
115
    """
115
116
    stop_early = False
 
117
    
 
118
    def __init__(self, stream, descriptions, verbosity, pb=None):
 
119
        unittest._TextTestResult.__init__(self, stream, descriptions, verbosity)
 
120
        self.pb = pb
116
121
 
117
122
    def _elapsedTime(self):
118
123
        return "%5dms" % (1000 * (time.time() - self._start_time))
119
124
 
 
125
    def _ellipsise_unimportant_words(self, a_string, final_width,
 
126
                                   keep_start=False):
 
127
        """Add ellipsese (sp?) for overly long strings.
 
128
        
 
129
        :param keep_start: If true preserve the start of a_string rather
 
130
                           than the end of it.
 
131
        """
 
132
        if keep_start:
 
133
            if len(a_string) > final_width:
 
134
                result = a_string[:final_width-3] + '...'
 
135
            else:
 
136
                result = a_string
 
137
        else:
 
138
            if len(a_string) > final_width:
 
139
                result = '...' + a_string[3-final_width:]
 
140
            else:
 
141
                result = a_string
 
142
        return result.ljust(final_width)
 
143
 
120
144
    def startTest(self, test):
121
145
        unittest.TestResult.startTest(self, test)
122
146
        # In a short description, the important words are in
123
147
        # the beginning, but in an id, the important words are
124
148
        # at the end
125
149
        SHOW_DESCRIPTIONS = False
 
150
 
 
151
        if not self.showAll and self.dots and self.pb is not None:
 
152
            final_width = 13
 
153
        else:
 
154
            final_width = osutils.terminal_width()
 
155
            final_width = final_width - 15
 
156
        what = None
 
157
        if SHOW_DESCRIPTIONS:
 
158
            what = test.shortDescription()
 
159
            if what:
 
160
                what = self._ellipsise_unimportant_words(what, final_width, keep_start=True)
 
161
        if what is None:
 
162
            what = test.id()
 
163
            if what.startswith('bzrlib.tests.'):
 
164
                what = what[13:]
 
165
            what = self._ellipsise_unimportant_words(what, final_width)
126
166
        if self.showAll:
127
 
            width = osutils.terminal_width()
128
 
            name_width = width - 15
129
 
            what = None
130
 
            if SHOW_DESCRIPTIONS:
131
 
                what = test.shortDescription()
132
 
                if what:
133
 
                    if len(what) > name_width:
134
 
                        what = what[:name_width-3] + '...'
135
 
            if what is None:
136
 
                what = test.id()
137
 
                if what.startswith('bzrlib.tests.'):
138
 
                    what = what[13:]
139
 
                if len(what) > name_width:
140
 
                    what = '...' + what[3-name_width:]
141
 
            what = what.ljust(name_width)
142
167
            self.stream.write(what)
 
168
        elif self.dots and self.pb is not None:
 
169
            self.pb.update(what, self.testsRun - 1, None)
143
170
        self.stream.flush()
144
171
        self._start_time = time.time()
145
172
 
149
176
        unittest.TestResult.addError(self, test, err)
150
177
        if self.showAll:
151
178
            self.stream.writeln("ERROR %s" % self._elapsedTime())
152
 
        elif self.dots:
 
179
        elif self.dots and self.pb is None:
153
180
            self.stream.write('E')
 
181
        elif self.dots:
 
182
            self.pb.update(self._ellipsise_unimportant_words('ERROR', 13), self.testsRun, None)
154
183
        self.stream.flush()
155
184
        if self.stop_early:
156
185
            self.stop()
159
188
        unittest.TestResult.addFailure(self, test, err)
160
189
        if self.showAll:
161
190
            self.stream.writeln(" FAIL %s" % self._elapsedTime())
162
 
        elif self.dots:
 
191
        elif self.dots and self.pb is None:
163
192
            self.stream.write('F')
 
193
        elif self.dots:
 
194
            self.pb.update(self._ellipsise_unimportant_words('FAIL', 13), self.testsRun, None)
164
195
        self.stream.flush()
165
196
        if self.stop_early:
166
197
            self.stop()
168
199
    def addSuccess(self, test):
169
200
        if self.showAll:
170
201
            self.stream.writeln('   OK %s' % self._elapsedTime())
171
 
        elif self.dots:
 
202
        elif self.dots and self.pb is None:
172
203
            self.stream.write('~')
 
204
        elif self.dots:
 
205
            self.pb.update(self._ellipsise_unimportant_words('OK', 13), self.testsRun, None)
173
206
        self.stream.flush()
174
207
        unittest.TestResult.addSuccess(self, test)
175
208
 
177
210
        if self.showAll:
178
211
            print >>self.stream, ' SKIP %s' % self._elapsedTime()
179
212
            print >>self.stream, '     %s' % skip_excinfo[1]
180
 
        elif self.dots:
 
213
        elif self.dots and self.pb is None:
181
214
            self.stream.write('S')
 
215
        elif self.dots:
 
216
            self.pb.update(self._ellipsise_unimportant_words('SKIP', 13), self.testsRun, None)
182
217
        self.stream.flush()
183
218
        # seems best to treat this as success from point-of-view of unittest
184
219
        # -- it actually does nothing so it barely matters :)
199
234
            self.stream.writeln("%s" % err)
200
235
 
201
236
 
202
 
class TextTestRunner(unittest.TextTestRunner):
 
237
class TextTestRunner(object):
203
238
    stop_on_failure = False
204
239
 
 
240
    def __init__(self,
 
241
                 stream=sys.stderr,
 
242
                 descriptions=0,
 
243
                 verbosity=1,
 
244
                 keep_output=False,
 
245
                 pb=None):
 
246
        self.stream = unittest._WritelnDecorator(stream)
 
247
        self.descriptions = descriptions
 
248
        self.verbosity = verbosity
 
249
        self.keep_output = keep_output
 
250
        self.pb = pb
 
251
 
205
252
    def _makeResult(self):
206
 
        result = _MyResult(self.stream, self.descriptions, self.verbosity)
 
253
        result = _MyResult(self.stream,
 
254
                           self.descriptions,
 
255
                           self.verbosity,
 
256
                           pb=self.pb)
207
257
        result.stop_early = self.stop_on_failure
208
258
        return result
209
259
 
 
260
    def run(self, test):
 
261
        "Run the given test case or test suite."
 
262
        result = self._makeResult()
 
263
        startTime = time.time()
 
264
        if self.pb is not None:
 
265
            self.pb.update('Running tests', 0, test.countTestCases())
 
266
        test.run(result)
 
267
        stopTime = time.time()
 
268
        timeTaken = stopTime - startTime
 
269
        result.printErrors()
 
270
        self.stream.writeln(result.separator2)
 
271
        run = result.testsRun
 
272
        self.stream.writeln("Ran %d test%s in %.3fs" %
 
273
                            (run, run != 1 and "s" or "", timeTaken))
 
274
        self.stream.writeln()
 
275
        if not result.wasSuccessful():
 
276
            self.stream.write("FAILED (")
 
277
            failed, errored = map(len, (result.failures, result.errors))
 
278
            if failed:
 
279
                self.stream.write("failures=%d" % failed)
 
280
            if errored:
 
281
                if failed: self.stream.write(", ")
 
282
                self.stream.write("errors=%d" % errored)
 
283
            self.stream.writeln(")")
 
284
        else:
 
285
            self.stream.writeln("OK")
 
286
        if self.pb is not None:
 
287
            self.pb.update('Cleaning up', 0, 1)
 
288
        # This is still a little bogus, 
 
289
        # but only a little. Folk not using our testrunner will
 
290
        # have to delete their temp directories themselves.
 
291
        test_root = TestCaseInTempDir.TEST_ROOT
 
292
        if result.wasSuccessful() or not self.keep_output:
 
293
            if test_root is not None:
 
294
                    osutils.rmtree(test_root)
 
295
        else:
 
296
            if self.pb is not None:
 
297
                self.pb.note("Failed tests working directories are in '%s'\n",
 
298
                             test_root)
 
299
            else:
 
300
                self.stream.writeln(
 
301
                    "Failed tests working directories are in '%s'\n" %
 
302
                    test_root)
 
303
        TestCaseInTempDir.TEST_ROOT = None
 
304
        if self.pb is not None:
 
305
            self.pb.clear()
 
306
        return result
 
307
 
210
308
 
211
309
def iter_suite_tests(suite):
212
310
    """Return all tests in a suite, recursing through nested suites"""
474
572
        handler.setLevel(logging.INFO)
475
573
        logger = logging.getLogger('')
476
574
        logger.addHandler(handler)
477
 
        old_stdin = getattr(bzrlib.ui.ui_factory, "stdin", None)
 
575
        old_ui_factory = bzrlib.ui.ui_factory
 
576
        bzrlib.ui.ui_factory = bzrlib.tests.blackbox.TestUIFactory(
 
577
            stdout=stdout,
 
578
            stderr=stderr)
478
579
        bzrlib.ui.ui_factory.stdin = stdin
479
580
        try:
480
581
            result = self.apply_redirected(stdin, stdout, stderr,
482
583
                                           argv)
483
584
        finally:
484
585
            logger.removeHandler(handler)
485
 
            bzrlib.ui.ui_factory.stdin = old_stdin
 
586
            bzrlib.ui.ui_factory = old_ui_factory
486
587
        out = stdout.getvalue()
487
588
        err = stderr.getvalue()
488
589
        if out:
899
1000
    TestCaseInTempDir._TEST_NAME = name
900
1001
    if verbose:
901
1002
        verbosity = 2
 
1003
        pb = None
902
1004
    else:
903
1005
        verbosity = 1
 
1006
        pb = progress.ProgressBar()
904
1007
    runner = TextTestRunner(stream=sys.stdout,
905
1008
                            descriptions=0,
906
 
                            verbosity=verbosity)
 
1009
                            verbosity=verbosity,
 
1010
                            keep_output=keep_output,
 
1011
                            pb=pb)
907
1012
    runner.stop_on_failure=stop_on_failure
908
1013
    if pattern != '.*':
909
1014
        suite = filter_suite_by_re(suite, pattern)
910
1015
    result = runner.run(suite)
911
 
    # This is still a little bogus, 
912
 
    # but only a little. Folk not using our testrunner will
913
 
    # have to delete their temp directories themselves.
914
 
    test_root = TestCaseInTempDir.TEST_ROOT
915
 
    if result.wasSuccessful() or not keep_output:
916
 
        if test_root is not None:
917
 
            print 'Deleting test root %s...' % test_root
918
 
            try:
919
 
                osutils.rmtree(test_root)
920
 
            finally:
921
 
                print
922
 
    else:
923
 
        print "Failed tests working directories are in '%s'\n" % TestCaseInTempDir.TEST_ROOT
924
1016
    return result.wasSuccessful()
925
1017
 
926
1018