/brz/remove-bazaar

To get this branch, use:
bzr branch http://gegoxaren.bato24.eu/bzr/brz/remove-bazaar

« back to all changes in this revision

Viewing changes to bzrlib/tests/__init__.py

  • Committer: Aaron Bentley
  • Date: 2006-11-17 04:06:03 UTC
  • mfrom: (2139 +trunk)
  • mto: This revision was merged to the branch mainline in revision 2162.
  • Revision ID: aaron.bentley@utoronto.ca-20061117040603-pgebxndswvwk26tt
Merge from bzr.dev

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
# Copyright (C) 2005, 2006 by Canonical Ltd
 
1
# Copyright (C) 2005, 2006 Canonical Ltd
2
2
#
3
3
# This program is free software; you can redistribute it and/or modify
4
4
# it under the terms of the GNU General Public License as published by
43
43
import time
44
44
 
45
45
 
46
 
from bzrlib import memorytree
 
46
from bzrlib import (
 
47
    bzrdir,
 
48
    debug,
 
49
    errors,
 
50
    memorytree,
 
51
    osutils,
 
52
    progress,
 
53
    urlutils,
 
54
    )
47
55
import bzrlib.branch
48
 
import bzrlib.bzrdir as bzrdir
49
56
import bzrlib.commands
50
57
import bzrlib.bundle.serializer
51
 
import bzrlib.errors as errors
 
58
import bzrlib.export
52
59
import bzrlib.inventory
53
60
import bzrlib.iterablefile
54
61
import bzrlib.lockdir
60
67
from bzrlib.merge import merge_inner
61
68
import bzrlib.merge3
62
69
import bzrlib.osutils
63
 
import bzrlib.osutils as osutils
64
70
import bzrlib.plugin
65
 
import bzrlib.progress as progress
66
71
from bzrlib.revision import common_ancestor
67
72
import bzrlib.store
68
73
from bzrlib import symbol_versioning
69
74
import bzrlib.trace
70
75
from bzrlib.transport import get_transport
71
76
import bzrlib.transport
72
 
from bzrlib.transport.local import LocalRelpathServer
 
77
from bzrlib.transport.local import LocalURLServer
 
78
from bzrlib.transport.memory import MemoryServer
73
79
from bzrlib.transport.readonly import ReadonlyServer
74
 
from bzrlib.trace import mutter
 
80
from bzrlib.trace import mutter, note
75
81
from bzrlib.tests import TestUtil
76
82
from bzrlib.tests.TestUtil import (
77
83
                          TestSuite,
78
84
                          TestLoader,
79
85
                          )
80
86
from bzrlib.tests.treeshape import build_tree_contents
81
 
import bzrlib.urlutils as urlutils
82
87
from bzrlib.workingtree import WorkingTree, WorkingTreeFormat2
83
88
 
84
 
default_transport = LocalRelpathServer
 
89
default_transport = LocalURLServer
85
90
 
86
91
MODULES_TO_TEST = []
87
92
MODULES_TO_DOCTEST = [
88
 
                      bzrlib.branch,
89
93
                      bzrlib.bundle.serializer,
90
 
                      bzrlib.commands,
91
94
                      bzrlib.errors,
 
95
                      bzrlib.export,
92
96
                      bzrlib.inventory,
93
97
                      bzrlib.iterablefile,
94
98
                      bzrlib.lockdir,
95
99
                      bzrlib.merge3,
96
100
                      bzrlib.option,
97
 
                      bzrlib.osutils,
98
101
                      bzrlib.store,
99
 
                      bzrlib.transport,
100
102
                      ]
101
103
 
102
104
 
132
134
            ]
133
135
 
134
136
 
135
 
class _MyResult(unittest._TextTestResult):
136
 
    """Custom TestResult.
 
137
class ExtendedTestResult(unittest._TextTestResult):
 
138
    """Accepts, reports and accumulates the results of running tests.
137
139
 
138
 
    Shows output in a different format, including displaying runtime for tests.
 
140
    Compared to this unittest version this class adds support for profiling,
 
141
    benchmarking, stopping as soon as a test fails,  and skipping tests.
 
142
    There are further-specialized subclasses for different types of display.
139
143
    """
 
144
 
140
145
    stop_early = False
141
146
    
142
 
    def __init__(self, stream, descriptions, verbosity, pb=None,
143
 
                 bench_history=None):
 
147
    def __init__(self, stream, descriptions, verbosity,
 
148
                 bench_history=None,
 
149
                 num_tests=None,
 
150
                 ):
144
151
        """Construct new TestResult.
145
152
 
146
153
        :param bench_history: Optionally, a writable file object to accumulate
147
154
            benchmark results.
148
155
        """
149
156
        unittest._TextTestResult.__init__(self, stream, descriptions, verbosity)
150
 
        self.pb = pb
151
157
        if bench_history is not None:
152
158
            from bzrlib.version import _get_bzr_source_tree
153
159
            src_tree = _get_bzr_source_tree()
163
169
                revision_id = ''
164
170
            bench_history.write("--date %s %s\n" % (time.time(), revision_id))
165
171
        self._bench_history = bench_history
 
172
        self.ui = bzrlib.ui.ui_factory
 
173
        self.num_tests = num_tests
 
174
        self.error_count = 0
 
175
        self.failure_count = 0
 
176
        self.skip_count = 0
 
177
        self.count = 0
 
178
        self._overall_start_time = time.time()
166
179
    
167
180
    def extractBenchmarkTime(self, testCase):
168
181
        """Add a benchmark time for the current test case."""
184
197
        """Format seconds as milliseconds with leading spaces."""
185
198
        return "%5dms" % (1000 * seconds)
186
199
 
187
 
    def _ellipsise_unimportant_words(self, a_string, final_width,
188
 
                                   keep_start=False):
189
 
        """Add ellipses (sp?) for overly long strings.
190
 
        
191
 
        :param keep_start: If true preserve the start of a_string rather
192
 
                           than the end of it.
