~bzr-pqm/bzr/bzr.dev

« back to all changes in this revision

Viewing changes to bzrlib/tests/__init__.py

Merge bzr.dev.

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
# Copyright (C) 2005, 2006 Canonical Ltd
 
1
# Copyright (C) 2005, 2006, 2007 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
33
33
import errno
34
34
import logging
35
35
import os
 
36
from pprint import pformat
 
37
import random
36
38
import re
37
 
import shlex
38
39
import stat
39
40
from subprocess import Popen, PIPE
40
41
import sys
50
51
    memorytree,
51
52
    osutils,
52
53
    progress,
 
54
    ui,
53
55
    urlutils,
 
56
    workingtree,
54
57
    )
55
58
import bzrlib.branch
56
59
import bzrlib.commands
57
 
import bzrlib.bundle.serializer
 
60
import bzrlib.timestamp
58
61
import bzrlib.export
59
62
import bzrlib.inventory
60
63
import bzrlib.iterablefile
87
90
from bzrlib.tests.treeshape import build_tree_contents
88
91
from bzrlib.workingtree import WorkingTree, WorkingTreeFormat2
89
92
 
 
93
# Mark this python module as being part of the implementation
 
94
# of unittest: this gives us better tracebacks where the last
 
95
# shown frame is the test code, not our assertXYZ.
 
96
__unittest = 1
 
97
 
90
98
default_transport = LocalURLServer
91
99
 
