~bzr-pqm/bzr/bzr.dev

« back to all changes in this revision

Viewing changes to bzrlib/tests/__init__.py

  • Committer: John Arbash Meinel
  • Date: 2006-10-10 06:26:39 UTC
  • mto: This revision was merged to the branch mainline in revision 2070.
  • Revision ID: john@arbash-meinel.com-20061010062639-6d527d0f9a3401d8
Catch an exception while opening /dev/urandom rather than using os.path.exists()

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
# Copyright (C) 2005 by Canonical Ltd
2
 
 
 
1
# Copyright (C) 2005, 2006 by Canonical Ltd
 
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
21
21
# little as possible, so this should be used rarely if it's added at all.
22
22
# (Suggestion from j-a-meinel, 2005-11-24)
23
23
 
 
24
# NOTE: Some classes in here use camelCaseNaming() rather than
 
25
# underscore_naming().  That's for consistency with unittest; it's not the
 
26
# general style of bzrlib.  Please continue that consistency when adding e.g.
 
27
# new assertFoo() methods.
 
28
 
 
29
import codecs
24
30
from cStringIO import StringIO
25
31
import difflib
 
32
import doctest
26
33
import errno
27
34
import logging
28
35
import os
29
36
import re
30
 
import shutil
 
37
import shlex
31
38
import stat
 
39
from subprocess import Popen, PIPE
32
40
import sys
33
41
import tempfile
34
42
import unittest
35
43
import time
36
 
import codecs
37
 
 
 
44
 
 
45
 
 
46
from bzrlib import memorytree
38
47
import bzrlib.branch
 
48
import bzrlib.bzrdir as bzrdir
39
49
import bzrlib.commands
40
 
from bzrlib.errors import BzrError
 
50
import bzrlib.bundle.serializer
 
51
import bzrlib.errors as errors
 
52
import bzrlib.export
41
53
import bzrlib.inventory
42
54
import bzrlib.iterablefile
 
55
import bzrlib.lockdir
 
56
try:
 
57
    import bzrlib.lsprof
 
58
except ImportError:
 
59
    # lsprof not available
 
60
    pass
 
61
from bzrlib.merge import merge_inner
43
62
import bzrlib.merge3
44
63
import bzrlib.osutils
45
64
import bzrlib.osutils as osutils
46
65
import bzrlib.plugin
 
66
import bzrlib.progress as progress
 
67
from bzrlib.revision import common_ancestor
47
68
import bzrlib.store
 
69
from bzrlib import symbol_versioning
48
70
import bzrlib.trace
49
 
from bzrlib.transport import urlescape
 
71
from bzrlib.transport import get_transport
 
72
import bzrlib.transport
 
73
from bzrlib.transport.local import LocalRelpathServer
 
74
from bzrlib.transport.memory import MemoryServer
 
75
from bzrlib.transport.readonly import ReadonlyServer
50
76
from bzrlib.trace import mutter
51
 
from bzrlib.tests.TestUtil import TestLoader, TestSuite
 
77
from bzrlib.tests import TestUtil
 
78
from bzrlib.tests.TestUtil import (
 
79
                          TestSuite,
 
80
                          TestLoader,
 
81
                          )
52
82
from bzrlib.tests.treeshape import build_tree_contents
 
83
import bzrlib.urlutils as urlutils
 
84
from bzrlib.workingtree import WorkingTree, WorkingTreeFormat2
 
85
 
 
86
default_transport = LocalRelpathServer
53
87
 
54
88
MODULES_TO_TEST = []
55
89
MODULES_TO_DOCTEST = [
56
90
                      bzrlib.branch,
 
91
                      bzrlib.bundle.serializer,
57
92
                      bzrlib.commands,
58
93
                      bzrlib.errors,
 
94
                      bzrlib.export,
59
95
                      bzrlib.inventory,
60
96
                      bzrlib.iterablefile,
 
97
                      bzrlib.lockdir,
61
98
                      bzrlib.merge3,
62
99
                      bzrlib.option,
63
100
                      bzrlib.osutils,
64
 
                      bzrlib.store
 
101
                      bzrlib.store,
 
102
                      bzrlib.transport,
65
103
                      ]
 
104
 
 
105
 
66
106
def packages_to_test():
67
107
    """Return a list of packages to test.
68
108
 
71
111
    """
72
112
    import bzrlib.doc
73
113
    import bzrlib.tests.blackbox
 
114
    import bzrlib.tests.branch_implementations
 
115
    import bzrlib.tests.bzrdir_implementations
 
116
    import bzrlib.tests.interrepository_implementations
 
117
    import bzrlib.tests.interversionedfile_implementations
 
118
    import bzrlib.tests.intertree_implementations
 
119
    import bzrlib.tests.repository_implementations
 
120
    import bzrlib.tests.revisionstore_implementations
 
121
    import bzrlib.tests.tree_implementations
 
122
    import bzrlib.tests.workingtree_implementations
74
123
    return [
75
124
            bzrlib.doc,
76
 
            bzrlib.tests.blackbox
 
125
            bzrlib.tests.blackbox,
 
126
            bzrlib.tests.branch_implementations,
 
127
            bzrlib.tests.bzrdir_implementations,
 
128
            bzrlib.tests.interrepository_implementations,
 
129
            bzrlib.tests.interversionedfile_implementations,
 
130
            bzrlib.tests.intertree_implementations,
 
131
            bzrlib.tests.repository_implementations,
 
132
            bzrlib.tests.revisionstore_implementations,
 
133
            bzrlib.tests.tree_implementations,
 
134
            bzrlib.tests.workingtree_implementations,
77
135
            ]
78
136
 
79
137
 
83
141
    Shows output in a different format, including displaying runtime for tests.
84
142
    """
85
143
    stop_early = False
86
 
 
87
 
    def _elapsedTime(self):
88
 
        return "%5dms" % (1000 * (time.time() - self._start_time))
 
144
    
 
145
    def __init__(self, stream, descriptions, verbosity, pb=None,
 
146
                 bench_history=None):
 
147
        """Construct new TestResult.
 
148
 
 
149
        :param bench_history: Optionally, a writable file object to accumulate
 
150
            benchmark results.
 
151
        """
 
152
        unittest._TextTestResult.__init__(self, stream, descriptions, verbosity)
 
153
        self.pb = pb
 
154
        if bench_history is not None:
 
155
            from bzrlib.version import _get_bzr_source_tree
 
156
            src_tree = _get_bzr_source_tree()
 
157
            if src_tree:
 
158
                try:
 
159
                    revision_id = src_tree.get_parent_ids()[0]
 
160
                except IndexError:
 
161
                    # XXX: if this is a brand new tree, do the same as if there
 
162
                    # is no branch.
 
163
                    revision_id = ''
 
164
            else:
 
165
                # XXX: If there's no branch, what should we do?
 
166
                revision_id = ''
 
167
            bench_history.write("--date %s %s\n" % (time.time(), revision_id))
 
168
        self._bench_history = bench_history
 
169
    
 
170
    def extractBenchmarkTime(self, testCase):
 
171
        """Add a benchmark time for the current test case."""
 
172
        self._benchmarkTime = getattr(testCase, "_benchtime", None)
 
173
    
 
174
    def _elapsedTestTimeString(self):
 
175
        """Return a time string for the overall time the current test has taken."""
 
176
        return self._formatTime(time.time() - self._start_time)
 
177
 
 
178
    def _testTimeString(self):
 
179
        if self._benchmarkTime is not None:
 
180
            return "%s/%s" % (
 
181
                self._formatTime(self._benchmarkTime),
 
182
                self._elapsedTestTimeString())
 
183
        else:
 
184
            return "      %s" % self._elapsedTestTimeString()
 
185
 
 
186
    def _formatTime(self, seconds):
 
187
        """Format seconds as milliseconds with leading spaces."""
 
188
        return "%5dms" % (1000 * seconds)
 
189
 
 
190
    def _ellipsise_unimportant_words(self, a_string, final_width,
 
191
                                   keep_start=False):
 
192
        """Add ellipses (sp?) for overly long strings.
 
193
        
 
194
        :param keep_start: If true preserve the start of a_string rather
 
195
                           than the end of it.
 
