/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

[merge] bzr.dev 2240

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
52
58
import bzrlib.export
53
59
import bzrlib.inventory
54
60
import bzrlib.iterablefile
61
67
from bzrlib.merge import merge_inner
62
68
import bzrlib.merge3
63
69
import bzrlib.osutils
64
 
import bzrlib.osutils as osutils
65
70
import bzrlib.plugin
66
 
import bzrlib.progress as progress
67
71
from bzrlib.revision import common_ancestor
68
72
import bzrlib.store
69
73
from bzrlib import symbol_versioning
70
74
import bzrlib.trace
71
75
from bzrlib.transport import get_transport
72
76
import bzrlib.transport
73
 
from bzrlib.transport.local import LocalRelpathServer
 
77
from bzrlib.transport.local import LocalURLServer
74
78
from bzrlib.transport.memory import MemoryServer
75
79
from bzrlib.transport.readonly import ReadonlyServer
76
 
from bzrlib.trace import mutter
 
80
from bzrlib.trace import mutter, note
77
81
from bzrlib.tests import TestUtil
 
82
from bzrlib.tests.HttpServer import HttpServer
78
83
from bzrlib.tests.TestUtil import (
79
84
                          TestSuite,
80
85
                          TestLoader,
81
86
                          )
82
87
from bzrlib.tests.treeshape import build_tree_contents
83
 
import bzrlib.urlutils as urlutils
84
88
from bzrlib.workingtree import WorkingTree, WorkingTreeFormat2
85
89
 
86
 
default_transport = LocalRelpathServer
 
90
default_transport = LocalURLServer
87
91
 
88
92
MODULES_TO_TEST = []
89
93
MODULES_TO_DOCTEST = [
90
 
                      bzrlib.branch,
91
94
                      bzrlib.bundle.serializer,
92
 
                      bzrlib.commands,
93
95
                      bzrlib.errors,
94
96
                      bzrlib.export,
95
97
                      bzrlib.inventory,
97
99
                      bzrlib.lockdir,
98
100
                      bzrlib.merge3,
99
101
                      bzrlib.option,
100
 
                      bzrlib.osutils,
101
102
                      bzrlib.store,
102
 
                      bzrlib.transport,
103
103
                      ]
104
104
 
105
105
 
135
135
            ]
136
136
 
137
137
 
138
 
class _MyResult(unittest._TextTestResult):
139
 
    """Custom TestResult.
 
138
class ExtendedTestResult(unittest._TextTestResult):
 
139
    """Accepts, reports and accumulates the results of running tests.
140
140
 
141
 
    Shows output in a different format, including displaying runtime for tests.
 
141
    Compared to this unittest version this class adds support for profiling,
 
142
    benchmarking, stopping as soon as a test fails,  and skipping tests.
 
143
    There are further-specialized subclasses for different types of display.
142
144
    """
 
145
 
143
146
    stop_early = False
144
147
    
145
 
    def __init__(self, stream, descriptions, verbosity, pb=None,
146
 
                 bench_history=None):
 
148
    def __init__(self, stream, descriptions, verbosity,
 
149
                 bench_history=None,
 
150
                 num_tests=None,
 
151
                 ):
147
152
        """Construct new TestResult.
148
153
 
149
154
        :param bench_history: Optionally, a writable file object to accumulate
150
155
            benchmark results.
151
156
        """
152
157
        unittest._TextTestResult.__init__(self, stream, descriptions, verbosity)
153
 
        self.pb = pb
154
158
        if bench_history is not None:
155
159
            from bzrlib.version import _get_bzr_source_tree
156
160
            src_tree = _get_bzr_source_tree()
166
170
                revision_id = ''
167
171
            bench_history.write("--date %s %s\n" % (time.time(), revision_id))
168
172
        self._bench_history = bench_history
 
173
        self.ui = bzrlib.ui.ui_factory
 
174
        self.num_tests = num_tests
 
175
        self.error_count = 0
 
176
        self.failure_count = 0
 
177
        self.skip_count = 0
 
178
        self.count = 0
 
179
        self._overall_start_time = time.time()
169
180
    
170
181
    def extractBenchmarkTime(self, testCase):
171
182
        """Add a benchmark time for the current test case."""
181
192
                self._formatTime(self._benchmarkTime),
182
193
                self._elapsedTestTimeString())
183
194
        else:
184
 
            return "      %s" % self._elapsedTestTimeString()
 
195
            return "           %s" % self._elapsedTestTimeString()
185
196
 
186
197
    def _formatTime(self, seconds):
187
198
        """Format seconds as milliseconds with leading spaces."""
188
 
        return "%5dms" % (1000 * seconds)
 
199
        # some benchmarks can take thousands of seconds to run, so we need 8
 
200
        # places
 
201
        return "%8dms" % (1000 * seconds)
189
202
 
190
 
    def _ellipsise_unimportant_words(self, a_string, final_width,
191
 
                                   keep_start=False):
192
 
        """Add ellipses (sp?) for overly long strings.