92
100
MODULES_TO_TEST = []
93
101
MODULES_TO_DOCTEST = [
94
 
                      bzrlib.bundle.serializer,
 
102
                      bzrlib.timestamp,
95
103
                      bzrlib.errors,
96
104
                      bzrlib.export,
97
105
                      bzrlib.inventory,
116
124
    import bzrlib.tests.interrepository_implementations
117
125
    import bzrlib.tests.interversionedfile_implementations
118
126
    import bzrlib.tests.intertree_implementations
 
127
    import bzrlib.tests.per_lock
119
128
    import bzrlib.tests.repository_implementations
120
129
    import bzrlib.tests.revisionstore_implementations
121
130
    import bzrlib.tests.tree_implementations
128
137
            bzrlib.tests.interrepository_implementations,
129
138
            bzrlib.tests.interversionedfile_implementations,
130
139
            bzrlib.tests.intertree_implementations,
 
140
            bzrlib.tests.per_lock,
131
141
            bzrlib.tests.repository_implementations,
132
142
            bzrlib.tests.revisionstore_implementations,
133
143
            bzrlib.tests.tree_implementations,
148
158
    def __init__(self, stream, descriptions, verbosity,
149
159
                 bench_history=None,
150
160
                 num_tests=None,
 
161
                 use_numbered_dirs=False,
151
162
                 ):
152
163
        """Construct new TestResult.
153
164
 
170
181
                revision_id = ''
171
182
            bench_history.write("--date %s %s\n" % (time.time(), revision_id))
172
183
        self._bench_history = bench_history
173
 
        self.ui = bzrlib.ui.ui_factory
 
184
        self.ui = ui.ui_factory
174
185
        self.num_tests = num_tests
175
186
        self.error_count = 0
176
187
        self.failure_count = 0
 
188
        self.known_failure_count = 0
177
189
        self.skip_count = 0
 
190
        self.unsupported = {}
178
191
        self.count = 0
 
192
        self.use_numbered_dirs = use_numbered_dirs
179
193
        self._overall_start_time = time.time()
180
194
    
181
195
    def extractBenchmarkTime(self, testCase):
208
222
    def startTest(self, test):
209
223
        unittest.TestResult.startTest(self, test)
210
224
        self.report_test_start(test)
 
225
        test.number = self.count
211
226
        self._recordTestStartTime()
212
227
 
213
228
    def _recordTestStartTime(self):
214
229
        """Record that a test has started."""
215
230
        self._start_time = time.time()
216
231
 
 
232
    def _cleanupLogFile(self, test):
 
233
        # We can only do this if we have one of our TestCases, not if
 
234
        # we have a doctest.
 
235
        setKeepLogfile = getattr(test, 'setKeepLogfile', None)
 
236
        if setKeepLogfile is not None:
 
237
            setKeepLogfile()
 
238
 
217
239
    def addError(self, test, err):
 
240
        self.extractBenchmarkTime(test)
 
241
        self._cleanupLogFile(test)
218
242
        if isinstance(err[1], TestSkipped):
219
 
            return self.addSkipped(test, err)    
 
243
            return self.addSkipped(test, err)
 
244
        elif isinstance(err[1], UnavailableFeature):
 
245
            return self.addNotSupported(test, err[1].args[0])
220
246
        unittest.TestResult.addError(self, test, err)
221
 
        # We can only do this if we have one of our TestCases, not if
222
 
        # we have a doctest.
223
 
        setKeepLogfile = getattr(test, 'setKeepLogfile', None)
224
 
        if setKeepLogfile is not None:
225
 
            setKeepLogfile()
226
 
        self.extractBenchmarkTime(test)
 
247
        self.error_count += 1
227
248
        self.report_error(test, err)
228
249
        if self.stop_early:
229
250
            self.stop()
230
251
 
231
252
    def addFailure(self, test, err):
 
253
        self._cleanupLogFile(test)
 
254
        self.extractBenchmarkTime(test)
 
255
        if isinstance(err[1], KnownFailure):
 
256
            return self.addKnownFailure(test, err)
232
257
        unittest.TestResult.addFailure(self, test, err)
233
 
        # We can only do this if we have one of our TestCases, not if
234
 
        # we have a doctest.
235
 
        setKeepLogfile = getattr(test, 'setKeepLogfile', None)
236
 
        if setKeepLogfile is not None:
237
 
            setKeepLogfile()
238
 
        self.extractBenchmarkTime(test)
 
258
        self.failure_count += 1
239
259
        self.report_failure(test, err)
240
260
        if self.stop_early:
241
261
            self.stop()
242
262
 
 
263
    def addKnownFailure(self, test, err):
 
264
        self.known_failure_count += 1
 
265
        self.report_known_failure(test, err)
 
266
 
 
267
    def addNotSupported(self, test, feature):
 
268
        self.unsupported.setdefault(str(feature), 0)
 
269
        self.unsupported[str(feature)] += 1
 
270
        self.report_unsupported(test, feature)
 
271
 
243
272
    def addSuccess(self, test):
244
273
        self.extractBenchmarkTime(test)
245
274
        if self._bench_history is not None:
251
280
        unittest.TestResult.addSuccess(self, test)
252
281
 
253
282
    def addSkipped(self, test, skip_excinfo):
254
 
        self.extractBenchmarkTime(test)
255
283
        self.report_skip(test, skip_excinfo)
256
284
        # seems best to treat this as success from point-of-view of unittest
257
285
        # -- it actually does nothing so it barely matters :)
267
295
    def printErrorList(self, flavour, errors):
268
296
        for test, err in errors:
269
297
            self.stream.writeln(self.separator1)
270
 
            self.stream.writeln("%s: %s" % (flavour, self.getDescription(test)))
 
298
            self.stream.write("%s: " % flavour)
 
299
            if self.use_numbered_dirs:
 
300
                self.stream.write('#%d ' % test.number)
 
301
            self.stream.writeln(self.getDescription(test))
271
302
            if getattr(test, '_get_log', None) is not None:
272
303
                print >>self.stream
273
304
                print >>self.stream, \
291
322
class TextTestResult(ExtendedTestResult):
292
323
    """Displays progress and results of tests in text form"""
293
324
 
294
 
    def __init__(self, *args, **kw):
295
 
        ExtendedTestResult.__init__(self, *args, **kw)
296
 
        self.pb = self.ui.nested_progress_bar()
 
325
    def __init__(self, stream, descriptions, verbosity,
 
326
                 bench_history=None,
 
327
                 num_tests=None,
 
328
                 pb=None,
 
329
                 use_numbered_dirs=False,
 
330
                 ):
 
331
        ExtendedTestResult.__init__(self, stream, descriptions, verbosity,
 
332
            bench_history, num_tests, use_numbered_dirs)
 
333
        if pb is None:
 
334
            self.pb = self.ui.nested_progress_bar()
 
335
            self._supplied_pb = False
 
336
        else:
 
337
            self.pb = pb
 
338
            self._supplied_pb = True
297
339
        self.pb.show_pct = False
298
340
        self.pb.show_spinner = False
299
 
        self.pb.show_eta = False, 
 
341
        self.pb.show_eta = False,
300
342
        self.pb.show_count = False
301
343
        self.pb.show_bar = False
302
344
 
312
354
            a += ', %d errors' % self.error_count
313
355
        if self.failure_count:
314
356
            a += ', %d failed' % self.failure_count
 
357
        if self.known_failure_count:
 
358
            a += ', %d known failures' % self.known_failure_count
315
359
        if self.skip_count:
316
360
            a += ', %d skipped' % self.skip_count
 
361
        if self.unsupported:
 
362
            a += ', %d missing features' % len(self.unsupported)
317
363
        a += ']'
318
364
        return a
319
365
 
324
370
                + ' ' 
325
371
                + self._shortened_test_description(test))
326
372
 
 
373
    def _test_description(self, test):
 
374
        if self.use_numbered_dirs:
 
375
            return '#%d %s' % (self.count,
 
376
                               self._shortened_test_description(test))
 
377
        else:
 
378
            return self._shortened_test_description(test)
 
379
 
327
380
    def report_error(self, test, err):
328
 
        self.error_count += 1
329
381
        self.pb.note('ERROR: %s\n    %s\n', 
330
 
            self._shortened_test_description(test),
 
382
            self._test_description(test),
331
383
            err[1],
332
384
            )
333
385
 
334
386
    def report_failure(self, test, err):
335
 
        self.failure_count += 1
336
387
        self.pb.note('FAIL: %s\n    %s\n', 
337
 
            self._shortened_test_description(test),
 
388
            self._test_description(test),
338
389
            err[1],
339
390
            )
340
391
 
 
392
    def report_known_failure(self, test, err):
 
393
        self.pb.note('XFAIL: %s\n%s\n',
 
394
            self._test_description(test), err[1])
 
395
 
341
396
    def report_skip(self, test, skip_excinfo):
342
397
        self.skip_count += 1
343
398
        if False:
354
409
                # progress bar...
355
410
                self.pb.note('SKIP: %s', skip_excinfo[1])
356
411
 
 
412
    def report_unsupported(self, test, feature):
 
413
        """test cannot be run because feature is missing."""
 
414
                  
357
415
    def report_cleaning_up(self):
358
416
        self.pb.update('cleaning up...')
359
417
 
360
418
    def finished(self):
361
 
        self.pb.finished()
 
419
        if not self._supplied_pb:
 
420
            self.pb.finished()
362
421
 
363
422
 
364
423
class VerboseTestResult(ExtendedTestResult):
380
439
        name = self._shortened_test_description(test)
381
440
        # width needs space for 6 char status, plus 1 for slash, plus 2 10-char
382
441
        # numbers, plus a trailing blank
383
 
        self.stream.write(self._ellipsize_to_right(name,
384
 
                            osutils.terminal_width()-30))
 
442
        # when NUMBERED_DIRS: plus 5 chars on test number, plus 1 char on space
 
443
        if self.use_numbered_dirs:
 
444
            self.stream.write('%5d ' % self.count)
 
445
            self.stream.write(self._ellipsize_to_right(name,
 
446
                                osutils.terminal_width()-36))
 
447
        else:
 
448
            self.stream.write(self._ellipsize_to_right(name,
 
449
                                osutils.terminal_width()-30))
385
450
        self.stream.flush()
386
451
 
 
452
    def _error_summary(self, err):
 
453
        indent = ' ' * 4
 
454
        if self.use_numbered_dirs:
 
455
            indent += ' ' * 6
 
456
        return '%s%s' % (indent, err[1])
 
457
 
387
458
    def report_error(self, test, err):
388
 
        self.error_count += 1
389
 
        self.stream.writeln('ERROR %s\n    %s' 
390
 
                % (self._testTimeString(), err[1]))
 
459
        self.stream.writeln('ERROR %s\n%s'
 
460
                % (self._testTimeString(),
 
461
                   self._error_summary(err)))
391
462
 
392
463
    def report_failure(self, test, err):
393
 
        self.failure_count += 1
394
 
        self.stream.writeln(' FAIL %s\n    %s'
395
 
                % (self._testTimeString(), err[1]))
 
464
        self.stream.writeln(' FAIL %s\n%s'
 
465
                % (self._testTimeString(),
 
466
                   self._error_summary(err)))
 
467
 
 
468
    def report_known_failure(self, test, err):
 
469
        self.stream.writeln('XFAIL %s\n%s'
 
470
                % (self._testTimeString(),
 
471
                   self._error_summary(err)))
396
472
 
397
473
    def report_success(self, test):
398
474
        self.stream.writeln('   OK %s' % self._testTimeString())
399
475
        for bench_called, stats in getattr(test, '_benchcalls', []):
400
476
            self.stream.writeln('LSProf output for %s(%s, %s)' % bench_called)
401
477
            stats.pprint(file=self.stream)
 
478
        # flush the stream so that we get smooth output. This verbose mode is
 
479
        # used to show the output in PQM.
402
480
        self.stream.flush()
403
481
 
404
482
    def report_skip(self, test, skip_excinfo):
405
 
        print >>self.stream, ' SKIP %s' % self._testTimeString()
406
 
        print >>self.stream, '     %s' % skip_excinfo[1]
 
483
        self.skip_count += 1
 
484
        self.stream.writeln(' SKIP %s\n%s'
 
485
                % (self._testTimeString(),
 
486
                   self._error_summary(skip_excinfo)))
 
487
 
 
488
    def report_unsupported(self, test, feature):
 
489
        """test cannot be run because feature is missing."""
 
490
        self.stream.writeln("NODEP %s\n    The feature '%s' is not available."
 
491
                %(self._testTimeString(), feature))
 
492
                  
407
493
 
408
494
 
409
495
class TextTestRunner(object):
414
500
                 descriptions=0,
415
501
                 verbosity=1,
416
502
                 keep_output=False,
417
 
                 bench_history=None):
 
503
                 bench_history=None,
 
504
                 use_numbered_dirs=False,
 
505
                 list_only=False
 
506
                 ):
418
507
        self.stream = unittest._WritelnDecorator(stream)
419
508
        self.descriptions = descriptions
420
509
        self.verbosity = verbosity
421
510
        self.keep_output = keep_output
422
511
        self._bench_history = bench_history
 
512
        self.use_numbered_dirs = use_numbered_dirs
 
513
        self.list_only = list_only
423
514
 
424
515
    def run(self, test):
425
516
        "Run the given test case or test suite."
433
524
                              self.verbosity,
434
525
                              bench_history=self._bench_history,
435
526
                              num_tests=test.countTestCases(),
 
527
                              use_numbered_dirs=self.use_numbered_dirs,
436
528
                              )
437
529
        result.stop_early = self.stop_on_failure
438
530
        result.report_starting()
439
 
        test.run(result)
 
531
        if self.list_only:
 
532
            if self.verbosity >= 2:
 
533
                self.stream.writeln("Listing tests only ...\n")
 
534
            run = 0
 
535
            for t in iter_suite_tests(test):
 
536
                self.stream.writeln("%s" % (t.id()))
 
537
                run += 1
 
538
            actionTaken = "Listed"
 
539
        else: 
 
540
            test.run(result)
 
541
            run = result.testsRun
 
542
            actionTaken = "Ran"
440
543
        stopTime = time.time()
441
544
        timeTaken = stopTime - startTime
442
545
        result.printErrors()
443
546
        self.stream.writeln(result.separator2)
444
 
        run = result.testsRun
445
 
        self.stream.writeln("Ran %d test%s in %.3fs" %
446
 
                            (run, run != 1 and "s" or "", timeTaken))
 
547
        self.stream.writeln("%s %d test%s in %.3fs" % (actionTaken,
 
548
                            run, run != 1 and "s" or "", timeTaken))
447
549
        self.stream.writeln()
448
550
        if not result.wasSuccessful():
449
551
            self.stream.write("FAILED (")
453
555
            if errored:
454
556
                if failed: self.stream.write(", ")
455
557
                self.stream.write("errors=%d" % errored)
 
558
            if result.known_failure_count:
 
559
                if failed or errored: self.stream.write(", ")
 
560
                self.stream.write("known_failure_count=%d" %
 
561
                    result.known_failure_count)
456
562
            self.stream.writeln(")")
457
563
        else:
458
 
            self.stream.writeln("OK")
 
564
            if result.known_failure_count:
 
565
                self.stream.writeln("OK (known_failures=%d)" %
 
566
                    result.known_failure_count)
 
567
            else:
 
568
                self.stream.writeln("OK")
 
569
        if result.skip_count > 0:
 
570
            skipped = result.skip_count
 
571
            self.stream.writeln('%d test%s skipped' %
 
572
                                (skipped, skipped != 1 and "s" or ""))
 
573
        if result.unsupported:
 
574
            for feature, count in sorted(result.unsupported.items()):
 
575
                self.stream.writeln("Missing feature '%s' skipped %d tests." %
 
576
                    (feature, count))
459
577
        result.report_cleaning_up()
460
578
        # This is still a little bogus, 
461
579
        # but only a little. Folk not using our testrunner will
475
593
                else:
476
594
                    test_root = test_root.encode(
477
595
                        sys.getfilesystemencoding())
478
 
                osutils.rmtree(test_root)
 
596
                _rmtree_temp_dir(test_root)
479
597
        else:
480
598
            note("Failed tests working directories are in '%s'\n", test_root)
481
599
        TestCaseWithMemoryTransport.TEST_ROOT = None
500
618
    """Indicates that a test was intentionally skipped, rather than failing."""
501
619
 
502
620
 
 
621
class KnownFailure(AssertionError):
 
622
    """Indicates that a test failed in a precisely expected manner.
 
623
 
 
624
    Such failures dont block the whole test suite from passing because they are
 
625
    indicators of partially completed code or of future work. We have an
 
626
    explicit error for them so that we can ensure that they are always visible:
 
627
    KnownFailures are always shown in the output of bzr selftest.
 
628
    """
 
629
 
 
630
 
 
631
class UnavailableFeature(Exception):
 
632
    """A feature required for this test was not available.
 
633
 
 
634
    The feature should be used to construct the exception.
 
635
    """
 
636
 
 
637
 
503
638
class CommandFailed(Exception):
504
639
    pass
505
640
 
530
665
            return setattr(self._cstring, name, val)
531
666
 
532
667
 
 
668
class TestUIFactory(ui.CLIUIFactory):
 
669
    """A UI Factory for testing.
 
670
 
 
671
    Hide the progress bar but emit note()s.
 
672
    Redirect stdin.
 
673
    Allows get_password to be tested without real tty attached.
 
674
    """
 
675
 
 
676
    def __init__(self,
 
677
                 stdout=None,
 
678
                 stderr=None,
 
679
                 stdin=None):
 
680
        super(TestUIFactory, self).__init__()
 
681
        if stdin is not None:
 
682
            # We use a StringIOWrapper to be able to test various
 
683
            # encodings, but the user is still responsible to
 
684
            # encode the string and to set the encoding attribute
 
685
            # of StringIOWrapper.
 
686
            self.stdin = StringIOWrapper(stdin)
 
687
        if stdout is None:
 
688
            self.stdout = sys.stdout
 
689
        else:
 
690
            self.stdout = stdout
 
691
        if stderr is None:
 
692
            self.stderr = sys.stderr
 
693
        else:
 
694
            self.stderr = stderr
 
695
 
 
696
    def clear(self):
 
697
        """See progress.ProgressBar.clear()."""
 
698
 
 
699
    def clear_term(self):
 
700
        """See progress.ProgressBar.clear_term()."""
 
701
 
 
702
    def clear_term(self):
 
703
        """See progress.ProgressBar.clear_term()."""
 
704
 
 
705
    def finished(self):
 
706
        """See progress.ProgressBar.finished()."""
 
707
 
 
708
    def note(self, fmt_string, *args, **kwargs):
 
709
        """See progress.ProgressBar.note()."""
 
710
        self.stdout.write((fmt_string + "\n") % args)
 
711
 
 
712
    def progress_bar(self):
 
713
        return self
 
714
 
 
715
    def nested_progress_bar(self):
 
716
        return self
 
717
 
 
718
    def update(self, message, count=None, total=None):
 
719
        """See progress.ProgressBar.update()."""
 
720
 
 
721
    def get_non_echoed_password(self, prompt):
 
722
        """Get password from stdin without trying to handle the echo mode"""
 
723
        if prompt:
 
724
            self.stdout.write(prompt)
 
725
        password = self.stdin.readline()
 
726
        if not password:
 
727
            raise EOFError
 
728
        if password[-1] == '\n':
 
729
            password = password[:-1]
 
730
        return password
 
731
 
 
732
 
533
733
class TestCase(unittest.TestCase):
534
734
    """Base class for bzr unit tests.
535
735
    
569
769
        self._startLogFile()
570
770
        self._benchcalls = []
571
771
        self._benchtime = None
 
772
        self._clear_hooks()
 
773
 
 
774
    def _clear_hooks(self):
 
775
        # prevent hooks affecting tests
 
776
        import bzrlib.branch
 
777
        import bzrlib.smart.server
 
778
        self._preserved_hooks = {
 
779
            bzrlib.branch.Branch: bzrlib.branch.Branch.hooks,
 
780
            bzrlib.smart.server.SmartTCPServer: bzrlib.smart.server.SmartTCPServer.hooks,
 
781
            }
 
782
        self.addCleanup(self._restoreHooks)
 
783
        # this list of hooks must be kept in sync with the defaults
 
784
        # in branch.py
 
785
        bzrlib.branch.Branch.hooks = bzrlib.branch.BranchHooks()
 
786
        bzrlib.smart.server.SmartTCPServer.hooks = \
 
787
            bzrlib.smart.server.SmartServerHooks()
572
788
 
573
789
    def _silenceUI(self):
574
790
        """Turn off UI for duration of test"""
575
791
        # by default the UI is off; tests can turn it on if they want it.
576
 
        saved = bzrlib.ui.ui_factory
 
792
        saved = ui.ui_factory
577
793
        def _restore():
578
 
            bzrlib.ui.ui_factory = saved
579
 
        bzrlib.ui.ui_factory = bzrlib.ui.SilentUIFactory()
 
794
            ui.ui_factory = saved
 
795
        ui.ui_factory = ui.SilentUIFactory()
580
796
        self.addCleanup(_restore)
581
797
 
582
798
    def _ndiff_strings(self, a, b):
594
810
                                  charjunk=lambda x: False)