193
 
        """
194
 
        if keep_start:
195
 
            if len(a_string) > final_width:
196
 
                result = a_string[:final_width-3] + '...'
197
 
            else:
198
 
                result = a_string
199
 
        else:
200
 
            if len(a_string) > final_width:
201
 
                result = '...' + a_string[3-final_width:]
202
 
            else:
203
 
                result = a_string
204
 
        return result.ljust(final_width)
 
200
    def _shortened_test_description(self, test):
 
201
        what = test.id()
 
202
        what = re.sub(r'^bzrlib\.(tests|benchmark)\.', '', what)
 
203
        return what
205
204
 
206
205
    def startTest(self, test):
207
206
        unittest.TestResult.startTest(self, test)
208
 
        # In a short description, the important words are in
209
 
        # the beginning, but in an id, the important words are
210
 
        # at the end
211
 
        SHOW_DESCRIPTIONS = False
212
 
 
213
 
        if not self.showAll and self.dots and self.pb is not None:
214
 
            final_width = 13
215
 
        else:
216
 
            final_width = osutils.terminal_width()
217
 
            final_width = final_width - 15 - 8
218
 
        what = None
219
 
        if SHOW_DESCRIPTIONS:
220
 
            what = test.shortDescription()
221
 
            if what:
222
 
                what = self._ellipsise_unimportant_words(what, final_width, keep_start=True)
223
 
        if what is None:
224
 
            what = test.id()
225
 
            if what.startswith('bzrlib.tests.'):
226
 
                what = what[13:]
227
 
            what = self._ellipsise_unimportant_words(what, final_width)
228
 
        if self.showAll:
229
 
            self.stream.write(what)
230
 
        elif self.dots and self.pb is not None:
231
 
            self.pb.update(what, self.testsRun - 1, None)
232
 
        self.stream.flush()
 
207
        self.report_test_start(test)
233
208
        self._recordTestStartTime()
234
209
 
235
210
    def _recordTestStartTime(self):
240
215
        if isinstance(err[1], TestSkipped):
241
216
            return self.addSkipped(test, err)    
242
217
        unittest.TestResult.addError(self, test, err)
 
218
        # We can only do this if we have one of our TestCases, not if
 
219
        # we have a doctest.
 
220
        setKeepLogfile = getattr(test, 'setKeepLogfile', None)
 
221
        if setKeepLogfile is not None:
 
222
            setKeepLogfile()
243
223
        self.extractBenchmarkTime(test)
244
 
        if self.showAll:
245
 
            self.stream.writeln("ERROR %s" % self._testTimeString())
246
 
        elif self.dots and self.pb is None:
247
 
            self.stream.write('E')
248
 
        elif self.dots:
249
 
            self.pb.update(self._ellipsise_unimportant_words('ERROR', 13), self.testsRun, None)
250
 
            self.pb.note(self._ellipsise_unimportant_words(
251
 
                            test.id() + ': ERROR',
252
 
                            osutils.terminal_width()))
253
 
        self.stream.flush()
 
224
        self.report_error(test, err)
254
225
        if self.stop_early:
255
226
            self.stop()
256
227
 
257
228
    def addFailure(self, test, err):
258
229
        unittest.TestResult.addFailure(self, test, err)
 
230
        # We can only do this if we have one of our TestCases, not if
 
231
        # we have a doctest.
 
232
        setKeepLogfile = getattr(test, 'setKeepLogfile', None)
 
233
        if setKeepLogfile is not None:
 
234
            setKeepLogfile()
259
235
        self.extractBenchmarkTime(test)
260
 
        if self.showAll:
261
 
            self.stream.writeln(" FAIL %s" % self._testTimeString())
262
 
        elif self.dots and self.pb is None:
263
 
            self.stream.write('F')
264
 
        elif self.dots:
265
 
            self.pb.update(self._ellipsise_unimportant_words('FAIL', 13), self.testsRun, None)
266
 
            self.pb.note(self._ellipsise_unimportant_words(
267
 
                            test.id() + ': FAIL',
268
 
                            osutils.terminal_width()))
269
 
        self.stream.flush()
 
236
        self.report_failure(test, err)
270
237
        if self.stop_early:
271
238
            self.stop()
272
239
 
277
244
                self._bench_history.write("%s %s\n" % (
278
245
                    self._formatTime(self._benchmarkTime),
279
246
                    test.id()))
280
 
        if self.showAll:
281
 
            self.stream.writeln('   OK %s' % self._testTimeString())
282
 
            for bench_called, stats in getattr(test, '_benchcalls', []):
283
 
                self.stream.writeln('LSProf output for %s(%s, %s)' % bench_called)
284
 
                stats.pprint(file=self.stream)
285
 
        elif self.dots and self.pb is None:
286
 
            self.stream.write('~')
287
 
        elif self.dots:
288
 
            self.pb.update(self._ellipsise_unimportant_words('OK', 13), self.testsRun, None)
289
 
        self.stream.flush()
 
247
        self.report_success(test)
290
248
        unittest.TestResult.addSuccess(self, test)
291
249
 
292
250
    def addSkipped(self, test, skip_excinfo):
293
251
        self.extractBenchmarkTime(test)
294
 
        if self.showAll:
295
 
            print >>self.stream, ' SKIP %s' % self._testTimeString()
296
 
            print >>self.stream, '     %s' % skip_excinfo[1]
297
 
        elif self.dots and self.pb is None:
298
 
            self.stream.write('S')
299
 
        elif self.dots:
300
 
            self.pb.update(self._ellipsise_unimportant_words('SKIP', 13), self.testsRun, None)
301
 
        self.stream.flush()
 
252
        self.report_skip(test, skip_excinfo)
302
253
        # seems best to treat this as success from point-of-view of unittest
303
254
        # -- it actually does nothing so it barely matters :)
304
255
        try:
324
275
            self.stream.writeln(self.separator2)
325
276
            self.stream.writeln("%s" % err)
326
277
 
 
278
    def finished(self):
 
279
        pass
 
280
 
 
281
    def report_cleaning_up(self):
 
282
        pass
 
283
 
 
284
    def report_success(self, test):
 
285
        pass
 
286
 
 
287
 
 
288
class TextTestResult(ExtendedTestResult):
 
289
    """Displays progress and results of tests in text form"""
 
290
 
 
291
    def __init__(self, *args, **kw):
 
292
        ExtendedTestResult.__init__(self, *args, **kw)
 
293
        self.pb = self.ui.nested_progress_bar()
 
294
        self.pb.show_pct = False
 
295
        self.pb.show_spinner = False
 
296
        self.pb.show_eta = False, 
 
297
        self.pb.show_count = False
 
298
        self.pb.show_bar = False
 
299
 
 
300
    def report_starting(self):
 
301
        self.pb.update('[test 0/%d] starting...' % (self.num_tests))
 
302
 
 
303
    def _progress_prefix_text(self):
 
304
        a = '[%d' % self.count
 
305
        if self.num_tests is not None:
 
306
            a +='/%d' % self.num_tests
 
307
        a += ' in %ds' % (time.time() - self._overall_start_time)
 
308
        if self.error_count:
 
309
            a += ', %d errors' % self.error_count
 
310
        if self.failure_count:
 
311
            a += ', %d failed' % self.failure_count
 
312
        if self.skip_count:
 
313
            a += ', %d skipped' % self.skip_count
 
314
        a += ']'
 
315
        return a
 
316
 
 
317
    def report_test_start(self, test):
 
318
        self.count += 1
 
319
        self.pb.update(
 
320
                self._progress_prefix_text()
 
321
                + ' ' 
 
322
                + self._shortened_test_description(test))
 
323
 
 
324
    def report_error(self, test, err):
 
325
        self.error_count += 1
 
326
        self.pb.note('ERROR: %s\n    %s\n' % (
 
327
            self._shortened_test_description(test),
 
328
            err[1],
 
329
            ))
 
330
 
 
331
    def report_failure(self, test, err):
 
332
        self.failure_count += 1
 
333
        self.pb.note('FAIL: %s\n    %s\n' % (
 
334
            self._shortened_test_description(test),
 
335
            err[1],
 
336
            ))
 
337
 
 
338
    def report_skip(self, test, skip_excinfo):
 
339
        self.skip_count += 1
 
340
        if False:
 
341
            # at the moment these are mostly not things we can fix
 
342
            # and so they just produce stipple; use the verbose reporter
 
343
            # to see them.
 
344
            if False:
 
345
                # show test and reason for skip
 
346
                self.pb.note('SKIP: %s\n    %s\n' % (
 
347
                    self._shortened_test_description(test),
 
348
                    skip_excinfo[1]))
 
349
            else:
 
350
                # since the class name was left behind in the still-visible
 
351
                # progress bar...
 
352
                self.pb.note('SKIP: %s' % (skip_excinfo[1]))
 
353
 
 
354
    def report_cleaning_up(self):
 
355
        self.pb.update('cleaning up...')
 
356
 
 
357
    def finished(self):
 
358
        self.pb.finished()
 
359
 
 
360
 
 
361
class VerboseTestResult(ExtendedTestResult):
 
362
    """Produce long output, with one line per test run plus times"""
 
363
 
 
364
    def _ellipsize_to_right(self, a_string, final_width):
 
365
        """Truncate and pad a string, keeping the right hand side"""
 
366
        if len(a_string) > final_width:
 
367
            result = '...' + a_string[3-final_width:]
 
368
        else:
 
369
            result = a_string
 
370
        return result.ljust(final_width)
 
371
 
 
372
    def report_starting(self):
 
373
        self.stream.write('running %d tests...\n' % self.num_tests)
 
374
 
 
375
    def report_test_start(self, test):
 
376
        self.count += 1
 
377
        name = self._shortened_test_description(test)
 
378
        self.stream.write(self._ellipsize_to_right(name, 60))
 
379
        self.stream.flush()
 
380
 
 
381
    def report_error(self, test, err):
 
382
        self.error_count += 1
 
383
        self.stream.writeln('ERROR %s\n    %s' 
 
384
                % (self._testTimeString(), err[1]))
 
385
 
 
386
    def report_failure(self, test, err):
 
387
        self.failure_count += 1
 
388
        self.stream.writeln('FAIL %s\n    %s'
 
389
                % (self._testTimeString(), err[1]))
 
390
 
 
391
    def report_success(self, test):
 
392
        self.stream.writeln('   OK %s' % self._testTimeString())
 
393
        for bench_called, stats in getattr(test, '_benchcalls', []):
 
394
            self.stream.writeln('LSProf output for %s(%s, %s)' % bench_called)
 
395
            stats.pprint(file=self.stream)
 
396
        self.stream.flush()
 
397
 
 
398
    def report_skip(self, test, skip_excinfo):
 
399
        print >>self.stream, ' SKIP %s' % self._testTimeString()
 
400
        print >>self.stream, '     %s' % skip_excinfo[1]
 
401
 
327
402
 
328
403
class TextTestRunner(object):
329
404
    stop_on_failure = False
333
408
                 descriptions=0,
334
409
                 verbosity=1,
335
410
                 keep_output=False,
336
 
                 pb=None,
337
411
                 bench_history=None):
338
412
        self.stream = unittest._WritelnDecorator(stream)
339
413
        self.descriptions = descriptions
340
414
        self.verbosity = verbosity
341
415
        self.keep_output = keep_output
342
 
        self.pb = pb
343
416
        self._bench_history = bench_history
344
417
 
345
 
    def _makeResult(self):
346
 
        result = _MyResult(self.stream,
347
 
                           self.descriptions,
348
 
                           self.verbosity,
349
 
                           pb=self.pb,
350
 
                           bench_history=self._bench_history)
351
 
        result.stop_early = self.stop_on_failure
352
 
        return result
353
 
 
354
418
    def run(self, test):
355
419
        "Run the given test case or test suite."
356
 
        result = self._makeResult()
357
420
        startTime = time.time()
358
 
        if self.pb is not None:
359
 
            self.pb.update('Running tests', 0, test.countTestCases())
 
421
        if self.verbosity == 1:
 
422
            result_class = TextTestResult
 
423
        elif self.verbosity >= 2:
 
424
            result_class = VerboseTestResult
 
425
        result = result_class(self.stream,
 
426
                              self.descriptions,
 
427
                              self.verbosity,
 
428
                              bench_history=self._bench_history,
 
429
                              num_tests=test.countTestCases(),
 
430
                              )
 
431
        result.stop_early = self.stop_on_failure
 
432
        result.report_starting()
360
433
        test.run(result)
361
434
        stopTime = time.time()
362
435
        timeTaken = stopTime - startTime
377
450
            self.stream.writeln(")")
378
451
        else:
379
452
            self.stream.writeln("OK")
380
 
        if self.pb is not None:
381
 
            self.pb.update('Cleaning up', 0, 1)
 
453
        result.report_cleaning_up()
382
454
        # This is still a little bogus, 
383
455
        # but only a little. Folk not using our testrunner will
384
456
        # have to delete their temp directories themselves.
385
 
        test_root = TestCaseInTempDir.TEST_ROOT
 
457
        test_root = TestCaseWithMemoryTransport.TEST_ROOT
386
458
        if result.wasSuccessful() or not self.keep_output:
387
459
            if test_root is not None:
388
460
                # If LANG=C we probably have created some bogus paths
399
471
                        sys.getfilesystemencoding())
400
472
                osutils.rmtree(test_root)
401
473
        else:
402
 
            if self.pb is not None:
403
 
                self.pb.note("Failed tests working directories are in '%s'\n",
404
 
                             test_root)
405
 
            else:
406
 
                self.stream.writeln(
407
 
                    "Failed tests working directories are in '%s'\n" %
408
 
                    test_root)
409
 
        TestCaseInTempDir.TEST_ROOT = None
410
 
        if self.pb is not None:
411
 
            self.pb.clear()
 
474
            note("Failed tests working directories are in '%s'\n", test_root)
 
475
        TestCaseWithMemoryTransport.TEST_ROOT = None
 
476
        result.finished()
412
477
        return result
413
478
 
414
479
 
482
547
 
483
548
    _log_file_name = None
484
549
    _log_contents = ''
 
550
    _keep_log_file = False
485
551
    # record lsprof data when performing benchmark calls.
486
552
    _gather_lsprof_in_benchmarks = False
487
553
 
493
559
        unittest.TestCase.setUp(self)
494
560
        self._cleanEnvironment()
495
561
        bzrlib.trace.disable_default_logging()
 
562
        self._silenceUI()
496
563
        self._startLogFile()
497
564
        self._benchcalls = []
498
565
        self._benchtime = None
499
566
 
 
567
    def _silenceUI(self):
 
568
        """Turn off UI for duration of test"""
 
569
        # by default the UI is off; tests can turn it on if they want it.
 
570
        saved = bzrlib.ui.ui_factory
 
571
        def _restore():
 
572
            bzrlib.ui.ui_factory = saved
 
573
        bzrlib.ui.ui_factory = bzrlib.ui.SilentUIFactory()
 
574
        self.addCleanup(_restore)
 
575
 
500
576
    def _ndiff_strings(self, a, b):
501
577
        """Return ndiff between two strings containing lines.