193
 
        
194
 
        :param keep_start: If true preserve the start of a_string rather
195
 
                           than the end of it.
196
 
        """
197
 
        if keep_start:
198
 
            if len(a_string) > final_width:
199
 
                result = a_string[:final_width-3] + '...'
200
 
            else:
201
 
                result = a_string
202
 
        else:
203
 
            if len(a_string) > final_width:
204
 
                result = '...' + a_string[3-final_width:]
205
 
            else:
206
 
                result = a_string
207
 
        return result.ljust(final_width)
 
203
    def _shortened_test_description(self, test):
 
204
        what = test.id()
 
205
        what = re.sub(r'^bzrlib\.(tests|benchmarks)\.', '', what)
 
206
        return what
208
207
 
209
208
    def startTest(self, test):
210
209
        unittest.TestResult.startTest(self, test)
211
 
        # In a short description, the important words are in
212
 
        # the beginning, but in an id, the important words are
213
 
        # at the end
214
 
        SHOW_DESCRIPTIONS = False
215
 
 
216
 
        if not self.showAll and self.dots and self.pb is not None:
217
 
            final_width = 13
218
 
        else:
219
 
            final_width = osutils.terminal_width()
220
 
            final_width = final_width - 15 - 8
221
 
        what = None
222
 
        if SHOW_DESCRIPTIONS:
223
 
            what = test.shortDescription()
224
 
            if what:
225
 
                what = self._ellipsise_unimportant_words(what, final_width, keep_start=True)
226
 
        if what is None:
227
 
            what = test.id()
228
 
            if what.startswith('bzrlib.tests.'):
229
 
                what = what[13:]
230
 
            what = self._ellipsise_unimportant_words(what, final_width)
231
 
        if self.showAll:
232
 
            self.stream.write(what)
233
 
        elif self.dots and self.pb is not None:
234
 
            self.pb.update(what, self.testsRun - 1, None)
235
 
        self.stream.flush()
 
210
        self.report_test_start(test)
236
211
        self._recordTestStartTime()
237
212
 
238
213
    def _recordTestStartTime(self):
249
224
        if setKeepLogfile is not None:
250
225
            setKeepLogfile()
251
226
        self.extractBenchmarkTime(test)
252
 
        if self.showAll:
253
 
            self.stream.writeln("ERROR %s" % self._testTimeString())
254
 
        elif self.dots and self.pb is None:
255
 
            self.stream.write('E')
256
 
        elif self.dots:
257
 
            self.pb.update(self._ellipsise_unimportant_words('ERROR', 13), self.testsRun, None)
258
 
            self.pb.note(self._ellipsise_unimportant_words(
259
 
                            test.id() + ': ERROR',
260
 
                            osutils.terminal_width()))
261
 
        self.stream.flush()
 
227
        self.report_error(test, err)
262
228
        if self.stop_early:
263
229
            self.stop()
264
230
 
270
236
        if setKeepLogfile is not None:
271
237
            setKeepLogfile()
272
238
        self.extractBenchmarkTime(test)
273
 
        if self.showAll:
274
 
            self.stream.writeln(" FAIL %s" % self._testTimeString())
275
 
        elif self.dots and self.pb is None:
276
 
            self.stream.write('F')
277
 
        elif self.dots:
278
 
            self.pb.update(self._ellipsise_unimportant_words('FAIL', 13), self.testsRun, None)
279
 
            self.pb.note(self._ellipsise_unimportant_words(
280
 
                            test.id() + ': FAIL',
281
 
                            osutils.terminal_width()))
282
 
        self.stream.flush()
 
239
        self.report_failure(test, err)
283
240
        if self.stop_early:
284
241
            self.stop()
285
242
 
290
247
                self._bench_history.write("%s %s\n" % (
291
248
                    self._formatTime(self._benchmarkTime),
292
249
                    test.id()))
293
 
        if self.showAll:
294
 
            self.stream.writeln('   OK %s' % self._testTimeString())
295
 
            for bench_called, stats in getattr(test, '_benchcalls', []):
296
 
                self.stream.writeln('LSProf output for %s(%s, %s)' % bench_called)
297
 
                stats.pprint(file=self.stream)
298
 
        elif self.dots and self.pb is None:
299
 
            self.stream.write('~')
300
 
        elif self.dots:
301
 
            self.pb.update(self._ellipsise_unimportant_words('OK', 13), self.testsRun, None)
302
 
        self.stream.flush()
 
250
        self.report_success(test)
303
251
        unittest.TestResult.addSuccess(self, test)
304
252
 
305
253
    def addSkipped(self, test, skip_excinfo):
306
254
        self.extractBenchmarkTime(test)
307
 
        if self.showAll:
308
 
            print >>self.stream, ' SKIP %s' % self._testTimeString()
309
 
            print >>self.stream, '     %s' % skip_excinfo[1]
310
 
        elif self.dots and self.pb is None:
311
 
            self.stream.write('S')
312
 
        elif self.dots:
313
 
            self.pb.update(self._ellipsise_unimportant_words('SKIP', 13), self.testsRun, None)
314
 
        self.stream.flush()
 
255
        self.report_skip(test, skip_excinfo)
315
256
        # seems best to treat this as success from point-of-view of unittest
316
257
        # -- it actually does nothing so it barely matters :)
317
258
        try:
337
278
            self.stream.writeln(self.separator2)
338
279
            self.stream.writeln("%s" % err)
339
280
 
 
281
    def finished(self):
 
282
        pass
 
283
 
 
284
    def report_cleaning_up(self):
 
285
        pass
 
286
 
 
287
    def report_success(self, test):
 
288
        pass
 
289
 
 
290
 
 
291
class TextTestResult(ExtendedTestResult):
 
292
    """Displays progress and results of tests in text form"""
 
293
 
 
294
    def __init__(self, *args, **kw):
 
295
        ExtendedTestResult.__init__(self, *args, **kw)
 
296
        self.pb = self.ui.nested_progress_bar()
 
297
        self.pb.show_pct = False
 
298
        self.pb.show_spinner = False
 
299
        self.pb.show_eta = False, 
 
300
        self.pb.show_count = False
 
301
        self.pb.show_bar = False
 
302
 
 
303
    def report_starting(self):
 
304
        self.pb.update('[test 0/%d] starting...' % (self.num_tests))
 
305
 
 
306
    def _progress_prefix_text(self):
 
307
        a = '[%d' % self.count
 
308
        if self.num_tests is not None:
 
309
            a +='/%d' % self.num_tests
 
310
        a += ' in %ds' % (time.time() - self._overall_start_time)
 
311
        if self.error_count:
 
312
            a += ', %d errors' % self.error_count
 
313
        if self.failure_count:
 
314
            a += ', %d failed' % self.failure_count
 
315
        if self.skip_count:
 
316
            a += ', %d skipped' % self.skip_count
 
317
        a += ']'
 
318
        return a
 
319
 
 
320
    def report_test_start(self, test):
 
321
        self.count += 1
 
322
        self.pb.update(
 
323
                self._progress_prefix_text()
 
324
                + ' ' 
 
325
                + self._shortened_test_description(test))
 
326
 
 
327
    def report_error(self, test, err):
 
328
        self.error_count += 1
 
329
        self.pb.note('ERROR: %s\n    %s\n', 
 
330
            self._shortened_test_description(test),
 
331
            err[1],
 
332
            )
 
333
 
 
334
    def report_failure(self, test, err):
 
335
        self.failure_count += 1
 
336
        self.pb.note('FAIL: %s\n    %s\n', 
 
337
            self._shortened_test_description(test),
 
338
            err[1],
 
339
            )
 
340
 
 
341
    def report_skip(self, test, skip_excinfo):
 
342
        self.skip_count += 1
 
343
        if False:
 
344
            # at the moment these are mostly not things we can fix
 
345
            # and so they just produce stipple; use the verbose reporter
 
346
            # to see them.
 
347
            if False:
 
348
                # show test and reason for skip
 
349
                self.pb.note('SKIP: %s\n    %s\n', 
 
350
                    self._shortened_test_description(test),
 
351
                    skip_excinfo[1])
 
352
            else:
 
353
                # since the class name was left behind in the still-visible
 
354
                # progress bar...
 
355
                self.pb.note('SKIP: %s', skip_excinfo[1])
 
356
 
 
357
    def report_cleaning_up(self):
 
358
        self.pb.update('cleaning up...')
 
359
 
 
360
    def finished(self):
 
361
        self.pb.finished()
 
362
 
 
363
 
 
364
class VerboseTestResult(ExtendedTestResult):
 
365
    """Produce long output, with one line per test run plus times"""
 
366
 
 
367
    def _ellipsize_to_right(self, a_string, final_width):
 
368
        """Truncate and pad a string, keeping the right hand side"""
 
369
        if len(a_string) > final_width:
 
370
            result = '...' + a_string[3-final_width:]
 
371
        else:
 
372
            result = a_string
 
373
        return result.ljust(final_width)
 
374
 
 
375
    def report_starting(self):
 
376
        self.stream.write('running %d tests...\n' % self.num_tests)
 
377
 
 
378
    def report_test_start(self, test):
 
379
        self.count += 1
 
380
        name = self._shortened_test_description(test)
 
381
        # width needs space for 6 char status, plus 1 for slash, plus 2 10-char
 
382
        # numbers, plus a trailing blank
 
383
        self.stream.write(self._ellipsize_to_right(name,
 
384
                            osutils.terminal_width()-30))
 
385
        self.stream.flush()
 
386
 
 
387
    def report_error(self, test, err):
 
388
        self.error_count += 1
 
389
        self.stream.writeln('ERROR %s\n    %s' 
 
390
                % (self._testTimeString(), err[1]))
 
391
 
 
392
    def report_failure(self, test, err):
 
393
        self.failure_count += 1
 
394
        self.stream.writeln(' FAIL %s\n    %s'
 
395
                % (self._testTimeString(), err[1]))
 
396
 
 
397
    def report_success(self, test):
 
398
        self.stream.writeln('   OK %s' % self._testTimeString())
 
399
        for bench_called, stats in getattr(test, '_benchcalls', []):
 
400
            self.stream.writeln('LSProf output for %s(%s, %s)' % bench_called)
 
401
            stats.pprint(file=self.stream)
 
402
        self.stream.flush()
 
403
 
 
404
    def report_skip(self, test, skip_excinfo):
 
405
        print >>self.stream, ' SKIP %s' % self._testTimeString()
 
406
        print >>self.stream, '     %s' % skip_excinfo[1]
 
407
 
340
408
 
341
409
class TextTestRunner(object):
342
410
    stop_on_failure = False
346
414
                 descriptions=0,
347
415
                 verbosity=1,
348
416
                 keep_output=False,
349
 
                 pb=None,
350
417
                 bench_history=None):
351
418
        self.stream = unittest._WritelnDecorator(stream)
352
419
        self.descriptions = descriptions
353
420
        self.verbosity = verbosity
354
421
        self.keep_output = keep_output
355
 
        self.pb = pb
356
422
        self._bench_history = bench_history
357
423
 
358
 
    def _makeResult(self):
359
 
        result = _MyResult(self.stream,
360
 
                           self.descriptions,
361
 
                           self.verbosity,
362
 
                           pb=self.pb,
363
 
                           bench_history=self._bench_history)
364
 
        result.stop_early = self.stop_on_failure
365
 
        return result
366
 
 
367
424
    def run(self, test):
368
425
        "Run the given test case or test suite."
369
 
        result = self._makeResult()
370
426
        startTime = time.time()
371
 
        if self.pb is not None:
372
 
            self.pb.update('Running tests', 0, test.countTestCases())
 
427
        if self.verbosity == 1:
 
428
            result_class = TextTestResult
 
429
        elif self.verbosity >= 2:
 
430
            result_class = VerboseTestResult
 
431
        result = result_class(self.stream,
 
432
                              self.descriptions,
 
433
                              self.verbosity,
 
434
                              bench_history=self._bench_history,
 
435
                              num_tests=test.countTestCases(),
 
436
                              )
 
437
        result.stop_early = self.stop_on_failure
 
438
        result.report_starting()
373
439
        test.run(result)
374
440
        stopTime = time.time()
375
441
        timeTaken = stopTime - startTime
390
456
            self.stream.writeln(")")
391
457
        else:
392
458
            self.stream.writeln("OK")
393
 
        if self.pb is not None:
394
 
            self.pb.update('Cleaning up', 0, 1)
 
459
        result.report_cleaning_up()
395
460
        # This is still a little bogus, 
396
461
        # but only a little. Folk not using our testrunner will
397
462
        # have to delete their temp directories themselves.
412
477
                        sys.getfilesystemencoding())
413
478
                osutils.rmtree(test_root)
414
479
        else:
415
 
            if self.pb is not None:
416
 
                self.pb.note("Failed tests working directories are in '%s'\n",
417
 
                             test_root)
418
 
            else:
419
 
                self.stream.writeln(
420
 
                    "Failed tests working directories are in '%s'\n" %
421
 
                    test_root)
 
480
            note("Failed tests working directories are in '%s'\n", test_root)
422
481
        TestCaseWithMemoryTransport.TEST_ROOT = None
423
 
        if self.pb is not None:
424
 
            self.pb.clear()
 
482
        result.finished()
425
483
        return result
426
484
 
427
485
 
507
565
        unittest.TestCase.setUp(self)
508
566
        self._cleanEnvironment()
509
567
        bzrlib.trace.disable_default_logging()
 
568
        self._silenceUI()
510
569
        self._startLogFile()
511
570
        self._benchcalls = []
512
571
        self._benchtime = None
513
572
 
 
573
    def _silenceUI(self):
 
574
        """Turn off UI for duration of test"""
 
575
        # by default the UI is off; tests can turn it on if they want it.
 
576
        saved = bzrlib.ui.ui_factory
 
577
        def _restore():
 
578
            bzrlib.ui.ui_factory = saved
 
579
        bzrlib.ui.ui_factory = bzrlib.ui.SilentUIFactory()
 
580
        self.addCleanup(_restore)
 
581
 
514
582
    def _ndiff_strings(self, a, b):
515
583
        """Return ndiff between two strings containing lines.
