~bzr-pqm/bzr/bzr.dev

« back to all changes in this revision

Viewing changes to bzrlib/tests/__init__.py

  • Committer: Andrew Bennetts
  • Date: 2007-03-28 07:08:42 UTC
  • mfrom: (2380 +trunk)
  • mto: (2018.5.146 hpss)
  • mto: This revision was merged to the branch mainline in revision 2414.
  • Revision ID: andrew.bennetts@canonical.com-20070328070842-r843houy668oxb9o
Merge from 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
36
37
import re
37
38
import shlex
38
39
import stat
50
51
    memorytree,
51
52
    osutils,
52
53
    progress,
 
54
    ui,
53
55
    urlutils,
54
56
    )
55
57
import bzrlib.branch
56
58
import bzrlib.commands
57
 
import bzrlib.bundle.serializer
 
59
import bzrlib.timestamp
58
60
import bzrlib.export
59
61
import bzrlib.inventory
60
62
import bzrlib.iterablefile
91
93
 
92
94
MODULES_TO_TEST = []
93
95
MODULES_TO_DOCTEST = [
94
 
                      bzrlib.bundle.serializer,
 
96
                      bzrlib.timestamp,
95
97
                      bzrlib.errors,
96
98
                      bzrlib.export,
97
99
                      bzrlib.inventory,
102
104
                      bzrlib.store,
103
105
                      ]
104
106
 
 
107
NUMBERED_DIRS = False   # dirs kind for TestCaseInTempDir (numbered or named)
 
108
 
105
109
 