502
578
        
593
669
            a_callable(*args, **kwargs).
594
670
        """
595
671
        local_warnings = []
596
 
        def capture_warnings(msg, cls, stacklevel=None):
 
672
        def capture_warnings(msg, cls=None, stacklevel=None):
597
673
            # we've hooked into a deprecation specific callpath,
598
674
            # only deprecations should getting sent via it.
599
675
            self.assertEqual(cls, DeprecationWarning)
662
738
    def _finishLogFile(self):
663
739
        """Finished with the log file.
664
740
 
665
 
        Read contents into memory, close, and delete.
 
741
        Close the file and delete it, unless setKeepLogfile was called.
666
742
        """
667
743
        if self._log_file is None:
668
744
            return
669
745
        bzrlib.trace.disable_test_log(self._log_nonce)
670
 
        self._log_file.seek(0)
671
 
        self._log_contents = self._log_file.read()
672
746
        self._log_file.close()
673
 
        os.remove(self._log_file_name)
674
 
        self._log_file = self._log_file_name = None
 
747
        self._log_file = None
 
748
        if not self._keep_log_file:
 
749
            os.remove(self._log_file_name)
 
750
            self._log_file_name = None
 
751
 
 
752
    def setKeepLogfile(self):
 
753
        """Make the logfile not be deleted when _finishLogFile is called."""
 
754
        self._keep_log_file = True
675
755
 
676
756
    def addCleanup(self, callable):
677
757
        """Arrange to run a callable when this case is torn down.