595
811
        return ''.join(difflines)
596
812
 
 
813
    def assertEqual(self, a, b, message=''):
 
814
        try:
 
815
            if a == b:
 
816
                return
 
817
        except UnicodeError, e:
 
818
            # If we can't compare without getting a UnicodeError, then
 
819
            # obviously they are different
 
820
            mutter('UnicodeError: %s', e)
 
821
        if message:
 
822
            message += '\n'
 
823
        raise AssertionError("%snot equal:\na = %s\nb = %s\n"
 
824
            % (message,
 
825
               pformat(a, indent=4), pformat(b, indent=4)))
 
826
 
 
827
    assertEquals = assertEqual
 
828
 
597
829
    def assertEqualDiff(self, a, b, message=None):
598
830
        """Assert two texts are equal, if not raise an exception.
599
831
        
624
856
    def assertContainsRe(self, haystack, needle_re):
625
857
        """Assert that a contains something matching a regular expression."""
626
858
        if not re.search(needle_re, haystack):
627
 
            raise AssertionError('pattern "%s" not found in "%s"'
 
859
            raise AssertionError('pattern "%r" not found in "%r"'
628
860
                    % (needle_re, haystack))
629
861
 
630
862
    def assertNotContainsRe(self, haystack, needle_re):
661
893
                excName = str(excClass)
662
894
            raise self.failureException, "%s not raised" % excName
663
895
 
664
 
    def assertIs(self, left, right):
 
896
    def assertRaises(self, excClass, func, *args, **kwargs):
 
897
        """Assert that a callable raises a particular exception.
 
898
 
 
899
        :param excClass: As for the except statement, this may be either an
 
900
        exception class, or a tuple of classes.
 
901
 
 
902
        Returns the exception so that you can examine it.
 
903
        """
 
904
        try:
 
905
            func(*args, **kwargs)
 
906
        except excClass, e:
 
907
            return e
 
908
        else:
 
909
            if getattr(excClass,'__name__', None) is not None:
 
910
                excName = excClass.__name__
 
911
            else:
 
912
                # probably a tuple
 
913
                excName = str(excClass)
 
914
            raise self.failureException, "%s not raised" % excName
 
915
 
 
916
    def assertIs(self, left, right, message=None):
665
917
        if not (left is right):
666
 
            raise AssertionError("%r is not %r." % (left, right))
 
918
            if message is not None:
 
919
                raise AssertionError(message)
 
920
            else:
 
921
                raise AssertionError("%r is not %r." % (left, right))
 
922
 
 
923
    def assertIsNot(self, left, right, message=None):
 
924
        if (left is right):
 
925
            if message is not None:
 
926
                raise AssertionError(message)
 
927
            else:
 
928
                raise AssertionError("%r is %r." % (left, right))
667
929
 
668
930
    def assertTransportMode(self, transport, path, mode):
669
931
        """Fail if a path does not have mode mode.