516
584
        
575
643
            raise AssertionError("value(s) %r not present in container %r" % 
576
644
                                 (missing, superlist))
577
645
 
 
646
    def assertListRaises(self, excClass, func, *args, **kwargs):
 
647
        """Fail unless excClass is raised when the iterator from func is used.
 
648
        
 
649
        Many functions can return generators this makes sure
 
650
        to wrap them in a list() call to make sure the whole generator
 
651
        is run, and that the proper exception is raised.
 
652
        """
 
653
        try:
 
654
            list(func(*args, **kwargs))
 
655
        except excClass:
 
656
            return
 
657
        else:
 
658
            if getattr(excClass,'__name__', None) is not None:
 
659
                excName = excClass.__name__
 
660
            else:
 
661
                excName = str(excClass)
 
662
            raise self.failureException, "%s not raised" % excName
 
663
 
578
664
    def assertIs(self, left, right):
579
665
        if not (left is right):
580
666
            raise AssertionError("%r is not %r." % (left, right))
607
693
            a_callable(*args, **kwargs).
608
694
        """
609
695
        local_warnings = []
610
 
        def capture_warnings(msg, cls, stacklevel=None):
 
696
        def capture_warnings(msg, cls=None, stacklevel=None):
611
697
            # we've hooked into a deprecation specific callpath,
612
698
            # only deprecations should getting sent via it.
613
699
            self.assertEqual(cls, DeprecationWarning)
711
797
            'BZREMAIL': None, # may still be present in the environment
712
798
            'EMAIL': None,
713
799
            'BZR_PROGRESS_BAR': None,
 
800
            # Proxies
 
801
            'http_proxy': None,
 
802
            'HTTP_PROXY': None,
 
803
            'https_proxy': None,
 
804
            'HTTPS_PROXY': None,
 
805
            'no_proxy': None,
 
806
            'NO_PROXY': None,
 
807
            'all_proxy': None,
 
808
            'ALL_PROXY': None,
 
809
            # Nobody cares about these ones AFAIK. So far at
 
810
            # least. If you do (care), please update this comment
 
811
            # -- vila 20061212
 
812
            'ftp_proxy': None,
 
813
            'FTP_PROXY': None,
714
814
        }
715
815
        self.__old_env = {}
716
816
        self.addCleanup(self._restoreEnvironment)
841
941
            os.chdir(working_dir)
842
942
 
843
943
        try:
844
 
            result = self.apply_redirected(stdin, stdout, stderr,
845
 
                                           bzrlib.commands.run_bzr_catch_errors,
846
 
                                           argv)
 
944
            saved_debug_flags = frozenset(debug.debug_flags)
 
945
            debug.debug_flags.clear()
 
946
            try:
 
947
                result = self.apply_redirected(stdin, stdout, stderr,
 
948
                                               bzrlib.commands.run_bzr_catch_errors,
 
949
                                               argv)
 
950
            finally:
 
951
                debug.debug_flags.update(saved_debug_flags)
847
952
        finally:
848
953
            logger.removeHandler(handler)
849
954
            bzrlib.ui.ui_factory = old_ui_factory
931
1036
            The values must be strings. The change will only occur in the
932
1037
            child, so you don't need to fix the environment after running.
933
1038
        :param universal_newlines: Convert CRLF => LF
 
1039
        :param allow_plugins: By default the subprocess is run with
 
1040
            --no-plugins to ensure test reproducibility. Also, it is possible
 
1041
            for system-wide plugins to create unexpected output on stderr,
 
1042
            which can cause unnecessary test failures.
934
1043
        """