686
766
 
687
767
    def _cleanEnvironment(self):
688
768
        new_env = {
 
769
            'BZR_HOME': None, # Don't inherit BZR_HOME to all the tests.
689
770
            'HOME': os.getcwd(),
690
771
            'APPDATA': os.getcwd(),
691
772
            'BZR_EMAIL': None,
745
826
    def log(self, *args):
746
827
        mutter(*args)
747
828
 
748
 
    def _get_log(self):
749
 
        """Return as a string the log for this test"""
750
 
        if self._log_file_name:
751
 
            return open(self._log_file_name).read()
752
 
        else:
 
829
    def _get_log(self, keep_log_file=False):
 
830
        """Return as a string the log for this test. If the file is still
 
831
        on disk and keep_log_file=False, delete the log file and store the
 
832
        content in self._log_contents."""
 
833
        # flush the log file, to get all content
 
834
        import bzrlib.trace
 
835
        bzrlib.trace._trace_file.flush()
 
836
        if self._log_contents:
753
837
            return self._log_contents
754
 
        # TODO: Delete the log after it's been read in
 
838
        if self._log_file_name is not None:
 
839
            logfile = open(self._log_file_name)
 
840
            try:
 
841
                log_contents = logfile.read()
 
842
            finally:
 
843
                logfile.close()
 
844
            if not keep_log_file:
 
845
                self._log_contents = log_contents
 
846
                os.remove(self._log_file_name)
 
847
            return log_contents
 
848
        else:
 
849
            return "DELETED log file to reduce memory footprint"
755
850
 
756
851
    def capture(self, cmd, retcode=0):
757
852
        """Shortcut that splits cmd into words, runs, and returns stdout"""
758
853
        return self.run_bzr_captured(cmd.split(), retcode=retcode)[0]
759
854
 
760
 
    def run_bzr_captured(self, argv, retcode=0, encoding=None, stdin=None):
 
855
    def run_bzr_captured(self, argv, retcode=0, encoding=None, stdin=None,
 
856
                         working_dir=None):
761
857
        """Invoke bzr and return (stdout, stderr).
762
858
 
763
859
        Useful for code that wants to check the contents of the
778
874
        :param retcode: expected return code, or None for don't-care.
779
875
        :param encoding: encoding for sys.stdout and sys.stderr
780
876
        :param stdin: A string to be used as stdin for the command.
 
877
        :param working_dir: Change to this directory before running
781
878
        """
782
879
        if encoding is None:
783
880
            encoding = bzrlib.user_encoding
799
896
            stdout=stdout,
800
897
            stderr=stderr)
801
898
        bzrlib.ui.ui_factory.stdin = stdin
 
899
 
 
900
        cwd = None
 
901
        if working_dir is not None:
 
902
            cwd = osutils.getcwd()
 
903
            os.chdir(working_dir)
 
904
 
802
905
        try:
803
 
            result = self.apply_redirected(stdin, stdout, stderr,
804
 
                                           bzrlib.commands.run_bzr_catch_errors,
805
 
                                           argv)
 
906
            saved_debug_flags = frozenset(debug.debug_flags)
 
907
            debug.debug_flags.clear()
 
908
            try:
 
909
                result = self.apply_redirected(stdin, stdout, stderr,
 
910
                                               bzrlib.commands.run_bzr_catch_errors,
 
911
                                               argv)
 
912
            finally:
 
913
                debug.debug_flags.update(saved_debug_flags)
806
914
        finally:
807
915
            logger.removeHandler(handler)
808
916
            bzrlib.ui.ui_factory = old_ui_factory
 
917
            if cwd is not None:
 
918
                os.chdir(cwd)
809
919
 
810
920
        out = stdout.getvalue()
811
921
        err = stderr.getvalue()
832
942
        retcode = kwargs.pop('retcode', 0)
833
943
        encoding = kwargs.pop('encoding', None)
834
944
        stdin = kwargs.pop('stdin', None)
835
 
        return self.run_bzr_captured(args, retcode=retcode, encoding=encoding, stdin=stdin)
 
945
        working_dir = kwargs.pop('working_dir', None)
 