683
945
            self.fail("%r is an instance of %s rather than %s" % (
684
946
                obj, obj.__class__, kls))
685
947
 
 
948
    def expectFailure(self, reason, assertion, *args, **kwargs):
 
949
        """Invoke a test, expecting it to fail for the given reason.
 
950
 
 
951
        This is for assertions that ought to succeed, but currently fail.
 
952
        (The failure is *expected* but not *wanted*.)  Please be very precise
 
953
        about the failure you're expecting.  If a new bug is introduced,
 
954
        AssertionError should be raised, not KnownFailure.
 
955
 
 
956
        Frequently, expectFailure should be followed by an opposite assertion.
 
957
        See example below.
 
958
 
 
959
        Intended to be used with a callable that raises AssertionError as the
 
960
        'assertion' parameter.  args and kwargs are passed to the 'assertion'.
 
961
 
 
962
        Raises KnownFailure if the test fails.  Raises AssertionError if the
 
963
        test succeeds.
 
964
 
 
965
        example usage::
 
966
 
 
967
          self.expectFailure('Math is broken', self.assertNotEqual, 54,
 
968
                             dynamic_val)
 
969
          self.assertEqual(42, dynamic_val)
 
970
 
 
971
          This means that a dynamic_val of 54 will cause the test to raise
 
972
          a KnownFailure.  Once math is fixed and the expectFailure is removed,
 
973
          only a dynamic_val of 42 will allow the test to pass.  Anything other
 
974
          than 54 or 42 will cause an AssertionError.
 
975
        """
 
976
        try:
 
977
            assertion(*args, **kwargs)
 
978
        except AssertionError:
 
979
            raise KnownFailure(reason)
 
980
        else:
 
981
            self.fail('Unexpected success.  Should have failed: %s' % reason)
 
982
 
686
983
    def _capture_warnings(self, a_callable, *args, **kwargs):
687
984
        """A helper for callDeprecated and applyDeprecated.
688
985
 
725
1022
        expected_first_warning = symbol_versioning.deprecation_string(
726
1023
            a_callable, deprecation_format)
727
1024
        if len(call_warnings) == 0:
728
 
            self.fail("No assertion generated by call to %s" %
 
1025
            self.fail("No deprecation warning generated by call to %s" %
729
1026
                a_callable)
730
1027
        self.assertEqual(expected_first_warning, call_warnings[0])
731
1028
        return result
792
1089
        new_env = {
793
1090
            'BZR_HOME': None, # Don't inherit BZR_HOME to all the tests.
794
1091
            'HOME': os.getcwd(),
795
 
            'APPDATA': os.getcwd(),
 
1092
            'APPDATA': None,  # bzr now use Win32 API and don't rely on APPDATA
796
1093
            'BZR_EMAIL': None,
797
1094
            'BZREMAIL': None, # may still be present in the environment
798
1095
            'EMAIL': None,
825
1122
        for name, value in self.__old_env.iteritems():
826
1123
            osutils.set_or_unset_env(name, value)
827
1124
 
 
1125
    def _restoreHooks(self):
 
1126
        for klass, hooks in self._preserved_hooks.items():
 
1127
            setattr(klass, 'hooks', hooks)
 
1128
 
 
1129
    def knownFailure(self, reason):
 
1130
        """This test has failed for some known reason."""
 
1131
        raise KnownFailure(reason)
 
1132
 
 
1133
    def run(self, result=None):
 
1134
        if result is None: result = self.defaultTestResult()
 
1135
        for feature in getattr(self, '_test_needs_features', []):
 
1136
            if not feature.available():
 
1137
                result.startTest(self)
 
1138
                if getattr(result, 'addNotSupported', None):
 
1139
                    result.addNotSupported(self, feature)
 
1140
                else:
 
1141
                    result.addSuccess(self)
 
1142
                result.stopTest(self)
 
1143
                return
 
1144
        return unittest.TestCase.run(self, result)
 
1145
 
828
1146
    def tearDown(self):
829
1147
        self._runCleanups()
830
1148
        unittest.TestCase.tearDown(self)
858
1176
        """
859
1177
        # TODO: Perhaps this should keep running cleanups even if 
860
1178
        # one of them fails?
861
 
        for cleanup_fn in reversed(self._cleanups):
862
 
            cleanup_fn()
 
1179
 
 
1180
        # Actually pop the cleanups from the list so tearDown running
 
1181
        # twice is safe (this happens for skipped tests).
 
1182
        while self._cleanups:
 
1183
            self._cleanups.pop()()
863
1184
 
864
1185
    def log(self, *args):
865
1186
        mutter(*args)
881
1202
                logfile.close()
882
1203
            if not keep_log_file:
883
1204
                self._log_contents = log_contents
884
 
                os.remove(self._log_file_name)
 
1205
                try:
 
1206
                    os.remove(self._log_file_name)
 
1207
                except OSError, e:
 
1208
                    if sys.platform == 'win32' and e.errno == errno.EACCES:
 
1209
                        print >>sys.stderr, ('Unable to delete log file '
 
1210
                                             ' %r' % self._log_file_name)
 
1211
                    else:
 
1212
                        raise
885
1213
            return log_contents
886
1214
        else:
887
1215
            return "DELETED log file to reduce memory footprint"
890
1218
        """Shortcut that splits cmd into words, runs, and returns stdout"""
891
1219
        return self.run_bzr_captured(cmd.split(), retcode=retcode)[0]
892
1220
 
 
1221
    def requireFeature(self, feature):
 
1222
        """This test requires a specific feature is available.
 
1223
 
 
1224
        :raises UnavailableFeature: When feature is not available.
 
1225
        """
 
1226
        if not feature.available():
 
1227
            raise UnavailableFeature(feature)
 
1228
 
893
1229
    def run_bzr_captured(self, argv, retcode=0, encoding=None, stdin=None,
894
1230
                         working_dir=None):
895
1231
        """Invoke bzr and return (stdout, stderr).
916
1252
        """
917
1253
        if encoding is None:
918
1254
            encoding = bzrlib.user_encoding
919
 
        if stdin is not None:
920
 
            stdin = StringIO(stdin)
921
1255
        stdout = StringIOWrapper()
922
1256
        stderr = StringIOWrapper()
923
1257
        stdout.encoding = encoding
929
1263
        handler.setLevel(logging.INFO)
930
1264
        logger = logging.getLogger('')
931
1265
        logger.addHandler(handler)
932
 
        old_ui_factory = bzrlib.ui.ui_factory
933
 
        bzrlib.ui.ui_factory = bzrlib.tests.blackbox.TestUIFactory(
934
 
            stdout=stdout,
935
 
            stderr=stderr)
936
 
        bzrlib.ui.ui_factory.stdin = stdin
 
1266
        old_ui_factory = ui.ui_factory
 
1267
        ui.ui_factory = TestUIFactory(stdin=stdin, stdout=stdout, stderr=stderr)
937
1268
 
938
1269
        cwd = None
939
1270
        if working_dir is not None:
944
1275
            saved_debug_flags = frozenset(debug.debug_flags)
945
1276
            debug.debug_flags.clear()
946
1277
            try:
947
 
                result = self.apply_redirected(stdin, stdout, stderr,
 
1278
                result = self.apply_redirected(ui.ui_factory.stdin,
 
1279
                                               stdout, stderr,
948
1280
                                               bzrlib.commands.run_bzr_catch_errors,
949
1281
                                               argv)
950
1282
            finally:
951
1283
                debug.debug_flags.update(saved_debug_flags)
952
1284
        finally:
953
1285
            logger.removeHandler(handler)
954
 
            bzrlib.ui.ui_factory = old_ui_factory
 
1286
            ui.ui_factory = old_ui_factory
955
1287
            if cwd is not None:
956
1288
                os.chdir(cwd)
957
1289
 
962
1294
        if err:
963
1295
            self.log('errors:\n%r', err)
964
1296
        if retcode is not None:
965
 
            self.assertEquals(retcode, result)
 
1297
            self.assertEquals(retcode, result,
 
1298
                              message='Unexpected return code')
966
1299
        return out, err
967
1300
 
968
1301
    def run_bzr(self, *args, **kwargs):
976
1309
        where it may be useful for debugging.  See also run_captured.
977
1310
 
978
1311
        :param stdin: A string to be used as stdin for the command.
 
1312
        :param retcode: The status code the command should return
 
1313
        :param working_dir: The directory to run the command in
979
1314
        """
980
1315
        retcode = kwargs.pop('retcode', 0)
981
1316
        encoding = kwargs.pop('encoding', None)
982
1317
        stdin = kwargs.pop('stdin', None)
983
1318
        working_dir = kwargs.pop('working_dir', None)
984
 
        return self.run_bzr_captured(args, retcode=retcode, encoding=encoding,
985
 
                                     stdin=stdin, working_dir=working_dir)
 
1319
        error_regexes = kwargs.pop('error_regexes', [])
 
1320
 
 
1321
        out, err = self.run_bzr_captured(args, retcode=retcode,
 
1322
            encoding=encoding, stdin=stdin, working_dir=working_dir)
 
1323
 
 
1324
        for regex in error_regexes:
 
1325
            self.assertContainsRe(err, regex)
 
1326
        return out, err
 
1327
 
986
1328
 
987
1329
    def run_bzr_decode(self, *args, **kwargs):
988
1330
        if 'encoding' in kwargs:
1015
1357
                               'commit', '--strict', '-m', 'my commit comment')
1016
1358
        """
1017
1359
        kwargs.setdefault('retcode', 3)
1018
 
        out, err = self.run_bzr(*args, **kwargs)
1019
 
        for regex in error_regexes:
1020
 
            self.assertContainsRe(err, regex)
 
1360
        out, err = self.run_bzr(error_regexes=error_regexes, *args, **kwargs)
1021
1361
        return out, err
1022
1362
 
1023
1363
    def run_bzr_subprocess(self, *args, **kwargs):
1230
1570
                    this_tree=wt_to)
1231
1571
        wt_to.add_parent_tree_id(branch_from.last_revision())
1232
1572
 
 
1573
    def reduceLockdirTimeout(self):
 
1574
        """Reduce the default lock timeout for the duration of the test, so that
 
1575
        if LockContention occurs during a test, it does so quickly.
 
1576
 
 
1577
        Tests that expect to provoke LockContention errors should call this.
 
1578
        """
 
1579
        orig_timeout = bzrlib.lockdir._DEFAULT_TIMEOUT_SECONDS
 
1580
        def resetTimeout():
 
1581
            bzrlib.lockdir._DEFAULT_TIMEOUT_SECONDS = orig_timeout
 
1582
        self.addCleanup(resetTimeout)
 
1583
        bzrlib.lockdir._DEFAULT_TIMEOUT_SECONDS = 0
1233
1584
 
1234
1585
BzrTestBase = TestCase
1235
1586
 
1259
1610
        # execution. Variables that the parameteriser sets need to be 
1260
1611
        # ones that are not set by setUp, or setUp will trash them.
1261
1612
        super(TestCaseWithMemoryTransport, self).__init__(methodName)
1262
 
        self.transport_server = default_transport
 
1613
        self.vfs_transport_factory = default_transport
 
1614
        self.transport_server = None
1263
1615
        self.transport_readonly_server = None
1264
 
 
1265
 
    def failUnlessExists(self, path):
1266
 
        """Fail unless path, which may be abs or relative, exists."""
1267
 
        self.failUnless(osutils.lexists(path))
1268
 
 
1269
 
    def failIfExists(self, path):
1270
 
        """Fail if path, which may be abs or relative, exists."""
1271
 
        self.failIf(osutils.lexists(path))
1272
 
        
 
1616
        self.__vfs_server = None
 
1617
 
1273
1618
    def get_transport(self):
1274
1619
        """Return a writeable transport for the test scratch space"""
1275
1620
        t = get_transport(self.get_url())
1302
1647
            if self.transport_readonly_server is None:
1303
1648
                # readonly decorator requested
1304
1649
                # bring up the server
1305
 
                self.get_url()
1306
1650
                self.__readonly_server = ReadonlyServer()
1307
 
                self.__readonly_server.setUp(self.__server)
 
1651
                self.__readonly_server.setUp(self.get_vfs_only_server())
1308
1652
            else:
1309
1653
                self.__readonly_server = self.create_transport_readonly_server()
1310
 
                self.__readonly_server.setUp()
 
1654
                self.__readonly_server.setUp(self.get_vfs_only_server())
1311
1655
            self.addCleanup(self.__readonly_server.tearDown)
1312
1656
        return self.__readonly_server
1313
1657
 
1326
1670
            base = base + relpath
1327
1671
        return base
1328
1672
 
1329
 
    def get_server(self):
1330
 
        """Get the read/write server instance.
 
1673
    def get_vfs_only_server(self):
 
1674
        """Get the vfs only read/write server instance.
1331
1675
 
1332
1676
        This is useful for some tests with specific servers that need
1333
1677
        diagnostics.
1335
1679
        For TestCaseWithMemoryTransport this is always a MemoryServer, and there
1336
1680
        is no means to override it.
1337
1681
        """
 
1682
        if self.__vfs_server is None:
 
1683
            self.__vfs_server = MemoryServer()
 
1684
            self.__vfs_server.setUp()
 
1685
            self.addCleanup(self.__vfs_server.tearDown)
 
1686
        return self.__vfs_server
 
1687
 
 
1688
    def get_server(self):
 
1689
        """Get the read/write server instance.
 
1690
 
 
1691
        This is useful for some tests with specific servers that need
 
1692
        diagnostics.
 
1693
 
 
1694
        This is built from the self.transport_server factory. If that is None,
 
1695
        then the self.get_vfs_server is returned.
 
1696
        """
1338
1697
        if self.__server is None:
1339
 
            self.__server = MemoryServer()
1340
 
            self.__server.setUp()
 
1698
            if self.transport_server is None or self.transport_server is self.vfs_transport_factory:
 
1699
                return self.get_vfs_only_server()
 
1700
            else:
 
1701
                # bring up a decorated means of access to the vfs only server.
 
1702
                self.__server = self.transport_server()
 
1703
                try:
 
1704
                    self.__server.setUp(self.get_vfs_only_server())
 
1705
                except TypeError, e:
 
1706
                    # This should never happen; the try:Except here is to assist
 
1707
                    # developers having to update code rather than seeing an
 
1708
                    # uninformative TypeError.
 
1709
                    raise Exception, "Old server API in use: %s, %s" % (self.__server, e)
1341
1710
            self.addCleanup(self.__server.tearDown)
1342
1711
        return self.__server
1343
1712
 
1344
 
    def get_url(self, relpath=None):
 
1713
    def _adjust_url(self, base, relpath):
1345
1714
        """Get a URL (or maybe a path) for the readwrite transport.
1346
1715
 
1347
1716
        This will either be backed by '.' or to an equivalent non-file based
1349
1718
        relpath provides for clients to get a path relative to the base url.
1350
1719
        These should only be downwards relative, not upwards.
1351
1720
        """
1352
 
        base = self.get_server().get_url()
1353
1721
        if relpath is not None and relpath != '.':
1354
1722
            if not base.endswith('/'):
1355
1723
                base = base + '/'
1363
1731
                base += urlutils.escape(relpath)
1364
1732
        return base
1365
1733
 
 
1734
    def get_url(self, relpath=None):
 
1735
        """Get a URL (or maybe a path) for the readwrite transport.
 
1736
 
 
1737
        This will either be backed by '.' or to an equivalent non-file based
 
1738
        facility.
 
1739
        relpath provides for clients to get a path relative to the base url.
 
1740
        These should only be downwards relative, not upwards.
 