196
        """
 
197
        if keep_start:
 
198
            if len(a_string) > final_width:
 
199
                result = a_string[:final_width-3] + '...'
 
200
            else:
 
201
                result = a_string
 
202
        else:
 
203
            if len(a_string) > final_width:
 
204
                result = '...' + a_string[3-final_width:]
 
205
            else:
 
206
                result = a_string
 
207
        return result.ljust(final_width)
89
208
 
90
209
    def startTest(self, test):
91
210
        unittest.TestResult.startTest(self, test)
93
212
        # the beginning, but in an id, the important words are
94
213
        # at the end
95
214
        SHOW_DESCRIPTIONS = False
 
215
 
 
216
        if not self.showAll and self.dots and self.pb is not None:
 
217
            final_width = 13
 
218
        else:
 
219
            final_width = osutils.terminal_width()
 
220
            final_width = final_width - 15 - 8
 
221
        what = None
 
222
        if SHOW_DESCRIPTIONS:
 
223
            what = test.shortDescription()
 
224
            if what:
 
225
                what = self._ellipsise_unimportant_words(what, final_width, keep_start=True)
 
226
        if what is None:
 
227
            what = test.id()
 
228
            if what.startswith('bzrlib.tests.'):
 
229
                what = what[13:]
 
230
            what = self._ellipsise_unimportant_words(what, final_width)
96
231
        if self.showAll:
97
 
            width = osutils.terminal_width()
98
 
            name_width = width - 15
99
 
            what = None
100
 
            if SHOW_DESCRIPTIONS:
101
 
                what = test.shortDescription()
102
 
                if what:
103
 
                    if len(what) > name_width:
104
 
                        what = what[:name_width-3] + '...'
105
 
            if what is None:
106
 
                what = test.id()
107
 
                if what.startswith('bzrlib.tests.'):
108
 
                    what = what[13:]
109
 
                if len(what) > name_width:
110
 
                    what = '...' + what[3-name_width:]
111
 
            what = what.ljust(name_width)
112
232
            self.stream.write(what)
 
233
        elif self.dots and self.pb is not None:
 
234
            self.pb.update(what, self.testsRun - 1, None)
113
235
        self.stream.flush()
 
236
        self._recordTestStartTime()
 
237
 
 
238
    def _recordTestStartTime(self):
 
239
        """Record that a test has started."""
114
240
        self._start_time = time.time()
115
241
 
116
242
    def addError(self, test, err):
117
243
        if isinstance(err[1], TestSkipped):
118
244
            return self.addSkipped(test, err)    
119
245
        unittest.TestResult.addError(self, test, err)
 
246
        # We can only do this if we have one of our TestCases, not if
 
247
        # we have a doctest.
 
248
        setKeepLogfile = getattr(test, 'setKeepLogfile', None)
 
249
        if setKeepLogfile is not None:
 
250
            setKeepLogfile()
 
251
        self.extractBenchmarkTime(test)
120
252
        if self.showAll:
121
 
            self.stream.writeln("ERROR %s" % self._elapsedTime())
122
 
        elif self.dots:
 
253
            self.stream.writeln("ERROR %s" % self._testTimeString())
 
254
        elif self.dots and self.pb is None:
123
255
            self.stream.write('E')
 
256
        elif self.dots:
 
257
            self.pb.update(self._ellipsise_unimportant_words('ERROR', 13), self.testsRun, None)
 
258
            self.pb.note(self._ellipsise_unimportant_words(
 
259
                            test.id() + ': ERROR',
 
260
                            osutils.terminal_width()))
124
261
        self.stream.flush()
125
262
        if self.stop_early:
126
263
            self.stop()
127
264
 
128
265
    def addFailure(self, test, err):
129
266
        unittest.TestResult.addFailure(self, test, err)
 
267
        # We can only do this if we have one of our TestCases, not if
 
268
        # we have a doctest.
 
269
        setKeepLogfile = getattr(test, 'setKeepLogfile', None)
 
270
        if setKeepLogfile is not None:
 
271
            setKeepLogfile()
 
272
        self.extractBenchmarkTime(test)
130
273
        if self.showAll:
131
 
            self.stream.writeln(" FAIL %s" % self._elapsedTime())
132
 
        elif self.dots:
 
274
            self.stream.writeln(" FAIL %s" % self._testTimeString())
 
275
        elif self.dots and self.pb is None:
133
276
            self.stream.write('F')
 
277
        elif self.dots:
 
278
            self.pb.update(self._ellipsise_unimportant_words('FAIL', 13), self.testsRun, None)
 
279
            self.pb.note(self._ellipsise_unimportant_words(
 
280
                            test.id() + ': FAIL',
 
281
                            osutils.terminal_width()))
134
282
        self.stream.flush()
135
283
        if self.stop_early:
136
284
            self.stop()
137
285
 
138
286
    def addSuccess(self, test):
 
287
        self.extractBenchmarkTime(test)
 
288
        if self._bench_history is not None:
 
289
            if self._benchmarkTime is not None:
 
290
                self._bench_history.write("%s %s\n" % (
 
291
                    self._formatTime(self._benchmarkTime),
 
292
                    test.id()))
139
293
        if self.showAll:
140
 
            self.stream.writeln('   OK %s' % self._elapsedTime())
141
 
        elif self.dots:
 
294
            self.stream.writeln('   OK %s' % self._testTimeString())
 
295
            for bench_called, stats in getattr(test, '_benchcalls', []):
 
296
                self.stream.writeln('LSProf output for %s(%s, %s)' % bench_called)
 
297
                stats.pprint(file=self.stream)
 
298
        elif self.dots and self.pb is None:
142
299
            self.stream.write('~')
 
300
        elif self.dots:
 
301
            self.pb.update(self._ellipsise_unimportant_words('OK', 13), self.testsRun, None)
143
302
        self.stream.flush()
144
303
        unittest.TestResult.addSuccess(self, test)
145
304
 
146
305
    def addSkipped(self, test, skip_excinfo):
 
306
        self.extractBenchmarkTime(test)
147
307
        if self.showAll:
148
 
            print >>self.stream, ' SKIP %s' % self._elapsedTime()
 
308
            print >>self.stream, ' SKIP %s' % self._testTimeString()
149
309
            print >>self.stream, '     %s' % skip_excinfo[1]
150
 
        elif self.dots:
 
310
        elif self.dots and self.pb is None:
151
311
            self.stream.write('S')
 
312
        elif self.dots:
 
313
            self.pb.update(self._ellipsise_unimportant_words('SKIP', 13), self.testsRun, None)
152
314
        self.stream.flush()
153
315
        # seems best to treat this as success from point-of-view of unittest
154
316
        # -- it actually does nothing so it barely matters :)
155
 
        unittest.TestResult.addSuccess(self, test)
 
317
        try:
 
318
            test.tearDown()
 
319
        except KeyboardInterrupt:
 
320
            raise
 
321
        except:
 
322
            self.addError(test, test.__exc_info())
 
323
        else:
 
324
            unittest.TestResult.addSuccess(self, test)
156
325
 
157
326
    def printErrorList(self, flavour, errors):
158
327
        for test, err in errors:
159
328
            self.stream.writeln(self.separator1)
160
329
            self.stream.writeln("%s: %s" % (flavour, self.getDescription(test)))
161
 
            if hasattr(test, '_get_log'):
 
330
            if getattr(test, '_get_log', None) is not None:
162
331
                print >>self.stream
163
332
                print >>self.stream, \
164
333
                        ('vvvv[log from %s]' % test.id()).ljust(78,'-')
169
338
            self.stream.writeln("%s" % err)
170
339
 
171
340
 
172
 
class TextTestRunner(unittest.TextTestRunner):
 
341
class TextTestRunner(object):
173
342
    stop_on_failure = False
174
343
 
 
344
    def __init__(self,
 
345
                 stream=sys.stderr,
 
346
                 descriptions=0,
 
347
                 verbosity=1,
 
348
                 keep_output=False,
 
349
                 pb=None,
 
350
                 bench_history=None):
 
351
        self.stream = unittest._WritelnDecorator(stream)
 
352
        self.descriptions = descriptions
 
353
        self.verbosity = verbosity
 
354
        self.keep_output = keep_output
 
355
        self.pb = pb
 
356
        self._bench_history = bench_history
 
357
 
175
358
    def _makeResult(self):
176
 
        result = _MyResult(self.stream, self.descriptions, self.verbosity)
 
359
        result = _MyResult(self.stream,
 
360
                           self.descriptions,
 
361
                           self.verbosity,
 
362
                           pb=self.pb,
 
363
                           bench_history=self._bench_history)
177
364
        result.stop_early = self.stop_on_failure
178
365
        return result
179
366
 
 
367
    def run(self, test):
 
368
        "Run the given test case or test suite."
 
369
        result = self._makeResult()
 
370
        startTime = time.time()
 
371
        if self.pb is not None:
 
372
            self.pb.update('Running tests', 0, test.countTestCases())
 
373
        test.run(result)
 
374
        stopTime = time.time()
 
375
        timeTaken = stopTime - startTime
 
376
        result.printErrors()
 
377
        self.stream.writeln(result.separator2)
 
378
        run = result.testsRun
 
379
        self.stream.writeln("Ran %d test%s in %.3fs" %
 
380
                            (run, run != 1 and "s" or "", timeTaken))
 
381
        self.stream.writeln()
 
382
        if not result.wasSuccessful():
 
383
            self.stream.write("FAILED (")
 
384
            failed, errored = map(len, (result.failures, result.errors))
 
385
            if failed:
 
386
                self.stream.write("failures=%d" % failed)
 
387
            if errored:
 
388
                if failed: self.stream.write(", ")
 
389
                self.stream.write("errors=%d" % errored)
 
390
            self.stream.writeln(")")
 
391
        else:
 
392
            self.stream.writeln("OK")
 
393
        if self.pb is not None:
 
394
            self.pb.update('Cleaning up', 0, 1)
 
395
        # This is still a little bogus, 
 
396
        # but only a little. Folk not using our testrunner will
 
397
        # have to delete their temp directories themselves.
 
398
        test_root = TestCaseWithMemoryTransport.TEST_ROOT
 
399
        if result.wasSuccessful() or not self.keep_output:
 
400
            if test_root is not None:
 
401
                # If LANG=C we probably have created some bogus paths
 
402
                # which rmtree(unicode) will fail to delete
 
403
                # so make sure we are using rmtree(str) to delete everything
 
404
                # except on win32, where rmtree(str) will fail
 
405
                # since it doesn't have the property of byte-stream paths
 
406
                # (they are either ascii or mbcs)
 
407
                if sys.platform == 'win32':
 
408
                    # make sure we are using the unicode win32 api
 
409
                    test_root = unicode(test_root)
 
410
                else:
 
411
                    test_root = test_root.encode(
 
412
                        sys.getfilesystemencoding())
 
413
                osutils.rmtree(test_root)
 
414
        else:
 
415
            if self.pb is not None:
 
416
                self.pb.note("Failed tests working directories are in '%s'\n",
 
417
                             test_root)
 
418
            else:
 
419
                self.stream.writeln(
 
420
                    "Failed tests working directories are in '%s'\n" %
 
421
                    test_root)
 
422
        TestCaseWithMemoryTransport.TEST_ROOT = None
 
423
        if self.pb is not None:
 
424
            self.pb.clear()
 
425
        return result
 
426
 
180
427
 
181
428
def iter_suite_tests(suite):
182
429
    """Return all tests in a suite, recursing through nested suites"""
193
440
 
194
441
class TestSkipped(Exception):
195
442
    """Indicates that a test was intentionally skipped, rather than failing."""
196
 
    # XXX: Not used yet
197
443
 
198
444
 
199
445
class CommandFailed(Exception):
200
446
    pass
201
447
 
 
448
 
 
449
class StringIOWrapper(object):
 
450
    """A wrapper around cStringIO which just adds an encoding attribute.
 
451
    
 
452
    Internally we can check sys.stdout to see what the output encoding
 
453
    should be. However, cStringIO has no encoding attribute that we can
 
454
    set. So we wrap it instead.
 