946
        return self.run_bzr_captured(args, retcode=retcode, encoding=encoding,
 
947
                                     stdin=stdin, working_dir=working_dir)
836
948
 
837
949
    def run_bzr_decode(self, *args, **kwargs):
838
950
        if 'encoding' in kwargs:
886
998
            The values must be strings. The change will only occur in the
887
999
            child, so you don't need to fix the environment after running.
888
1000
        :param universal_newlines: Convert CRLF => LF
 
1001
        :param allow_plugins: By default the subprocess is run with
 
1002
            --no-plugins to ensure test reproducibility. Also, it is possible
 
1003
            for system-wide plugins to create unexpected output on stderr,
 
1004
            which can cause unnecessary test failures.
889
1005
        """
890
1006
        env_changes = kwargs.get('env_changes', {})
891
 
        process = self.start_bzr_subprocess(args, env_changes=env_changes)
 
1007
        working_dir = kwargs.get('working_dir', None)
 
1008
        allow_plugins = kwargs.get('allow_plugins', False)
 
1009
        process = self.start_bzr_subprocess(args, env_changes=env_changes,
 
1010
                                            working_dir=working_dir,
 
1011
                                            allow_plugins=allow_plugins)
892
1012
        # We distinguish between retcode=None and retcode not passed.
893
1013
        supplied_retcode = kwargs.get('retcode', 0)
894
1014
        return self.finish_bzr_subprocess(process, retcode=supplied_retcode,
896
1016
            process_args=args)
897
1017
 
898
1018
    def start_bzr_subprocess(self, process_args, env_changes=None,
899
 
                             skip_if_plan_to_signal=False):
 
1019
                             skip_if_plan_to_signal=False,
 
1020
                             working_dir=None,
 
1021
                             allow_plugins=False):
900
1022
        """Start bzr in a subprocess for testing.
901
1023
 
902
1024
        This starts a new Python interpreter and runs bzr in there.
913
1035
            child, so you don't need to fix the environment after running.
914
1036
        :param skip_if_plan_to_signal: raise TestSkipped when true and os.kill
915
1037
            is not available.
 
1038
        :param allow_plugins: If False (default) pass --no-plugins to bzr.
916
1039
 
917
1040
        :returns: Popen object for the started process.
918
1041
        """
934
1057
 
935
1058
        bzr_path = self.get_bzr_path()
936
1059
 
 
1060
        cwd = None
 
1061
        if working_dir is not None:
 
1062
            cwd = osutils.getcwd()
 
1063
            os.chdir(working_dir)
 
1064
 
937
1065
        try:
938
1066
            # win32 subprocess doesn't support preexec_fn
939
1067
            # so we will avoid using it on all platforms, just to
940
1068
            # make sure the code path is used, and we don't break on win32
941
1069
            cleanup_environment()
942
 
            process = Popen([sys.executable, bzr_path] + list(process_args),
943
 
                             stdin=PIPE, stdout=PIPE, stderr=PIPE)
 
1070
            command = [sys.executable, bzr_path]
 
1071
            if not allow_plugins:
 
1072
                command.append('--no-plugins')
 
1073
            command.extend(process_args)
 
1074
            process = self._popen(command, stdin=PIPE, stdout=PIPE, stderr=PIPE)
944
1075
        finally:
945
1076
            restore_environment()
 
1077
            if cwd is not None:
 
1078
                os.chdir(cwd)
 
1079
 
946
1080
        return process
947
1081
 
 
1082
    def _popen(self, *args, **kwargs):
 
1083
        """Place a call to Popen.
 
1084
 
 
1085
        Allows tests to override this method to intercept the calls made to
 
1086
        Popen for introspection.
 
1087
        """
 
1088
        return Popen(*args, **kwargs)
 
1089
 
948
1090
    def get_bzr_path(self):
949
1091
        """Return the path of the 'bzr' executable for this test suite."""
950
1092
        bzr_path = os.path.dirname(os.path.dirname(bzrlib.__file__))+'/bzr'
1053
1195
 
1054
1196
BzrTestBase = TestCase
1055
1197
 
 
1198
 
 
1199
class TestCaseWithMemoryTransport(TestCase):
 
1200
    """Common test class for tests that do not need disk resources.
 
1201
 
 
1202
    Tests that need disk resources should derive from TestCaseWithTransport.
 
1203
 
 
1204
    TestCaseWithMemoryTransport sets the TEST_ROOT variable for all bzr tests.
 
1205
 
 
1206
    For TestCaseWithMemoryTransport the test_home_dir is set to the name of
 
1207
    a directory which does not exist. This serves to help ensure test isolation
 
1208
    is preserved. test_dir is set to the TEST_ROOT, as is cwd, because they
 
1209
    must exist. However, TestCaseWithMemoryTransport does not offer local
 
1210
    file defaults for the transport in tests, nor does it obey the command line
 
1211
    override, so tests that accidentally write to the common directory should
 
1212
    be rare.
 
1213
    """
 
1214
 
 
1215
    TEST_ROOT = None
 
1216
    _TEST_NAME = 'test'
 
1217
 
 
1218
 
 
1219
    def __init__(self, methodName='runTest'):
 
1220
        # allow test parameterisation after test construction and before test
 
1221
        # execution. Variables that the parameteriser sets need to be 
 
1222
        # ones that are not set by setUp, or setUp will trash them.
 
1223
        super(TestCaseWithMemoryTransport, self).__init__(methodName)
 
1224
        self.transport_server = default_transport
 
1225
        self.transport_readonly_server = None
 
1226
 
 
1227
    def failUnlessExists(self, path):
 
1228
        """Fail unless path, which may be abs or relative, exists."""
 
1229
        self.failUnless(osutils.lexists(path))
 
1230
 
 
1231
    def failIfExists(self, path):
 
1232
        """Fail if path, which may be abs or relative, exists."""
 
1233
        self.failIf(osutils.lexists(path))
 
1234
        
 
1235
    def get_transport(self):
 
1236
        """Return a writeable transport for the test scratch space"""
 
1237
        t = get_transport(self.get_url())
 
1238
        self.assertFalse(t.is_readonly())
 
1239
        return t
 
1240
 
 
1241
    def get_readonly_transport(self):
 
1242
        """Return a readonly transport for the test scratch space
 
1243
        
 
1244
        This can be used to test that operations which should only need
 
1245
        readonly access in fact do not try to write.
 
1246
        """
 
1247
        t = get_transport(self.get_readonly_url())
 
1248
        self.assertTrue(t.is_readonly())
 
1249
        return t
 
1250
 
 
1251
    def get_readonly_server(self):
 
1252
        """Get the server instance for the readonly transport
 
1253
 
 
1254
        This is useful for some tests with specific servers to do diagnostics.
 