106
110
def packages_to_test():
107
111
    """Return a list of packages to test.
116
120
    import bzrlib.tests.interrepository_implementations
117
121
    import bzrlib.tests.interversionedfile_implementations
118
122
    import bzrlib.tests.intertree_implementations
 
123
    import bzrlib.tests.per_lock
119
124
    import bzrlib.tests.repository_implementations
120
125
    import bzrlib.tests.revisionstore_implementations
121
126
    import bzrlib.tests.tree_implementations
128
133
            bzrlib.tests.interrepository_implementations,
129
134
            bzrlib.tests.interversionedfile_implementations,
130
135
            bzrlib.tests.intertree_implementations,
 
136
            bzrlib.tests.per_lock,
131
137
            bzrlib.tests.repository_implementations,
132
138
            bzrlib.tests.revisionstore_implementations,
133
139
            bzrlib.tests.tree_implementations,
170
176
                revision_id = ''
171
177
            bench_history.write("--date %s %s\n" % (time.time(), revision_id))
172
178
        self._bench_history = bench_history
173
 
        self.ui = bzrlib.ui.ui_factory
 
179
        self.ui = ui.ui_factory
174
180
        self.num_tests = num_tests
175
181
        self.error_count = 0
176
182
        self.failure_count = 0
 
183
        self.known_failure_count = 0
177
184
        self.skip_count = 0
 
185
        self.unsupported = {}
178
186
        self.count = 0
179
187
        self._overall_start_time = time.time()
180
188
    
208
216
    def startTest(self, test):
209
217
        unittest.TestResult.startTest(self, test)
210
218
        self.report_test_start(test)
 
219
        test.number = self.count
211
220
        self._recordTestStartTime()
212
221
 
213
222
    def _recordTestStartTime(self):
214
223
        """Record that a test has started."""
215
224
        self._start_time = time.time()
216
225
 
 
226
    def _cleanupLogFile(self, test):
 
227
        # We can only do this if we have one of our TestCases, not if
 
228
        # we have a doctest.
 
229
        setKeepLogfile = getattr(test, 'setKeepLogfile', None)
 
230
        if setKeepLogfile is not None:
 
231
            setKeepLogfile()
 
232
 
217
233
    def addError(self, test, err):
 
234
        self.extractBenchmarkTime(test)
 
235
        self._cleanupLogFile(test)
218
236
        if isinstance(err[1], TestSkipped):
219
 
            return self.addSkipped(test, err)    
 
237
            return self.addSkipped(test, err)
 
238
        elif isinstance(err[1], UnavailableFeature):
 
239
            return self.addNotSupported(test, err[1].args[0])
220
240
        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)
 
241
        self.error_count += 1
227
242
        self.report_error(test, err)
228
243
        if self.stop_early:
229
244
            self.stop()
230
245
 
231
246
    def addFailure(self, test, err):
 
247
        self._cleanupLogFile(test)
 
248
        self.extractBenchmarkTime(test)
 
249
        if isinstance(err[1], KnownFailure):
 
250
            return self.addKnownFailure(test, err)
232
251
        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)
 
252
        self.failure_count += 1
239
253
        self.report_failure(test, err)
240
254
        if self.stop_early:
241
255
            self.stop()
242
256
 
 
257
    def addKnownFailure(self, test, err):
 
258
        self.known_failure_count += 1
 
259
        self.report_known_failure(test, err)
 
260
 
 
261
    def addNotSupported(self, test, feature):
 
262
        self.unsupported.setdefault(str(feature), 0)
 
263
        self.unsupported[str(feature)] += 1
 
264
        self.report_unsupported(test, feature)
 
265
 
243
266
    def addSuccess(self, test):
244
267
        self.extractBenchmarkTime(test)
245
268
        if self._bench_history is not None:
251
274
        unittest.TestResult.addSuccess(self, test)
252
275
 
253
276
    def addSkipped(self, test, skip_excinfo):
254
 
        self.extractBenchmarkTime(test)
255
277
        self.report_skip(test, skip_excinfo)
256
278
        # seems best to treat this as success from point-of-view of unittest
257
279
        # -- it actually does nothing so it barely matters :)
267
289
    def printErrorList(self, flavour, errors):
268
290
        for test, err in errors:
269
291
            self.stream.writeln(self.separator1)
270
 
            self.stream.writeln("%s: %s" % (flavour, self.getDescription(test)))
 
292
            self.stream.write("%s: " % flavour)
 
293
            if NUMBERED_DIRS:
 
294
                self.stream.write('#%d ' % test.number)
 
295
            self.stream.writeln(self.getDescription(test))
271
296
            if getattr(test, '_get_log', None) is not None:
272
297
                print >>self.stream
273
298
                print >>self.stream, \
291
316
class TextTestResult(ExtendedTestResult):
292
317
    """Displays progress and results of tests in text form"""
293
318
 
294
 
    def __init__(self, *args, **kw):
295
 
        ExtendedTestResult.__init__(self, *args, **kw)
296
 
        self.pb = self.ui.nested_progress_bar()
 
319
    def __init__(self, stream, descriptions, verbosity,
 
320
                 bench_history=None,
 
321
                 num_tests=None,
 
322
                 pb=None,
 
323
                 ):
 
324
        ExtendedTestResult.__init__(self, stream, descriptions, verbosity,
 
325
            bench_history, num_tests)
 
326
        if pb is None:
 
327
            self.pb = self.ui.nested_progress_bar()
 
328
            self._supplied_pb = False
 
329
        else:
 
330
            self.pb = pb
 
331
            self._supplied_pb = True
297
332
        self.pb.show_pct = False
298
333
        self.pb.show_spinner = False
299
 
        self.pb.show_eta = False, 
 
334
        self.pb.show_eta = False,
300
335
        self.pb.show_count = False
301
336
        self.pb.show_bar = False
302
337
 
312
347
            a += ', %d errors' % self.error_count
313
348
        if self.failure_count:
314
349
            a += ', %d failed' % self.failure_count
 
350
        if self.known_failure_count:
 
351
            a += ', %d known failures' % self.known_failure_count
315
352
        if self.skip_count:
316
353
            a += ', %d skipped' % self.skip_count
 
354
        if self.unsupported:
 
355
            a += ', %d missing features' % len(self.unsupported)
317
356
        a += ']'
318
357
        return a
319
358
 
324
363
                + ' ' 
325
364
                + self._shortened_test_description(test))
326
365
 
 
366
    def _test_description(self, test):
 
367
        if NUMBERED_DIRS:
 
368
            return '#%d %s' % (self.count,
 
369
                               self._shortened_test_description(test))
 
370
        else:
 
371
            return self._shortened_test_description(test)
 
372
 
327
373
    def report_error(self, test, err):
328
 
        self.error_count += 1
329
374
        self.pb.note('ERROR: %s\n    %s\n', 
330
 
            self._shortened_test_description(test),
 
375
            self._test_description(test),
331
376
            err[1],
332
377
            )
333
378
 
334
379
    def report_failure(self, test, err):
335
 
        self.failure_count += 1
336
380
        self.pb.note('FAIL: %s\n    %s\n', 
337
 
            self._shortened_test_description(test),
 
381
            self._test_description(test),
338
382
            err[1],
339
383
            )
340
384
 
 
385
    def report_known_failure(self, test, err):
 
386
        self.pb.note('XFAIL: %s\n%s\n',
 
387
            self._test_description(test), err[1])
 
388
 
341
389
    def report_skip(self, test, skip_excinfo):
342
390
        self.skip_count += 1
343
391
        if False:
354
402
                # progress bar...
355
403
                self.pb.note('SKIP: %s', skip_excinfo[1])
356
404
 
 
405
    def report_unsupported(self, test, feature):
 
406
        """test cannot be run because feature is missing."""
 
407
                  
357
408
    def report_cleaning_up(self):
358
409
        self.pb.update('cleaning up...')
359
410
 
360
411
    def finished(self):
361
 
        self.pb.finished()
 
412
        if not self._supplied_pb:
 
413
            self.pb.finished()
362
414
 
363
415
 
364
416
class VerboseTestResult(ExtendedTestResult):
380
432
        name = self._shortened_test_description(test)
381
433
        # width needs space for 6 char status, plus 1 for slash, plus 2 10-char
382
434
        # numbers, plus a trailing blank
383
 
        self.stream.write(self._ellipsize_to_right(name,
384
 
                            osutils.terminal_width()-30))
 
435
        # when NUMBERED_DIRS: plus 5 chars on test number, plus 1 char on space
 
436
        if NUMBERED_DIRS:
 
437
            self.stream.write('%5d ' % self.count)
 
438
            self.stream.write(self._ellipsize_to_right(name,
 
439
                                osutils.terminal_width()-36))
 
440
        else:
 
441
            self.stream.write(self._ellipsize_to_right(name,
 
442
                                osutils.terminal_width()-30))
385
443
        self.stream.flush()
386
444
 
 
445
    def _error_summary(self, err):
 
446
        indent = ' ' * 4
 
447
        if NUMBERED_DIRS:
 
448
            indent += ' ' * 6
 
449
        return '%s%s' % (indent, err[1])
 
450
 
387
451
    def report_error(self, test, err):
388
 
        self.error_count += 1
389
 
        self.stream.writeln('ERROR %s\n    %s' 
390
 
                % (self._testTimeString(), err[1]))
 
452
        self.stream.writeln('ERROR %s\n%s'
 
453
                % (self._testTimeString(),
 
454
                   self._error_summary(err)))
391
455
 
392
456
    def report_failure(self, test, err):
393
 
        self.failure_count += 1
394
 
        self.stream.writeln(' FAIL %s\n    %s'
395
 
                % (self._testTimeString(), err[1]))
 
457
        self.stream.writeln(' FAIL %s\n%s'
 
458
                % (self._testTimeString(),
 
459
                   self._error_summary(err)))
 
460
 
 
461
    def report_known_failure(self, test, err):
 
462
        self.stream.writeln('XFAIL %s\n%s'
 
463
                % (self._testTimeString(),
 
464
                   self._error_summary(err)))
396
465
 
397
466
    def report_success(self, test):
398
467
        self.stream.writeln('   OK %s' % self._testTimeString())
399
468
        for bench_called, stats in getattr(test, '_benchcalls', []):
400
469
            self.stream.writeln('LSProf output for %s(%s, %s)' % bench_called)
401
470
            stats.pprint(file=self.stream)
 
471
        # flush the stream so that we get smooth output. This verbose mode is
 
472
        # used to show the output in PQM.
402
473
        self.stream.flush()
403
474
 
404
475
    def report_skip(self, test, skip_excinfo):
405
 
        print >>self.stream, ' SKIP %s' % self._testTimeString()
406
 
        print >>self.stream, '     %s' % skip_excinfo[1]
 
476
        self.skip_count += 1
 
477
        self.stream.writeln(' SKIP %s\n%s'
 
478
                % (self._testTimeString(),
 
479
                   self._error_summary(skip_excinfo)))
 
480
 
 
481
    def report_unsupported(self, test, feature):
 
482
        """test cannot be run because feature is missing."""
 
483
        self.stream.writeln("NODEP %s\n    The feature '%s' is not available."
 
484
                %(self._testTimeString(), feature))
 
485
                  
407
486
 
408
487
 
409
488
class TextTestRunner(object):
453
532
            if errored:
454
533
                if failed: self.stream.write(", ")
455
534
                self.stream.write("errors=%d" % errored)
 
535
            if result.known_failure_count:
 
536
                if failed or errored: self.stream.write(", ")
 
537
                self.stream.write("known_failure_count=%d" %
 
538
                    result.known_failure_count)
456
539
            self.stream.writeln(")")
457
540
        else:
458
 
            self.stream.writeln("OK")
 
541
            if result.known_failure_count:
 
542
                self.stream.writeln("OK (known_failures=%d)" %
 
543
                    result.known_failure_count)
 
544
            else:
 
545
                self.stream.writeln("OK")
 
546
        if result.skip_count > 0:
 
547
            skipped = result.skip_count
 
548
            self.stream.writeln('%d test%s skipped' %
 
549
                                (skipped, skipped != 1 and "s" or ""))
 
550
        if result.unsupported:
 
551
            for feature, count in sorted(result.unsupported.items()):
 
552
                self.stream.writeln("Missing feature '%s' skipped %d tests." %
 
553
                    (feature, count))
459
554
        result.report_cleaning_up()
460
555
        # This is still a little bogus, 
461
556
        # but only a little. Folk not using our testrunner will
475
570
                else:
476
571
                    test_root = test_root.encode(
477
572
                        sys.getfilesystemencoding())
478
 
                osutils.rmtree(test_root)
 
573
                try:
 
574
                    osutils.rmtree(test_root)
 
575
                except OSError, e:
 
576
                    if sys.platform == 'win32' and e.errno == errno.EACCES:
 
577
                        print >>sys.stderr, ('Permission denied: '
 
578
                                             'unable to remove testing dir '
 
579
                                             '%s' % os.path.basename(test_root))
 
580
                    else:
 
581
                        raise
479
582
        else:
480
583
            note("Failed tests working directories are in '%s'\n", test_root)
481
584
        TestCaseWithMemoryTransport.TEST_ROOT = None
500
603
    """Indicates that a test was intentionally skipped, rather than failing."""
501
604
 
502
605
 
 
606
class KnownFailure(AssertionError):
 
607
    """Indicates that a test failed in a precisely expected manner.
 
