~bzr-pqm/bzr/bzr.dev

« back to all changes in this revision

Viewing changes to bzrlib/tests/__init__.py

Late bind to PatienceSequenceMatcher to allow plugin to override.

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
1
# Copyright (C) 2005, 2006 by 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
5
5
# the Free Software Foundation; either version 2 of the License, or
6
6
# (at your option) any later version.
7
 
#
 
7
 
8
8
# This program is distributed in the hope that it will be useful,
9
9
# but WITHOUT ANY WARRANTY; without even the implied warranty of
10
10
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
11
11
# GNU General Public License for more details.
12
 
#
 
12
 
13
13
# You should have received a copy of the GNU General Public License
14
14
# along with this program; if not, write to the Free Software
15
15
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
29
29
import codecs
30
30
from cStringIO import StringIO
31
31
import difflib
32
 
import doctest
33
32
import errno
34
33
import logging
35
34
import os
36
35
import re
37
 
import shlex
38
36
import stat
39
 
from subprocess import Popen, PIPE
40
37
import sys
41
38
import tempfile
42
39
import unittest
46
43
import bzrlib.branch
47
44
import bzrlib.bzrdir as bzrdir
48
45
import bzrlib.commands
49
 
import bzrlib.bundle.serializer
50
46
import bzrlib.errors as errors
51
47
import bzrlib.inventory
52
48
import bzrlib.iterablefile
65
61
from bzrlib.revision import common_ancestor
66
62
import bzrlib.store
67
63
import bzrlib.trace
68
 
from bzrlib.transport import get_transport
 
64
from bzrlib.transport import urlescape, get_transport
69
65
import bzrlib.transport
70
66
from bzrlib.transport.local import LocalRelpathServer
71
67
from bzrlib.transport.readonly import ReadonlyServer
72
68
from bzrlib.trace import mutter
73
 
from bzrlib.tests import TestUtil
74
 
from bzrlib.tests.TestUtil import (
75
 
                          TestSuite,
76
 
                          TestLoader,
77
 
                          )
 
69
from bzrlib.tests.TestUtil import TestLoader, TestSuite
78
70
from bzrlib.tests.treeshape import build_tree_contents
79
 
import bzrlib.urlutils as urlutils
80
71
from bzrlib.workingtree import WorkingTree, WorkingTreeFormat2
81
72
 
82
73
default_transport = LocalRelpathServer
84
75
MODULES_TO_TEST = []
85
76
MODULES_TO_DOCTEST = [
86
77
                      bzrlib.branch,
87
 
                      bzrlib.bundle.serializer,
88
78
                      bzrlib.commands,
89
79
                      bzrlib.errors,
90
80
                      bzrlib.inventory,
95
85
                      bzrlib.osutils,
96
86
                      bzrlib.store
97
87
                      ]
