/brz/remove-bazaar

To get this branch, use:
bzr branch http://gegoxaren.bato24.eu/bzr/brz/remove-bazaar

« back to all changes in this revision

Viewing changes to bzrlib/tests/__init__.py

Merge bzr.dev.

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
1
# Copyright (C) 2005, 2006 by Canonical Ltd
2
 
 
 
2
#
3
3
# This program is free software; you can redistribute it and/or modify
4
4
# it under the terms of the GNU General Public License as published by
5
5
# the Free Software Foundation; either version 2 of the License, or
6
6
# (at your option) any later version.
7
 
 
 
7
#
8
8
# This program is distributed in the hope that it will be useful,
9
9
# but WITHOUT ANY WARRANTY; without even the implied warranty of
10
10
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
11
11
# GNU General Public License for more details.
12
 
 
 
12
#
13
13
# You should have received a copy of the GNU General Public License
14
14
# along with this program; if not, write to the Free Software
15
15
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
29
29
import codecs
30
30
from cStringIO import StringIO
31
31
import difflib
 
32
import doctest
32
33
import errno
33
34
import logging
34
35
import os
35
36
import re
36
 
import shutil
 
37
import shlex
37
38
import stat
 
39
from subprocess import Popen, PIPE
38
40
import sys
39
41
import tempfile
40
42
import unittest
44
46
import bzrlib.branch
45
47
import bzrlib.bzrdir as bzrdir
46
48
import bzrlib.commands
 
49
import bzrlib.bundle.serializer
47
50
import bzrlib.errors as errors
48
51
import bzrlib.inventory
49
52
import bzrlib.iterablefile
50
53
import bzrlib.lockdir
 
54
try:
 
55
    import bzrlib.lsprof
 
56
except ImportError:
 
57
    # lsprof not available
 
58
    pass
51
59
from bzrlib.merge import merge_inner
52
60
import bzrlib.merge3
53
61
import bzrlib.osutils
54
62
import bzrlib.osutils as osutils
55
63
import bzrlib.plugin
 
64
import bzrlib.progress as progress
56
65
from bzrlib.revision import common_ancestor
 
66
from bzrlib.revisionspec import RevisionSpec
57
67
import bzrlib.store
 
68
from bzrlib import symbol_versioning
58
69
import bzrlib.trace
59
 
from bzrlib.transport import urlescape, get_transport
 
70
from bzrlib.transport import get_transport
60
71
import bzrlib.transport
61
72
from bzrlib.transport.local import LocalRelpathServer
62
73
from bzrlib.transport.readonly import ReadonlyServer
63
74
from bzrlib.trace import mutter
64
 
from bzrlib.tests.TestUtil import TestLoader, TestSuite
 
75
from bzrlib.tests import TestUtil
 
76
from bzrlib.tests.TestUtil import (
 
77
                          TestSuite,
 
78
                          TestLoader,
 
79
                          )
65
80
from bzrlib.tests.treeshape import build_tree_contents
 
81
import bzrlib.urlutils as urlutils
66
82
from bzrlib.workingtree import WorkingTree, WorkingTreeFormat2
67
83
 
68
84
default_transport = LocalRelpathServer
70
86
MODULES_TO_TEST = []
71
87
MODULES_TO_DOCTEST = [
72
88
                      bzrlib.branch,
 
89
                      bzrlib.bundle.serializer,
73
90
                      bzrlib.commands,
74
91
                      bzrlib.errors,
75
92
                      bzrlib.inventory,
80
97
                      bzrlib.osutils,
81
98
                      bzrlib.store
82
99
                      ]
 
100
 
 
101
 
83
102
def packages_to_test():
84
103
    """Return a list of packages to test.
85
104
 
92
111
    import bzrlib.tests.bzrdir_implementations
93
112
    import bzrlib.tests.interrepository_implementations
94
113
    import bzrlib.tests.interversionedfile_implementations
 
114
    import bzrlib.tests.intertree_implementations
95
115
    import bzrlib.tests.repository_implementations
96
116
    import bzrlib.tests.revisionstore_implementations
 
117
    import bzrlib.tests.tree_implementations
97
118
    import bzrlib.tests.workingtree_implementations
98
119
    return [
99
120
            bzrlib.doc,
102
123
            bzrlib.tests.bzrdir_implementations,
103
124
            bzrlib.tests.interrepository_implementations,
104
125
            bzrlib.tests.interversionedfile_implementations,
 
126
            bzrlib.tests.intertree_implementations,
105
127
            bzrlib.tests.repository_implementations,
106
128
            bzrlib.tests.revisionstore_implementations,
 
129
            bzrlib.tests.tree_implementations,
107
130
            bzrlib.tests.workingtree_implementations,
108
131
            ]
109
132
 
114
137
    Shows output in a different format, including displaying runtime for tests.
115
138
    """
116
139
    stop_early = False
117
 
 
118
 
    def _elapsedTime(self):
119
 
        return "%5dms" % (1000 * (time.time() - self._start_time))
 
140
    
 
141
    def __init__(self, stream, descriptions, verbosity, pb=None,
 
142
                 bench_history=None):
 
143
        """Construct new TestResult.
 
144
 
 
145
        :param bench_history: Optionally, a writable file object to accumulate
 
146
            benchmark results.
 
147
        """
 
148
        unittest._TextTestResult.__init__(self, stream, descriptions, verbosity)
 
149
        self.pb = pb
 
150
        if bench_history is not None:
 
151
            from bzrlib.version import _get_bzr_source_tree
 
152
            src_tree = _get_bzr_source_tree()
 
153
            if src_tree:
 
154
                revision_id = src_tree.last_revision()
 
155
            else:
 
156
                # XXX: If there's no branch, what should we do?
 
157
                revision_id = ''
 
158
            bench_history.write("--date %s %s\n" % (time.time(), revision_id))
 
159
        self._bench_history = bench_history
 
160
    
 
161
    def extractBenchmarkTime(self, testCase):
 
162
        """Add a benchmark time for the current test case."""
 