608
 
 
609
    Such failures dont block the whole test suite from passing because they are
 
610
    indicators of partially completed code or of future work. We have an
 
611
    explicit error for them so that we can ensure that they are always visible:
 
612
    KnownFailures are always shown in the output of bzr selftest.
 
613
    """
 
614
 
 
615
 
 
616
class UnavailableFeature(Exception):
 
617
    """A feature required for this test was not available.
 
618
 
 
619
    The feature should be used to construct the exception.
 
620
    """
 
621
 
 
622
 
503
623
class CommandFailed(Exception):
504
624
    pass
505
625
 
530
650
            return setattr(self._cstring, name, val)
531
651
 
532
652
 
 
653
class TestUIFactory(ui.CLIUIFactory):
 
654
    """A UI Factory for testing.
 
655
 
 
656
    Hide the progress bar but emit note()s.
 
657
    Redirect stdin.
 
658
    Allows get_password to be tested without real tty attached.
 
659
    """
 
660
 
 
661
    def __init__(self,
 
662
                 stdout=None,
 
663
                 stderr=None,
 
664
                 stdin=None):
 
665
        super(TestUIFactory, self).__init__()
 
666
        if stdin is not None:
 
667
            # We use a StringIOWrapper to be able to test various
 
668
            # encodings, but the user is still responsible to
 
669
            # encode the string and to set the encoding attribute
 
670
            # of StringIOWrapper.
 
671
            self.stdin = StringIOWrapper(stdin)
 
672
        if stdout is None:
 
673
            self.stdout = sys.stdout
 
674
        else:
 
675
            self.stdout = stdout
 
676
        if stderr is None:
 
677
            self.stderr = sys.stderr
 
678
        else:
 
679
            self.stderr = stderr
 
680
 
 
681
    def clear(self):
 
682
        """See progress.ProgressBar.clear()."""
 
683
 
 
684
    def clear_term(self):
 
685
        """See progress.ProgressBar.clear_term()."""
 
686
 
 
687
    def clear_term(self):
 
688
        """See progress.ProgressBar.clear_term()."""
 
689
 
 
690
    def finished(self):
 
691
        """See progress.ProgressBar.finished()."""
 
692
 
 
693
    def note(self, fmt_string, *args, **kwargs):
 
694
        """See progress.ProgressBar.note()."""
 
695
        self.stdout.write((fmt_string + "\n") % args)
 
696
 
 
697
    def progress_bar(self):
 
698
        return self
 
699
 
 
700
    def nested_progress_bar(self):
 
701
        return self
 
702
 
 
703
    def update(self, message, count=None, total=None):
 
704
        """See progress.ProgressBar.update()."""
 
705
 
 
706
    def get_non_echoed_password(self, prompt):
 
707
        """Get password from stdin without trying to handle the echo mode"""
 
708
        if prompt:
 
709
            self.stdout.write(prompt)
 
710
        password = self.stdin.readline()
 
711
        if not password:
 
712
            raise EOFError
 
713
        if password[-1] == '\n':
 
714
            password = password[:-1]
 
715
        return password
 
716
 
 
717
 
533
718
class TestCase(unittest.TestCase):
534
719
    """Base class for bzr unit tests.