935
1044
        env_changes = kwargs.get('env_changes', {})
936
1045
        working_dir = kwargs.get('working_dir', None)
 
1046
        allow_plugins = kwargs.get('allow_plugins', False)
937
1047
        process = self.start_bzr_subprocess(args, env_changes=env_changes,
938
 
                                            working_dir=working_dir)
 
1048
                                            working_dir=working_dir,
 
1049
                                            allow_plugins=allow_plugins)
939
1050
        # We distinguish between retcode=None and retcode not passed.
940
1051
        supplied_retcode = kwargs.get('retcode', 0)
941
1052
        return self.finish_bzr_subprocess(process, retcode=supplied_retcode,
944
1055
 
945
1056
    def start_bzr_subprocess(self, process_args, env_changes=None,
946
1057
                             skip_if_plan_to_signal=False,
947
 
                             working_dir=None):
 
1058
                             working_dir=None,
 
1059
                             allow_plugins=False):
948
1060
        """Start bzr in a subprocess for testing.
949
1061
 
950
1062
        This starts a new Python interpreter and runs bzr in there.
961
1073
            child, so you don't need to fix the environment after running.
962
1074
        :param skip_if_plan_to_signal: raise TestSkipped when true and os.kill
963
1075
            is not available.
 
1076
        :param allow_plugins: If False (default) pass --no-plugins to bzr.
964
1077
 
965
1078
        :returns: Popen object for the started process.
966
1079
        """