163
        self._benchmarkTime = getattr(testCase, "_benchtime", None)
 
164
    
 
165
    def _elapsedTestTimeString(self):
 
166
        """Return a time string for the overall time the current test has taken."""
 
167
        return self._formatTime(time.time() - self._start_time)
 
168
 
 
169
    def _testTimeString(self):
 
170
        if self._benchmarkTime is not None:
 
171
            return "%s/%s" % (
 
172
                self._formatTime(self._benchmarkTime),
 
173
                self._elapsedTestTimeString())
 
174
        else:
 
175
            return "      %s" % self._elapsedTestTimeString()
 
176
 
 
177
    def _formatTime(self, seconds):
 
178
        """Format seconds as milliseconds with leading spaces."""
 
179
        return "%5dms" % (1000 * seconds)
 
180
 
 
181
    def _ellipsise_unimportant_words(self, a_string, final_width,
 
182
                                   keep_start=False):
 
183
        """Add ellipses (sp?) for overly long strings.
 
184
        
 
185
        :param keep_start: If true preserve the start of a_string rather
 
186
                           than the end of it.
 
187
        """
 
188
        if keep_start:
 
189
            if len(a_string) > final_width:
 
190
                result = a_string[:final_width-3] + '...'
 
191
            else:
 
192
                result = a_string
 
193
        else:
 
194
            if len(a_string) > final_width:
 
195
                result = '...' + a_string[3-final_width:]
 
196
            else:
 
197
                result = a_string
 
198
        return result.ljust(final_width)
120
199
 
121
200
    def startTest(self, test):
122
201
        unittest.TestResult.startTest(self, test)
124
203
        # the beginning, but in an id, the important words are
125
204
        # at the end
126
205
        SHOW_DESCRIPTIONS = False
 
206
 
 
207
        if not self.showAll and self.dots and self.pb is not None:
 
208
            final_width = 13
 
209
        else:
 
210
            final_width = osutils.terminal_width()
 
211
            final_width = final_width - 15 - 8
 
212
        what = None
 
213
        if SHOW_DESCRIPTIONS:
 
214
            what = test.shortDescription()
 
215
            if what:
 
216
                what = self._ellipsise_unimportant_words(what, final_width, keep_start=True)
 
217
        if what is None:
 
218
            what = test.id()
 
219
            if what.startswith('bzrlib.tests.'):
 
220
                what = what[13:]
 
221
            what = self._ellipsise_unimportant_words(what, final_width)
127
222
        if self.showAll:
128
 
            width = osutils.terminal_width()
129
 
            name_width = width - 15
130
 
            what = None
131
 
            if SHOW_DESCRIPTIONS:
132
 
                what = test.shortDescription()
133
 
                if what:
134
 
                    if len(what) > name_width:
135
 
                        what = what[:name_width-3] + '...'
136
 
            if what is None:
137
 
                what = test.id()
138
 
                if what.startswith('bzrlib.tests.'):
139
 
                    what = what[13:]
140
 
                if len(what) > name_width:
141
 
                    what = '...' + what[3-name_width:]
142
 
            what = what.ljust(name_width)
143
223
            self.stream.write(what)
 
224
        elif self.dots and self.pb is not None:
 
225
            self.pb.update(what, self.testsRun - 1, None)
144
226
        self.stream.flush()
 
227
        self._recordTestStartTime()
 
228
 
 
229
    def _recordTestStartTime(self):
 
230
        """Record that a test has started."""
145
231
        self._start_time = time.time()
146
232
 
147
233
    def addError(self, test, err):
148
234
        if isinstance(err[1], TestSkipped):
149
235
            return self.addSkipped(test, err)    
150
236
        unittest.TestResult.addError(self, test, err)
 
237
        self.extractBenchmarkTime(test)
151
238
        if self.showAll:
152
 
            self.stream.writeln("ERROR %s" % self._elapsedTime())
153
 
        elif self.dots:
 
239
            self.stream.writeln("ERROR %s" % self._testTimeString())
 
240
        elif self.dots and self.pb is None:
154
241
            self.stream.write('E')
 
242
        elif self.dots:
 
243
            self.pb.update(self._ellipsise_unimportant_words('ERROR', 13), self.testsRun, None)
 
244
            self.pb.note(self._ellipsise_unimportant_words(
 
245
                            test.id() + ': ERROR',
 
246
                            osutils.terminal_width()))
155
247
        self.stream.flush()
156
248
        if self.stop_early:
157
249
            self.stop()
158
250
 
159
251
    def addFailure(self, test, err):
160
252
        unittest.TestResult.addFailure(self, test, err)
 
253
        self.extractBenchmarkTime(test)
161
254
        if self.showAll:
162
 
            self.stream.writeln(" FAIL %s" % self._elapsedTime())
163
 
        elif self.dots:
 
255
            self.stream.writeln(" FAIL %s" % self._testTimeString())
 
256
        elif self.dots and self.pb is None:
164
257
            self.stream.write('F')
 
258
        elif self.dots:
 
259
            self.pb.update(self._ellipsise_unimportant_words('FAIL', 13), self.testsRun, None)
 
260
            self.pb.note(self._ellipsise_unimportant_words(
 
261
                            test.id() + ': FAIL',
 
262
                            osutils.terminal_width()))
165
263
        self.stream.flush()
166
264
        if self.stop_early:
167
265
            self.stop()
168
266
 
169
267
    def addSuccess(self, test):
 
268
        self.extractBenchmarkTime(test)
 
269
        if self._bench_history is not None:
 
270
            if self._benchmarkTime is not None:
 
271
                self._bench_history.write("%s %s\n" % (
 
272
                    self._formatTime(self._benchmarkTime),
 
273
                    test.id()))
170
274
        if self.showAll:
171
 
            self.stream.writeln('   OK %s' % self._elapsedTime())
172
 
        elif self.dots:
 
275
            self.stream.writeln('   OK %s' % self._testTimeString())
 
276
            for bench_called, stats in getattr(test, '_benchcalls', []):
 