535
720
    
579
764
    def _silenceUI(self):
580
765
        """Turn off UI for duration of test"""
581
766
        # by default the UI is off; tests can turn it on if they want it.
582
 
        saved = bzrlib.ui.ui_factory
 
767
        saved = ui.ui_factory
583
768
        def _restore():
584
 
            bzrlib.ui.ui_factory = saved
585
 
        bzrlib.ui.ui_factory = bzrlib.ui.SilentUIFactory()
 
769
            ui.ui_factory = saved
 
770
        ui.ui_factory = ui.SilentUIFactory()
586
771
        self.addCleanup(_restore)
587
772
 
588
773
    def _ndiff_strings(self, a, b):
600
785
                                  charjunk=lambda x: False)
601
786
        return ''.join(difflines)
602
787
 
 
788
    def assertEqual(self, a, b, message=''):
 
789
        try:
 
790
            if a == b:
 
791
                return
 
792
        except UnicodeError, e:
 
793
            # If we can't compare without getting a UnicodeError, then
 
794
            # obviously they are different
 
795
            mutter('UnicodeError: %s', e)
 
796
        if message:
 
797
            message += '\n'
 
798
        raise AssertionError("%snot equal:\na = %s\nb = %s\n"
 
799
            % (message,
 
800
               pformat(a, indent=4), pformat(b, indent=4)))
 