98
 
 
99
 
 
100
88
def packages_to_test():
101
89
    """Return a list of packages to test.
102
90
 
109
97
    import bzrlib.tests.bzrdir_implementations
110
98
    import bzrlib.tests.interrepository_implementations
111
99
    import bzrlib.tests.interversionedfile_implementations
112
 
    import bzrlib.tests.intertree_implementations
113
100
    import bzrlib.tests.repository_implementations
114
101
    import bzrlib.tests.revisionstore_implementations
115
 
    import bzrlib.tests.tree_implementations
116
102
    import bzrlib.tests.workingtree_implementations
117
103
    return [
118
104
            bzrlib.doc,
121
107
            bzrlib.tests.bzrdir_implementations,
122
108
            bzrlib.tests.interrepository_implementations,
123
109
            bzrlib.tests.interversionedfile_implementations,
124
 
            bzrlib.tests.intertree_implementations,
125
110
            bzrlib.tests.repository_implementations,
126
111
            bzrlib.tests.revisionstore_implementations,
127
 
            bzrlib.tests.tree_implementations,
128
112
            bzrlib.tests.workingtree_implementations,
129
113
            ]
130
114
 
223
207
            self.stream.write('E')
224
208
        elif self.dots:
225
209
            self.pb.update(self._ellipsise_unimportant_words('ERROR', 13), self.testsRun, None)
226
 
            self.pb.note(self._ellipsise_unimportant_words(
227
 
                            test.id() + ': ERROR',
228
 
                            osutils.terminal_width()))
229
210
        self.stream.flush()
230
211
        if self.stop_early:
231
212
            self.stop()
239
220
            self.stream.write('F')
240
221
        elif self.dots:
241
222
            self.pb.update(self._ellipsise_unimportant_words('FAIL', 13), self.testsRun, None)
242
 
            self.pb.note(self._ellipsise_unimportant_words(
243
 
                            test.id() + ': FAIL',
244
 
                            osutils.terminal_width()))
245
223
        self.stream.flush()
246
224
        if self.stop_early:
247
225
            self.stop()
272
250
        self.stream.flush()
273
251
        # seems best to treat this as success from point-of-view of unittest
274
252
        # -- it actually does nothing so it barely matters :)
275
 
        try:
276
 
            test.tearDown()
277
 
        except KeyboardInterrupt:
278
 
            raise
279
 
        except:
280
 
            self.addError(test, test.__exc_info())
281
 
        else:
282
 
            unittest.TestResult.addSuccess(self, test)
 
253
        unittest.TestResult.addSuccess(self, test)
283
254
 
284
255
    def printErrorList(self, flavour, errors):
285
256
        for test, err in errors:
353
324
        test_root = TestCaseInTempDir.TEST_ROOT
354
325
        if result.wasSuccessful() or not self.keep_output:
355
326
            if test_root is not None:
356
 
                # If LANG=C we probably have created some bogus paths
357
 
                # which rmtree(unicode) will fail to delete
358
 
                # so make sure we are using rmtree(str) to delete everything
359
 
                # except on win32, where rmtree(str) will fail
360
 
                # since it doesn't have the property of byte-stream paths
361
 
                # (they are either ascii or mbcs)
362
 
                if sys.platform == 'win32':
363
 
                    # make sure we are using the unicode win32 api
364
 
                    test_root = unicode(test_root)
365
 
                else:
366
 
                    test_root = test_root.encode(
367
 
                        sys.getfilesystemencoding())
368
 
                osutils.rmtree(test_root)
 
327
                    osutils.rmtree(test_root)
369
328
        else:
370
329
            if self.pb is not None:
371
330
                self.pb.note("Failed tests working directories are in '%s'\n",
401
360
class CommandFailed(Exception):
402
361
    pass
403
362
 
404
 
 
405
 
class StringIOWrapper(object):
406
 
    """A wrapper around cStringIO which just adds an encoding attribute.
407
 
    
408
 
    Internally we can check sys.stdout to see what the output encoding
409
 
    should be. However, cStringIO has no encoding attribute that we can
410
 
    set. So we wrap it instead.
411
 
    """
412
 
    encoding='ascii'
413
 
    _cstring = None
414
 
 
415
 
    def __init__(self, s=None):
416
 
        if s is not None:
417
 
            self.__dict__['_cstring'] = StringIO(s)
418
 
        else:
419
 
            self.__dict__['_cstring'] = StringIO()
420
 
 
421
 
    def __getattr__(self, name, getattr=getattr):
422
 
        return getattr(self.__dict__['_cstring'], name)
423
 
 
424
 
    def __setattr__(self, name, val):
425
 
        if name == 'encoding':
426
 
            self.__dict__['encoding'] = val
427
 
        else:
428
 
            return setattr(self._cstring, name, val)
429
 
 
430
 
 
431
363
class TestCase(unittest.TestCase):
432
364
    """Base class for bzr unit tests.
433
365
    
514
446
            raise AssertionError('pattern "%s" not found in "%s"'
515
447
                    % (needle_re, haystack))
516
448
 
517
 
    def assertNotContainsRe(self, haystack, needle_re):
518
 
        """Assert that a does not match a regular expression"""
519
 
        if re.search(needle_re, haystack):