992
1105
            # so we will avoid using it on all platforms, just to
993
1106
            # make sure the code path is used, and we don't break on win32
994
1107
            cleanup_environment()
995
 
            process = Popen([sys.executable, bzr_path] + list(process_args),
996
 
                             stdin=PIPE, stdout=PIPE, stderr=PIPE)
 
1108
            command = [sys.executable, bzr_path]
 
1109
            if not allow_plugins:
 
1110
                command.append('--no-plugins')
 
1111
            command.extend(process_args)
 
1112
            process = self._popen(command, stdin=PIPE, stdout=PIPE, stderr=PIPE)
997
1113
        finally:
998
1114
            restore_environment()
999
1115
            if cwd is not None:
1001
1117
 
1002
1118
        return process
1003
1119
 
 
1120
    def _popen(self, *args, **kwargs):
 
1121
        """Place a call to Popen.
 
1122
 
 
1123
        Allows tests to override this method to intercept the calls made to
 
1124
        Popen for introspection.
 
1125
        """
 
1126
        return Popen(*args, **kwargs)
 
1127
 
1004
1128
    def get_bzr_path(self):
1005
1129
        """Return the path of the 'bzr' executable for this test suite."""
1006
1130
        bzr_path = os.path.dirname(os.path.dirname(bzrlib.__file__))+'/bzr'