455
    """
 
456
    encoding='ascii'
 
457
    _cstring = None
 
458
 
 
459
    def __init__(self, s=None):
 
460
        if s is not None:
 
461
            self.__dict__['_cstring'] = StringIO(s)
 
462
        else:
 
463
            self.__dict__['_cstring'] = StringIO()
 
464
 
 
465
    def __getattr__(self, name, getattr=getattr):
 
466
        return getattr(self.__dict__['_cstring'], name)
 
467
 
 
468
    def __setattr__(self, name, val):
 
469
        if name == 'encoding':
 
470
            self.__dict__['encoding'] = val
 
471
        else:
 
472
            return setattr(self._cstring, name, val)
 
473
 
 
474
 
202
475
class TestCase(unittest.TestCase):
203
476
    """Base class for bzr unit tests.
204
477
    
220
493
    accidentally overlooked.
221
494
    """
222
495
 
223
 
    BZRPATH = 'bzr'
224
496
    _log_file_name = None
225
497
    _log_contents = ''
 
498
    _keep_log_file = False
 
499
    # record lsprof data when performing benchmark calls.
 
500
    _gather_lsprof_in_benchmarks = False
 
501
 
 
502
    def __init__(self, methodName='testMethod'):
 
503
        super(TestCase, self).__init__(methodName)
 
504
        self._cleanups = []
226
505
 
227
506
    def setUp(self):
228
507
        unittest.TestCase.setUp(self)
229
 
        self._cleanups = []
230
508
        self._cleanEnvironment()
231
509
        bzrlib.trace.disable_default_logging()
232
510
        self._startLogFile()
 
511
        self._benchcalls = []
 
512
        self._benchtime = None
233
513
 
234
514
    def _ndiff_strings(self, a, b):
235
515
        """Return ndiff between two strings containing lines.
246
526
                                  charjunk=lambda x: False)
247
527
        return ''.join(difflines)
248
528
 
249
 
    def assertEqualDiff(self, a, b):
 
529
    def assertEqualDiff(self, a, b, message=None):
250
530
        """Assert two texts are equal, if not raise an exception.
251
531
        
252
532
        This is intended for use with multi-line strings where it can 
255
535
        # TODO: perhaps override assertEquals to call this for strings?
256
536
        if a == b:
257
537
            return
258
 
        raise AssertionError("texts not equal:\n" + 
 
538
        if message is None:
 
539
            message = "texts not equal:\n"
 
540
        raise AssertionError(message + 
259
541
                             self._ndiff_strings(a, b))      
260
542
        
 
543
    def assertEqualMode(self, mode, mode_test):
 
544
        self.assertEqual(mode, mode_test,
 
545
                         'mode mismatch %o != %o' % (mode, mode_test))
 
546
 
261
547
    def assertStartsWith(self, s, prefix):
262
548
        if not s.startswith(prefix):
263
549
            raise AssertionError('string %r does not start with %r' % (s, prefix))
264
550
 
265
551
    def assertEndsWith(self, s, suffix):
266
 
        if not s.endswith(prefix):
 
552
        """Asserts that s ends with suffix."""
 
553
        if not s.endswith(suffix):
267
554
            raise AssertionError('string %r does not end with %r' % (s, suffix))
268
555
 
269
556
    def assertContainsRe(self, haystack, needle_re):
272
559
            raise AssertionError('pattern "%s" not found in "%s"'
273
560
                    % (needle_re, haystack))
274
561
 
275
 
    def AssertSubset(self, sublist, superlist):
 
562
    def assertNotContainsRe(self, haystack, needle_re):
 
563
        """Assert that a does not match a regular expression"""
 
564
        if re.search(needle_re, haystack):
 
565
            raise AssertionError('pattern "%s" found in "%s"'
 
566
                    % (needle_re, haystack))
 
567
 
 
568
    def assertSubset(self, sublist, superlist):
276
569
        """Assert that every entry in sublist is present in superlist."""
277
570
        missing = []
278
571
        for entry in sublist:
289
582
    def assertTransportMode(self, transport, path, mode):
290
583
        """Fail if a path does not have mode mode.
291
584
        
292
 
        If modes are not supported on this platform, the test is skipped.
 
585
        If modes are not supported on this transport, the assertion is ignored.
293
586
        """
294
 
        if sys.platform == 'win32':
 
587
        if not transport._can_roundtrip_unix_modebits():
295
588
            return
296
589
        path_stat = transport.stat(path)
297
590
        actual_mode = stat.S_IMODE(path_stat.st_mode)
298
591
        self.assertEqual(mode, actual_mode,
299
592
            'mode of %r incorrect (%o != %o)' % (path, mode, actual_mode))
300
593
 
 
594
    def assertIsInstance(self, obj, kls):
 
595
        """Fail if obj is not an instance of kls"""
 
596
        if not isinstance(obj, kls):
 
597
            self.fail("%r is an instance of %s rather than %s" % (
 
598
                obj, obj.__class__, kls))
 
599
 
 
600
    def _capture_warnings(self, a_callable, *args, **kwargs):
 
601
        """A helper for callDeprecated and applyDeprecated.
 
602
 
 
603
        :param a_callable: A callable to call.
 
604
        :param args: The positional arguments for the callable
 
605
        :param kwargs: The keyword arguments for the callable
 
606
        :return: A tuple (warnings, result). result is the result of calling
 
607
            a_callable(*args, **kwargs).
 
608
        """
 
609
        local_warnings = []
 
610
        def capture_warnings(msg, cls, stacklevel=None):
 
611
            # we've hooked into a deprecation specific callpath,
 
612
            # only deprecations should getting sent via it.
 
613
            self.assertEqual(cls, DeprecationWarning)
 
614
            local_warnings.append(msg)
 
615
        original_warning_method = symbol_versioning.warn
 
616
        symbol_versioning.set_warning_method(capture_warnings)
 
617
        try:
 
618
            result = a_callable(*args, **kwargs)
 
619
        finally:
 
620
            symbol_versioning.set_warning_method(original_warning_method)
 
621
        return (local_warnings, result)
 
622
 
 
623
    def applyDeprecated(self, deprecation_format, a_callable, *args, **kwargs):
 
624
        """Call a deprecated callable without warning the user.
 
625
 
 
626
        :param deprecation_format: The deprecation format that the callable
 
627
            should have been deprecated with. This is the same type as the 
 
628
            parameter to deprecated_method/deprecated_function. If the 
 
629
            callable is not deprecated with this format, an assertion error
 
630
            will be raised.
 
631
        :param a_callable: A callable to call. This may be a bound method or
 
632
            a regular function. It will be called with *args and **kwargs.
 
633
        :param args: The positional arguments for the callable
 
634
        :param kwargs: The keyword arguments for the callable
 
635
        :return: The result of a_callable(*args, **kwargs)
 
636
        """
 
637
        call_warnings, result = self._capture_warnings(a_callable,
 
638
            *args, **kwargs)
 
639
        expected_first_warning = symbol_versioning.deprecation_string(
 
640
            a_callable, deprecation_format)
 
641
        if len(call_warnings) == 0:
 
642
            self.fail("No assertion generated by call to %s" %
 
643
                a_callable)
 
644
        self.assertEqual(expected_first_warning, call_warnings[0])
 
645
        return result
 
646
 
 
647
    def callDeprecated(self, expected, callable, *args, **kwargs):
 
648
        """Assert that a callable is deprecated in a particular way.
 
649
 
 
650
        This is a very precise test for unusual requirements. The 
 
651
        applyDeprecated helper function is probably more suited for most tests
 
652
        as it allows you to simply specify the deprecation format being used
 
653
        and will ensure that that is issued for the function being called.
 
654
 
 
655
        :param expected: a list of the deprecation warnings expected, in order
 
656
        :param callable: The callable to call
 
657
        :param args: The positional arguments for the callable
 
658
        :param kwargs: The keyword arguments for the callable
 
659
        """
 
660
        call_warnings, result = self._capture_warnings(callable,
 
661
            *args, **kwargs)
 
662
        self.assertEqual(expected, call_warnings)
 
663
        return result
 
664
 
301
665
    def _startLogFile(self):
302
666
        """Send bzr and test log messages to a temporary file.
303
667
 
304
668
        The file is removed as the test is torn down.
305
669
        """
306
670
        fileno, name = tempfile.mkstemp(suffix='.log', prefix='testbzr')
307
 
        encoder, decoder, stream_reader, stream_writer = codecs.lookup('UTF-8')
308
 
        self._log_file = stream_writer(os.fdopen(fileno, 'w+'))
309
 
        bzrlib.trace.enable_test_log(self._log_file)
 
671
        self._log_file = os.fdopen(fileno, 'w+')
 
672
        self._log_nonce = bzrlib.trace.enable_test_log(self._log_file)
310
673
        self._log_file_name = name
311
674
        self.addCleanup(self._finishLogFile)
312
675
 
313
676
    def _finishLogFile(self):
314
677
        """Finished with the log file.
315
678
 
316
 
        Read contents into memory, close, and delete.
 
679
        Close the file and delete it, unless setKeepLogfile was called.
317
680
        """
318
 
        bzrlib.trace.disable_test_log()
319
 
        self._log_file.seek(0)
320
 
        self._log_contents = self._log_file.read()
 
681
        if self._log_file is None:
 
682
            return
 
683
        bzrlib.trace.disable_test_log(self._log_nonce)
321
684
        self._log_file.close()
322
 
        os.remove(self._log_file_name)
323
 
        self._log_file = self._log_file_name = None
 
685
        self._log_file = None
 
686
        if not self._keep_log_file:
 
687
            os.remove(self._log_file_name)
 
688
            self._log_file_name = None
 
689
 
 
690
    def setKeepLogfile(self):
 
691
        """Make the logfile not be deleted when _finishLogFile is called."""
 
692
        self._keep_log_file = True
324
693
 
325
694
    def addCleanup(self, callable):
326
695
        """Arrange to run a callable when this case is torn down.
335
704
 
336
705
    def _cleanEnvironment(self):
337
706
        new_env = {
 
707
            'BZR_HOME': None, # Don't inherit BZR_HOME to all the tests.
338
708
            'HOME': os.getcwd(),
339
709
            'APPDATA': os.getcwd(),
340
 
            'BZREMAIL': None,
 
710
            'BZR_EMAIL': None,
 
711
            'BZREMAIL': None, # may still be present in the environment
341
712
            'EMAIL': None,
 
713
            'BZR_PROGRESS_BAR': None,
342
714
        }
343
715
        self.__old_env = {}