277
                self.stream.writeln('LSProf output for %s(%s, %s)' % bench_called)
 
278
                stats.pprint(file=self.stream)
 
279
        elif self.dots and self.pb is None:
173
280
            self.stream.write('~')
 
281
        elif self.dots:
 
282
            self.pb.update(self._ellipsise_unimportant_words('OK', 13), self.testsRun, None)
174
283
        self.stream.flush()
175
284
        unittest.TestResult.addSuccess(self, test)
176
285
 
177
286
    def addSkipped(self, test, skip_excinfo):
 
287
        self.extractBenchmarkTime(test)
178
288
        if self.showAll:
179
 
            print >>self.stream, ' SKIP %s' % self._elapsedTime()
 
289
            print >>self.stream, ' SKIP %s' % self._testTimeString()
180
290
            print >>self.stream, '     %s' % skip_excinfo[1]
181
 
        elif self.dots:
 
291
        elif self.dots and self.pb is None:
182
292
            self.stream.write('S')
 
293
        elif self.dots:
 
294
            self.pb.update(self._ellipsise_unimportant_words('SKIP', 13), self.testsRun, None)
183
295
        self.stream.flush()
184
296
        # seems best to treat this as success from point-of-view of unittest
185
297
        # -- it actually does nothing so it barely matters :)
186
 
        unittest.TestResult.addSuccess(self, test)
 
298
        try:
 
299
            test.tearDown()
 
300
        except KeyboardInterrupt:
 
301
            raise
 
302
        except:
 
303
            self.addError(test, test.__exc_info())
 
304
        else:
 
305
            unittest.TestResult.addSuccess(self, test)
187
306
 
188
307
    def printErrorList(self, flavour, errors):
189
308
        for test, err in errors:
200
319
            self.stream.writeln("%s" % err)
201
320
 
202
321
 
203
 
class TextTestRunner(unittest.TextTestRunner):
 
322
class TextTestRunner(object):
204
323
    stop_on_failure = False
205
324
 
 
325
    def __init__(self,
 
326
                 stream=sys.stderr,
 
327
                 descriptions=0,
 
328
                 verbosity=1,
 
329
                 keep_output=False,
 
330
                 pb=None,
 
331
                 bench_history=None):
 
332
        self.stream = unittest._WritelnDecorator(stream)
 
333
        self.descriptions = descriptions
 
334
        self.verbosity = verbosity
 
335
        self.keep_output = keep_output
 
336
        self.pb = pb
 
337
        self._bench_history = bench_history
 
338
 
206
339
    def _makeResult(self):
207
 
        result = _MyResult(self.stream, self.descriptions, self.verbosity)
 
340
        result = _MyResult(self.stream,
 
341
                           self.descriptions,
 
342
                           self.verbosity,
 
343
                           pb=self.pb,
 
344
                           bench_history=self._bench_history)
208
345
        result.stop_early = self.stop_on_failure
209
346
        return result
210
347
 
 
348
    def run(self, test):
 
349
        "Run the given test case or test suite."
 
350
        result = self._makeResult()
 
351
        startTime = time.time()
 
352
        if self.pb is not None:
 
353
            self.pb.update('Running tests', 0, test.countTestCases())
 
354
        test.run(result)
 
355
        stopTime = time.time()
 
356
        timeTaken = stopTime - startTime
 
357
        result.printErrors()
 
358
        self.stream.writeln(result.separator2)
 
359
        run = result.testsRun
 
360
        self.stream.writeln("Ran %d test%s in %.3fs" %
 
361
                            (run, run != 1 and "s" or "", timeTaken))
 
362
        self.stream.writeln()
 
363
        if not result.wasSuccessful():
 
364
            self.stream.write("FAILED (")
 
365
            failed, errored = map(len, (result.failures, result.errors))
 
366
            if failed:
 
367
                self.stream.write("failures=%d" % failed)
 
368
            if errored:
 
369
                if failed: self.stream.write(", ")
 
370
                self.stream.write("errors=%d" % errored)
 
371
            self.stream.writeln(")")
 
372
        else:
 
373
            self.stream.writeln("OK")
 
374
        if self.pb is not None:
 
375
            self.pb.update('Cleaning up', 0, 1)
 
376
        # This is still a little bogus, 
 
377
        # but only a little. Folk not using our testrunner will
 
378
        # have to delete their temp directories themselves.
 
379
        test_root = TestCaseInTempDir.TEST_ROOT
 
380
        if result.wasSuccessful() or not self.keep_output:
 
381
            if test_root is not None:
 
382
                # If LANG=C we probably have created some bogus paths
 
383
                # which rmtree(unicode) will fail to delete
 
384
                # so make sure we are using rmtree(str) to delete everything
 
385
                # except on win32, where rmtree(str) will fail
 
386
                # since it doesn't have the property of byte-stream paths
 
387
                # (they are either ascii or mbcs)
 
388
                if sys.platform == 'win32':
 
389
                    # make sure we are using the unicode win32 api
 
390
                    test_root = unicode(test_root)
 
391
                else:
 
392
                    test_root = test_root.encode(
 
393
                        sys.getfilesystemencoding())
 
394
                osutils.rmtree(test_root)
 
395
        else:
 
396
            if self.pb is not None:
 
397
                self.pb.note("Failed tests working directories are in '%s'\n",
 
398
                             test_root)
 
399
            else:
 
400
                self.stream.writeln(
 
401
                    "Failed tests working directories are in '%s'\n" %
 
402
                    test_root)
 
403
        TestCaseInTempDir.TEST_ROOT = None
 
404
        if self.pb is not None:
 
405
            self.pb.clear()
 
406
        return result
 
407
 
211
408
 
212
409
def iter_suite_tests(suite):
213
410
    """Return all tests in a suite, recursing through nested suites"""
224
421
 
225
422
class TestSkipped(Exception):
226
423
    """Indicates that a test was intentionally skipped, rather than failing."""
227
 
    # XXX: Not used yet
228
424
 
229
425
 
230
426
class CommandFailed(Exception):
231
427
    pass