1741
        """
 
1742
        base = self.get_server().get_url()
 
1743
        return self._adjust_url(base, relpath)
 
1744
 
 
1745
    def get_vfs_only_url(self, relpath=None):
 
1746
        """Get a URL (or maybe a path for the plain old vfs transport.
 
1747
 
 
1748
        This will never be a smart protocol.
 
1749
        :param relpath: provides for clients to get a path relative to the base
 
1750
            url.  These should only be downwards relative, not upwards.
 
1751
        """
 
1752
        base = self.get_vfs_only_server().get_url()
 
1753
        return self._adjust_url(base, relpath)
 
1754
 
1366
1755
    def _make_test_root(self):
1367
1756
        if TestCaseWithMemoryTransport.TEST_ROOT is not None:
1368
1757
            return
1414
1803
                except errors.FileExists:
1415
1804
                    pass
1416
1805
            if format is None:
1417
 
                format = bzrlib.bzrdir.BzrDirFormat.get_default_format()
 
1806
                format = 'default'
 
1807
            if isinstance(format, basestring):
 
1808
                format = bzrdir.format_registry.make_bzrdir(format)
1418
1809
            return format.initialize_on_transport(t)
1419
1810
        except errors.UninitializableFormat:
1420
1811
            raise TestSkipped("Format %s is not initializable." % format)
1431
1822
 
1432
1823
    def overrideEnvironmentForTesting(self):
1433
1824
        os.environ['HOME'] = self.test_home_dir
1434
 
        os.environ['APPDATA'] = self.test_home_dir
 
1825
        os.environ['BZR_HOME'] = self.test_home_dir
1435
1826
        
1436
1827
    def setUp(self):
1437
1828
        super(TestCaseWithMemoryTransport, self).setUp()
1444
1835
        self.overrideEnvironmentForTesting()
1445
1836
        self.__readonly_server = None
1446
1837
        self.__server = None
 
1838
        self.reduceLockdirTimeout()
1447
1839
 
1448
1840
     
1449
1841
class TestCaseInTempDir(TestCaseWithMemoryTransport):
1460
1852
    """
1461
1853
 
1462
1854
    OVERRIDE_PYTHON = 'python'
 
1855
    use_numbered_dirs = False
1463
1856
 
1464
1857
    def check_file_contents(self, filename, expect):
1465
1858
        self.log("check contents of file %s" % filename)
1475
1868
        For TestCaseInTempDir we create a temporary directory based on the test
1476
1869
        name and then create two subdirs - test and home under it.
1477
1870
        """
 
1871
        if self.use_numbered_dirs:  # strongly recommended on Windows
 
1872
                                    # due the path length limitation (260 ch.)
 
1873
            candidate_dir = '%s/%dK/%05d' % (self.TEST_ROOT,
 
1874
                                             int(self.number/1000),
 
1875
                                             self.number)
 
1876
            os.makedirs(candidate_dir)
 
1877
            self.test_home_dir = candidate_dir + '/home'
 
1878
            os.mkdir(self.test_home_dir)
 
1879
            self.test_dir = candidate_dir + '/work'
 
1880
            os.mkdir(self.test_dir)
 
1881
            os.chdir(self.test_dir)
 
1882
            # put name of test inside
 
1883
            f = file(candidate_dir + '/name', 'w')
 
1884
            f.write(self.id())
 
1885
            f.close()
 
1886
            return
 
1887
        # Else NAMED DIRS
1478
1888
        # shorten the name, to avoid test failures due to path length
1479
1889
        short_id = self.id().replace('bzrlib.tests.', '') \
1480
1890
                   .replace('__main__.', '')[-100:]
1529
1939
                elif line_endings == 'native':
1530
1940
                    end = os.linesep
1531
1941
                else:
1532
 
                    raise errors.BzrError('Invalid line ending request %r' % (line_endings,))
 
1942
                    raise errors.BzrError(
 
1943
                        'Invalid line ending request %r' % line_endings)
1533
1944
                content = "contents of %s%s" % (name.encode('utf-8'), end)
1534
 
                # Technically 'put()' is the right command. However, put
1535
 
                # uses an AtomicFile, which requires an extra rename into place
1536
 
                # As long as the files didn't exist in the past, append() will
1537
 
                # do the same thing as put()
1538
 
                # On jam's machine, make_kernel_like_tree is:
1539
 
                #   put:    4.5-7.5s (averaging 6s)
1540
 
                #   append: 2.9-4.5s
1541
 
                #   put_non_atomic: 2.9-4.5s
1542
1945
                transport.put_bytes_non_atomic(urlutils.escape(name), content)
1543
1946
 
1544
1947
    def build_tree_contents(self, shape):
1546
1949
 
1547
1950
    def assertFileEqual(self, content, path):
1548
1951
        """Fail if path does not contain 'content'."""
1549
 
        self.failUnless(osutils.lexists(path))
 
1952
        self.failUnlessExists(path)
1550
1953
        # TODO: jam 20060427 Shouldn't this be 'rb'?
1551
 
        self.assertEqualDiff(content, open(path, 'r').read())
 
1954
        f = file(path, 'r')
 
1955
        try:
 
1956
            s = f.read()
 
1957
        finally:
 
1958
            f.close()
 
1959
        self.assertEqualDiff(content, s)
 
1960
 
 
1961
    def failUnlessExists(self, path):
 
1962
        """Fail unless path or paths, which may be abs or relative, exist."""
 
1963
        if not isinstance(path, basestring):
 
1964
            for p in path:
 
1965
                self.failUnlessExists(p)
 
1966
        else:
 
1967
            self.failUnless(osutils.lexists(path),path+" does not exist")
 
1968
 
 
1969
    def failIfExists(self, path):
 
1970
        """Fail if path or paths, which may be abs or relative, exist."""
 
1971
        if not isinstance(path, basestring):
 
1972
            for p in path:
 
1973
                self.failIfExists(p)
 
1974
        else:
 
1975
            self.failIf(osutils.lexists(path),path+" exists")
 
1976
 
 
1977
    def assertInWorkingTree(self,path,root_path='.',tree=None):
 
1978
        """Assert whether path or paths are in the WorkingTree"""
 
1979
        if tree is None:
 
1980
            tree = workingtree.WorkingTree.open(root_path)
 
1981
        if not isinstance(path, basestring):
 
1982
            for p in path:
 
1983
                self.assertInWorkingTree(p,tree=tree)
 
1984
        else:
 
1985
            self.assertIsNot(tree.path2id(path), None,
 
1986
                path+' not in working tree.')
 
1987
 
 
1988
    def assertNotInWorkingTree(self,path,root_path='.',tree=None):
 
1989
        """Assert whether path or paths are not in the WorkingTree"""
 
1990
        if tree is None:
 
1991
            tree = workingtree.WorkingTree.open(root_path)
 
1992
        if not isinstance(path, basestring):
 
1993
            for p in path:
 
1994
                self.assertNotInWorkingTree(p,tree=tree)
 
1995
        else:
 
1996
            self.assertIs(tree.path2id(path), None, path+' in working tree.')
1552
1997
 
1553
1998
 
1554
1999
class TestCaseWithTransport(TestCaseInTempDir):
1565
2010
    readwrite one must both define get_url() as resolving to os.getcwd().
1566
2011
    """
1567
2012
 
1568
 
    def create_transport_server(self):
1569
 
        """Create a transport server from class defined at init.
1570
 
 
1571
 
        This is mostly a hook for daughter classes.
1572
 
        """
1573
 
        return self.transport_server()
1574
 
 
1575
 
    def get_server(self):
 
2013
    def get_vfs_only_server(self):
1576
2014
        """See TestCaseWithMemoryTransport.
1577
2015
 
1578
2016
        This is useful for some tests with specific servers that need
1579
2017
        diagnostics.
1580
2018
        """
1581
 
        if self.__server is None:
1582
 
            self.__server = self.create_transport_server()
1583
 
            self.__server.setUp()
1584
 
            self.addCleanup(self.__server.tearDown)
1585
 
        return self.__server
 
2019
        if self.__vfs_server is None:
 
2020
            self.__vfs_server = self.vfs_transport_factory()
 
2021
            self.__vfs_server.setUp()
 
2022
            self.addCleanup(self.__vfs_server.tearDown)
 
2023
        return self.__vfs_server
1586
2024
 
1587
2025
    def make_branch_and_tree(self, relpath, format=None):
1588
2026
        """Create a branch on the transport and a tree locally.
1589
2027
 
1590
2028
        If the transport is not a LocalTransport, the Tree can't be created on
1591
 
        the transport.  In that case the working tree is created in the local
1592
 
        directory, and the returned tree's branch and repository will also be
1593
 
        accessed locally.
1594
 
 
1595
 
        This will fail if the original default transport for this test
1596
 
        case wasn't backed by the working directory, as the branch won't
1597
 
        be on disk for us to open it.  
 
2029
        the transport.  In that case if the vfs_transport_factory is
 
2030
        LocalURLServer the working tree is created in the local
 
2031
        directory backing the transport, and the returned tree's branch and
 
2032
        repository will also be accessed locally. Otherwise a lightweight
 
2033
        checkout is created and returned.
1598
2034
 
1599
2035
        :param format: The BzrDirFormat.
1600
2036
        :returns: the WorkingTree.
1608
2044
            return b.bzrdir.create_workingtree()
1609
2045
        except errors.NotLocalUrl:
1610
2046
            # We can only make working trees locally at the moment.  If the
1611
 
            # transport can't support them, then reopen the branch on a local
1612
 
            # transport, and create the working tree there.  
1613
 
            #
1614
 
            # Possibly we should instead keep
1615
 
            # the non-disk-backed branch and create a local checkout?
1616
 
            bd = bzrdir.BzrDir.open(relpath)
1617
 
            return bd.create_workingtree()
 
2047
            # transport can't support them, then we keep the non-disk-backed
 
2048
            # branch and create a local checkout.
 
2049
            if self.vfs_transport_factory is LocalURLServer:
 
2050
                # the branch is colocated on disk, we cannot create a checkout.
 
2051
                # hopefully callers will expect this.
 
2052
                local_controldir= bzrdir.BzrDir.open(self.get_vfs_only_url(relpath))
 
2053
                return local_controldir.create_workingtree()
 
2054
            else:
 
2055
                return b.create_checkout(relpath, lightweight=True)
1618
2056
 
1619
2057
    def assertIsDirectory(self, relpath, transport):
1620
2058
        """Assert that relpath within transport is a directory.
1631
2069
            self.fail("path %s is not a directory; has mode %#o"
1632
2070
                      % (relpath, mode))
1633
2071
 
 
2072
    def assertTreesEqual(self, left, right):
 
2073
        """Check that left and right have the same content and properties."""
 
2074
        # we use a tree delta to check for equality of the content, and we
 
2075
        # manually check for equality of other things such as the parents list.
 
2076
        self.assertEqual(left.get_parent_ids(), right.get_parent_ids())
 
2077
        differences = left.changes_from(right)
 
2078
        self.assertFalse(differences.has_changed(),
 
2079
            "Trees %r and %r are different: %r" % (left, right, differences))
 
2080
 
1634
2081
    def setUp(self):
1635
2082
        super(TestCaseWithTransport, self).setUp()
1636
 
        self.__server = None
 
2083
        self.__vfs_server = None
1637
2084
 
1638
2085
 
1639
2086
class ChrootedTestCase(TestCaseWithTransport):
1650
2097
 
1651
2098
    def setUp(self):
1652
2099
        super(ChrootedTestCase, self).setUp()
1653
 
        if not self.transport_server == MemoryServer:
 
2100
        if not self.vfs_transport_factory == MemoryServer:
1654
2101
            self.transport_readonly_server = HttpServer
1655
2102
 
1656
2103
 
1657
 
def filter_suite_by_re(suite, pattern):
1658
 
    result = TestUtil.TestSuite()
 
2104
def filter_suite_by_re(suite, pattern, exclude_pattern=None,
 
2105
                       random_order=False):
 
2106
    """Create a test suite by filtering another one.
 
2107
    
 
2108
    :param suite:           the source suite
 
2109
    :param pattern:         pattern that names must match
 
2110
    :param exclude_pattern: pattern that names must not match, if any
 
2111
    :param random_order:    if True, tests in the new suite will be put in
 
2112
                            random order
 
2113
    :returns: the newly created suite
 
2114
    """ 
 
2115
    return sort_suite_by_re(suite, pattern, exclude_pattern,
 
2116
        random_order, False)
 
2117
 
 
2118
 
 
2119
def sort_suite_by_re(suite, pattern, exclude_pattern=None,
 
2120
                     random_order=False, append_rest=True):
 
2121
    """Create a test suite by sorting another one.
 
2122
    
 
2123
    :param suite:           the source suite
 
2124
    :param pattern:         pattern that names must match in order to go
 
2125
                            first in the new suite
 
2126
    :param exclude_pattern: pattern that names must not match, if any
 
2127
    :param random_order:    if True, tests in the new suite will be put in
 
2128
                            random order
 
2129
    :param append_rest:     if False, pattern is a strict filter and not
 
2130
                            just an ordering directive
 
2131
    :returns: the newly created suite
 
2132
    """ 
 
2133
    first = []
 
2134
    second = []
1659
2135
    filter_re = re.compile(pattern)
 
2136
    if exclude_pattern is not None:
 
2137
        exclude_re = re.compile(exclude_pattern)
1660
2138
    for test in iter_suite_tests(suite):
1661
 
        if filter_re.search(test.id()):
1662
 
            result.addTest(test)
1663
 
    return result
 
2139
        test_id = test.id()
 
2140
        if exclude_pattern is None or not exclude_re.search(test_id):
 
2141
            if filter_re.search(test_id):
 
2142
                first.append(test)
 
2143
            elif append_rest:
 
2144
                second.append(test)
 
2145
    if random_order:
 
2146
        random.shuffle(first)
 
2147
        random.shuffle(second)
 
2148
    return TestUtil.TestSuite(first + second)
1664
2149
 
1665
2150
 
1666
2151
def run_suite(suite, name='test', verbose=False, pattern=".*",
1667
2152
              stop_on_failure=False, keep_output=False,
1668
 
              transport=None, lsprof_timed=None, bench_history=None):
 
2153
              transport=None, lsprof_timed=None, bench_history=None,
 
2154
              matching_tests_first=None,
 
2155
              numbered_dirs=None,
 
2156
              list_only=False,
 
2157
              random_seed=None,
 
2158
              exclude_pattern=None,
 
2159
              ):
 