520
 
            raise AssertionError('pattern "%s" found in "%s"'
521
 
                    % (needle_re, haystack))
522
 
 
523
449
    def assertSubset(self, sublist, superlist):
524
450
        """Assert that every entry in sublist is present in superlist."""
525
451
        missing = []
569
495
 
570
496
        Read contents into memory, close, and delete.
571
497
        """
572
 
        if self._log_file is None:
573
 
            return
574
498
        bzrlib.trace.disable_test_log(self._log_nonce)
575
499
        self._log_file.seek(0)
576
500
        self._log_contents = self._log_file.read()
593
517
        new_env = {
594
518
            'HOME': os.getcwd(),
595
519
            'APPDATA': os.getcwd(),
596
 
            'BZR_EMAIL': None,
 
520
            'BZREMAIL': None,
597
521
            'EMAIL': None,
598
522
        }
599
523
        self.__old_env = {}
674
598
        """Shortcut that splits cmd into words, runs, and returns stdout"""
675
599
        return self.run_bzr_captured(cmd.split(), retcode=retcode)[0]
676
600
 
677
 
    def run_bzr_captured(self, argv, retcode=0, encoding=None, stdin=None):
 
601
    def run_bzr_captured(self, argv, retcode=0, stdin=None):
678
602
        """Invoke bzr and return (stdout, stderr).
679
603
 
680
604
        Useful for code that wants to check the contents of the
691
615
        errors, and with logging set to something approximating the
692
616
        default, so that error reporting can be checked.
693
617
 
694
 
        :param argv: arguments to invoke bzr
695
 
        :param retcode: expected return code, or None for don't-care.
696
 
        :param encoding: encoding for sys.stdout and sys.stderr
 
618
        argv -- arguments to invoke bzr
 
619
        retcode -- expected return code, or None for don't-care.
697
620
        :param stdin: A string to be used as stdin for the command.
698
621
        """
699
 
        if encoding is None:
700
 
            encoding = bzrlib.user_encoding
701
622
        if stdin is not None:
702
623
            stdin = StringIO(stdin)
703
 
        stdout = StringIOWrapper()
704
 
        stderr = StringIOWrapper()
705
 
        stdout.encoding = encoding
706
 
        stderr.encoding = encoding
707
 
 
708
 
        self.log('run bzr: %r', argv)
 
624
        stdout = StringIO()
 
625
        stderr = StringIO()
 
626
        self.log('run bzr: %s', ' '.join(argv))
709
627
        # FIXME: don't call into logging here
710
628
        handler = logging.StreamHandler(stderr)
 
629
        handler.setFormatter(bzrlib.trace.QuietFormatter())
711
630
        handler.setLevel(logging.INFO)
712
631
        logger = logging.getLogger('')
713
632
        logger.addHandler(handler)
723
642
        finally:
724
643
            logger.removeHandler(handler)
725
644
            bzrlib.ui.ui_factory = old_ui_factory
726
 
 
727
645
        out = stdout.getvalue()
728
646
        err = stderr.getvalue()
729
647
        if out:
730
 
            self.log('output:\n%r', out)
 
648
            self.log('output:\n%s', out)
731
649
        if err:
732
 
            self.log('errors:\n%r', err)
 
650
            self.log('errors:\n%s', err)
733
651
        if retcode is not None:
734
 
            self.assertEquals(retcode, result)
 
652
            self.assertEquals(result, retcode)
735
653
        return out, err
736
654
 
737
655
    def run_bzr(self, *args, **kwargs):
747
665
        :param stdin: A string to be used as stdin for the command.
748
666
        """
749
667
        retcode = kwargs.pop('retcode', 0)
750
 
        encoding = kwargs.pop('encoding', None)
751
668
        stdin = kwargs.pop('stdin', None)
752
 
        return self.run_bzr_captured(args, retcode=retcode, encoding=encoding, stdin=stdin)
753
 
 
754
 
    def run_bzr_decode(self, *args, **kwargs):
755
 
        if kwargs.has_key('encoding'):