1255
        """
 
1256
        if self.__readonly_server is None:
 
1257
            if self.transport_readonly_server is None:
 
1258
                # readonly decorator requested
 
1259
                # bring up the server
 
1260
                self.get_url()
 
1261
                self.__readonly_server = ReadonlyServer()
 
1262
                self.__readonly_server.setUp(self.__server)
 
1263
            else:
 
1264
                self.__readonly_server = self.transport_readonly_server()
 
1265
                self.__readonly_server.setUp()
 
1266
            self.addCleanup(self.__readonly_server.tearDown)
 
1267
        return self.__readonly_server
 
1268
 
 
1269
    def get_readonly_url(self, relpath=None):
 
1270
        """Get a URL for the readonly transport.
 
1271
 
 
1272
        This will either be backed by '.' or a decorator to the transport 
 
1273
        used by self.get_url()
 
1274
        relpath provides for clients to get a path relative to the base url.
 
1275
        These should only be downwards relative, not upwards.
 
1276
        """
 
1277
        base = self.get_readonly_server().get_url()
 
1278
        if relpath is not None:
 
1279
            if not base.endswith('/'):
 
1280
                base = base + '/'
 
1281
            base = base + relpath
 
1282
        return base
 
1283
 
 
1284
    def get_server(self):
 
1285
        """Get the read/write server instance.
 
1286
 
 
1287
        This is useful for some tests with specific servers that need
 
1288
        diagnostics.
 
1289
 
 
1290
        For TestCaseWithMemoryTransport this is always a MemoryServer, and there
 
1291
        is no means to override it.
 
1292
        """
 
1293
        if self.__server is None:
 
1294
            self.__server = MemoryServer()
 
1295
            self.__server.setUp()
 
1296
            self.addCleanup(self.__server.tearDown)
 
1297
        return self.__server
 
1298
 
 
1299
    def get_url(self, relpath=None):
 
1300
        """Get a URL (or maybe a path) for the readwrite transport.
 
1301
 
 
1302
        This will either be backed by '.' or to an equivalent non-file based
 
1303
        facility.
 
1304
        relpath provides for clients to get a path relative to the base url.
 
1305
        These should only be downwards relative, not upwards.
 
1306
        """
 
1307
        base = self.get_server().get_url()
 
1308
        if relpath is not None and relpath != '.':
 
1309
            if not base.endswith('/'):
 
1310
                base = base + '/'
 
1311
            # XXX: Really base should be a url; we did after all call
 
1312
            # get_url()!  But sometimes it's just a path (from
 
1313
            # LocalAbspathServer), and it'd be wrong to append urlescaped data
 
1314
            # to a non-escaped local path.
 
1315
            if base.startswith('./') or base.startswith('/'):
 
1316
                base += relpath
 
1317
            else:
 
1318
                base += urlutils.escape(relpath)
 
1319
        return base
 
1320
 
 
1321
    def _make_test_root(self):
 
1322
        if TestCaseWithMemoryTransport.TEST_ROOT is not None:
 
1323
            return
 
1324
        i = 0
 
1325
        while True:
 
1326
            root = u'test%04d.tmp' % i
 
1327
            try:
 
1328
                os.mkdir(root)
 
1329
            except OSError, e:
 
1330
                if e.errno == errno.EEXIST:
 
1331
                    i += 1
 
1332
                    continue
 
1333
                else:
 
1334
                    raise
 
1335
            # successfully created
 
1336
            TestCaseWithMemoryTransport.TEST_ROOT = osutils.abspath(root)
 
1337
            break
 
1338
        # make a fake bzr directory there to prevent any tests propagating
 
1339
        # up onto the source directory's real branch
 
1340
        bzrdir.BzrDir.create_standalone_workingtree(
 
1341
            TestCaseWithMemoryTransport.TEST_ROOT)
 
1342
 
 
1343
    def makeAndChdirToTestDir(self):
 
1344
        """Create a temporary directories for this one test.
 
1345
        
 
1346
        This must set self.test_home_dir and self.test_dir and chdir to
 
1347
        self.test_dir.
 
1348
        
 
1349
        For TestCaseWithMemoryTransport we chdir to the TEST_ROOT for this test.
 
1350
        """
 
1351
        os.chdir(TestCaseWithMemoryTransport.TEST_ROOT)
 
1352
        self.test_dir = TestCaseWithMemoryTransport.TEST_ROOT
 
1353
        self.test_home_dir = self.test_dir + "/MemoryTransportMissingHomeDir"
 
1354
        
 
1355
    def make_branch(self, relpath, format=None):
 
1356
        """Create a branch on the transport at relpath."""
 
1357
        repo = self.make_repository(relpath, format=format)
 
1358
        return repo.bzrdir.create_branch()
 
1359
 
 
1360
    def make_bzrdir(self, relpath, format=None):
 
1361
        try:
 
1362
            # might be a relative or absolute path
 
1363
            maybe_a_url = self.get_url(relpath)
 
1364
            segments = maybe_a_url.rsplit('/', 1)
 
1365
            t = get_transport(maybe_a_url)
 
1366
            if len(segments) > 1 and segments[-1] not in ('', '.'):
 
1367
                try:
 
1368
                    t.mkdir('.')
 
1369
                except errors.FileExists:
 
1370
                    pass
 
1371
            if format is None:
 
1372
                format = bzrlib.bzrdir.BzrDirFormat.get_default_format()
 
1373
            return format.initialize_on_transport(t)
 
1374
        except errors.UninitializableFormat:
 
1375
            raise TestSkipped("Format %s is not initializable." % format)
 
1376
 
 
1377
    def make_repository(self, relpath, shared=False, format=None):
 
1378
        """Create a repository on our default transport at relpath."""
 
1379
        made_control = self.make_bzrdir(relpath, format=format)
 
1380
        return made_control.create_repository(shared=shared)
 
1381
 
 
1382
    def make_branch_and_memory_tree(self, relpath, format=None):
 
1383
        """Create a branch on the default transport and a MemoryTree for it."""
 
1384
        b = self.make_branch(relpath, format=format)
 
1385
        return memorytree.MemoryTree.create_on_branch(b)
 
1386
 
 
1387
    def overrideEnvironmentForTesting(self):
 
1388
        os.environ['HOME'] = self.test_home_dir
 
1389
        os.environ['APPDATA'] = self.test_home_dir
 
1390
        
 
1391
    def setUp(self):
 
1392
        super(TestCaseWithMemoryTransport, self).setUp()
 
1393
        self._make_test_root()
 
1394
        _currentdir = os.getcwdu()
 
1395
        def _leaveDirectory():
 
1396
            os.chdir(_currentdir)
 
1397
        self.addCleanup(_leaveDirectory)
 
1398
        self.makeAndChdirToTestDir()
 
1399
        self.overrideEnvironmentForTesting()
 
1400
        self.__readonly_server = None
 
1401
        self.__server = None
 
1402
 
1056
1403
     
1057
 
class TestCaseInTempDir(TestCase):
 
1404
class TestCaseInTempDir(TestCaseWithMemoryTransport):
1058
1405
    """Derived class that runs a test within a temporary directory.