2160
    use_numbered_dirs = bool(numbered_dirs)
 
2161
 
1669
2162
    TestCase._gather_lsprof_in_benchmarks = lsprof_timed
 
2163
    if numbered_dirs is not None:
 
2164
        TestCaseInTempDir.use_numbered_dirs = use_numbered_dirs
1670
2165
    if verbose:
1671
2166
        verbosity = 2
1672
2167
    else:
1675
2170
                            descriptions=0,
1676
2171
                            verbosity=verbosity,
1677
2172
                            keep_output=keep_output,
1678
 
                            bench_history=bench_history)
 
2173
                            bench_history=bench_history,
 
2174
                            use_numbered_dirs=use_numbered_dirs,
 
2175
                            list_only=list_only,
 
2176
                            )
1679
2177
    runner.stop_on_failure=stop_on_failure
1680
 
    if pattern != '.*':
1681
 
        suite = filter_suite_by_re(suite, pattern)
 
2178
    # Initialise the random number generator and display the seed used.
 
2179
    # We convert the seed to a long to make it reuseable across invocations.
 
2180
    random_order = False
 
2181
    if random_seed is not None:
 
2182
        random_order = True
 
2183
        if random_seed == "now":
 
2184
            random_seed = long(time.time())
 
2185
        else:
 
2186
            # Convert the seed to a long if we can
 
2187
            try:
 
2188
                random_seed = long(random_seed)
 
2189
            except:
 
2190
                pass
 
2191
        runner.stream.writeln("Randomizing test order using seed %s\n" %
 
2192
            (random_seed))
 
2193
        random.seed(random_seed)
 
2194
    # Customise the list of tests if requested
 
2195
    if pattern != '.*' or exclude_pattern is not None or random_order:
 
2196
        if matching_tests_first:
 
2197
            suite = sort_suite_by_re(suite, pattern, exclude_pattern,
 
2198
                random_order)
 
2199
        else:
 
2200
            suite = filter_suite_by_re(suite, pattern, exclude_pattern,
 
2201
                random_order)
1682
2202
    result = runner.run(suite)
1683
2203
    return result.wasSuccessful()
1684
2204
 
1688
2208
             transport=None,
1689
2209
             test_suite_factory=None,
1690
2210
             lsprof_timed=None,
1691
 
             bench_history=None):
 
2211
             bench_history=None,
 
2212
             matching_tests_first=None,
 
2213
             numbered_dirs=None,
 
2214
             list_only=False,
 
2215
             random_seed=None,
 
2216
             exclude_pattern=None):
1692
2217
    """Run the whole test suite under the enhanced runner"""
1693
2218
    # XXX: Very ugly way to do this...
1694
2219
    # Disable warning about old formats because we don't want it to disturb
1710
2235
                     stop_on_failure=stop_on_failure, keep_output=keep_output,
1711
2236
                     transport=transport,
1712
2237
                     lsprof_timed=lsprof_timed,
1713
 
                     bench_history=bench_history)
 
2238
                     bench_history=bench_history,
 