232
428
 
 
429
 
 
430
class StringIOWrapper(object):
 
431
    """A wrapper around cStringIO which just adds an encoding attribute.
 
432
    
 
433
    Internally we can check sys.stdout to see what the output encoding
 
434
    should be. However, cStringIO has no encoding attribute that we can
 
435
    set. So we wrap it instead.
 
436
    """
 
437
    encoding='ascii'
 
438
    _cstring = None
 
439
 
 
440
    def __init__(self, s=None):
 
441
        if s is not None:
 
442
            self.__dict__['_cstring'] = StringIO(s)
 
443
        else:
 
444
            self.__dict__['_cstring'] = StringIO()
 
445
 
 
446
    def __getattr__(self, name, getattr=getattr):
 
447
        return getattr(self.__dict__['_cstring'], name)
 
448
 
 
449
    def __setattr__(self, name, val):
 
450
        if name == 'encoding':
 
451
            self.__dict__['encoding'] = val
 
452
        else:
 
453
            return setattr(self._cstring, name, val)
 
454
 
 
455
 
233
456
class TestCase(unittest.TestCase):
234
457
    """Base class for bzr unit tests.
235
458
    
251
474
    accidentally overlooked.
252
475
    """
253
476
 
254
 
    BZRPATH = 'bzr'
255
477
    _log_file_name = None
256
478
    _log_contents = ''
 
479
    # record lsprof data when performing benchmark calls.
 
480
    _gather_lsprof_in_benchmarks = False
257
481
 
258
482
    def __init__(self, methodName='testMethod'):
259
483
        super(TestCase, self).__init__(methodName)
264
488
        self._cleanEnvironment()
265
489
        bzrlib.trace.disable_default_logging()
266
490
        self._startLogFile()
 
491
        self._benchcalls = []
 
492
        self._benchtime = None
267
493
 
268
494
    def _ndiff_strings(self, a, b):
269
495
        """Return ndiff between two strings containing lines.
303
529
            raise AssertionError('string %r does not start with %r' % (s, prefix))
304
530
 
305
531
    def assertEndsWith(self, s, suffix):
306
 
        if not s.endswith(prefix):
 
532
        """Asserts that s ends with suffix."""
 
533
        if not s.endswith(suffix):
307
534
            raise AssertionError('string %r does not end with %r' % (s, suffix))
308
535
 
309
536
    def assertContainsRe(self, haystack, needle_re):
312
539
            raise AssertionError('pattern "%s" not found in "%s"'
313
540
                    % (needle_re, haystack))
314
541
 
 
542
    def assertNotContainsRe(self, haystack, needle_re):
 
543
        """Assert that a does not match a regular expression"""
 
544
        if re.search(needle_re, haystack):
 
545
            raise AssertionError('pattern "%s" found in "%s"'
 
546
                    % (needle_re, haystack))
 
547
 
315
548
    def assertSubset(self, sublist, superlist):
316
549
        """Assert that every entry in sublist is present in superlist."""
317
550
        missing = []
341
574
    def assertIsInstance(self, obj, kls):
342
575
        """Fail if obj is not an instance of kls"""
343
576
        if not isinstance(obj, kls):
344
 
            self.fail("%r is not an instance of %s" % (obj, kls))
 
577
            self.fail("%r is an instance of %s rather than %s" % (
 
578
                obj, obj.__class__, kls))
 
579
 
 
580
    def assertDeprecated(self, expected, callable, *args, **kwargs):
 
581
        """Assert that a callable is deprecated in a particular way.
 
582
 
 
583
        :param expected: a list of the deprecation warnings expected, in order
 
584
        :param callable: The callable to call
 
585
        :param args: The positional arguments for the callable
 
586
        :param kwargs: The keyword arguments for the callable
 
587
        """
 
588
        local_warnings = []
 
589
        def capture_warnings(msg, cls, stacklevel=None):
 
590
            self.assertEqual(cls, DeprecationWarning)
 
591
            local_warnings.append(msg)
 
592
        method = symbol_versioning.warn
 
593
        symbol_versioning.set_warning_method(capture_warnings)
 
594
        try:
 
595
            callable(*args, **kwargs)
 
596
        finally:
 
597
            result = symbol_versioning.set_warning_method(method)
 
598
        self.assertEqual(expected, local_warnings)
 
599
        return result
345
600
 
346
601
    def _startLogFile(self):
347
602
        """Send bzr and test log messages to a temporary file.
360
615
 
361
616
        Read contents into memory, close, and delete.
362
617
        """
 
618
        if self._log_file is None:
 
619
            return
363
620
        bzrlib.trace.disable_test_log(self._log_nonce)
364
621
        self._log_file.seek(0)
365
622
        self._log_contents = self._log_file.read()
382
639
        new_env = {
383
640
            'HOME': os.getcwd(),
384
641
            'APPDATA': os.getcwd(),
385
 
            'BZREMAIL': None,
 
642
            'BZR_EMAIL': None,
 
643
            'BZREMAIL': None, # may still be present in the environment
386
644
            'EMAIL': None,
387
645
        }
388
646
        self.__old_env = {}
416
674
        self._runCleanups()
417
675
        unittest.TestCase.tearDown(self)
418
676
 
 
677
    def time(self, callable, *args, **kwargs):
 
678
        """Run callable and accrue the time it takes to the benchmark time.
 
679
        
 
680
        If lsprofiling is enabled (i.e. by --lsprof-time to bzr selftest) then
 
681
        this will cause lsprofile statistics to be gathered and stored in
 
682
        self._benchcalls.
 
683
        """
 
684
        if self._benchtime is None:
 
685
            self._benchtime = 0
 
686
        start = time.time()
 
687
        try:
 
688
            if not self._gather_lsprof_in_benchmarks:
 
689
                return callable(*args, **kwargs)
 
690
            else:
 
691
                # record this benchmark
 
692
                ret, stats = bzrlib.lsprof.profile(callable, *args, **kwargs)
 
693
                stats.sort()
 
694
                self._benchcalls.append(((callable, args, kwargs), stats))
 
695
                return ret
 
696
        finally:
 
697
            self._benchtime += time.time() - start
 
698
 
419
699
    def _runCleanups(self):
420
700
        """Run registered cleanup functions. 