344
716
        self.addCleanup(self._restoreEnvironment)
345
717
        for name, value in new_env.iteritems():
346
718
            self._captureVar(name, value)
347
719
 
348
 
 
349
720
    def _captureVar(self, name, newvalue):
350
 
        """Set an environment variable, preparing it to be reset when finished."""
351
 
        self.__old_env[name] = os.environ.get(name, None)
352
 
        if newvalue is None:
353
 
            if name in os.environ:
354
 
                del os.environ[name]
355
 
        else:
356
 
            os.environ[name] = newvalue
357
 
 
358
 
    @staticmethod
359
 
    def _restoreVar(name, value):
360
 
        if value is None:
361
 
            if name in os.environ:
362
 
                del os.environ[name]
363
 
        else:
364
 
            os.environ[name] = value
 
721
        """Set an environment variable, and reset it when finished."""
 
722
        self.__old_env[name] = osutils.set_or_unset_env(name, newvalue)
365
723
 
366
724
    def _restoreEnvironment(self):
367
725
        for name, value in self.__old_env.iteritems():
368
 
            self._restoreVar(name, value)
 
726
            osutils.set_or_unset_env(name, value)
369
727
 
370
728
    def tearDown(self):
371
729
        self._runCleanups()
372
730
        unittest.TestCase.tearDown(self)
373
731
 
 
732
    def time(self, callable, *args, **kwargs):
 
733
        """Run callable and accrue the time it takes to the benchmark time.
 
734
        
 
735
        If lsprofiling is enabled (i.e. by --lsprof-time to bzr selftest) then
 
736
        this will cause lsprofile statistics to be gathered and stored in
 
737
        self._benchcalls.
 
738
        """
 
739
        if self._benchtime is None:
 
740
            self._benchtime = 0
 
741
        start = time.time()
 
742
        try:
 
743
            if not self._gather_lsprof_in_benchmarks:
 
744
                return callable(*args, **kwargs)
 
745
            else:
 
746
                # record this benchmark
 
747
                ret, stats = bzrlib.lsprof.profile(callable, *args, **kwargs)
 
748
                stats.sort()
 
749
                self._benchcalls.append(((callable, args, kwargs), stats))
 
750
                return ret
 
751
        finally:
 
752
            self._benchtime += time.time() - start
 
753
 
374
754
    def _runCleanups(self):
375
755
        """Run registered cleanup functions. 
376
756
 
384
764
    def log(self, *args):
385
765
        mutter(*args)
386
766
 
387
 
    def _get_log(self):
388
 
        """Return as a string the log for this test"""
389
 
        if self._log_file_name:
390
 
            return open(self._log_file_name).read()
391
 
        else:
 
767
    def _get_log(self, keep_log_file=False):
 
768
        """Return as a string the log for this test. If the file is still
 
769
        on disk and keep_log_file=False, delete the log file and store the
 
770
        content in self._log_contents."""
 
771
        # flush the log file, to get all content
 
772
        import bzrlib.trace
 
773
        bzrlib.trace._trace_file.flush()
 
774
        if self._log_contents:
392
775
            return self._log_contents
393
 
        # TODO: Delete the log after it's been read in
 
776
        if self._log_file_name is not None:
 
777
            logfile = open(self._log_file_name)
 
778
            try:
 
779
                log_contents = logfile.read()
 
780
            finally:
 
781
                logfile.close()
 
782
            if not keep_log_file:
 
783
                self._log_contents = log_contents
 
784
                os.remove(self._log_file_name)
 
785
            return log_contents
 
786
        else:
 
787
            return "DELETED log file to reduce memory footprint"
394
788
 
395
789
    def capture(self, cmd, retcode=0):
396
790
        """Shortcut that splits cmd into words, runs, and returns stdout"""
397
791
        return self.run_bzr_captured(cmd.split(), retcode=retcode)[0]
398
792
 
399
 
    def run_bzr_captured(self, argv, retcode=0):
 
793
    def run_bzr_captured(self, argv, retcode=0, encoding=None, stdin=None,
 
794
                         working_dir=None):
400
795
        """Invoke bzr and return (stdout, stderr).
401
796
 
402
797
        Useful for code that wants to check the contents of the
413
808
        errors, and with logging set to something approximating the
414
809
        default, so that error reporting can be checked.
415
810
 
416
 
        argv -- arguments to invoke bzr
417
 
        retcode -- expected return code, or None for don't-care.
 
811
        :param argv: arguments to invoke bzr
 
812
        :param retcode: expected return code, or None for don't-care.
 
813
        :param encoding: encoding for sys.stdout and sys.stderr
 
814
        :param stdin: A string to be used as stdin for the command.
 
815
        :param working_dir: Change to this directory before running
418
816
        """
419
 
        stdout = StringIO()
420
 
        stderr = StringIO()
421
 
        self.log('run bzr: %s', ' '.join(argv))
 
817
        if encoding is None:
 
818
            encoding = bzrlib.user_encoding
 
819
        if stdin is not None:
 
820
            stdin = StringIO(stdin)
 
821
        stdout = StringIOWrapper()
 
822
        stderr = StringIOWrapper()
 
823
        stdout.encoding = encoding
 
824
        stderr.encoding = encoding
 
825
 
 
826
        self.log('run bzr: %r', argv)
422
827
        # FIXME: don't call into logging here
423
828
        handler = logging.StreamHandler(stderr)
424
 
        handler.setFormatter(bzrlib.trace.QuietFormatter())
425
829
        handler.setLevel(logging.INFO)
426
830
        logger = logging.getLogger('')
427
831
        logger.addHandler(handler)
 
832
        old_ui_factory = bzrlib.ui.ui_factory
 
833
        bzrlib.ui.ui_factory = bzrlib.tests.blackbox.TestUIFactory(
 
834
            stdout=stdout,
 
835
            stderr=stderr)
 
836
        bzrlib.ui.ui_factory.stdin = stdin
 
837
 
 
838
        cwd = None
 
839
        if working_dir is not None:
 
840
            cwd = osutils.getcwd()
 
841
            os.chdir(working_dir)
 
842
 
428
843
        try:
429
 
            result = self.apply_redirected(None, stdout, stderr,
 
844
            result = self.apply_redirected(stdin, stdout, stderr,
430
845
                                           bzrlib.commands.run_bzr_catch_errors,
431
846
                                           argv)
432
847
        finally:
433
848
            logger.removeHandler(handler)
 
849
            bzrlib.ui.ui_factory = old_ui_factory
 
850
            if cwd is not None:
 
851
                os.chdir(cwd)
 
852
 
434
853
        out = stdout.getvalue()
435
854
        err = stderr.getvalue()
436
855
        if out:
437
 
            self.log('output:\n%s', out)
 
856
            self.log('output:\n%r', out)
438
857
        if err:
439
 
            self.log('errors:\n%s', err)
 
858
            self.log('errors:\n%r', err)
440
859
        if retcode is not None:
441
 
            self.assertEquals(result, retcode)
 
860
            self.assertEquals(retcode, result)
442
861
        return out, err
443
862
 
444
863
    def run_bzr(self, *args, **kwargs):
450
869
 
451
870
        This sends the stdout/stderr results into the test's log,
452
871
        where it may be useful for debugging.  See also run_captured.
 
872
 
 
873
        :param stdin: A string to be used as stdin for the command.
453
874
        """
454
875
        retcode = kwargs.pop('retcode', 0)
455
 
        return self.run_bzr_captured(args, retcode)
 
876
        encoding = kwargs.pop('encoding', None)
 
877
        stdin = kwargs.pop('stdin', None)
 
878
        working_dir = kwargs.pop('working_dir', None)
 
879
        return self.run_bzr_captured(args, retcode=retcode, encoding=encoding,
 
880
                                     stdin=stdin, working_dir=working_dir)
 
881
 
 
882
    def run_bzr_decode(self, *args, **kwargs):
 
883
        if 'encoding' in kwargs:
 
884
            encoding = kwargs['encoding']
 
885
        else:
 
886
            encoding = bzrlib.user_encoding
 
887
        return self.run_bzr(*args, **kwargs)[0].decode(encoding)
 
888
 
 
889
    def run_bzr_error(self, error_regexes, *args, **kwargs):
 
890
        """Run bzr, and check that stderr contains the supplied regexes
 
891
        
 
892
        :param error_regexes: Sequence of regular expressions which 
 
893
            must each be found in the error output. The relative ordering
 
894
            is not enforced.
 
895
        :param args: command-line arguments for bzr
 
896
        :param kwargs: Keyword arguments which are interpreted by run_bzr
 
897
            This function changes the default value of retcode to be 3,
 
898
            since in most cases this is run when you expect bzr to fail.
 
899
        :return: (out, err) The actual output of running the command (in case you
 
900
                 want to do more inspection)
 
901
 
 
902
        Examples of use:
 
903
            # Make sure that commit is failing because there is nothing to do
 
904
            self.run_bzr_error(['no changes to commit'],
 
905
                               'commit', '-m', 'my commit comment')
 
906
            # Make sure --strict is handling an unknown file, rather than
 
907
            # giving us the 'nothing to do' error
 
908
            self.build_tree(['unknown'])
 
909
            self.run_bzr_error(['Commit refused because there are unknown files'],
 
910
                               'commit', '--strict', '-m', 'my commit comment')
 
911
        """
 
912
        kwargs.setdefault('retcode', 3)
 
913
        out, err = self.run_bzr(*args, **kwargs)
 
914
        for regex in error_regexes:
 
915
            self.assertContainsRe(err, regex)
 
916
        return out, err
 
917
 
 
918
    def run_bzr_subprocess(self, *args, **kwargs):
 
919
        """Run bzr in a subprocess for testing.
 
920
 
 
921
        This starts a new Python interpreter and runs bzr in there. 
 
922
        This should only be used for tests that have a justifiable need for
 
923
        this isolation: e.g. they are testing startup time, or signal
 
924
        handling, or early startup code, etc.  Subprocess code can't be 
 
925
        profiled or debugged so easily.
 
926
 
 
927
        :param retcode: The status code that is expected.  Defaults to 0.  If
 
928
            None is supplied, the status code is not checked.
 
929
        :param env_changes: A dictionary which lists changes to environment
 
930
            variables. A value of None will unset the env variable.
 
931
            The values must be strings. The change will only occur in the
 
932
            child, so you don't need to fix the environment after running.
 
933
        :param universal_newlines: Convert CRLF => LF
 
934
        """
 