1138
1262
        self.transport_server = default_transport
1139
1263
        self.transport_readonly_server = None
1140
1264
 
1141
 
    def failUnlessExists(self, path):
1142
 
        """Fail unless path, which may be abs or relative, exists."""
1143
 
        self.failUnless(osutils.lexists(path))
1144
 
 
1145
 
    def failIfExists(self, path):
1146
 
        """Fail if path, which may be abs or relative, exists."""
1147
 
        self.failIf(osutils.lexists(path))
1148
 
        
1149
1265
    def get_transport(self):
1150
1266
        """Return a writeable transport for the test scratch space"""
1151
1267
        t = get_transport(self.get_url())
1162
1278
        self.assertTrue(t.is_readonly())
1163
1279
        return t
1164
1280
 
 
1281
    def create_transport_readonly_server(self):
 
1282
        """Create a transport server from class defined at init.
 
1283
 
 
1284
        This is mostly a hook for daughter classes.
 
1285
        """
 
1286
        return self.transport_readonly_server()
 
1287
 
1165
1288
    def get_readonly_server(self):
1166
1289
        """Get the server instance for the readonly transport
1167
1290
 
1175
1298
                self.__readonly_server = ReadonlyServer()
1176
1299
                self.__readonly_server.setUp(self.__server)
1177
1300
            else:
1178
 
                self.__readonly_server = self.transport_readonly_server()
 
1301
                self.__readonly_server = self.create_transport_readonly_server()
1179
1302
                self.__readonly_server.setUp()
1180
1303
            self.addCleanup(self.__readonly_server.tearDown)
1181
1304
        return self.__readonly_server
1282
1405
                    t.mkdir('.')
1283
1406
                except errors.FileExists:
1284
1407
                    pass
1285
 
            if format is None:
 
1408
            if isinstance(format, basestring):
 
1409
                format = bzrdir.format_registry.make_bzrdir(format)
 
1410
            elif format is None:
1286
1411
                format = bzrlib.bzrdir.BzrDirFormat.get_default_format()
1287
1412
            return format.initialize_on_transport(t)
1288
1413
        except errors.UninitializableFormat:
1367
1492
                os.chdir(self.test_dir)
1368
1493
                break
1369
1494
 
1370
 
    def build_tree(self, shape, line_endings='native', transport=None):
 
1495
    def build_tree(self, shape, line_endings='binary', transport=None):
1371
1496
        """Build a test tree according to a pattern.
1372
1497
 
1373
1498
        shape is a sequence of file specifications.  If the final
1398
1523
                elif line_endings == 'native':
1399
1524
                    end = os.linesep
1400
1525
                else:
1401
 
                    raise errors.BzrError('Invalid line ending request %r' % (line_endings,))
 
1526
                    raise errors.BzrError(
 
1527
                        'Invalid line ending request %r' % line_endings)
1402
1528
                content = "contents of %s%s" % (name.encode('utf-8'), end)
1403
 
                # Technically 'put()' is the right command. However, put
1404
 
                # uses an AtomicFile, which requires an extra rename into place
1405
 
                # As long as the files didn't exist in the past, append() will
1406
 
                # do the same thing as put()
1407
 
                # On jam's machine, make_kernel_like_tree is:
1408
 
                #   put:    4.5-7.5s (averaging 6s)
1409
 
                #   append: 2.9-4.5s
1410
 
                #   put_non_atomic: 2.9-4.5s
1411
1529
                transport.put_bytes_non_atomic(urlutils.escape(name), content)
1412
1530
 
1413
1531
    def build_tree_contents(self, shape):
1415
1533
 
1416
1534
    def assertFileEqual(self, content, path):
1417
1535
        """Fail if path does not contain 'content'."""
1418
 
        self.failUnless(osutils.lexists(path))
 
1536
        self.failUnlessExists(path)
1419
1537
        # TODO: jam 20060427 Shouldn't this be 'rb'?
1420
1538
        self.assertEqualDiff(content, open(path, 'r').read())