756
 
            encoding = kwargs['encoding']
757
 
        else:
758
 
            encoding = bzrlib.user_encoding
759
 
        return self.run_bzr(*args, **kwargs)[0].decode(encoding)
760
 
 
761
 
    def run_bzr_error(self, error_regexes, *args, **kwargs):
762
 
        """Run bzr, and check that stderr contains the supplied regexes
763
 
        
764
 
        :param error_regexes: Sequence of regular expressions which 
765
 
            must each be found in the error output. The relative ordering
766
 
            is not enforced.
767
 
        :param args: command-line arguments for bzr
768
 
        :param kwargs: Keyword arguments which are interpreted by run_bzr
769
 
            This function changes the default value of retcode to be 3,
770
 
            since in most cases this is run when you expect bzr to fail.
771
 
        :return: (out, err) The actual output of running the command (in case you
772
 
                 want to do more inspection)
773
 
 
774
 
        Examples of use:
775
 
            # Make sure that commit is failing because there is nothing to do
776
 
            self.run_bzr_error(['no changes to commit'],
777
 
                               'commit', '-m', 'my commit comment')
778
 
            # Make sure --strict is handling an unknown file, rather than
779
 
            # giving us the 'nothing to do' error
780
 
            self.build_tree(['unknown'])
781
 
            self.run_bzr_error(['Commit refused because there are unknown files'],
782
 
                               'commit', '--strict', '-m', 'my commit comment')
783
 
        """
784
 
        kwargs.setdefault('retcode', 3)
785
 
        out, err = self.run_bzr(*args, **kwargs)
786
 
        for regex in error_regexes:
787
 
            self.assertContainsRe(err, regex)
788
 
        return out, err
789
 
 
790
 
    def run_bzr_subprocess(self, *args, **kwargs):
791
 
        """Run bzr in a subprocess for testing.
792
 
 
793
 
        This starts a new Python interpreter and runs bzr in there. 
794
 
        This should only be used for tests that have a justifiable need for
795
 
        this isolation: e.g. they are testing startup time, or signal
796
 
        handling, or early startup code, etc.  Subprocess code can't be 
797
 
        profiled or debugged so easily.
798
 
 
799
 
        :param retcode: The status code that is expected.  Defaults to 0.  If
800
 
        None is supplied, the status code is not checked.
801
 
        """
802
 
        bzr_path = os.path.dirname(os.path.dirname(bzrlib.__file__))+'/bzr'
803
 
        args = list(args)
804
 
        process = Popen([sys.executable, bzr_path]+args, stdout=PIPE, 
805
 
                         stderr=PIPE)
806
 
        out = process.stdout.read()
807
 
        err = process.stderr.read()
808
 
        retcode = process.wait()
809
 
        supplied_retcode = kwargs.get('retcode', 0)
810
 
        if supplied_retcode is not None:
811
 
            assert supplied_retcode == retcode
812
 
        return [out, err]
 
669
        return self.run_bzr_captured(args, retcode, stdin)
813
670
 
814
671
    def check_inventory_shape(self, inv, shape):
815
672
        """Compare an inventory to a list of expected names.
964
821
        shape is a sequence of file specifications.  If the final
965
822
        character is '/', a directory is created.
966
823
 
967
 
        This assumes that all the elements in the tree being built are new.
968
 
 
969
824
        This doesn't add anything to a branch.
970
825
        :param line_endings: Either 'binary' or 'native'
971
826
                             in binary mode, exact contents are written
976
831
                          VFS's. If the transport is readonly or None,
977
832
                          "." is opened automatically.
978
833
        """
979
 
        # It's OK to just create them using forward slashes on windows.
 
834
        # XXX: It's OK to just create them using forward slashes on windows?
980
835
        if transport is None or transport.is_readonly():
981
836
            transport = get_transport(".")
982
837
        for name in shape:
983
838
            self.assert_(isinstance(name, basestring))
984
839
            if name[-1] == '/':
985
 
                transport.mkdir(urlutils.escape(name[:-1]))
 
840
                transport.mkdir(urlescape(name[:-1]))