801
 
 
802
    assertEquals = assertEqual
 
803
 
603
804
    def assertEqualDiff(self, a, b, message=None):
604
805
        """Assert two texts are equal, if not raise an exception.
605
806
        
630
831
    def assertContainsRe(self, haystack, needle_re):
631
832
        """Assert that a contains something matching a regular expression."""
632
833
        if not re.search(needle_re, haystack):
633
 
            raise AssertionError('pattern "%s" not found in "%s"'
 
834
            raise AssertionError('pattern "%r" not found in "%r"'
634
835
                    % (needle_re, haystack))
635
836
 
636
837
    def assertNotContainsRe(self, haystack, needle_re):
741
942
        expected_first_warning = symbol_versioning.deprecation_string(
742
943
            a_callable, deprecation_format)
743
944
        if len(call_warnings) == 0:
744
 
            self.fail("No assertion generated by call to %s" %
 
945
            self.fail("No deprecation warning generated by call to %s" %
745
946
                a_callable)
746
947
        self.assertEqual(expected_first_warning, call_warnings[0])
747
948
        return result
808
1009
        new_env = {
809
1010
            'BZR_HOME': None, # Don't inherit BZR_HOME to all the tests.
810
1011
            'HOME': os.getcwd(),
811
 
            'APPDATA': os.getcwd(),
 
1012
            'APPDATA': None,  # bzr now use Win32 API and don't rely on APPDATA
812
1013
            'BZR_EMAIL': None,
813
1014
            'BZREMAIL': None, # may still be present in the environment
814
1015
            'EMAIL': None,
844
1045
    def _restoreHooks(self):
845
1046
        bzrlib.branch.Branch.hooks = self._preserved_hooks
846
1047
 
 
1048
    def knownFailure(self, reason):
 
1049
        """This test has failed for some known reason."""
 
1050
        raise KnownFailure(reason)
 
1051
 
 
1052
    def run(self, result=None):
 
1053
        if result is None: result = self.defaultTestResult()
 
1054
        for feature in getattr(self, '_test_needs_features', []):
 
1055
            if not feature.available():
 
1056
                result.startTest(self)
 
1057
                if getattr(result, 'addNotSupported', None):
 
1058
                    result.addNotSupported(self, feature)
 
1059
                else:
 
1060
                    result.addSuccess(self)
 
1061
                result.stopTest(self)
 
1062
                return
 
1063
        return unittest.TestCase.run(self, result)
 
1064
 
847
1065
    def tearDown(self):
848
1066
        self._runCleanups()
849
1067
        unittest.TestCase.tearDown(self)
877
1095
        """
878
1096
        # TODO: Perhaps this should keep running cleanups even if 
879
1097
        # one of them fails?
880
 
        for cleanup_fn in reversed(self._cleanups):
881
 
            cleanup_fn()
 
1098
 
 
1099
        # Actually pop the cleanups from the list so tearDown running
 
1100
        # twice is safe (this happens for skipped tests).
 
1101
        while self._cleanups:
 
1102
            self._cleanups.pop()()
882
1103
 
883
1104
    def log(self, *args):
884
1105
        mutter(*args)
900
1121
                logfile.close()
901
1122
            if not keep_log_file:
902
1123
                self._log_contents = log_contents
903
 
                os.remove(self._log_file_name)
 
1124
                try:
 
1125
                    os.remove(self._log_file_name)
 