935
        env_changes = kwargs.get('env_changes', {})
 
936
        working_dir = kwargs.get('working_dir', None)
 
937
        process = self.start_bzr_subprocess(args, env_changes=env_changes,
 
938
                                            working_dir=working_dir)
 
939
        # We distinguish between retcode=None and retcode not passed.
 
940
        supplied_retcode = kwargs.get('retcode', 0)
 
941
        return self.finish_bzr_subprocess(process, retcode=supplied_retcode,
 
942
            universal_newlines=kwargs.get('universal_newlines', False),
 
943
            process_args=args)
 
944
 
 
945
    def start_bzr_subprocess(self, process_args, env_changes=None,
 
946
                             skip_if_plan_to_signal=False,
 
947
                             working_dir=None):
 
948
        """Start bzr in a subprocess for testing.
 
949
 
 
950
        This starts a new Python interpreter and runs bzr in there.
 
951
        This should only be used for tests that have a justifiable need for
 
952
        this isolation: e.g. they are testing startup time, or signal
 
953
        handling, or early startup code, etc.  Subprocess code can't be
 
954
        profiled or debugged so easily.
 
955
 
 
956
        :param process_args: a list of arguments to pass to the bzr executable,
 
957
            for example `['--version']`.
 
958
        :param env_changes: A dictionary which lists changes to environment
 
959
            variables. A value of None will unset the env variable.
 
960
            The values must be strings. The change will only occur in the
 
961
            child, so you don't need to fix the environment after running.
 
962
        :param skip_if_plan_to_signal: raise TestSkipped when true and os.kill
 
963
            is not available.
 
964
 
 
965
        :returns: Popen object for the started process.
 
966
        """
 
967
        if skip_if_plan_to_signal:
 
968
            if not getattr(os, 'kill', None):
 
969
                raise TestSkipped("os.kill not available.")
 
970
 
 
971
        if env_changes is None:
 
972
            env_changes = {}
 
973
        old_env = {}
 
974
 
 
975
        def cleanup_environment():
 
976
            for env_var, value in env_changes.iteritems():
 
977
                old_env[env_var] = osutils.set_or_unset_env(env_var, value)
 
978
 
 
979
        def restore_environment():
 
980
            for env_var, value in old_env.iteritems():
 
981
                osutils.set_or_unset_env(env_var, value)
 
982
 
 
983
        bzr_path = self.get_bzr_path()
 
984
 
 
985
        cwd = None
 
986
        if working_dir is not None:
 
987
            cwd = osutils.getcwd()
 
988
            os.chdir(working_dir)
 
989
 
 
990
        try:
 
991
            # win32 subprocess doesn't support preexec_fn
 
992
            # so we will avoid using it on all platforms, just to
 
993
            # make sure the code path is used, and we don't break on win32
 
994
            cleanup_environment()
 
995
            process = Popen([sys.executable, bzr_path] + list(process_args),
 
996
                             stdin=PIPE, stdout=PIPE, stderr=PIPE)
 
997
        finally:
 
998
            restore_environment()
 
999
            if cwd is not None:
 
1000
                os.chdir(cwd)
 
1001
 
 
1002
        return process
 
1003
 
 
1004
    def get_bzr_path(self):
 
1005
        """Return the path of the 'bzr' executable for this test suite."""
 
1006
        bzr_path = os.path.dirname(os.path.dirname(bzrlib.__file__))+'/bzr'
 
1007
        if not os.path.isfile(bzr_path):
 
1008
            # We are probably installed. Assume sys.argv is the right file
 
1009
            bzr_path = sys.argv[0]
 
1010
        return bzr_path
 
1011
 
 
1012
    def finish_bzr_subprocess(self, process, retcode=0, send_signal=None,
 
1013
                              universal_newlines=False, process_args=None):
 
1014
        """Finish the execution of process.
 
1015
 
 
1016
        :param process: the Popen object returned from start_bzr_subprocess.
 
1017
        :param retcode: The status code that is expected.  Defaults to 0.  If
 
1018
            None is supplied, the status code is not checked.
 
1019
        :param send_signal: an optional signal to send to the process.
 
1020
        :param universal_newlines: Convert CRLF => LF
 
1021
        :returns: (stdout, stderr)
 
1022
        """
 
1023
        if send_signal is not None:
 
1024
            os.kill(process.pid, send_signal)
 
1025
        out, err = process.communicate()
 
1026
 
 
1027
        if universal_newlines:
 
1028
            out = out.replace('\r\n', '\n')
 
1029
            err = err.replace('\r\n', '\n')
 
1030
 
 
1031
        if retcode is not None and retcode != process.returncode:
 
1032
            if process_args is None:
 
1033
                process_args = "(unknown args)"
 
1034
            mutter('Output of bzr %s:\n%s', process_args, out)
 
1035
            mutter('Error for bzr %s:\n%s', process_args, err)
 
1036
            self.fail('Command bzr %s failed with retcode %s != %s'
 
1037
                      % (process_args, retcode, process.returncode))
 
1038
        return [out, err]
456
1039
 
457
1040
    def check_inventory_shape(self, inv, shape):
458
1041
        """Compare an inventory to a list of expected names.
484
1067
        if stdin is None:
485
1068
            stdin = StringIO("")
486
1069
        if stdout is None:
487
 
            if hasattr(self, "_log_file"):
 
1070
            if getattr(self, "_log_file", None) is not None:
488
1071
                stdout = self._log_file
489
1072
            else:
490
1073
                stdout = StringIO()
491
1074
        if stderr is None:
492
 
            if hasattr(self, "_log_file"):
 
1075
            if getattr(self, "_log_file", None is not None):
493
1076
                stderr = self._log_file
494
1077
            else:
495
1078
                stderr = StringIO()
506
1089
            sys.stderr = real_stderr
507
1090
            sys.stdin = real_stdin
508
1091
 
 
1092
    @symbol_versioning.deprecated_method(symbol_versioning.zero_eleven)
 
1093
    def merge(self, branch_from, wt_to):
 
1094
        """A helper for tests to do a ui-less merge.
 
1095
 
 
1096
        This should move to the main library when someone has time to integrate
 
1097
        it in.
 
1098
        """
 
1099
        # minimal ui-less merge.
 
1100
        wt_to.branch.fetch(branch_from)
 
1101
        base_rev = common_ancestor(branch_from.last_revision(),
 
1102
                                   wt_to.branch.last_revision(),
 
1103
                                   wt_to.branch.repository)
 
1104
        merge_inner(wt_to.branch, branch_from.basis_tree(),
 
1105
                    wt_to.branch.repository.revision_tree(base_rev),
 
1106
                    this_tree=wt_to)
 
1107
        wt_to.add_parent_tree_id(branch_from.last_revision())
 
1108
 
509
1109
 
510
1110
BzrTestBase = TestCase
511
1111
 
512
 
     
513
 
class TestCaseInTempDir(TestCase):
514
 
    """Derived class that runs a test within a temporary directory.
515
 
 
516
 
    This is useful for tests that need to create a branch, etc.
517
 
 
518
 
    The directory is created in a slightly complex way: for each
519
 
    Python invocation, a new temporary top-level directory is created.
520
 
    All test cases create their own directory within that.  If the
521
 
    tests complete successfully, the directory is removed.
522
 
 
523
 
    InTempDir is an old alias for FunctionalTestCase.
 
1112
 
 
1113
class TestCaseWithMemoryTransport(TestCase):
 
1114
    """Common test class for tests that do not need disk resources.
 
1115
 
 
1116
    Tests that need disk resources should derive from TestCaseWithTransport.
 
1117
 
 
1118
    TestCaseWithMemoryTransport sets the TEST_ROOT variable for all bzr tests.
 
1119
 
 
1120
    For TestCaseWithMemoryTransport the test_home_dir is set to the name of
 
1121
    a directory which does not exist. This serves to help ensure test isolation
 
1122
    is preserved. test_dir is set to the TEST_ROOT, as is cwd, because they
 
1123
    must exist. However, TestCaseWithMemoryTransport does not offer local
 
1124
    file defaults for the transport in tests, nor does it obey the command line
 
1125
    override, so tests that accidentally write to the common directory should
 
1126
    be rare.
524
1127
    """
525
1128
 
526
1129
    TEST_ROOT = None
527
1130
    _TEST_NAME = 'test'
528
 
    OVERRIDE_PYTHON = 'python'
529
 
 
530
 
    def check_file_contents(self, filename, expect):
531
 
        self.log("check contents of file %s" % filename)
532
 
        contents = file(filename, 'r').read()
533
 
        if contents != expect:
534
 
            self.log("expected: %r" % expect)
535
 
            self.log("actually: %r" % contents)
536
 
            self.fail("contents of %s not as expected" % filename)
 
1131
 
 
1132
 
 
1133
    def __init__(self, methodName='runTest'):
 
1134
        # allow test parameterisation after test construction and before test
 
1135
        # execution. Variables that the parameteriser sets need to be 
 
1136
        # ones that are not set by setUp, or setUp will trash them.
 
1137
        super(TestCaseWithMemoryTransport, self).__init__(methodName)
 
1138
        self.transport_server = default_transport
 
1139
        self.transport_readonly_server = None
 
1140
 
 
1141
    def failUnlessExists(self, path):
 
1142
        """Fail unless path, which may be abs or relative, exists."""
 
1143
        self.failUnless(osutils.lexists(path))
 
1144
 
 
1145
    def failIfExists(self, path):
 
1146
        """Fail if path, which may be abs or relative, exists."""
 
1147
        self.failIf(osutils.lexists(path))
 
1148
        
 
1149
    def get_transport(self):
 
1150
        """Return a writeable transport for the test scratch space"""
 
1151
        t = get_transport(self.get_url())
 
1152
        self.assertFalse(t.is_readonly())
 
1153
        return t
 
1154
 
 
1155
    def get_readonly_transport(self):
 
1156
        """Return a readonly transport for the test scratch space
 
1157
        
 
1158
        This can be used to test that operations which should only need
 
1159
        readonly access in fact do not try to write.
 
1160
        """
 