986
841
            else:
987
842
                if line_endings == 'binary':
988
843
                    end = '\n'
990
845
                    end = os.linesep
991
846
                else:
992
847
                    raise errors.BzrError('Invalid line ending request %r' % (line_endings,))
993
 
                content = "contents of %s%s" % (name.encode('utf-8'), end)
994
 
                # Technically 'put()' is the right command. However, put
995
 
                # uses an AtomicFile, which requires an extra rename into place
996
 
                # As long as the files didn't exist in the past, append() will
997
 
                # do the same thing as put()
998
 
                # On jam's machine, make_kernel_like_tree is:
999
 
                #   put:    4.5-7.5s (averaging 6s)
1000
 
                #   append: 2.9-4.5s
1001
 
                transport.append(urlutils.escape(name), StringIO(content))
 
848
                content = "contents of %s%s" % (name, end)
 
849
                transport.put(urlescape(name), StringIO(content))
1002
850
 
1003
851
    def build_tree_contents(self, shape):
1004
852
        build_tree_contents(shape)
1014
862
    def assertFileEqual(self, content, path):
1015
863
        """Fail if path does not contain 'content'."""
1016
864
        self.failUnless(osutils.lexists(path))
1017
 
        # TODO: jam 20060427 Shouldn't this be 'rb'?
1018
865
        self.assertEqualDiff(content, open(path, 'r').read())
1019
866
 
1020
867
 
1096
943
        if relpath is not None and relpath != '.':
1097
944
            if not base.endswith('/'):
1098
945
                base = base + '/'
1099
 
            base = base + urlutils.escape(relpath)
 
946
            base = base + relpath
1100
947
        return base
1101
948
 
1102
949
    def get_transport(self):
1123
970
    def make_bzrdir(self, relpath, format=None):
1124
971
        try:
1125
972
            url = self.get_url(relpath)
1126
 
            mutter('relpath %r => url %r', relpath, url)
1127
 
            segments = url.split('/')
 
973
            segments = relpath.split('/')
1128
974
            if segments and segments[-1] not in ('', '.'):
1129
 
                parent = '/'.join(segments[:-1])
 
975
                parent = self.get_url('/'.join(segments[:-1]))
1130
976
                t = get_transport(parent)
1131
977
                try:
1132
978
                    t.mkdir(segments[-1])
1198
1044
 
1199
1045
 
1200
1046
def filter_suite_by_re(suite, pattern):
1201
 
    result = TestUtil.TestSuite()
 
1047
    result = TestSuite()
1202
1048
    filter_re = re.compile(pattern)
1203
1049
    for test in iter_suite_tests(suite):
1204
1050
        if filter_re.search(test.id()):
1235
1081
             test_suite_factory=None,
1236
1082
             lsprof_timed=None):
1237
1083
    """Run the whole test suite under the enhanced runner"""
1238
 
    # XXX: Very ugly way to do this...
1239
 
    # Disable warning about old formats because we don't want it to disturb
1240
 
    # any blackbox tests.
1241
 
    from bzrlib import repository
1242
 
    repository._deprecation_warning_done = True
1243
 
 
1244
1084
    global default_transport
1245
1085
    if transport is None:
1246
1086
        transport = default_transport
1265
1105
    This function can be replaced if you need to change the default test
1266
1106
    suite on a global basis, but it is not encouraged.