421
701
 
441
721
        """Shortcut that splits cmd into words, runs, and returns stdout"""
442
722
        return self.run_bzr_captured(cmd.split(), retcode=retcode)[0]
443
723
 
444
 
    def run_bzr_captured(self, argv, retcode=0):
 
724
    def run_bzr_captured(self, argv, retcode=0, encoding=None, stdin=None):
445
725
        """Invoke bzr and return (stdout, stderr).
446
726
 
447
727
        Useful for code that wants to check the contents of the
458
738
        errors, and with logging set to something approximating the
459
739
        default, so that error reporting can be checked.
460
740
 
461
 
        argv -- arguments to invoke bzr
462
 
        retcode -- expected return code, or None for don't-care.
 
741
        :param argv: arguments to invoke bzr
 
742
        :param retcode: expected return code, or None for don't-care.
 
743
        :param encoding: encoding for sys.stdout and sys.stderr
 
744
        :param stdin: A string to be used as stdin for the command.
463
745
        """
464
 
        stdout = StringIO()
465
 
        stderr = StringIO()
466
 
        self.log('run bzr: %s', ' '.join(argv))
 
746
        if encoding is None:
 
747
            encoding = bzrlib.user_encoding
 
748
        if stdin is not None:
 
749
            stdin = StringIO(stdin)
 
750
        stdout = StringIOWrapper()
 
751
        stderr = StringIOWrapper()
 
752
        stdout.encoding = encoding
 
753
        stderr.encoding = encoding
 
754
 
 
755
        self.log('run bzr: %r', argv)
467
756
        # FIXME: don't call into logging here
468
757
        handler = logging.StreamHandler(stderr)
469
 
        handler.setFormatter(bzrlib.trace.QuietFormatter())
470
758
        handler.setLevel(logging.INFO)
471
759
        logger = logging.getLogger('')
472
760
        logger.addHandler(handler)
 
761
        old_ui_factory = bzrlib.ui.ui_factory
 
762
        bzrlib.ui.ui_factory = bzrlib.tests.blackbox.TestUIFactory(
 
763
            stdout=stdout,
 
764
            stderr=stderr)
 
765
        bzrlib.ui.ui_factory.stdin = stdin
473
766
        try:
474
 
            result = self.apply_redirected(None, stdout, stderr,
 
767
            result = self.apply_redirected(stdin, stdout, stderr,
475
768
                                           bzrlib.commands.run_bzr_catch_errors,
476
769
                                           argv)
477
770
        finally:
478
771
            logger.removeHandler(handler)
 
772
            bzrlib.ui.ui_factory = old_ui_factory
 
773
 
479
774
        out = stdout.getvalue()
480
775
        err = stderr.getvalue()
481
776
        if out:
482
 
            self.log('output:\n%s', out)
 
777
            self.log('output:\n%r', out)
483
778
        if err:
484
 
            self.log('errors:\n%s', err)
 
779
            self.log('errors:\n%r', err)
485
780
        if retcode is not None:
486
 
            self.assertEquals(result, retcode)
 
781
            self.assertEquals(retcode, result)
487
782
        return out, err
488
783
 
489
784
    def run_bzr(self, *args, **kwargs):
495
790
 
496
791
        This sends the stdout/stderr results into the test's log,
497
792
        where it may be useful for debugging.  See also run_captured.
 
793
 
 
794
        :param stdin: A string to be used as stdin for the command.
498
795
        """
499
796
        retcode = kwargs.pop('retcode', 0)
500
 
        return self.run_bzr_captured(args, retcode)
 
797
        encoding = kwargs.pop('encoding', None)
 
798
        stdin = kwargs.pop('stdin', None)
 
799
        return self.run_bzr_captured(args, retcode=retcode, encoding=encoding, stdin=stdin)
 
800
 
 
801
    def run_bzr_decode(self, *args, **kwargs):
 
802
        if kwargs.has_key('encoding'):
 
803
            encoding = kwargs['encoding']
 
804
        else:
 
805
            encoding = bzrlib.user_encoding
 
806
        return self.run_bzr(*args, **kwargs)[0].decode(encoding)
 
807
 
 
808
    def run_bzr_error(self, error_regexes, *args, **kwargs):
 
809
        """Run bzr, and check that stderr contains the supplied regexes
 
810
        
 
811
        :param error_regexes: Sequence of regular expressions which 
 
812
            must each be found in the error output. The relative ordering
 
813
            is not enforced.
 
814
        :param args: command-line arguments for bzr
 
815
        :param kwargs: Keyword arguments which are interpreted by run_bzr
 
816
            This function changes the default value of retcode to be 3,
 
817
            since in most cases this is run when you expect bzr to fail.
 
818
        :return: (out, err) The actual output of running the command (in case you
 
819
                 want to do more inspection)
 
820
 
 
821
        Examples of use:
 
822
            # Make sure that commit is failing because there is nothing to do
 
823
            self.run_bzr_error(['no changes to commit'],
 
824
                               'commit', '-m', 'my commit comment')
 
825
            # Make sure --strict is handling an unknown file, rather than
 
826
            # giving us the 'nothing to do' error
 
827
            self.build_tree(['unknown'])
 
828
            self.run_bzr_error(['Commit refused because there are unknown files'],
 
829
                               'commit', '--strict', '-m', 'my commit comment')
 
830
        """
 
831
        kwargs.setdefault('retcode', 3)
 
832
        out, err = self.run_bzr(*args, **kwargs)
 
833
        for regex in error_regexes:
 
834
            self.assertContainsRe(err, regex)
 
835
        return out, err
 
836
 
 
837
    def run_bzr_subprocess(self, *args, **kwargs):
 
838
        """Run bzr in a subprocess for testing.
 
839
 
 
840
        This starts a new Python interpreter and runs bzr in there. 
 
841
        This should only be used for tests that have a justifiable need for
 
842
        this isolation: e.g. they are testing startup time, or signal
 
843
        handling, or early startup code, etc.  Subprocess code can't be 
 
844
        profiled or debugged so easily.
 
845
 
 
846
        :param retcode: The status code that is expected.  Defaults to 0.  If
 
847
        None is supplied, the status code is not checked.
 
848
        """
 
849
        bzr_path = os.path.dirname(os.path.dirname(bzrlib.__file__))+'/bzr'
 
850
        args = list(args)
 
851
        process = Popen([sys.executable, bzr_path]+args, stdout=PIPE, 
 
852
                         stderr=PIPE)
 
853
        out = process.stdout.read()
 
854
        err = process.stderr.read()
 
855
        retcode = process.wait()
 
856
        supplied_retcode = kwargs.get('retcode', 0)
 
857
        if supplied_retcode is not None:
 
858
            assert supplied_retcode == retcode
 
859
        return [out, err]
501
860
 
502
861
    def check_inventory_shape(self, inv, shape):
503
862
        """Compare an inventory to a list of expected names.
652
1011
        shape is a sequence of file specifications.  If the final
653
1012
        character is '/', a directory is created.
654
1013
 
 
1014
        This assumes that all the elements in the tree being built are new.
 
1015
 
655
1016
        This doesn't add anything to a branch.
656
1017
        :param line_endings: Either 'binary' or 'native'
657
1018
                             in binary mode, exact contents are written
662
1023
                          VFS's. If the transport is readonly or None,
663
1024
                          "." is opened automatically.
664
1025
        """
665
 
        # XXX: It's OK to just create them using forward slashes on windows?
 
1026
        # It's OK to just create them using forward slashes on windows.
666
1027
        if transport is None or transport.is_readonly():
667
1028
            transport = get_transport(".")
668
1029
        for name in shape:
669
1030
            self.assert_(isinstance(name, basestring))
670
1031
            if name[-1] == '/':
671
 
                transport.mkdir(urlescape(name[:-1]))
 
1032
                transport.mkdir(urlutils.escape(name[:-1]))
672
1033
            else:
673
1034
                if line_endings == 'binary':
674
1035
                    end = '\n'
676
1037
                    end = os.linesep
677
1038
                else:
678
1039
                    raise errors.BzrError('Invalid line ending request %r' % (line_endings,))
679
 
                content = "contents of %s%s" % (name, end)
680
 
                transport.put(urlescape(name), StringIO(content))
 
1040
                content = "contents of %s%s" % (name.encode('utf-8'), end)
 
1041
                # Technically 'put()' is the right command. However, put
 
1042
                # uses an AtomicFile, which requires an extra rename into place
 
1043
                # As long as the files didn't exist in the past, append() will
 
1044
                # do the same thing as put()
 
1045
                # On jam's machine, make_kernel_like_tree is:
 
1046
                #   put:    4.5-7.5s (averaging 6s)
 
1047
                #   append: 2.9-4.5s
 
1048
                transport.append(urlutils.escape(name), StringIO(content))
681
1049
 
682
1050
    def build_tree_contents(self, shape):
683
1051
        build_tree_contents(shape)
693
1061
    def assertFileEqual(self, content, path):
694
1062
        """Fail if path does not contain 'content'."""
695
1063
        self.failUnless(osutils.lexists(path))
 
1064
        # TODO: jam 20060427 Shouldn't this be 'rb'?
696
1065
        self.assertEqualDiff(content, open(path, 'r').read())
697
1066
 
698
1067
 
774
1143
        if relpath is not None and relpath != '.':
775
1144
            if not base.endswith('/'):
776
1145
                base = base + '/'
777
 
            base = base + relpath
 
1146
            base = base + urlutils.escape(relpath)
778
1147
        return base
779
1148
 
780
1149
    def get_transport(self):
793
1162
        self.assertTrue(t.is_readonly())
794
1163
        return t
795
1164
 
796
 
    def make_branch(self, relpath):
 
1165
    def make_branch(self, relpath, format=None):
797
1166
        """Create a branch on the transport at relpath."""
798
 
        repo = self.make_repository(relpath)
 
1167
        repo = self.make_repository(relpath, format=format)
799
1168
        return repo.bzrdir.create_branch()
800
1169
 
801
 
    def make_bzrdir(self, relpath):
 
1170
    def make_bzrdir(self, relpath, format=None):
802
1171
        try:
803
1172
            url = self.get_url(relpath)
804
 
            segments = relpath.split('/')
 
1173
            mutter('relpath %r => url %r', relpath, url)
 
1174
            segments = url.split('/')
805
1175
            if segments and segments[-1] not in ('', '.'):
806
 
                parent = self.get_url('/'.join(segments[:-1]))
 
1176
                parent = '/'.join(segments[:-1])
807
1177
                t = get_transport(parent)
808
1178
                try:
809
1179
                    t.mkdir(segments[-1])
810
1180
                except errors.FileExists:
811
1181
                    pass
812
 
            return bzrlib.bzrdir.BzrDir.create(url)
 
1182
            if format is None:
 
1183
                format=bzrlib.bzrdir.BzrDirFormat.get_default_format()
 
1184
            # FIXME: make this use a single transport someday. RBC 20060418
 
1185
            return format.initialize_on_transport(get_transport(relpath))
813
1186
        except errors.UninitializableFormat:
814
 
            raise TestSkipped("Format %s is not initializable.")
 
1187
            raise TestSkipped("Format %s is not initializable." % format)
815
1188
 
816
 
    def make_repository(self, relpath, shared=False):
 
1189
    def make_repository(self, relpath, shared=False, format=None):
817
1190
        """Create a repository on our default transport at relpath."""
818
 
        made_control = self.make_bzrdir(relpath)
 
1191
        made_control = self.make_bzrdir(relpath, format=format)
819
1192
        return made_control.create_repository(shared=shared)
820
1193
 
821
 
    def make_branch_and_tree(self, relpath):
 
1194
    def make_branch_and_tree(self, relpath, format=None):
822
1195
        """Create a branch on the transport and a tree locally.
823
1196
 
824
1197
        Returns the tree.
827
1200
        # this obviously requires a format that supports branch references
828
1201
        # so check for that by checking bzrdir.BzrDirFormat.get_default_format()
829
1202
        # RBC 20060208
830
 
        b = self.make_branch(relpath)
 
1203
        b = self.make_branch(relpath, format=format)
831
1204
        try:
832
1205
            return b.bzrdir.create_workingtree()
833
1206
        except errors.NotLocalUrl:
872
1245
 
873
1246
 
874
1247
def filter_suite_by_re(suite, pattern):
875
 
    result = TestSuite()
 
1248
    result = TestUtil.TestSuite()
876
1249
    filter_re = re.compile(pattern)
877
1250
    for test in iter_suite_tests(suite):
878
1251
        if filter_re.search(test.id()):
882
1255
 
883
1256
def run_suite(suite, name='test', verbose=False, pattern=".*",
884
1257
              stop_on_failure=False, keep_output=False,
885
 
              transport=None):
 
1258
              transport=None, lsprof_timed=None, bench_history=None):