1059
1406
 
1060
1407
    This is useful for tests that need to create a branch, etc.
1067
1414
    InTempDir is an old alias for FunctionalTestCase.
1068
1415
    """
1069
1416
 
1070
 
    TEST_ROOT = None
1071
 
    _TEST_NAME = 'test'
1072
1417
    OVERRIDE_PYTHON = 'python'
1073
1418
 
1074
1419
    def check_file_contents(self, filename, expect):
1079
1424
            self.log("actually: %r" % contents)
1080
1425
            self.fail("contents of %s not as expected" % filename)
1081
1426
 
1082
 
    def _make_test_root(self):
1083
 
        if TestCaseInTempDir.TEST_ROOT is not None:
1084
 
            return
1085
 
        i = 0
1086
 
        while True:
1087
 
            root = u'test%04d.tmp' % i
1088
 
            try:
1089
 
                os.mkdir(root)
1090
 
            except OSError, e:
1091
 
                if e.errno == errno.EEXIST:
1092
 
                    i += 1
1093
 
                    continue
1094
 
                else:
1095
 
                    raise
1096
 
            # successfully created
1097
 
            TestCaseInTempDir.TEST_ROOT = osutils.abspath(root)
1098
 
            break
1099
 
        # make a fake bzr directory there to prevent any tests propagating
1100
 
        # up onto the source directory's real branch
1101
 
        bzrdir.BzrDir.create_standalone_workingtree(TestCaseInTempDir.TEST_ROOT)
1102
 
 
1103
 
    def setUp(self):
1104
 
        super(TestCaseInTempDir, self).setUp()
1105
 
        self._make_test_root()
1106
 
        _currentdir = os.getcwdu()
 
1427
    def makeAndChdirToTestDir(self):
 
1428
        """See TestCaseWithMemoryTransport.makeAndChdirToTestDir().
 
1429
        
 
1430
        For TestCaseInTempDir we create a temporary directory based on the test
 
1431
        name and then create two subdirs - test and home under it.
 
1432
        """
1107
1433
        # shorten the name, to avoid test failures due to path length
1108
1434
        short_id = self.id().replace('bzrlib.tests.', '') \
1109
1435
                   .replace('__main__.', '')[-100:]
1126
1452
                os.mkdir(self.test_dir)
1127
1453
                os.chdir(self.test_dir)
1128
1454
                break
1129
 
        os.environ['HOME'] = self.test_home_dir
1130
 
        os.environ['APPDATA'] = self.test_home_dir
1131
 
        def _leaveDirectory():
1132
 
            os.chdir(_currentdir)
1133
 
        self.addCleanup(_leaveDirectory)
1134
 
        
 
1455
 
1135
1456
    def build_tree(self, shape, line_endings='native', transport=None):
1136
1457
        """Build a test tree according to a pattern.
1137
1458
 
1178
1499
    def build_tree_contents(self, shape):
1179
1500
        build_tree_contents(shape)
1180
1501
 
1181
 
    def failUnlessExists(self, path):
1182
 
        """Fail unless path, which may be abs or relative, exists."""
1183
 
        self.failUnless(osutils.lexists(path))
1184
 
 
1185
 
    def failIfExists(self, path):
1186
 
        """Fail if path, which may be abs or relative, exists."""
1187
 
        self.failIf(osutils.lexists(path))
1188
 
        
1189
1502
    def assertFileEqual(self, content, path):
1190
1503
        """Fail if path does not contain 'content'."""
1191
1504
        self.failUnless(osutils.lexists(path))
1207
1520
    readwrite one must both define get_url() as resolving to os.getcwd().
1208
1521
    """
1209
1522
 
1210
 
    def __init__(self, methodName='testMethod'):
1211
 
        super(TestCaseWithTransport, self).__init__(methodName)
1212
 
        self.__readonly_server = None
1213
 
        self.__server = None
1214
 
        self.transport_server = default_transport
1215
 
        self.transport_readonly_server = None
1216
 
 
1217
 
    def get_readonly_url(self, relpath=None):
1218
 
        """Get a URL for the readonly transport.
1219
 
 
1220
 
        This will either be backed by '.' or a decorator to the transport 
1221
 
        used by self.get_url()
1222
 
        relpath provides for clients to get a path relative to the base url.
1223
 
        These should only be downwards relative, not upwards.
1224
 
        """
1225
 
        base = self.get_readonly_server().get_url()
1226
 
        if relpath is not None:
1227
 
            if not base.endswith('/'):
1228
 
                base = base + '/'
1229
 
            base = base + relpath
1230
 
        return base
1231
 
 
1232
 
    def get_readonly_server(self):
1233
 
        """Get the server instance for the readonly transport
1234
 
 
1235
 
        This is useful for some tests with specific servers to do diagnostics.
1236
 
        """
1237
 
        if self.__readonly_server is None:
1238
 
            if self.transport_readonly_server is None:
1239
 
                # readonly decorator requested
1240
 
                # bring up the server
1241
 
                self.get_url()
1242
 
                self.__readonly_server = ReadonlyServer()
1243
 
                self.__readonly_server.setUp(self.__server)
1244
 
            else:
1245
 
                self.__readonly_server = self.transport_readonly_server()
1246
 
                self.__readonly_server.setUp()
1247
 
            self.addCleanup(self.__readonly_server.tearDown)
1248
 
        return self.__readonly_server
1249
 
 
1250
1523
    def get_server(self):
1251
 
        """Get the read/write server instance.
 
1524
        """See TestCaseWithMemoryTransport.
1252
1525
 
1253
1526
        This is useful for some tests with specific servers that need
1254
1527
        diagnostics.
1259
1532
            self.addCleanup(self.__server.tearDown)
1260
1533
        return self.__server
1261
1534
 
1262
 
    def get_url(self, relpath=None):
1263
 
        """Get a URL (or maybe a path) for the readwrite transport.
1264
 
 
1265
 
        This will either be backed by '.' or to an equivalent non-file based
1266
 
        facility.
1267
 
        relpath provides for clients to get a path relative to the base url.
1268
 
        These should only be downwards relative, not upwards.