1267
1107
    """
1268
 
    testmod_names = [
 
1108
    from doctest import DocTestSuite
 
1109
 
 
1110
    global MODULES_TO_DOCTEST
 
1111
 
 
1112
    testmod_names = [ \
1269
1113
                   'bzrlib.tests.test_ancestry',
1270
1114
                   'bzrlib.tests.test_api',
1271
 
                   'bzrlib.tests.test_atomicfile',
1272
1115
                   'bzrlib.tests.test_bad_files',
1273
1116
                   'bzrlib.tests.test_branch',
1274
 
                   'bzrlib.tests.test_bundle',
1275
1117
                   'bzrlib.tests.test_bzrdir',
1276
1118
                   'bzrlib.tests.test_command',
1277
1119
                   'bzrlib.tests.test_commit',
1288
1130
                   'bzrlib.tests.test_graph',
1289
1131
                   'bzrlib.tests.test_hashcache',
1290
1132
                   'bzrlib.tests.test_http',
1291
 
                   'bzrlib.tests.test_http_response',
1292
1133
                   'bzrlib.tests.test_identitymap',
1293
 
                   'bzrlib.tests.test_ignores',
1294
1134
                   'bzrlib.tests.test_inv',
1295
1135
                   'bzrlib.tests.test_knit',
1296
1136
                   'bzrlib.tests.test_lockdir',
1305
1145
                   'bzrlib.tests.test_options',
1306
1146
                   'bzrlib.tests.test_osutils',
1307
1147
                   'bzrlib.tests.test_patch',
1308
 
                   'bzrlib.tests.test_patches',
1309
1148
                   'bzrlib.tests.test_permissions',
1310
1149
                   'bzrlib.tests.test_plugins',
1311
1150
                   'bzrlib.tests.test_progress',
1313
1152
                   'bzrlib.tests.test_repository',
1314
1153
                   'bzrlib.tests.test_revision',
1315
1154
                   'bzrlib.tests.test_revisionnamespaces',
1316
 
                   'bzrlib.tests.test_revisiontree',
 
1155
                   'bzrlib.tests.test_revprops',
1317
1156
                   'bzrlib.tests.test_rio',
1318
1157
                   'bzrlib.tests.test_sampler',
1319
1158
                   'bzrlib.tests.test_selftest',
1331
1170
                   'bzrlib.tests.test_transactions',
1332
1171
                   'bzrlib.tests.test_transform',
1333
1172
                   'bzrlib.tests.test_transport',
1334
 
                   'bzrlib.tests.test_tree',
1335
1173
                   'bzrlib.tests.test_tsort',
1336
1174
                   'bzrlib.tests.test_tuned_gzip',
1337
1175
                   'bzrlib.tests.test_ui',
1338
1176
                   'bzrlib.tests.test_upgrade',
1339
 
                   'bzrlib.tests.test_urlutils',
1340
1177
                   'bzrlib.tests.test_versionedfile',
1341
1178
                   'bzrlib.tests.test_weave',
1342
1179
                   'bzrlib.tests.test_whitebox',
1344
1181
                   'bzrlib.tests.test_xml',
1345
1182
                   ]
1346
1183
    test_transport_implementations = [
1347
 
        'bzrlib.tests.test_transport_implementations',
1348
 
        'bzrlib.tests.test_read_bundle',
1349
 
        ]
1350
 
    suite = TestUtil.TestSuite()
 
1184
        'bzrlib.tests.test_transport_implementations']
 
1185
 
 
1186
    suite = TestSuite()
1351
1187
    loader = TestUtil.TestLoader()
1352
 
    suite.addTest(loader.loadTestsFromModuleNames(testmod_names))
1353
1188
    from bzrlib.transport import TransportTestProviderAdapter
1354
1189
    adapter = TransportTestProviderAdapter()
1355
1190
    adapt_modules(test_transport_implementations, adapter, loader, suite)
 
1191
    suite.addTest(loader.loadTestsFromModuleNames(testmod_names))
1356
1192
    for package in packages_to_test():
1357
1193
        suite.addTest(package.test_suite())
1358
1194
    for m in MODULES_TO_TEST:
1359
1195
        suite.addTest(loader.loadTestsFromModule(m))
1360
 
    for m in MODULES_TO_DOCTEST:
1361
 
        suite.addTest(doctest.DocTestSuite(m))
 
1196
    for m in (MODULES_TO_DOCTEST):
 
1197
        suite.addTest(DocTestSuite(m))
1362
1198
    for name, plugin in bzrlib.plugin.all_plugins().items():
1363
1199
        if getattr(plugin, 'test_suite', None) is not None:
1364
1200
            suite.addTest(plugin.test_suite())