886
1259
    TestCaseInTempDir._TEST_NAME = name
 
1260
    TestCase._gather_lsprof_in_benchmarks = lsprof_timed
887
1261
    if verbose:
888
1262
        verbosity = 2
 
1263
        pb = None
889
1264
    else:
890
1265
        verbosity = 1
 
1266
        pb = progress.ProgressBar()
891
1267
    runner = TextTestRunner(stream=sys.stdout,
892
1268
                            descriptions=0,
893
 
                            verbosity=verbosity)
 
1269
                            verbosity=verbosity,
 
1270
                            keep_output=keep_output,
 
1271
                            pb=pb,
 
1272
                            bench_history=bench_history)
894
1273
    runner.stop_on_failure=stop_on_failure
895
1274
    if pattern != '.*':
896
1275
        suite = filter_suite_by_re(suite, pattern)
897
1276
    result = runner.run(suite)
898
 
    # This is still a little bogus, 
899
 
    # but only a little. Folk not using our testrunner will
900
 
    # have to delete their temp directories themselves.
901
 
    test_root = TestCaseInTempDir.TEST_ROOT
902
 
    if result.wasSuccessful() or not keep_output:
903
 
        if test_root is not None:
904
 
            print 'Deleting test root %s...' % test_root
905
 
            try:
906
 
                shutil.rmtree(test_root)
907
 
            finally:
908
 
                print
909
 
    else:
910
 
        print "Failed tests working directories are in '%s'\n" % TestCaseInTempDir.TEST_ROOT
911
1277
    return result.wasSuccessful()
912
1278
 
913
1279
 
914
1280
def selftest(verbose=False, pattern=".*", stop_on_failure=True,
915
1281
             keep_output=False,
916
 
             transport=None):
 
1282
             transport=None,
 
1283
             test_suite_factory=None,
 
1284
             lsprof_timed=None,
 
1285
             bench_history=None):
917
1286
    """Run the whole test suite under the enhanced runner"""
 
1287
    # XXX: Very ugly way to do this...
 
1288
    # Disable warning about old formats because we don't want it to disturb
 
1289
    # any blackbox tests.
 
1290
    from bzrlib import repository
 
1291
    repository._deprecation_warning_done = True
 
1292
 
918
1293
    global default_transport
919
1294
    if transport is None:
920
1295
        transport = default_transport
921
1296
    old_transport = default_transport
922
1297
    default_transport = transport
923
 
    suite = test_suite()
924
1298
    try:
 
1299
        if test_suite_factory is None:
 
1300
            suite = test_suite()
 
1301
        else:
 
1302
            suite = test_suite_factory()
925
1303
        return run_suite(suite, 'testbzr', verbose=verbose, pattern=pattern,
926
1304
                     stop_on_failure=stop_on_failure, keep_output=keep_output,
927
 
                     transport=transport)
 
1305
                     transport=transport,
 
1306
                     lsprof_timed=lsprof_timed,
 
1307
                     bench_history=bench_history)
928
1308
    finally:
929
1309
        default_transport = old_transport
930
1310
 
931
1311
 
932
 
 
933
1312
def test_suite():
934
 
    """Build and return TestSuite for the whole program."""
935
 
    from doctest import DocTestSuite
936
 
 
937
 
    global MODULES_TO_DOCTEST
