~bzr-pqm/bzr/bzr.dev

« back to all changes in this revision

Viewing changes to bzrlib/tests/__init__.py

  • Committer: v.ladeuil+lp at free
  • Date: 2006-10-23 11:04:46 UTC
  • mto: (2145.1.1 keepalive)
  • mto: This revision was merged to the branch mainline in revision 2146.
  • Revision ID: v.ladeuil+lp@free.fr-20061023110446-1fddf0ae083c0c1d
Cosmetic fix for bug #57644.

* bzrlib/transport/http/_pycurl.py:
(PyCurlTransport._raise_curl_http_error): Mention url in aerror
message.

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