2239
                     matching_tests_first=matching_tests_first,
 
2240
                     numbered_dirs=numbered_dirs,
 
2241
                     list_only=list_only,
 
2242
                     random_seed=random_seed,
 
2243
                     exclude_pattern=exclude_pattern)
1714
2244
    finally:
1715
2245
        default_transport = old_transport
1716
2246
 
1728
2258
                   'bzrlib.tests.test_atomicfile',
1729
2259
                   'bzrlib.tests.test_bad_files',
1730
2260
                   'bzrlib.tests.test_branch',
 
2261
                   'bzrlib.tests.test_bugtracker',
1731
2262
                   'bzrlib.tests.test_bundle',
1732
2263
                   'bzrlib.tests.test_bzrdir',
1733
2264
                   'bzrlib.tests.test_cache_utf8',
1737
2268
                   'bzrlib.tests.test_config',
1738
2269
                   'bzrlib.tests.test_conflicts',
1739
2270
                   'bzrlib.tests.test_decorators',
 
2271
                   'bzrlib.tests.test_delta',
1740
2272
                   'bzrlib.tests.test_diff',
1741
 
                   'bzrlib.tests.test_doc_generate',
 
2273
                   'bzrlib.tests.test_dirstate',
1742
2274
                   'bzrlib.tests.test_errors',
1743
2275
                   'bzrlib.tests.test_escaped_store',
 
2276
                   'bzrlib.tests.test_extract',
1744
2277
                   'bzrlib.tests.test_fetch',
1745
2278
                   'bzrlib.tests.test_ftp_transport',
 
2279
                   'bzrlib.tests.test_generate_docs',
1746
2280
                   'bzrlib.tests.test_generate_ids',
1747
2281
                   'bzrlib.tests.test_globbing',
1748
2282
                   'bzrlib.tests.test_gpg',
1749
2283
                   'bzrlib.tests.test_graph',
1750
2284
                   'bzrlib.tests.test_hashcache',
 
2285
                   'bzrlib.tests.test_help',
1751
2286
                   'bzrlib.tests.test_http',
1752
2287
                   'bzrlib.tests.test_http_response',
 
2288
                   'bzrlib.tests.test_https_ca_bundle',
1753
2289
                   'bzrlib.tests.test_identitymap',
1754
2290
                   'bzrlib.tests.test_ignores',
1755
2291
                   'bzrlib.tests.test_inv',
1763
2299
                   'bzrlib.tests.test_merge',
1764
2300
                   'bzrlib.tests.test_merge3',
1765
2301
                   'bzrlib.tests.test_merge_core',
 
2302
                   'bzrlib.tests.test_merge_directive',
1766
2303
                   'bzrlib.tests.test_missing',
1767
2304
                   'bzrlib.tests.test_msgeditor',
1768
2305
                   'bzrlib.tests.test_nonascii',
1769
2306
                   'bzrlib.tests.test_options',
1770
2307
                   'bzrlib.tests.test_osutils',
 
2308
                   'bzrlib.tests.test_osutils_encodings',
1771
2309
                   'bzrlib.tests.test_patch',
1772
2310
                   'bzrlib.tests.test_patches',
1773
2311
                   'bzrlib.tests.test_permissions',
1775
2313
                   'bzrlib.tests.test_progress',
1776
2314
                   'bzrlib.tests.test_reconcile',
1777
2315
                   'bzrlib.tests.test_registry',
 
2316
                   'bzrlib.tests.test_remote',
1778
2317
                   'bzrlib.tests.test_repository',
1779
2318
                   'bzrlib.tests.test_revert',
1780
2319
                   'bzrlib.tests.test_revision',
1785
2324
                   'bzrlib.tests.test_selftest',
1786
2325
                   'bzrlib.tests.test_setup',
1787
2326
                   'bzrlib.tests.test_sftp_transport',
 
2327
                   'bzrlib.tests.test_smart',
1788
2328
                   'bzrlib.tests.test_smart_add',
1789
2329
                   'bzrlib.tests.test_smart_transport',
1790
2330
                   'bzrlib.tests.test_source',
 
2331
                   'bzrlib.tests.test_ssh_transport',
1791
2332
                   'bzrlib.tests.test_status',
1792
2333
                   'bzrlib.tests.test_store',
 
2334
                   'bzrlib.tests.test_strace',
 
2335
                   'bzrlib.tests.test_subsume',
1793
2336
                   'bzrlib.tests.test_symbol_versioning',
 
2337
                   'bzrlib.tests.test_tag',
1794
2338
                   'bzrlib.tests.test_testament',
1795
2339
                   'bzrlib.tests.test_textfile',
1796
2340
                   'bzrlib.tests.test_textmerge',
 
2341
                   'bzrlib.tests.test_timestamp',
1797
2342
                   'bzrlib.tests.test_trace',
1798
2343
                   'bzrlib.tests.test_transactions',
1799
2344
                   'bzrlib.tests.test_transform',
1811
2356
                   'bzrlib.tests.test_weave',
1812
2357
                   'bzrlib.tests.test_whitebox',
1813
2358
                   'bzrlib.tests.test_workingtree',
 
2359
                   'bzrlib.tests.test_workingtree_4',
1814
2360
                   'bzrlib.tests.test_wsgi',
1815
2361
                   'bzrlib.tests.test_xml',
1816
2362
                   ]
1836
2382
            raise
1837
2383
    for name, plugin in bzrlib.plugin.all_plugins().items():
1838
2384
        if getattr(plugin, 'test_suite', None) is not None:
1839
 
            suite.addTest(plugin.test_suite())
 
2385
            default_encoding = sys.getdefaultencoding()
 
2386
            try:
 
2387
                plugin_suite = plugin.test_suite()
 
2388
            except ImportError, e:
 
2389
                bzrlib.trace.warning(
 
2390
                    'Unable to test plugin "%s": %s', name, e)
 
2391
            else:
 
2392
                suite.addTest(plugin_suite)
 
2393
            if default_encoding != sys.getdefaultencoding():
 
2394
                bzrlib.trace.warning(
 
2395
                    'Plugin "%s" tried to reset default encoding to: %s', name,
 
2396
                    sys.getdefaultencoding())
 
2397
                reload(sys)
 
2398
                sys.setdefaultencoding(default_encoding)
1840
2399
    return suite
1841
2400
 
1842
2401
 
1846
2405
        suite.addTests(adapter.adapt(test))
1847
2406
 
1848
2407
 
 
2408
def _rmtree_temp_dir(dirname):
 
2409
    try:
 
2410
        osutils.rmtree(dirname)
 
2411
    except OSError, e:
 
2412
        if sys.platform == 'win32' and e.errno == errno.EACCES:
 
2413
            print >>sys.stderr, ('Permission denied: '
 
2414
                                 'unable to remove testing dir '
 
2415
                                 '%s' % os.path.basename(dirname))
 
2416
        else:
 
2417
            raise
 
2418
 
 
2419
 
1849
2420
def clean_selftest_output(root=None, quiet=False):
1850
2421
    """Remove all selftest output directories from root directory.
1851
2422
 
1854
2425
    :param  quiet:  suppress report about deleting directories
1855
2426
    """
1856
2427
    import re
1857
 
    import shutil
1858
 
 
1859
2428
    re_dir = re.compile(r'''test\d\d\d\d\.tmp''')
1860
2429
    if root is None:
1861
2430
        root = u'.'
1863
2432
        if os.path.isdir(i) and re_dir.match(i):
1864
2433
            if not quiet:
1865
2434
                print 'delete directory:', i
1866
 
            shutil.rmtree(i)
 
2435
            _rmtree_temp_dir(i)
 
2436
 
 
2437
 
 
2438
class Feature(object):
 
2439
    """An operating system Feature."""
 
2440
 
 
2441
    def __init__(self):
 
2442
        self._available = None
 
2443
 
 
2444
    def available(self):
 
2445
        """Is the feature available?
 
2446
 
 
2447
        :return: True if the feature is available.
 
2448
        """
 
2449
        if self._available is None:
 
2450
            self._available = self._probe()
 
2451
        return self._available
 
2452
 
 
2453
    def _probe(self):
 
2454
        """Implement this method in concrete features.
 
2455
 
 
2456
        :return: True if the feature is available.
 
2457
        """
 
2458
        raise NotImplementedError
 
2459
 
 
2460
    def __str__(self):
 
2461
        if getattr(self, 'feature_name', None):
 
2462
            return self.feature_name()
 
2463
        return self.__class__.__name__