1421
1539
 
 
1540
    def failUnlessExists(self, path):
 
1541
        """Fail unless path, which may be abs or relative, exists."""
 
1542
        self.failUnless(osutils.lexists(path))
 
1543
 
 
1544
    def failIfExists(self, path):
 
1545
        """Fail if path, which may be abs or relative, exists."""
 
1546
        self.failIf(osutils.lexists(path))
 
1547
 
1422
1548
 
1423
1549
class TestCaseWithTransport(TestCaseInTempDir):
1424
1550
    """A test case that provides get_url and get_readonly_url facilities.
1434
1560
    readwrite one must both define get_url() as resolving to os.getcwd().
1435
1561
    """
1436
1562
 
 
1563
    def create_transport_server(self):
 
1564
        """Create a transport server from class defined at init.
 
1565
 
 
1566
        This is mostly a hook for daughter classes.
 
1567
        """
 
1568
        return self.transport_server()
 
1569
 
1437
1570
    def get_server(self):
1438
1571
        """See TestCaseWithMemoryTransport.
1439
1572
 
1441
1574
        diagnostics.
1442
1575
        """
1443
1576
        if self.__server is None:
1444
 
            self.__server = self.transport_server()
 
1577
            self.__server = self.create_transport_server()
1445
1578
            self.__server.setUp()
1446
1579
            self.addCleanup(self.__server.tearDown)
1447
1580
        return self.__server
1496
1629
    def setUp(self):
1497
1630
        super(TestCaseWithTransport, self).setUp()
1498
1631
        self.__server = None
1499
 
        self.transport_server = default_transport
1500
1632
 
1501
1633
 
1502
1634
class ChrootedTestCase(TestCaseWithTransport):
1513
1645
 
1514
1646
    def setUp(self):
1515
1647
        super(ChrootedTestCase, self).setUp()
1516
 
        if not self.transport_server == bzrlib.transport.memory.MemoryServer:
1517
 
            self.transport_readonly_server = bzrlib.transport.http.HttpServer
 
1648
        if not self.transport_server == MemoryServer:
 
1649
            self.transport_readonly_server = HttpServer
1518
1650
 
1519
1651
 
1520
1652
def filter_suite_by_re(suite, pattern):
1526
1658
    return result
1527
1659
 
1528
1660
 
 
1661
def sort_suite_by_re(suite, pattern):
 
1662
    first = []
 
1663
    second = []
 
1664
    filter_re = re.compile(pattern)
 
1665
    for test in iter_suite_tests(suite):
 
1666
        if filter_re.search(test.id()):
 
1667
            first.append(test)
 
1668
        else:
 
1669
            second.append(test)
 
1670
    return TestUtil.TestSuite(first + second)
 
1671
 
 
1672
 
1529
1673
def run_suite(suite, name='test', verbose=False, pattern=".*",
1530
1674
              stop_on_failure=False, keep_output=False,
1531
 
              transport=None, lsprof_timed=None, bench_history=None):
 
1675
              transport=None, lsprof_timed=None, bench_history=None,
 
1676
              matching_tests_first=None):
1532
1677
    TestCase._gather_lsprof_in_benchmarks = lsprof_timed
1533
1678
    if verbose:
1534
1679
        verbosity = 2
1535
 
        pb = None
1536
1680
    else:
1537
1681
        verbosity = 1
1538
 
        pb = progress.ProgressBar()
1539
1682
    runner = TextTestRunner(stream=sys.stdout,
1540
1683
                            descriptions=0,
1541
1684
                            verbosity=verbosity,
1542
1685
                            keep_output=keep_output,
1543
 
                            pb=pb,
1544
1686
                            bench_history=bench_history)
1545
1687
    runner.stop_on_failure=stop_on_failure
1546
1688
    if pattern != '.*':
1547
 
        suite = filter_suite_by_re(suite, pattern)
 
1689
        if matching_tests_first:
 
1690
            suite = sort_suite_by_re(suite, pattern)
 
1691
        else:
 
1692
            suite = filter_suite_by_re(suite, pattern)
1548
1693
    result = runner.run(suite)
1549
1694
    return result.wasSuccessful()
1550
1695
 
1554
1699
             transport=None,
1555
1700
             test_suite_factory=None,
1556
1701
             lsprof_timed=None,
1557
 
             bench_history=None):
 
1702
             bench_history=None,
 
1703
             matching_tests_first=None):
1558
1704
    """Run the whole test suite under the enhanced runner"""
1559
1705
    # XXX: Very ugly way to do this...
1560
1706
    # Disable warning about old formats because we don't want it to disturb
1576
1722
                     stop_on_failure=stop_on_failure, keep_output=keep_output,
1577
1723
                     transport=transport,
1578
1724
                     lsprof_timed=lsprof_timed,
1579
 
                     bench_history=bench_history)
 
1725
                     bench_history=bench_history,
 
1726
                     matching_tests_first=matching_tests_first)
1580
1727
    finally:
1581
1728
        default_transport = old_transport