1126
                except OSError, e:
 
1127
                    if sys.platform == 'win32' and e.errno == errno.EACCES:
 
1128
                        print >>sys.stderr, ('Unable to delete log file '
 
1129
                                             ' %r' % self._log_file_name)
 
1130
                    else:
 
1131
                        raise
904
1132
            return log_contents
905
1133
        else:
906
1134
            return "DELETED log file to reduce memory footprint"
909
1137
        """Shortcut that splits cmd into words, runs, and returns stdout"""
910
1138
        return self.run_bzr_captured(cmd.split(), retcode=retcode)[0]
911
1139
 
 
1140
    def requireFeature(self, feature):
 
1141
        """This test requires a specific feature is available.
 
1142
 
 
1143
        :raises UnavailableFeature: When feature is not available.
 
1144
        """
 
1145
        if not feature.available():
 
1146
            raise UnavailableFeature(feature)
 
1147
 
912
1148
    def run_bzr_captured(self, argv, retcode=0, encoding=None, stdin=None,
913
1149
                         working_dir=None):
914
1150
        """Invoke bzr and return (stdout, stderr).
935
1171
        """
936
1172
        if encoding is None:
937
1173
            encoding = bzrlib.user_encoding
938
 
        if stdin is not None:
939
 
            stdin = StringIO(stdin)
940
1174
        stdout = StringIOWrapper()
941
1175
        stderr = StringIOWrapper()
942
1176
        stdout.encoding = encoding
948
1182
        handler.setLevel(logging.INFO)
949
1183
        logger = logging.getLogger('')
950
1184
        logger.addHandler(handler)
951
 
        old_ui_factory = bzrlib.ui.ui_factory
952
 
        bzrlib.ui.ui_factory = bzrlib.tests.blackbox.TestUIFactory(
953
 
            stdout=stdout,
954
 
            stderr=stderr)
955
 
        bzrlib.ui.ui_factory.stdin = stdin
 
1185
        old_ui_factory = ui.ui_factory
 
1186
        ui.ui_factory = TestUIFactory(stdin=stdin, stdout=stdout, stderr=stderr)
956
1187
 
957
1188
        cwd = None
958
1189
        if working_dir is not None:
963
1194
            saved_debug_flags = frozenset(debug.debug_flags)
964
1195
            debug.debug_flags.clear()
965
1196
            try:
966
 
                result = self.apply_redirected(stdin, stdout, stderr,
 
1197
                result = self.apply_redirected(ui.ui_factory.stdin,
 
1198
                                               stdout, stderr,
967
1199
                                               bzrlib.commands.run_bzr_catch_errors,
968
1200
                                               argv)
969
1201
            finally:
970
1202
                debug.debug_flags.update(saved_debug_flags)
971
1203
        finally:
972
1204
            logger.removeHandler(handler)
973
 
            bzrlib.ui.ui_factory = old_ui_factory
 
1205
            ui.ui_factory = old_ui_factory
974
1206
            if cwd is not None:
975
1207
                os.chdir(cwd)
976
1208
 
995
1227
        where it may be useful for debugging.  See also run_captured.
996
1228
 
997
1229
        :param stdin: A string to be used as stdin for the command.
 
1230
        :param retcode: The status code the command should return
 
1231
        :param working_dir: The directory to run the command in
998
1232
        """
999
1233
        retcode = kwargs.pop('retcode', 0)
1000
1234
        encoding = kwargs.pop('encoding', None)
1424
1658
                    t.mkdir('.')
1425
1659
                except errors.FileExists:
1426
1660
                    pass
 
1661
            if format is None:
 
1662
                format = 'default'
1427
1663
            if isinstance(format, basestring):
1428
1664
                format = bzrdir.format_registry.make_bzrdir(format)
1429
 
            elif format is None:
1430
 
                format = bzrlib.bzrdir.BzrDirFormat.get_default_format()
1431
1665
            return format.initialize_on_transport(t)
1432
1666
        except errors.UninitializableFormat:
1433
1667
            raise TestSkipped("Format %s is not initializable." % format)
1444
1678
 
1445
1679
    def overrideEnvironmentForTesting(self):
1446
1680
        os.environ['HOME'] = self.test_home_dir
1447
 
        os.environ['APPDATA'] = self.test_home_dir
 
1681
        os.environ['BZR_HOME'] = self.test_home_dir
1448
1682
        
1449
1683
    def setUp(self):
1450
1684
        super(TestCaseWithMemoryTransport, self).setUp()
1488
1722
        For TestCaseInTempDir we create a temporary directory based on the test
1489
1723
        name and then create two subdirs - test and home under it.
1490
1724
        """
 
1725
        if NUMBERED_DIRS:       # strongly recommended on Windows
 
1726
                                # due the path length limitation (260 chars)
 
1727
            candidate_dir = '%s/%dK/%05d' % (self.TEST_ROOT,
 
1728
                                             int(self.number/1000),
 
1729
                                             self.number)
 
1730
            os.makedirs(candidate_dir)
 
1731
            self.test_home_dir = candidate_dir + '/home'
 
1732
            os.mkdir(self.test_home_dir)
 
1733
            self.test_dir = candidate_dir + '/work'
 
1734
            os.mkdir(self.test_dir)
 
1735
            os.chdir(self.test_dir)
 
1736
            # put name of test inside
 
1737
            f = file(candidate_dir + '/name', 'w')
 
1738
            f.write(self.id())
 
1739
            f.close()
 
1740
            return
 
1741
        # Else NAMED DIRS
1491
1742
        # shorten the name, to avoid test failures due to path length
1492
1743
        short_id = self.id().replace('bzrlib.tests.', '') \
1493
1744
                   .replace('__main__.', '')[-100:]
1554
1805
        """Fail if path does not contain 'content'."""
1555
1806
        self.failUnlessExists(path)
1556
1807
        # TODO: jam 20060427 Shouldn't this be 'rb'?
1557
 
        self.assertEqualDiff(content, open(path, 'r').read())
 
1808
        f = file(path, 'r')
 
1809
        try:
 
1810
            s = f.read()
 
1811
        finally:
 
1812
            f.close()
 
1813
        self.assertEqualDiff(content, s)
1558
1814
 
1559
1815
    def failUnlessExists(self, path):
1560
1816
        """Fail unless path, which may be abs or relative, exists."""
1645
1901
            self.fail("path %s is not a directory; has mode %#o"
1646
1902
                      % (relpath, mode))
1647
1903
 
 
1904
    def assertTreesEqual(self, left, right):
 
1905
        """Check that left and right have the same content and properties."""
 
1906
        # we use a tree delta to check for equality of the content, and we
 
1907
        # manually check for equality of other things such as the parents list.
 
1908
        self.assertEqual(left.get_parent_ids(), right.get_parent_ids())
 
1909
        differences = left.changes_from(right)
 
1910
        self.assertFalse(differences.has_changed(),
 
1911
            "Trees %r and %r are different: %r" % (left, right, differences))
 
1912
 
1648
1913
    def setUp(self):
1649
1914
        super(TestCaseWithTransport, self).setUp()
1650
1915
        self.__server = None
1692
1957
def run_suite(suite, name='test', verbose=False, pattern=".*",
1693
1958
              stop_on_failure=False, keep_output=False,
1694
1959
              transport=None, lsprof_timed=None, bench_history=None,
1695
 
              matching_tests_first=None):
 
1960
              matching_tests_first=None,
 
1961
              numbered_dirs=None):
 
1962
    global NUMBERED_DIRS
 
1963
    if numbered_dirs is not None:
 
1964
        NUMBERED_DIRS = bool(numbered_dirs)
 
1965
 
1696
1966
    TestCase._gather_lsprof_in_benchmarks = lsprof_timed
1697
1967
    if verbose:
1698
1968
        verbosity = 2
1719
1989
             test_suite_factory=None,
1720
1990
             lsprof_timed=None,
1721
1991
             bench_history=None,
1722
 
             matching_tests_first=None):
 
1992
             matching_tests_first=None,
 
1993
             numbered_dirs=None):
1723
1994
    """Run the whole test suite under the enhanced runner"""
1724
1995
    # XXX: Very ugly way to do this...
1725
1996
    # Disable warning about old formats because we don't want it to disturb
1742
2013
                     transport=transport,
1743
2014
                     lsprof_timed=lsprof_timed,
1744
2015
                     bench_history=bench_history,
1745
 
                     matching_tests_first=matching_tests_first)
 
2016
                     matching_tests_first=matching_tests_first,
 
2017
                     numbered_dirs=numbered_dirs)
1746
2018
    finally:
1747
2019
        default_transport = old_transport
1748
2020
 
1771
2043
                   'bzrlib.tests.test_decorators',
1772
2044
                   'bzrlib.tests.test_delta',
1773
2045
                   'bzrlib.tests.test_diff',
 
2046
                   'bzrlib.tests.test_dirstate',
1774
2047
                   'bzrlib.tests.test_doc_generate',
1775
2048
                   'bzrlib.tests.test_errors',
1776
2049
                   'bzrlib.tests.test_escaped_store',
 
2050
                   'bzrlib.tests.test_extract',