1269
 
        """
1270
 
        base = self.get_server().get_url()
1271
 
        if relpath is not None and relpath != '.':
1272
 
            if not base.endswith('/'):
1273
 
                base = base + '/'
1274
 
            # XXX: Really base should be a url; we did after all call
1275
 
            # get_url()!  But sometimes it's just a path (from
1276
 
            # LocalAbspathServer), and it'd be wrong to append urlescaped data
1277
 
            # to a non-escaped local path.
1278
 
            if base.startswith('./') or base.startswith('/'):
1279
 
                base += relpath
1280
 
            else:
1281
 
                base += urlutils.escape(relpath)
1282
 
        return base
1283
 
 
1284
 
    def get_transport(self):
1285
 
        """Return a writeable transport for the test scratch space"""
1286
 
        t = get_transport(self.get_url())
1287
 
        self.assertFalse(t.is_readonly())
1288
 
        return t
1289
 
 
1290
 
    def get_readonly_transport(self):
1291
 
        """Return a readonly transport for the test scratch space
1292
 
        
1293
 
        This can be used to test that operations which should only need
1294
 
        readonly access in fact do not try to write.
1295
 
        """
1296
 
        t = get_transport(self.get_readonly_url())
1297
 
        self.assertTrue(t.is_readonly())
1298
 
        return t
1299
 
 
1300
 
    def make_branch(self, relpath, format=None):
1301
 
        """Create a branch on the transport at relpath."""
1302
 
        repo = self.make_repository(relpath, format=format)
1303
 
        return repo.bzrdir.create_branch()
1304
 
 
1305
 
    def make_bzrdir(self, relpath, format=None):
1306
 
        try:
1307
 
            # might be a relative or absolute path
1308
 
            maybe_a_url = self.get_url(relpath)
1309
 
            segments = maybe_a_url.rsplit('/', 1)
1310
 
            t = get_transport(maybe_a_url)
1311
 
            if len(segments) > 1 and segments[-1] not in ('', '.'):
1312
 
                try:
1313
 
                    t.mkdir('.')
1314
 
                except errors.FileExists:
1315
 
                    pass
1316
 
            if format is None:
1317
 
                format = bzrlib.bzrdir.BzrDirFormat.get_default_format()
1318
 
            return format.initialize_on_transport(t)
1319
 
        except errors.UninitializableFormat:
1320
 
            raise TestSkipped("Format %s is not initializable." % format)
1321
 
 
1322
 
    def make_repository(self, relpath, shared=False, format=None):
1323
 
        """Create a repository on our default transport at relpath."""
1324
 
        made_control = self.make_bzrdir(relpath, format=format)
1325
 
        return made_control.create_repository(shared=shared)
1326
 
 
1327
 
    def make_branch_and_memory_tree(self, relpath):
1328
 
        """Create a branch on the default transport and a MemoryTree for it."""
1329
 
        b = self.make_branch(relpath)
1330
 
        return memorytree.MemoryTree.create_on_branch(b)
1331
 
 
1332
1535
    def make_branch_and_tree(self, relpath, format=None):
1333
1536
        """Create a branch on the transport and a tree locally.
1334
1537
 
1376
1579
            self.fail("path %s is not a directory; has mode %#o"
1377
1580
                      % (relpath, mode))
1378
1581
 
 
1582
    def setUp(self):
 
1583
        super(TestCaseWithTransport, self).setUp()
 
1584
        self.__server = None
 
1585
 
1379
1586
 
1380
1587
class ChrootedTestCase(TestCaseWithTransport):
1381
1588
    """A support class that provides readonly urls outside the local namespace.
1407
1614
def run_suite(suite, name='test', verbose=False, pattern=".*",
1408
1615
              stop_on_failure=False, keep_output=False,
1409
1616
              transport=None, lsprof_timed=None, bench_history=None):
1410
 
    TestCaseInTempDir._TEST_NAME = name
1411
1617
    TestCase._gather_lsprof_in_benchmarks = lsprof_timed
1412
1618
    if verbose:
1413
1619
        verbosity = 2
1414
 
        pb = None
1415
1620
    else:
1416
1621
        verbosity = 1
1417
 
        pb = progress.ProgressBar()
1418
1622
    runner = TextTestRunner(stream=sys.stdout,
1419
1623
                            descriptions=0,
1420
1624
                            verbosity=verbosity,
1421
1625
                            keep_output=keep_output,
1422
 
                            pb=pb,
1423
1626
                            bench_history=bench_history)
1424
1627
    runner.stop_on_failure=stop_on_failure
1425
1628
    if pattern != '.*':
1487
1690
                   'bzrlib.tests.test_escaped_store',
1488
1691
                   'bzrlib.tests.test_fetch',
1489
1692
                   'bzrlib.tests.test_ftp_transport',
 
1693
                   'bzrlib.tests.test_generate_ids',
1490
1694
                   'bzrlib.tests.test_gpg',
1491
1695
                   'bzrlib.tests.test_graph',
1492
1696
                   'bzrlib.tests.test_hashcache',
1497
1701
                   'bzrlib.tests.test_inv',
1498
1702
                   'bzrlib.tests.test_knit',
1499
1703
                   'bzrlib.tests.test_lazy_import',
 
1704
                   'bzrlib.tests.test_lazy_regex',
1500
1705
                   'bzrlib.tests.test_lockdir',
1501
1706
                   'bzrlib.tests.test_lockable_files',
1502
1707
                   'bzrlib.tests.test_log',
1515
1720
                   'bzrlib.tests.test_plugins',
1516
1721
                   'bzrlib.tests.test_progress',
1517
1722
                   'bzrlib.tests.test_reconcile',
 
1723
                   'bzrlib.tests.test_registry',
1518
1724
                   'bzrlib.tests.test_repository',
1519
1725
                   'bzrlib.tests.test_revert',
1520
1726
                   'bzrlib.tests.test_revision',
1547
1753
                   'bzrlib.tests.test_urlutils',
1548
1754
                   'bzrlib.tests.test_versionedfile',
1549
1755
                   'bzrlib.tests.test_version',
 
1756
                   'bzrlib.tests.test_version_info',
1550
1757
                   'bzrlib.tests.test_weave',
1551
1758
                   'bzrlib.tests.test_whitebox',
1552
1759
                   'bzrlib.tests.test_workingtree',
1567
1774
    for m in MODULES_TO_TEST:
1568
1775
        suite.addTest(loader.loadTestsFromModule(m))
1569
1776
    for m in MODULES_TO_DOCTEST:
1570
 
        suite.addTest(doctest.DocTestSuite(m))
 
1777
        try:
 
1778
            suite.addTest(doctest.DocTestSuite(m))
 
1779
        except ValueError, e:
 
1780
            print '**failed to get doctest for: %s\n%s' %(m,e)
 
1781
            raise
1571
1782
    for name, plugin in bzrlib.plugin.all_plugins().items():
1572
1783
        if getattr(plugin, 'test_suite', None) is not None:
1573
1784
            suite.addTest(plugin.test_suite())