1161
        t = get_transport(self.get_readonly_url())
 
1162
        self.assertTrue(t.is_readonly())
 
1163
        return t
 
1164
 
 
1165
    def get_readonly_server(self):
 
1166
        """Get the server instance for the readonly transport
 
1167
 
 
1168
        This is useful for some tests with specific servers to do diagnostics.
 
1169
        """
 
1170
        if self.__readonly_server is None:
 
1171
            if self.transport_readonly_server is None:
 
1172
                # readonly decorator requested
 
1173
                # bring up the server
 
1174
                self.get_url()
 
1175
                self.__readonly_server = ReadonlyServer()
 
1176
                self.__readonly_server.setUp(self.__server)
 
1177
            else:
 
1178
                self.__readonly_server = self.transport_readonly_server()
 
1179
                self.__readonly_server.setUp()
 
1180
            self.addCleanup(self.__readonly_server.tearDown)
 
1181
        return self.__readonly_server
 
1182
 
 
1183
    def get_readonly_url(self, relpath=None):
 
1184
        """Get a URL for the readonly transport.
 
1185
 
 
1186
        This will either be backed by '.' or a decorator to the transport 
 
1187
        used by self.get_url()
 
1188
        relpath provides for clients to get a path relative to the base url.
 
1189
        These should only be downwards relative, not upwards.
 
1190
        """
 
1191
        base = self.get_readonly_server().get_url()
 
1192
        if relpath is not None:
 
1193
            if not base.endswith('/'):
 
1194
                base = base + '/'
 
1195
            base = base + relpath
 
1196
        return base
 
1197
 
 
1198
    def get_server(self):
 
1199
        """Get the read/write server instance.
 
1200
 
 
1201
        This is useful for some tests with specific servers that need
 
1202
        diagnostics.
 
1203
 
 
1204
        For TestCaseWithMemoryTransport this is always a MemoryServer, and there
 
1205
        is no means to override it.
 
1206
        """
 
1207
        if self.__server is None:
 
1208
            self.__server = MemoryServer()
 
1209
            self.__server.setUp()
 
1210
            self.addCleanup(self.__server.tearDown)
 
1211
        return self.__server
 
1212
 
 
1213
    def get_url(self, relpath=None):
 
1214
        """Get a URL (or maybe a path) for the readwrite transport.
 
1215
 
 
1216
        This will either be backed by '.' or to an equivalent non-file based
 
1217
        facility.
 
1218
        relpath provides for clients to get a path relative to the base url.
 
1219
        These should only be downwards relative, not upwards.
 
1220
        """
 
1221
        base = self.get_server().get_url()
 
1222
        if relpath is not None and relpath != '.':
 
1223
            if not base.endswith('/'):
 
1224
                base = base + '/'
 
1225
            # XXX: Really base should be a url; we did after all call
 
1226
            # get_url()!  But sometimes it's just a path (from
 
1227
            # LocalAbspathServer), and it'd be wrong to append urlescaped data
 
1228
            # to a non-escaped local path.
 
1229
            if base.startswith('./') or base.startswith('/'):
 
1230
                base += relpath
 
1231
            else:
 
1232
                base += urlutils.escape(relpath)
 
1233
        return base
537
1234
 
538
1235
    def _make_test_root(self):
539
 
        if TestCaseInTempDir.TEST_ROOT is not None:
 
1236
        if TestCaseWithMemoryTransport.TEST_ROOT is not None:
540
1237
            return
541
1238
        i = 0
542
1239
        while True:
550
1247
                else:
551
1248
                    raise
552
1249
            # successfully created
553
 
            TestCaseInTempDir.TEST_ROOT = osutils.abspath(root)
 
1250
            TestCaseWithMemoryTransport.TEST_ROOT = osutils.abspath(root)
554
1251
            break
555
1252
        # make a fake bzr directory there to prevent any tests propagating
556
1253
        # up onto the source directory's real branch
557
 
        os.mkdir(osutils.pathjoin(TestCaseInTempDir.TEST_ROOT, '.bzr'))
558
 
 
 
1254
        bzrdir.BzrDir.create_standalone_workingtree(
 
1255
            TestCaseWithMemoryTransport.TEST_ROOT)
 
1256
 
 
1257
    def makeAndChdirToTestDir(self):
 
1258
        """Create a temporary directories for this one test.
 
1259
        
 
1260
        This must set self.test_home_dir and self.test_dir and chdir to
 
1261
        self.test_dir.
 
1262
        
 
1263
        For TestCaseWithMemoryTransport we chdir to the TEST_ROOT for this test.
 
1264
        """
 
1265
        os.chdir(TestCaseWithMemoryTransport.TEST_ROOT)
 
1266
        self.test_dir = TestCaseWithMemoryTransport.TEST_ROOT
 
1267
        self.test_home_dir = self.test_dir + "/MemoryTransportMissingHomeDir"
 
1268
        
 
1269
    def make_branch(self, relpath, format=None):
 
1270
        """Create a branch on the transport at relpath."""
 
1271
        repo = self.make_repository(relpath, format=format)
 
1272
        return repo.bzrdir.create_branch()
 
1273
 
 
1274
    def make_bzrdir(self, relpath, format=None):
 
1275
        try:
 
1276
            # might be a relative or absolute path
 
1277
            maybe_a_url = self.get_url(relpath)
 
1278
            segments = maybe_a_url.rsplit('/', 1)
 
1279
            t = get_transport(maybe_a_url)
 
1280
            if len(segments) > 1 and segments[-1] not in ('', '.'):
 
1281
                try:
 
1282
                    t.mkdir('.')
 
1283
                except errors.FileExists:
 
1284
                    pass
 
1285
            if format is None:
 
1286
                format = bzrlib.bzrdir.BzrDirFormat.get_default_format()
 
1287
            return format.initialize_on_transport(t)
 
1288
        except errors.UninitializableFormat:
 
1289
            raise TestSkipped("Format %s is not initializable." % format)
 
1290
 
 
1291
    def make_repository(self, relpath, shared=False, format=None):
 
1292
        """Create a repository on our default transport at relpath."""
 
1293
        made_control = self.make_bzrdir(relpath, format=format)
 
1294
        return made_control.create_repository(shared=shared)
 
1295
 
 
1296
    def make_branch_and_memory_tree(self, relpath):
 
1297
        """Create a branch on the default transport and a MemoryTree for it."""
 
1298
        b = self.make_branch(relpath)
 
1299
        return memorytree.MemoryTree.create_on_branch(b)
 
1300
 
 
1301
    def overrideEnvironmentForTesting(self):
 
1302
        os.environ['HOME'] = self.test_home_dir
 
1303
        os.environ['APPDATA'] = self.test_home_dir
 
1304
        
559
1305
    def setUp(self):
560
 
        super(TestCaseInTempDir, self).setUp()
 
1306
        super(TestCaseWithMemoryTransport, self).setUp()
561
1307
        self._make_test_root()
562
1308
        _currentdir = os.getcwdu()
563
 
        short_id = self.id().replace('bzrlib.tests.', '') \
564
 
                   .replace('__main__.', '')
565
 
        self.test_dir = osutils.pathjoin(self.TEST_ROOT, short_id)
566
 
        os.mkdir(self.test_dir)
567
 
        os.chdir(self.test_dir)
568
 
        os.environ['HOME'] = self.test_dir
569
 
        os.environ['APPDATA'] = self.test_dir
570
1309
        def _leaveDirectory():
571
1310
            os.chdir(_currentdir)
572
1311
        self.addCleanup(_leaveDirectory)
 
1312
        self.makeAndChdirToTestDir()
 
1313
        self.overrideEnvironmentForTesting()
 
1314
        self.__readonly_server = None
 
1315
        self.__server = None
 
1316
 
 
1317
     
 
1318
class TestCaseInTempDir(TestCaseWithMemoryTransport):
 
1319
    """Derived class that runs a test within a temporary directory.
 
1320
 
 
1321
    This is useful for tests that need to create a branch, etc.
 
1322
 
 
1323
    The directory is created in a slightly complex way: for each
 
1324
    Python invocation, a new temporary top-level directory is created.
 
1325
    All test cases create their own directory within that.  If the
 
1326
    tests complete successfully, the directory is removed.
 
1327
 
 
1328
    InTempDir is an old alias for FunctionalTestCase.
 
1329
    """
 
1330
 
 
1331
    OVERRIDE_PYTHON = 'python'
 
1332
 
 
1333
    def check_file_contents(self, filename, expect):
 
1334
        self.log("check contents of file %s" % filename)
 
1335
        contents = file(filename, 'r').read()
 
1336
        if contents != expect:
 
1337
            self.log("expected: %r" % expect)
 
1338
            self.log("actually: %r" % contents)
 
1339
            self.fail("contents of %s not as expected" % filename)
 
1340
 
 
1341
    def makeAndChdirToTestDir(self):
 
1342
        """See TestCaseWithMemoryTransport.makeAndChdirToTestDir().
573
1343
        
 
1344
        For TestCaseInTempDir we create a temporary directory based on the test
 
1345
        name and then create two subdirs - test and home under it.
 
1346
        """
 
1347
        # shorten the name, to avoid test failures due to path length
 
1348
        short_id = self.id().replace('bzrlib.tests.', '') \
 
1349
                   .replace('__main__.', '')[-100:]
 
1350
        # it's possible the same test class is run several times for
 
1351
        # parameterized tests, so make sure the names don't collide.  
 
1352
        i = 0
 
1353
        while True:
 
1354
            if i > 0:
 
1355
                candidate_dir = '%s/%s.%d' % (self.TEST_ROOT, short_id, i)
 
1356
            else:
 
1357
                candidate_dir = '%s/%s' % (self.TEST_ROOT, short_id)
 
1358
            if os.path.exists(candidate_dir):
 
1359
                i = i + 1
 
1360
                continue
 
1361
            else:
 
1362
                os.mkdir(candidate_dir)
 
1363
                self.test_home_dir = candidate_dir + '/home'
 
1364
                os.mkdir(self.test_home_dir)
 
1365
                self.test_dir = candidate_dir + '/work'
 
1366
                os.mkdir(self.test_dir)
 
1367
                os.chdir(self.test_dir)
 
1368
                break
 
1369
 
574
1370
    def build_tree(self, shape, line_endings='native', transport=None):