1777
2051
                   'bzrlib.tests.test_fetch',
1778
2052
                   'bzrlib.tests.test_ftp_transport',
1779
2053
                   'bzrlib.tests.test_generate_docs',
1784
2058
                   'bzrlib.tests.test_hashcache',
1785
2059
                   'bzrlib.tests.test_http',
1786
2060
                   'bzrlib.tests.test_http_response',
 
2061
                   'bzrlib.tests.test_https_ca_bundle',
1787
2062
                   'bzrlib.tests.test_identitymap',
1788
2063
                   'bzrlib.tests.test_ignores',
1789
2064
                   'bzrlib.tests.test_inv',
1797
2072
                   'bzrlib.tests.test_merge',
1798
2073
                   'bzrlib.tests.test_merge3',
1799
2074
                   'bzrlib.tests.test_merge_core',
 
2075
                   'bzrlib.tests.test_merge_directive',
1800
2076
                   'bzrlib.tests.test_missing',
1801
2077
                   'bzrlib.tests.test_msgeditor',
1802
2078
                   'bzrlib.tests.test_nonascii',
1823
2099
                   'bzrlib.tests.test_smart_add',
1824
2100
                   'bzrlib.tests.test_smart_transport',
1825
2101
                   'bzrlib.tests.test_source',
 
2102
                   'bzrlib.tests.test_ssh_transport',
1826
2103
                   'bzrlib.tests.test_status',
1827
2104
                   'bzrlib.tests.test_store',
 
2105
                   'bzrlib.tests.test_strace',
 
2106
                   'bzrlib.tests.test_subsume',
1828
2107
                   'bzrlib.tests.test_symbol_versioning',
 
2108
                   'bzrlib.tests.test_tag',
1829
2109
                   'bzrlib.tests.test_testament',
1830
2110
                   'bzrlib.tests.test_textfile',
1831
2111
                   'bzrlib.tests.test_textmerge',
 
2112
                   'bzrlib.tests.test_timestamp',
1832
2113
                   'bzrlib.tests.test_trace',
1833
2114
                   'bzrlib.tests.test_transactions',
1834
2115
                   'bzrlib.tests.test_transform',
1846
2127
                   'bzrlib.tests.test_weave',
1847
2128
                   'bzrlib.tests.test_whitebox',
1848
2129
                   'bzrlib.tests.test_workingtree',
 
2130
                   'bzrlib.tests.test_workingtree_4',
1849
2131
                   'bzrlib.tests.test_wsgi',
1850
2132
                   'bzrlib.tests.test_xml',
1851
2133
                   ]
1871
2153
            raise
1872
2154
    for name, plugin in bzrlib.plugin.all_plugins().items():
1873
2155
        if getattr(plugin, 'test_suite', None) is not None:
1874
 
            suite.addTest(plugin.test_suite())
 
2156
            default_encoding = sys.getdefaultencoding()
 
2157
            try:
 
2158
                plugin_suite = plugin.test_suite()
 
2159
            except ImportError, e:
 
2160
                bzrlib.trace.warning(
 
2161
                    'Unable to test plugin "%s": %s', name, e)
 
2162
            else:
 
2163
                suite.addTest(plugin_suite)
 
2164
            if default_encoding != sys.getdefaultencoding():
 
2165
                bzrlib.trace.warning(
 
2166
                    'Plugin "%s" tried to reset default encoding to: %s', name,
 
2167
                    sys.getdefaultencoding())
 
2168
                reload(sys)
 
2169
                sys.setdefaultencoding(default_encoding)
1875
2170
    return suite
1876
2171
 
1877
2172
 
1899
2194
            if not quiet:
1900
2195
                print 'delete directory:', i
1901
2196
            shutil.rmtree(i)
 
2197
 
 
2198
 
 
2199
class Feature(object):
 
2200
    """An operating system Feature."""
 
2201
 
 
2202
    def __init__(self):
 
2203
        self._available = None
 
2204
 
 
2205
    def available(self):
 
2206
        """Is the feature available?
 
2207
 
 
2208
        :return: True if the feature is available.
 
2209
        """
 
2210
        if self._available is None:
 
2211
            self._available = self._probe()
 
2212
        return self._available
 
2213
 
 
2214
    def _probe(self):
 
2215
        """Implement this method in concrete features.
 
2216
 
 
2217
        :return: True if the feature is available.
 
2218
        """
 
2219
        raise NotImplementedError
 
2220
 
 
2221
    def __str__(self):
 
2222
        if getattr(self, 'feature_name', None):
 
2223
            return self.feature_name()
 
2224
        return self.__class__.__name__