938
 
 
939
 
    testmod_names = [ \
 
1313
    """Build and return TestSuite for the whole of bzrlib.
 
1314
    
 
1315
    This function can be replaced if you need to change the default test
 
1316
    suite on a global basis, but it is not encouraged.
 
1317
    """
 
1318
    testmod_names = [
940
1319
                   'bzrlib.tests.test_ancestry',
941
 
                   'bzrlib.tests.test_annotate',
942
1320
                   'bzrlib.tests.test_api',
 
1321
                   'bzrlib.tests.test_atomicfile',
943
1322
                   'bzrlib.tests.test_bad_files',
944
 
                   'bzrlib.tests.test_basis_inventory',
945
1323
                   'bzrlib.tests.test_branch',
 
1324
                   'bzrlib.tests.test_bundle',
946
1325
                   'bzrlib.tests.test_bzrdir',
 
1326
                   'bzrlib.tests.test_cache_utf8',
947
1327
                   'bzrlib.tests.test_command',
948
1328
                   'bzrlib.tests.test_commit',
949
1329
                   'bzrlib.tests.test_commit_merge',
959
1339
                   'bzrlib.tests.test_graph',
960
1340
                   'bzrlib.tests.test_hashcache',
961
1341
                   'bzrlib.tests.test_http',
 
1342
                   'bzrlib.tests.test_http_response',
962
1343
                   'bzrlib.tests.test_identitymap',
 
1344
                   'bzrlib.tests.test_ignores',
963
1345
                   'bzrlib.tests.test_inv',
964
1346
                   'bzrlib.tests.test_knit',
965
1347
                   'bzrlib.tests.test_lockdir',
973
1355
                   'bzrlib.tests.test_nonascii',
974
1356
                   'bzrlib.tests.test_options',
975
1357
                   'bzrlib.tests.test_osutils',
 
1358
                   'bzrlib.tests.test_patch',
 
1359
                   'bzrlib.tests.test_patches',
976
1360
                   'bzrlib.tests.test_permissions',
977
1361
                   'bzrlib.tests.test_plugins',
978
1362
                   'bzrlib.tests.test_progress',
980
1364
                   'bzrlib.tests.test_repository',
981
1365
                   'bzrlib.tests.test_revision',
982
1366
                   'bzrlib.tests.test_revisionnamespaces',
983
 
                   'bzrlib.tests.test_revprops',
 
1367
                   'bzrlib.tests.test_revisiontree',
984
1368
                   'bzrlib.tests.test_rio',
985
1369
                   'bzrlib.tests.test_sampler',
986
1370
                   'bzrlib.tests.test_selftest',
988
1372
                   'bzrlib.tests.test_sftp_transport',
989
1373
                   'bzrlib.tests.test_smart_add',
990
1374
                   'bzrlib.tests.test_source',
 
1375
                   'bzrlib.tests.test_status',
991
1376
                   'bzrlib.tests.test_store',
992
1377
                   'bzrlib.tests.test_symbol_versioning',
993
1378
                   'bzrlib.tests.test_testament',
 
1379
                   'bzrlib.tests.test_textfile',
 
1380
                   'bzrlib.tests.test_textmerge',
994
1381
                   'bzrlib.tests.test_trace',
995
1382
                   'bzrlib.tests.test_transactions',
996
1383
                   'bzrlib.tests.test_transform',
997
1384
                   'bzrlib.tests.test_transport',
 
1385
                   'bzrlib.tests.test_tree',
998
1386
                   'bzrlib.tests.test_tsort',
 
1387
                   'bzrlib.tests.test_tuned_gzip',
999
1388
                   'bzrlib.tests.test_ui',
1000
1389
                   'bzrlib.tests.test_upgrade',
 
1390
                   'bzrlib.tests.test_urlutils',
1001
1391
                   'bzrlib.tests.test_versionedfile',
 
1392
                   'bzrlib.tests.test_version',
1002
1393
                   'bzrlib.tests.test_weave',
1003
1394
                   'bzrlib.tests.test_whitebox',
1004
1395
                   'bzrlib.tests.test_workingtree',
1005
1396
                   'bzrlib.tests.test_xml',
1006
1397
                   ]
1007
1398
    test_transport_implementations = [
1008
 
        'bzrlib.tests.test_transport_implementations']
1009
 
 
1010
 
    TestCase.BZRPATH = osutils.pathjoin(
1011
 
            osutils.realpath(osutils.dirname(bzrlib.__path__[0])), 'bzr')
1012
 
    print '%10s: %s' % ('bzr', osutils.realpath(sys.argv[0]))
1013
 
    print '%10s: %s' % ('bzrlib', bzrlib.__path__[0])
1014
 
    print
1015
 
    suite = TestSuite()
1016
 
    # python2.4's TestLoader.loadTestsFromNames gives very poor 
1017
 
    # errors if it fails to load a named module - no indication of what's
1018
 
    # actually wrong, just "no such module".  We should probably override that
1019
 
    # class, but for the moment just load them ourselves. (mbp 20051202)
1020
 
    loader = TestLoader()
 
1399
        'bzrlib.tests.test_transport_implementations',
 
1400
        'bzrlib.tests.test_read_bundle',
 
1401
        ]
 
1402
    suite = TestUtil.TestSuite()
 
1403
    loader = TestUtil.TestLoader()
 
1404
    suite.addTest(loader.loadTestsFromModuleNames(testmod_names))
1021
1405
    from bzrlib.transport import TransportTestProviderAdapter
1022
1406
    adapter = TransportTestProviderAdapter()
1023
1407
    adapt_modules(test_transport_implementations, adapter, loader, suite)
1024
 
    for mod_name in testmod_names:
1025
 
        mod = _load_module_by_name(mod_name)
1026
 
        suite.addTest(loader.loadTestsFromModule(mod))
1027
1408
    for package in packages_to_test():
1028
1409
        suite.addTest(package.test_suite())
1029
1410
    for m in MODULES_TO_TEST:
1030
1411
        suite.addTest(loader.loadTestsFromModule(m))
1031
 
    for m in (MODULES_TO_DOCTEST):
1032
 
        suite.addTest(DocTestSuite(m))
 
1412
    for m in MODULES_TO_DOCTEST:
 
1413
        suite.addTest(doctest.DocTestSuite(m))
1033
1414
    for name, plugin in bzrlib.plugin.all_plugins().items():
1034
1415
        if getattr(plugin, 'test_suite', None) is not None:
1035
1416
            suite.addTest(plugin.test_suite())
1038
1419
 
1039
1420
def adapt_modules(mods_list, adapter, loader, suite):
1040
1421
    """Adapt the modules in mods_list using adapter and add to suite."""
1041
 
    for mod_name in mods_list:
1042
 
        mod = _load_module_by_name(mod_name)
1043
 
        for test in iter_suite_tests(loader.loadTestsFromModule(mod)):
1044
 
            suite.addTests(adapter.adapt(test))
1045
 
 
1046
 
 
1047
 
def _load_module_by_name(mod_name):
1048
 
    parts = mod_name.split('.')
1049
 
    module = __import__(mod_name)
1050
 
    del parts[0]
1051
 
    # for historical reasons python returns the top-level module even though
1052
 
    # it loads the submodule; we need to walk down to get the one we want.
1053
 
    while parts:
1054
 
        module = getattr(module, parts.pop(0))
1055
 
    return module
 
1422
    for test in iter_suite_tests(loader.loadTestsFromModuleNames(mods_list)):
 
1423
        suite.addTests(adapter.adapt(test))