575
1371
        """Build a test tree according to a pattern.
576
1372
 
577
1373
        shape is a sequence of file specifications.  If the final
578
1374
        character is '/', a directory is created.
579
1375
 
 
1376
        This assumes that all the elements in the tree being built are new.
 
1377
 
580
1378
        This doesn't add anything to a branch.
581
1379
        :param line_endings: Either 'binary' or 'native'
582
1380
                             in binary mode, exact contents are written
587
1385
                          VFS's. If the transport is readonly or None,
588
1386
                          "." is opened automatically.
589
1387
        """
590
 
        # XXX: It's OK to just create them using forward slashes on windows?
 
1388
        # It's OK to just create them using forward slashes on windows.
591
1389
        if transport is None or transport.is_readonly():
592
 
            transport = bzrlib.transport.get_transport(".")
 
1390
            transport = get_transport(".")
593
1391
        for name in shape:
594
1392
            self.assert_(isinstance(name, basestring))
595
1393
            if name[-1] == '/':
596
 
                transport.mkdir(urlescape(name[:-1]))
 
1394
                transport.mkdir(urlutils.escape(name[:-1]))
597
1395
            else:
598
1396
                if line_endings == 'binary':
599
1397
                    end = '\n'
600
1398
                elif line_endings == 'native':
601
1399
                    end = os.linesep
602
1400
                else:
603
 
                    raise BzrError('Invalid line ending request %r' % (line_endings,))
604
 
                content = "contents of %s%s" % (name, end)
605
 
                transport.put(urlescape(name), StringIO(content))
 
1401
                    raise errors.BzrError('Invalid line ending request %r' % (line_endings,))
 
1402
                content = "contents of %s%s" % (name.encode('utf-8'), end)
 
1403
                # Technically 'put()' is the right command. However, put
 
1404
                # uses an AtomicFile, which requires an extra rename into place
 
1405
                # As long as the files didn't exist in the past, append() will
 
1406
                # do the same thing as put()
 
1407
                # On jam's machine, make_kernel_like_tree is:
 
1408
                #   put:    4.5-7.5s (averaging 6s)
 
1409
                #   append: 2.9-4.5s
 
1410
                #   put_non_atomic: 2.9-4.5s
 
1411
                transport.put_bytes_non_atomic(urlutils.escape(name), content)
606
1412
 
607
1413
    def build_tree_contents(self, shape):
608
1414
        build_tree_contents(shape)
609
1415
 
610
 
    def failUnlessExists(self, path):
611
 
        """Fail unless path, which may be abs or relative, exists."""
612
 
        self.failUnless(osutils.lexists(path))
613
 
 
614
 
    def failIfExists(self, path):
615
 
        """Fail if path, which may be abs or relative, exists."""
616
 
        self.failIf(osutils.lexists(path))
617
 
        
618
1416
    def assertFileEqual(self, content, path):
619
1417
        """Fail if path does not contain 'content'."""
620
1418
        self.failUnless(osutils.lexists(path))
 
1419
        # TODO: jam 20060427 Shouldn't this be 'rb'?
621
1420
        self.assertEqualDiff(content, open(path, 'r').read())
622
1421
 
623
1422
 
 
1423
class TestCaseWithTransport(TestCaseInTempDir):
 
1424
    """A test case that provides get_url and get_readonly_url facilities.
 
1425
 
 
1426
    These back onto two transport servers, one for readonly access and one for
 
1427
    read write access.
 
1428
 
 
1429
    If no explicit class is provided for readonly access, a
 
1430
    ReadonlyTransportDecorator is used instead which allows the use of non disk
 
1431
    based read write transports.
 
1432
 
 
1433
    If an explicit class is provided for readonly access, that server and the 
 
1434
    readwrite one must both define get_url() as resolving to os.getcwd().
 
1435
    """
 
1436
 
 
1437
    def get_server(self):
 
1438
        """See TestCaseWithMemoryTransport.
 
1439
 
 
1440
        This is useful for some tests with specific servers that need
 
1441
        diagnostics.
 
1442
        """
 
1443
        if self.__server is None:
 
1444
            self.__server = self.transport_server()
 
1445
            self.__server.setUp()
 
1446
            self.addCleanup(self.__server.tearDown)
 
1447
        return self.__server
 
1448
 
 
1449
    def make_branch_and_tree(self, relpath, format=None):
 
1450
        """Create a branch on the transport and a tree locally.
 
1451
 
 
1452
        If the transport is not a LocalTransport, the Tree can't be created on
 
1453
        the transport.  In that case the working tree is created in the local
 
1454
        directory, and the returned tree's branch and repository will also be
 
1455
        accessed locally.
 
1456
 
 
1457
        This will fail if the original default transport for this test
 
1458
        case wasn't backed by the working directory, as the branch won't
 
1459
        be on disk for us to open it.  
 
1460
 
 
1461
        :param format: The BzrDirFormat.
 
1462
        :returns: the WorkingTree.
 
1463
        """
 
1464
        # TODO: always use the local disk path for the working tree,
 
1465
        # this obviously requires a format that supports branch references
 
1466
        # so check for that by checking bzrdir.BzrDirFormat.get_default_format()
 
1467
        # RBC 20060208
 
1468
        b = self.make_branch(relpath, format=format)
 
1469
        try:
 
1470
            return b.bzrdir.create_workingtree()
 
1471
        except errors.NotLocalUrl:
 
1472
            # We can only make working trees locally at the moment.  If the
 
1473
            # transport can't support them, then reopen the branch on a local
 
1474
            # transport, and create the working tree there.  
 
1475
            #
 
1476
            # Possibly we should instead keep
 
1477
            # the non-disk-backed branch and create a local checkout?
 
1478
            bd = bzrdir.BzrDir.open(relpath)
 
1479
            return bd.create_workingtree()
 
1480
 
 
1481
    def assertIsDirectory(self, relpath, transport):
 
1482
        """Assert that relpath within transport is a directory.
 
1483
 
 
1484
        This may not be possible on all transports; in that case it propagates
 
1485
        a TransportNotPossible.
 
1486
        """
 
1487
        try:
 
1488
            mode = transport.stat(relpath).st_mode
 
1489
        except errors.NoSuchFile:
 
1490
            self.fail("path %s is not a directory; no such file"
 
1491
                      % (relpath))
 
1492
        if not stat.S_ISDIR(mode):
 
1493
            self.fail("path %s is not a directory; has mode %#o"
 
1494
                      % (relpath, mode))
 
1495
 
 
1496
    def setUp(self):
 
1497
        super(TestCaseWithTransport, self).setUp()
 
1498
        self.__server = None
 
1499
        self.transport_server = default_transport
 
1500
 
 
1501
 
 
1502
class ChrootedTestCase(TestCaseWithTransport):
 
1503
    """A support class that provides readonly urls outside the local namespace.
 
1504
 
 
1505
    This is done by checking if self.transport_server is a MemoryServer. if it
 
1506
    is then we are chrooted already, if it is not then an HttpServer is used
 
1507
    for readonly urls.
 
1508
 
 
1509
    TODO RBC 20060127: make this an option to TestCaseWithTransport so it can
 
1510
                       be used without needed to redo it when a different 
 
1511
                       subclass is in use ?
 
1512
    """
 
1513
 
 
1514
    def setUp(self):
 
1515
        super(ChrootedTestCase, self).setUp()
 
1516
        if not self.transport_server == bzrlib.transport.memory.MemoryServer:
 
1517
            self.transport_readonly_server = bzrlib.transport.http.HttpServer
 
1518
 
 
1519
 
624
1520
def filter_suite_by_re(suite, pattern):
625
 
    result = TestSuite()
 
1521
    result = TestUtil.TestSuite()
626
1522
    filter_re = re.compile(pattern)
627
1523
    for test in iter_suite_tests(suite):
628
1524
        if filter_re.search(test.id()):
631
1527
 
632
1528
 
633
1529
def run_suite(suite, name='test', verbose=False, pattern=".*",
634
 
              stop_on_failure=False, keep_output=False):
635
 
    TestCaseInTempDir._TEST_NAME = name
 
1530
              stop_on_failure=False, keep_output=False,
 
1531
              transport=None, lsprof_timed=None, bench_history=None):
 
1532
    TestCase._gather_lsprof_in_benchmarks = lsprof_timed
636
1533
    if verbose:
637
1534
        verbosity = 2
 
1535
        pb = None
638
1536
    else:
639
1537
        verbosity = 1
 
1538
        pb = progress.ProgressBar()
640
1539
    runner = TextTestRunner(stream=sys.stdout,
641
1540
                            descriptions=0,
642
 
                            verbosity=verbosity)
 
1541
                            verbosity=verbosity,
 
1542
                            keep_output=keep_output,
 
1543
                            pb=pb,
 
1544
                            bench_history=bench_history)
643
1545
    runner.stop_on_failure=stop_on_failure
644
1546
    if pattern != '.*':
645
1547
        suite = filter_suite_by_re(suite, pattern)
646
1548
    result = runner.run(suite)
647
 
    # This is still a little bogus, 
648
 
    # but only a little. Folk not using our testrunner will
649
 
    # have to delete their temp directories themselves.
650
 
    if result.wasSuccessful() or not keep_output:
651
 
        if TestCaseInTempDir.TEST_ROOT is not None:
652
 
            shutil.rmtree(TestCaseInTempDir.TEST_ROOT) 
653
 
    else:
654
 
        print "Failed tests working directories are in '%s'\n" % TestCaseInTempDir.TEST_ROOT
655
1549
    return result.wasSuccessful()
656
1550
 
657
1551
 
658
1552
def selftest(verbose=False, pattern=".*", stop_on_failure=True,
659
 
             keep_output=False):
 
1553
             keep_output=False,
 
1554
             transport=None,
 
1555
             test_suite_factory=None,
 
1556
             lsprof_timed=None,
 
1557
             bench_history=None):
660
1558
    """Run the whole test suite under the enhanced runner"""
661
 
    return run_suite(test_suite(), 'testbzr', verbose=verbose, pattern=pattern,
662
 
                     stop_on_failure=stop_on_failure, keep_output=keep_output)
 
1559
    # XXX: Very ugly way to do this...
 
1560
    # Disable warning about old formats because we don't want it to disturb
 