1582
1729
 
1589
1736
    """
1590
1737
    testmod_names = [
1591
1738
                   'bzrlib.tests.test_ancestry',
 
1739
                   'bzrlib.tests.test_annotate',
1592
1740
                   'bzrlib.tests.test_api',
1593
1741
                   'bzrlib.tests.test_atomicfile',
1594
1742
                   'bzrlib.tests.test_bad_files',
1596
1744
                   'bzrlib.tests.test_bundle',
1597
1745
                   'bzrlib.tests.test_bzrdir',
1598
1746
                   'bzrlib.tests.test_cache_utf8',
1599
 
                   'bzrlib.tests.test_command',
 
1747
                   'bzrlib.tests.test_commands',
1600
1748
                   'bzrlib.tests.test_commit',
1601
1749
                   'bzrlib.tests.test_commit_merge',
1602
1750
                   'bzrlib.tests.test_config',
1608
1756
                   'bzrlib.tests.test_escaped_store',
1609
1757
                   'bzrlib.tests.test_fetch',
1610
1758
                   'bzrlib.tests.test_ftp_transport',
 
1759
                   'bzrlib.tests.test_generate_docs',
 
1760
                   'bzrlib.tests.test_generate_ids',
 
1761
                   'bzrlib.tests.test_globbing',
1611
1762
                   'bzrlib.tests.test_gpg',
1612
1763
                   'bzrlib.tests.test_graph',
1613
1764
                   'bzrlib.tests.test_hashcache',
1618
1769
                   'bzrlib.tests.test_inv',
1619
1770
                   'bzrlib.tests.test_knit',
1620
1771
                   'bzrlib.tests.test_lazy_import',
 
1772
                   'bzrlib.tests.test_lazy_regex',
1621
1773
                   'bzrlib.tests.test_lockdir',
1622
1774
                   'bzrlib.tests.test_lockable_files',
1623
1775
                   'bzrlib.tests.test_log',
1630
1782
                   'bzrlib.tests.test_nonascii',
1631
1783
                   'bzrlib.tests.test_options',
1632
1784
                   'bzrlib.tests.test_osutils',
 
1785
                   'bzrlib.tests.test_osutils_encodings',
1633
1786
                   'bzrlib.tests.test_patch',
1634
1787
                   'bzrlib.tests.test_patches',
1635
1788
                   'bzrlib.tests.test_permissions',
1636
1789
                   'bzrlib.tests.test_plugins',
1637
1790
                   'bzrlib.tests.test_progress',
1638
1791
                   'bzrlib.tests.test_reconcile',
 
1792
                   'bzrlib.tests.test_registry',
1639
1793
                   'bzrlib.tests.test_repository',
1640
1794
                   'bzrlib.tests.test_revert',
1641
1795
                   'bzrlib.tests.test_revision',
1672
1826
                   'bzrlib.tests.test_weave',
1673
1827
                   'bzrlib.tests.test_whitebox',
1674
1828
                   'bzrlib.tests.test_workingtree',
 
1829
                   'bzrlib.tests.test_wsgi',
1675
1830
                   'bzrlib.tests.test_xml',
1676
1831
                   ]
1677
1832
    test_transport_implementations = [
1689
1844
    for m in MODULES_TO_TEST:
1690
1845
        suite.addTest(loader.loadTestsFromModule(m))
1691
1846
    for m in MODULES_TO_DOCTEST:
1692
 
        suite.addTest(doctest.DocTestSuite(m))
 
1847
        try:
 
1848
            suite.addTest(doctest.DocTestSuite(m))
 
1849
        except ValueError, e:
 
1850
            print '**failed to get doctest for: %s\n%s' %(m,e)
 
1851
            raise
1693
1852
    for name, plugin in bzrlib.plugin.all_plugins().items():
1694
1853
        if getattr(plugin, 'test_suite', None) is not None:
1695
1854
            suite.addTest(plugin.test_suite())
1700
1859
    """Adapt the modules in mods_list using adapter and add to suite."""
1701
1860
    for test in iter_suite_tests(loader.loadTestsFromModuleNames(mods_list)):
1702
1861
        suite.addTests(adapter.adapt(test))
 
1862
 
 
1863
 
 
1864
def clean_selftest_output(root=None, quiet=False):
 
1865
    """Remove all selftest output directories from root directory.
 
1866
 
 
1867
    :param  root:   root directory for clean
 
1868
                    (if ommitted or None then clean current directory).
 
1869
    :param  quiet:  suppress report about deleting directories
 
1870
    """
 
1871
    import re
 
1872
    import shutil
 
1873
 
 
1874
    re_dir = re.compile(r'''test\d\d\d\d\.tmp''')
 
1875
    if root is None:
 
1876
        root = u'.'
 
1877
    for i in os.listdir(root):
 
1878
        if os.path.isdir(i) and re_dir.match(i):
 
1879
            if not quiet:
 
1880
                print 'delete directory:', i
 
1881
            shutil.rmtree(i)