1561
    # any blackbox tests.
 
1562
    from bzrlib import repository
 
1563
    repository._deprecation_warning_done = True
 
1564
 
 
1565
    global default_transport
 
1566
    if transport is None:
 
1567
        transport = default_transport
 
1568
    old_transport = default_transport
 
1569
    default_transport = transport
 
1570
    try:
 
1571
        if test_suite_factory is None:
 
1572
            suite = test_suite()
 
1573
        else:
 
1574
            suite = test_suite_factory()
 
1575
        return run_suite(suite, 'testbzr', verbose=verbose, pattern=pattern,
 
1576
                     stop_on_failure=stop_on_failure, keep_output=keep_output,
 
1577
                     transport=transport,
 
1578
                     lsprof_timed=lsprof_timed,
 
1579
                     bench_history=bench_history)
 
1580
    finally:
 
1581
        default_transport = old_transport
663
1582
 
664
1583
 
665
1584
def test_suite():
666
 
    """Build and return TestSuite for the whole program."""
667
 
    from doctest import DocTestSuite
668
 
 
669
 
    global MODULES_TO_DOCTEST
670
 
 
671
 
    testmod_names = [ \
 
1585
    """Build and return TestSuite for the whole of bzrlib.
 
1586
    
 
1587
    This function can be replaced if you need to change the default test
 
1588
    suite on a global basis, but it is not encouraged.
 
1589
    """
 
1590
    testmod_names = [
672
1591
                   'bzrlib.tests.test_ancestry',
673
 
                   'bzrlib.tests.test_annotate',
674
1592
                   'bzrlib.tests.test_api',
 
1593
                   'bzrlib.tests.test_atomicfile',
675
1594
                   'bzrlib.tests.test_bad_files',
676
 
                   'bzrlib.tests.test_basis_inventory',
677
1595
                   'bzrlib.tests.test_branch',
 
1596
                   'bzrlib.tests.test_bundle',
 
1597
                   'bzrlib.tests.test_bzrdir',
 
1598
                   'bzrlib.tests.test_cache_utf8',
678
1599
                   'bzrlib.tests.test_command',
679
1600
                   'bzrlib.tests.test_commit',
680
1601
                   'bzrlib.tests.test_commit_merge',
681
1602
                   'bzrlib.tests.test_config',
682
1603
                   'bzrlib.tests.test_conflicts',
 
1604
                   'bzrlib.tests.test_decorators',
683
1605
                   'bzrlib.tests.test_diff',
684
 
                   'bzrlib.tests.test_decorators',
 
1606
                   'bzrlib.tests.test_doc_generate',
 
1607
                   'bzrlib.tests.test_errors',
 
1608
                   'bzrlib.tests.test_escaped_store',
685
1609
                   'bzrlib.tests.test_fetch',
686
 
                   'bzrlib.tests.test_fileid_involved',
 
1610
                   'bzrlib.tests.test_ftp_transport',
687
1611
                   'bzrlib.tests.test_gpg',
688
1612
                   'bzrlib.tests.test_graph',
689
1613
                   'bzrlib.tests.test_hashcache',
690
1614
                   'bzrlib.tests.test_http',
 
1615
                   'bzrlib.tests.test_http_response',
691
1616
                   'bzrlib.tests.test_identitymap',
 
1617
                   'bzrlib.tests.test_ignores',
692
1618
                   'bzrlib.tests.test_inv',
 
1619
                   'bzrlib.tests.test_knit',
 
1620
                   'bzrlib.tests.test_lazy_import',
 
1621
                   'bzrlib.tests.test_lockdir',
693
1622
                   'bzrlib.tests.test_lockable_files',
694
1623
                   'bzrlib.tests.test_log',
 
1624
                   'bzrlib.tests.test_memorytree',
695
1625
                   'bzrlib.tests.test_merge',
696
1626
                   'bzrlib.tests.test_merge3',
697
1627
                   'bzrlib.tests.test_merge_core',
700
1630
                   'bzrlib.tests.test_nonascii',
701
1631
                   'bzrlib.tests.test_options',
702
1632
                   'bzrlib.tests.test_osutils',
703
 
                   'bzrlib.tests.test_parent',
 
1633
                   'bzrlib.tests.test_patch',
 
1634
                   'bzrlib.tests.test_patches',
704
1635
                   'bzrlib.tests.test_permissions',
705
1636
                   'bzrlib.tests.test_plugins',
706
 
                   'bzrlib.tests.test_remove',
 
1637
                   'bzrlib.tests.test_progress',
 
1638
                   'bzrlib.tests.test_reconcile',
 
1639
                   'bzrlib.tests.test_repository',
 
1640
                   'bzrlib.tests.test_revert',
707
1641
                   'bzrlib.tests.test_revision',
708
1642
                   'bzrlib.tests.test_revisionnamespaces',
709
 
                   'bzrlib.tests.test_revprops',
710
 
                   'bzrlib.tests.test_reweave',
 
1643
                   'bzrlib.tests.test_revisiontree',
711
1644
                   'bzrlib.tests.test_rio',
712
1645
                   'bzrlib.tests.test_sampler',
713
1646
                   'bzrlib.tests.test_selftest',
714
1647
                   'bzrlib.tests.test_setup',
715
1648
                   'bzrlib.tests.test_sftp_transport',
716
1649
                   'bzrlib.tests.test_smart_add',
 
1650
                   'bzrlib.tests.test_smart_transport',
717
1651
                   'bzrlib.tests.test_source',
718
1652
                   'bzrlib.tests.test_status',
719
1653
                   'bzrlib.tests.test_store',
720
1654
                   'bzrlib.tests.test_symbol_versioning',
721
1655
                   'bzrlib.tests.test_testament',
 
1656
                   'bzrlib.tests.test_textfile',
 
1657
                   'bzrlib.tests.test_textmerge',
722
1658
                   'bzrlib.tests.test_trace',
723
1659
                   'bzrlib.tests.test_transactions',
 
1660
                   'bzrlib.tests.test_transform',
724
1661
                   'bzrlib.tests.test_transport',
 
1662
                   'bzrlib.tests.test_tree',
 
1663
                   'bzrlib.tests.test_treebuilder',
725
1664
                   'bzrlib.tests.test_tsort',
 
1665
                   'bzrlib.tests.test_tuned_gzip',
726
1666
                   'bzrlib.tests.test_ui',
727
 
                   'bzrlib.tests.test_uncommit',
728
1667
                   'bzrlib.tests.test_upgrade',
 
1668
                   'bzrlib.tests.test_urlutils',
 
1669
                   'bzrlib.tests.test_versionedfile',
 
1670
                   'bzrlib.tests.test_version',
 
1671
                   'bzrlib.tests.test_version_info',
729
1672
                   'bzrlib.tests.test_weave',
730
1673
                   'bzrlib.tests.test_whitebox',
731
1674
                   'bzrlib.tests.test_workingtree',
732
1675
                   'bzrlib.tests.test_xml',
733
1676
                   ]
734
1677
    test_transport_implementations = [
735
 
        'bzrlib.tests.test_transport_implementations']
736
 
 
737
 
    TestCase.BZRPATH = osutils.pathjoin(
738
 
            osutils.realpath(osutils.dirname(bzrlib.__path__[0])), 'bzr')
739
 
    print '%10s: %s' % ('bzr', osutils.realpath(sys.argv[0]))
740
 
    print '%10s: %s' % ('bzrlib', bzrlib.__path__[0])
741
 
    print
742
 
    suite = TestSuite()
743
 
    # python2.4's TestLoader.loadTestsFromNames gives very poor 
744
 
    # errors if it fails to load a named module - no indication of what's
745
 
    # actually wrong, just "no such module".  We should probably override that
746
 
    # class, but for the moment just load them ourselves. (mbp 20051202)
747
 
    loader = TestLoader()
 
1678
        'bzrlib.tests.test_transport_implementations',
 
1679
        'bzrlib.tests.test_read_bundle',
 
1680
        ]
 
1681
    suite = TestUtil.TestSuite()
 
1682
    loader = TestUtil.TestLoader()
 
1683
    suite.addTest(loader.loadTestsFromModuleNames(testmod_names))
748
1684
    from bzrlib.transport import TransportTestProviderAdapter
749
1685
    adapter = TransportTestProviderAdapter()
750
 
    for mod_name in test_transport_implementations:
751
 
        mod = _load_module_by_name(mod_name)
752
 
        for test in iter_suite_tests(loader.loadTestsFromModule(mod)):
753
 
            suite.addTests(adapter.adapt(test))
754
 
    for mod_name in testmod_names:
755
 
        mod = _load_module_by_name(mod_name)
756
 
        suite.addTest(loader.loadTestsFromModule(mod))
 
1686
    adapt_modules(test_transport_implementations, adapter, loader, suite)
757
1687
    for package in packages_to_test():
758
1688
        suite.addTest(package.test_suite())
759
1689
    for m in MODULES_TO_TEST:
760
1690
        suite.addTest(loader.loadTestsFromModule(m))
761
 
    for m in (MODULES_TO_DOCTEST):
762
 
        suite.addTest(DocTestSuite(m))
 
1691
    for m in MODULES_TO_DOCTEST:
 
1692
        suite.addTest(doctest.DocTestSuite(m))
763
1693
    for name, plugin in bzrlib.plugin.all_plugins().items():
764
 
        if hasattr(plugin, 'test_suite'):
 
1694
        if getattr(plugin, 'test_suite', None) is not None:
765
1695
            suite.addTest(plugin.test_suite())
766
1696
    return suite
767
1697
 
768
1698
 
769
 
def _load_module_by_name(mod_name):
770
 
    parts = mod_name.split('.')
771
 
    module = __import__(mod_name)
772
 
    del parts[0]
773
 
    # for historical reasons python returns the top-level module even though
774
 
    # it loads the submodule; we need to walk down to get the one we want.
775
 
    while parts:
776
 
        module = getattr(module, parts.pop(0))
777
 
    return module
 
1699
def adapt_modules(mods_list, adapter, loader, suite):
 
1700
    """Adapt the modules in mods_list using adapter and add to suite."""
 
1701
    for test in iter_suite_tests(loader.loadTestsFromModuleNames(mods_list)):
 
1702
        suite.addTests(adapter.adapt(test))