/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 Jan's benchmarks.

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
57
66
import bzrlib.store
58
67
import bzrlib.trace
59
 
from bzrlib.transport import urlescape, get_transport
 
68
from bzrlib.transport import get_transport
60
69
import bzrlib.transport
61
70
from bzrlib.transport.local import LocalRelpathServer
62
71
from bzrlib.transport.readonly import ReadonlyServer
63
72
from bzrlib.trace import mutter
64
 
from bzrlib.tests.TestUtil import TestLoader, TestSuite
 
73
from bzrlib.tests import TestUtil
 
74
from bzrlib.tests.TestUtil import (
 
75
                          TestSuite,
 
76
                          TestLoader,
 
77
                          )
65
78
from bzrlib.tests.treeshape import build_tree_contents
 
79
import bzrlib.urlutils as urlutils
66
80
from bzrlib.workingtree import WorkingTree, WorkingTreeFormat2
67
81
 
68
82
default_transport = LocalRelpathServer
70
84
MODULES_TO_TEST = []
71
85
MODULES_TO_DOCTEST = [
72
86
                      bzrlib.branch,
 
87
                      bzrlib.bundle.serializer,
73
88
                      bzrlib.commands,
74
89
                      bzrlib.errors,
75
90
                      bzrlib.inventory,
80
95
                      bzrlib.osutils,
81
96
                      bzrlib.store
82
97
                      ]
 
98
 
 
99
 
83
100
def packages_to_test():
84
101
    """Return a list of packages to test.
85
102
 
92
109
    import bzrlib.tests.bzrdir_implementations
93
110
    import bzrlib.tests.interrepository_implementations
94
111
    import bzrlib.tests.interversionedfile_implementations
 
112
    import bzrlib.tests.intertree_implementations
95
113
    import bzrlib.tests.repository_implementations
96
114
    import bzrlib.tests.revisionstore_implementations
 
115
    import bzrlib.tests.tree_implementations
97
116
    import bzrlib.tests.workingtree_implementations
98
117
    return [
99
118
            bzrlib.doc,
102
121
            bzrlib.tests.bzrdir_implementations,
103
122
            bzrlib.tests.interrepository_implementations,
104
123
            bzrlib.tests.interversionedfile_implementations,
 
124
            bzrlib.tests.intertree_implementations,
105
125
            bzrlib.tests.repository_implementations,
106
126
            bzrlib.tests.revisionstore_implementations,
 
127
            bzrlib.tests.tree_implementations,
107
128
            bzrlib.tests.workingtree_implementations,
108
129
            ]
109
130
 
114
135
    Shows output in a different format, including displaying runtime for tests.
115
136
    """
116
137
    stop_early = False
117
 
 
118
 
    def _elapsedTime(self):
119
 
        return "%5dms" % (1000 * (time.time() - self._start_time))
 
138
    
 
139
    def __init__(self, stream, descriptions, verbosity, pb=None):
 
140
        unittest._TextTestResult.__init__(self, stream, descriptions, verbosity)
 
141
        self.pb = pb
 
142
    
 
143
    def extractBenchmarkTime(self, testCase):
 
144
        """Add a benchmark time for the current test case."""
 
145
        self._benchmarkTime = getattr(testCase, "_benchtime", None)
 
146
    
 
147
    def _elapsedTestTimeString(self):
 
148
        """Return a time string for the overall time the current test has taken."""
 
149
        return self._formatTime(time.time() - self._start_time)
 
150
 
 
151
    def _testTimeString(self):
 
152
        if self._benchmarkTime is not None:
 
153
            return "%s/%s" % (
 
154
                self._formatTime(self._benchmarkTime),
 
155
                self._elapsedTestTimeString())
 
156
        else:
 
157
            return "      %s" % self._elapsedTestTimeString()
 
158
 
 
159
    def _formatTime(self, seconds):
 
160
        """Format seconds as milliseconds with leading spaces."""
 
161
        return "%5dms" % (1000 * seconds)
 
162
 
 
163
    def _ellipsise_unimportant_words(self, a_string, final_width,
 
164
                                   keep_start=False):
 
165
        """Add ellipses (sp?) for overly long strings.
 
166
        
 
167
        :param keep_start: If true preserve the start of a_string rather
 
168
                           than the end of it.
 
169
        """
 
170
        if keep_start:
 
171
            if len(a_string) > final_width:
 
172
                result = a_string[:final_width-3] + '...'
 
173
            else:
 
174
                result = a_string
 
175
        else:
 
176
            if len(a_string) > final_width:
 
177
                result = '...' + a_string[3-final_width:]
 
178
            else:
 
179
                result = a_string
 
180
        return result.ljust(final_width)
120
181
 
121
182
    def startTest(self, test):
122
183
        unittest.TestResult.startTest(self, test)
124
185
        # the beginning, but in an id, the important words are
125
186
        # at the end
126
187
        SHOW_DESCRIPTIONS = False
 
188
 
 
189
        if not self.showAll and self.dots and self.pb is not None:
 
190
            final_width = 13
 
191
        else:
 
192
            final_width = osutils.terminal_width()
 
193
            final_width = final_width - 15 - 8
 
194
        what = None
 
195
        if SHOW_DESCRIPTIONS:
 
196
            what = test.shortDescription()
 
197
            if what:
 
198
                what = self._ellipsise_unimportant_words(what, final_width, keep_start=True)
 
199
        if what is None:
 
200
            what = test.id()
 
201
            if what.startswith('bzrlib.tests.'):
 
202
                what = what[13:]
 
203
            what = self._ellipsise_unimportant_words(what, final_width)
127
204
        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
205
            self.stream.write(what)
 
206
        elif self.dots and self.pb is not None:
 
207
            self.pb.update(what, self.testsRun - 1, None)
144
208
        self.stream.flush()
 
209
        self._recordTestStartTime()
 
210
 
 
211
    def _recordTestStartTime(self):
 
212
        """Record that a test has started."""
145
213
        self._start_time = time.time()
146
214
 
147
215
    def addError(self, test, err):
148
216
        if isinstance(err[1], TestSkipped):
149
217
            return self.addSkipped(test, err)    
150
218
        unittest.TestResult.addError(self, test, err)
 
219
        self.extractBenchmarkTime(test)
151
220
        if self.showAll:
152
 
            self.stream.writeln("ERROR %s" % self._elapsedTime())
153
 
        elif self.dots:
 
221
            self.stream.writeln("ERROR %s" % self._testTimeString())
 
222
        elif self.dots and self.pb is None:
154
223
            self.stream.write('E')
 
224
        elif self.dots:
 
225
            self.pb.update(self._ellipsise_unimportant_words('ERROR', 13), self.testsRun, None)
 
226
            self.pb.note(self._ellipsise_unimportant_words(
 
227
                            test.id() + ': ERROR',
 
228
                            osutils.terminal_width()))
155
229
        self.stream.flush()
156
230
        if self.stop_early:
157
231
            self.stop()
158
232
 
159
233
    def addFailure(self, test, err):
160
234
        unittest.TestResult.addFailure(self, test, err)
 
235
        self.extractBenchmarkTime(test)
161
236
        if self.showAll:
162
 
            self.stream.writeln(" FAIL %s" % self._elapsedTime())
163
 
        elif self.dots:
 
237
            self.stream.writeln(" FAIL %s" % self._testTimeString())
 
238
        elif self.dots and self.pb is None:
164
239
            self.stream.write('F')
 
240
        elif self.dots:
 
241
            self.pb.update(self._ellipsise_unimportant_words('FAIL', 13), self.testsRun, None)
 
242
            self.pb.note(self._ellipsise_unimportant_words(
 
243
                            test.id() + ': FAIL',
 
244
                            osutils.terminal_width()))
165
245
        self.stream.flush()
166
246
        if self.stop_early:
167
247
            self.stop()
168
248
 
169
249
    def addSuccess(self, test):
 
250
        self.extractBenchmarkTime(test)
170
251
        if self.showAll:
171
 
            self.stream.writeln('   OK %s' % self._elapsedTime())
172
 
        elif self.dots:
 
252
            self.stream.writeln('   OK %s' % self._testTimeString())
 
253
            for bench_called, stats in getattr(test, '_benchcalls', []):
 
254
                self.stream.writeln('LSProf output for %s(%s, %s)' % bench_called)
 
255
                stats.pprint(file=self.stream)
 
256
        elif self.dots and self.pb is None:
173
257
            self.stream.write('~')
 
258
        elif self.dots:
 
259
            self.pb.update(self._ellipsise_unimportant_words('OK', 13), self.testsRun, None)
174
260
        self.stream.flush()
175
261
        unittest.TestResult.addSuccess(self, test)
176
262
 
177
263
    def addSkipped(self, test, skip_excinfo):
 
264
        self.extractBenchmarkTime(test)
178
265
        if self.showAll:
179
 
            print >>self.stream, ' SKIP %s' % self._elapsedTime()
 
266
            print >>self.stream, ' SKIP %s' % self._testTimeString()
180
267
            print >>self.stream, '     %s' % skip_excinfo[1]
181
 
        elif self.dots:
 
268
        elif self.dots and self.pb is None:
182
269
            self.stream.write('S')
 
270
        elif self.dots:
 
271
            self.pb.update(self._ellipsise_unimportant_words('SKIP', 13), self.testsRun, None)
183
272
        self.stream.flush()
184
273
        # seems best to treat this as success from point-of-view of unittest
185
274
        # -- it actually does nothing so it barely matters :)
186
 
        unittest.TestResult.addSuccess(self, test)
 
275
        try:
 
276
            test.tearDown()
 
277
        except KeyboardInterrupt:
 
278
            raise
 
279
        except:
 
280
            self.addError(test, test.__exc_info())
 
281
        else:
 
282
            unittest.TestResult.addSuccess(self, test)
187
283
 
188
284
    def printErrorList(self, flavour, errors):
189
285
        for test, err in errors:
200
296
            self.stream.writeln("%s" % err)
201
297
 
202
298
 
203
 
class TextTestRunner(unittest.TextTestRunner):
 
299
class TextTestRunner(object):
204
300
    stop_on_failure = False
205
301
 
 
302
    def __init__(self,
 
303
                 stream=sys.stderr,
 
304
                 descriptions=0,
 
305
                 verbosity=1,
 
306
                 keep_output=False,
 
307
                 pb=None):
 
308
        self.stream = unittest._WritelnDecorator(stream)
 
309
        self.descriptions = descriptions
 
310
        self.verbosity = verbosity
 
311
        self.keep_output = keep_output
 
312
        self.pb = pb
 
313
 
206
314
    def _makeResult(self):
207
 
        result = _MyResult(self.stream, self.descriptions, self.verbosity)
 
315
        result = _MyResult(self.stream,
 
316
                           self.descriptions,
 
317
                           self.verbosity,
 
318
                           pb=self.pb)
208
319
        result.stop_early = self.stop_on_failure
209
320
        return result
210
321
 
 
322
    def run(self, test):
 
323
        "Run the given test case or test suite."
 
324
        result = self._makeResult()
 
325
        startTime = time.time()
 
326
        if self.pb is not None:
 
327
            self.pb.update('Running tests', 0, test.countTestCases())
 
328
        test.run(result)
 
329
        stopTime = time.time()
 
330
        timeTaken = stopTime - startTime
 
331
        result.printErrors()
 
332
        self.stream.writeln(result.separator2)
 
333
        run = result.testsRun
 
334
        self.stream.writeln("Ran %d test%s in %.3fs" %
 
335
                            (run, run != 1 and "s" or "", timeTaken))
 
336
        self.stream.writeln()
 
337
        if not result.wasSuccessful():
 
338
            self.stream.write("FAILED (")
 
339
            failed, errored = map(len, (result.failures, result.errors))
 
340
            if failed:
 
341
                self.stream.write("failures=%d" % failed)
 
342
            if errored:
 
343
                if failed: self.stream.write(", ")
 
344
                self.stream.write("errors=%d" % errored)
 
345
            self.stream.writeln(")")
 
346
        else:
 
347
            self.stream.writeln("OK")
 
348
        if self.pb is not None:
 
349
            self.pb.update('Cleaning up', 0, 1)
 
350
        # This is still a little bogus, 
 
351
        # but only a little. Folk not using our testrunner will
 
352
        # have to delete their temp directories themselves.
 
353
        test_root = TestCaseInTempDir.TEST_ROOT
 
354
        if result.wasSuccessful() or not self.keep_output:
 
355
            if test_root is not None:
 
356
                # If LANG=C we probably have created some bogus paths
 
357
                # which rmtree(unicode) will fail to delete
 
358
                # so make sure we are using rmtree(str) to delete everything
 
359
                # except on win32, where rmtree(str) will fail
 
360
                # since it doesn't have the property of byte-stream paths
 
361
                # (they are either ascii or mbcs)
 
362
                if sys.platform == 'win32':
 
363
                    # make sure we are using the unicode win32 api
 
364
                    test_root = unicode(test_root)
 
365
                else:
 
366
                    test_root = test_root.encode(
 
367
                        sys.getfilesystemencoding())
 
368
                osutils.rmtree(test_root)
 
369
        else:
 
370
            if self.pb is not None:
 
371
                self.pb.note("Failed tests working directories are in '%s'\n",
 
372
                             test_root)
 
373
            else:
 
374
                self.stream.writeln(
 
375
                    "Failed tests working directories are in '%s'\n" %
 
376
                    test_root)
 
377
        TestCaseInTempDir.TEST_ROOT = None
 
378
        if self.pb is not None:
 
379
            self.pb.clear()
 
380
        return result
 
381
 
211
382
 
212
383
def iter_suite_tests(suite):
213
384
    """Return all tests in a suite, recursing through nested suites"""
230
401
class CommandFailed(Exception):
231
402
    pass
232
403
 
 
404
 
 
405
class StringIOWrapper(object):
 
406
    """A wrapper around cStringIO which just adds an encoding attribute.
 
407
    
 
408
    Internally we can check sys.stdout to see what the output encoding
 
409
    should be. However, cStringIO has no encoding attribute that we can
 
410
    set. So we wrap it instead.
 
411
    """
 
412
    encoding='ascii'
 
413
    _cstring = None
 
414
 
 
415
    def __init__(self, s=None):
 
416
        if s is not None:
 
417
            self.__dict__['_cstring'] = StringIO(s)
 
418
        else:
 
419
            self.__dict__['_cstring'] = StringIO()
 
420
 
 
421
    def __getattr__(self, name, getattr=getattr):
 
422
        return getattr(self.__dict__['_cstring'], name)
 
423
 
 
424
    def __setattr__(self, name, val):
 
425
        if name == 'encoding':
 
426
            self.__dict__['encoding'] = val
 
427
        else:
 
428
            return setattr(self._cstring, name, val)
 
429
 
 
430
 
233
431
class TestCase(unittest.TestCase):
234
432
    """Base class for bzr unit tests.
235
433
    
251
449
    accidentally overlooked.
252
450
    """
253
451
 
254
 
    BZRPATH = 'bzr'
255
452
    _log_file_name = None
256
453
    _log_contents = ''
 
454
    # record lsprof data when performing benchmark calls.
 
455
    _gather_lsprof_in_benchmarks = False
257
456
 
258
457
    def __init__(self, methodName='testMethod'):
259
458
        super(TestCase, self).__init__(methodName)
264
463
        self._cleanEnvironment()
265
464
        bzrlib.trace.disable_default_logging()
266
465
        self._startLogFile()
 
466
        self._benchcalls = []
 
467
        self._benchtime = None
267
468
 
268
469
    def _ndiff_strings(self, a, b):
269
470
        """Return ndiff between two strings containing lines.
303
504
            raise AssertionError('string %r does not start with %r' % (s, prefix))
304
505
 
305
506
    def assertEndsWith(self, s, suffix):
306
 
        if not s.endswith(prefix):
 
507
        """Asserts that s ends with suffix."""
 
508
        if not s.endswith(suffix):
307
509
            raise AssertionError('string %r does not end with %r' % (s, suffix))
308
510
 
309
511
    def assertContainsRe(self, haystack, needle_re):
312
514
            raise AssertionError('pattern "%s" not found in "%s"'
313
515
                    % (needle_re, haystack))
314
516
 
 
517
    def assertNotContainsRe(self, haystack, needle_re):
 
518
        """Assert that a does not match a regular expression"""
 
519
        if re.search(needle_re, haystack):
 
520
            raise AssertionError('pattern "%s" found in "%s"'
 
521
                    % (needle_re, haystack))
 
522
 
315
523
    def assertSubset(self, sublist, superlist):
316
524
        """Assert that every entry in sublist is present in superlist."""
317
525
        missing = []
341
549
    def assertIsInstance(self, obj, kls):
342
550
        """Fail if obj is not an instance of kls"""
343
551
        if not isinstance(obj, kls):
344
 
            self.fail("%r is not an instance of %s" % (obj, kls))
 
552
            self.fail("%r is an instance of %s rather than %s" % (
 
553
                obj, obj.__class__, kls))
345
554
 
346
555
    def _startLogFile(self):
347
556
        """Send bzr and test log messages to a temporary file.
360
569
 
361
570
        Read contents into memory, close, and delete.
362
571
        """
 
572
        if self._log_file is None:
 
573
            return
363
574
        bzrlib.trace.disable_test_log(self._log_nonce)
364
575
        self._log_file.seek(0)
365
576
        self._log_contents = self._log_file.read()
382
593
        new_env = {
383
594
            'HOME': os.getcwd(),
384
595
            'APPDATA': os.getcwd(),
385
 
            'BZREMAIL': None,
 
596
            'BZR_EMAIL': None,
386
597
            'EMAIL': None,
387
598
        }
388
599
        self.__old_env = {}
416
627
        self._runCleanups()
417
628
        unittest.TestCase.tearDown(self)
418
629
 
 
630
    def time(self, callable, *args, **kwargs):
 
631
        """Run callable and accrue the time it takes to the benchmark time.
 
632
        
 
633
        If lsprofiling is enabled (i.e. by --lsprof-time to bzr selftest) then
 
634
        this will cause lsprofile statistics to be gathered and stored in
 
635
        self._benchcalls.
 
636
        """
 
637
        if self._benchtime is None:
 
638
            self._benchtime = 0
 
639
        start = time.time()
 
640
        try:
 
641
            if not self._gather_lsprof_in_benchmarks:
 
642
                return callable(*args, **kwargs)
 
643
            else:
 
644
                # record this benchmark
 
645
                ret, stats = bzrlib.lsprof.profile(callable, *args, **kwargs)
 
646
                stats.sort()
 
647
                self._benchcalls.append(((callable, args, kwargs), stats))
 
648
                return ret
 
649
        finally:
 
650
            self._benchtime += time.time() - start
 
651
 
419
652
    def _runCleanups(self):
420
653
        """Run registered cleanup functions. 
421
654
 
441
674
        """Shortcut that splits cmd into words, runs, and returns stdout"""
442
675
        return self.run_bzr_captured(cmd.split(), retcode=retcode)[0]
443
676
 
444
 
    def run_bzr_captured(self, argv, retcode=0):
 
677
    def run_bzr_captured(self, argv, retcode=0, encoding=None, stdin=None):
445
678
        """Invoke bzr and return (stdout, stderr).
446
679
 
447
680
        Useful for code that wants to check the contents of the
458
691
        errors, and with logging set to something approximating the
459
692
        default, so that error reporting can be checked.
460
693
 
461
 
        argv -- arguments to invoke bzr
462
 
        retcode -- expected return code, or None for don't-care.
 
694
        :param argv: arguments to invoke bzr
 
695
        :param retcode: expected return code, or None for don't-care.
 
696
        :param encoding: encoding for sys.stdout and sys.stderr
 
697
        :param stdin: A string to be used as stdin for the command.
463
698
        """
464
 
        stdout = StringIO()
465
 
        stderr = StringIO()
466
 
        self.log('run bzr: %s', ' '.join(argv))
 
699
        if encoding is None:
 
700
            encoding = bzrlib.user_encoding
 
701
        if stdin is not None:
 
702
            stdin = StringIO(stdin)
 
703
        stdout = StringIOWrapper()
 
704
        stderr = StringIOWrapper()
 
705
        stdout.encoding = encoding
 
706
        stderr.encoding = encoding
 
707
 
 
708
        self.log('run bzr: %r', argv)
467
709
        # FIXME: don't call into logging here
468
710
        handler = logging.StreamHandler(stderr)
469
 
        handler.setFormatter(bzrlib.trace.QuietFormatter())
470
711
        handler.setLevel(logging.INFO)
471
712
        logger = logging.getLogger('')
472
713
        logger.addHandler(handler)
 
714
        old_ui_factory = bzrlib.ui.ui_factory
 
715
        bzrlib.ui.ui_factory = bzrlib.tests.blackbox.TestUIFactory(
 
716
            stdout=stdout,
 
717
            stderr=stderr)
 
718
        bzrlib.ui.ui_factory.stdin = stdin
473
719
        try:
474
 
            result = self.apply_redirected(None, stdout, stderr,
 
720
            result = self.apply_redirected(stdin, stdout, stderr,
475
721
                                           bzrlib.commands.run_bzr_catch_errors,
476
722
                                           argv)
477
723
        finally:
478
724
            logger.removeHandler(handler)
 
725
            bzrlib.ui.ui_factory = old_ui_factory
 
726
 
479
727
        out = stdout.getvalue()
480
728
        err = stderr.getvalue()
481
729
        if out:
482
 
            self.log('output:\n%s', out)
 
730
            self.log('output:\n%r', out)
483
731
        if err:
484
 
            self.log('errors:\n%s', err)
 
732
            self.log('errors:\n%r', err)
485
733
        if retcode is not None:
486
 
            self.assertEquals(result, retcode)
 
734
            self.assertEquals(retcode, result)
487
735
        return out, err
488
736
 
489
737
    def run_bzr(self, *args, **kwargs):
495
743
 
496
744
        This sends the stdout/stderr results into the test's log,
497
745
        where it may be useful for debugging.  See also run_captured.
 
746
 
 
747
        :param stdin: A string to be used as stdin for the command.
498
748
        """
499
749
        retcode = kwargs.pop('retcode', 0)
500
 
        return self.run_bzr_captured(args, retcode)
 
750
        encoding = kwargs.pop('encoding', None)
 
751
        stdin = kwargs.pop('stdin', None)
 
752
        return self.run_bzr_captured(args, retcode=retcode, encoding=encoding, stdin=stdin)
 
753
 
 
754
    def run_bzr_decode(self, *args, **kwargs):
 
755
        if kwargs.has_key('encoding'):
 
756
            encoding = kwargs['encoding']
 
757
        else:
 
758
            encoding = bzrlib.user_encoding
 
759
        return self.run_bzr(*args, **kwargs)[0].decode(encoding)
 
760
 
 
761
    def run_bzr_error(self, error_regexes, *args, **kwargs):
 
762
        """Run bzr, and check that stderr contains the supplied regexes
 
763
        
 
764
        :param error_regexes: Sequence of regular expressions which 
 
765
            must each be found in the error output. The relative ordering
 
766
            is not enforced.
 
767
        :param args: command-line arguments for bzr
 
768
        :param kwargs: Keyword arguments which are interpreted by run_bzr
 
769
            This function changes the default value of retcode to be 3,
 
770
            since in most cases this is run when you expect bzr to fail.
 
771
        :return: (out, err) The actual output of running the command (in case you
 
772
                 want to do more inspection)
 
773
 
 
774
        Examples of use:
 
775
            # Make sure that commit is failing because there is nothing to do
 
776
            self.run_bzr_error(['no changes to commit'],
 
777
                               'commit', '-m', 'my commit comment')
 
778
            # Make sure --strict is handling an unknown file, rather than
 
779
            # giving us the 'nothing to do' error
 
780
            self.build_tree(['unknown'])
 
781
            self.run_bzr_error(['Commit refused because there are unknown files'],
 
782
                               'commit', '--strict', '-m', 'my commit comment')
 
783
        """
 
784
        kwargs.setdefault('retcode', 3)
 
785
        out, err = self.run_bzr(*args, **kwargs)
 
786
        for regex in error_regexes:
 
787
            self.assertContainsRe(err, regex)
 
788
        return out, err
 
789
 
 
790
    def run_bzr_subprocess(self, *args, **kwargs):
 
791
        """Run bzr in a subprocess for testing.
 
792
 
 
793
        This starts a new Python interpreter and runs bzr in there. 
 
794
        This should only be used for tests that have a justifiable need for
 
795
        this isolation: e.g. they are testing startup time, or signal
 
796
        handling, or early startup code, etc.  Subprocess code can't be 
 
797
        profiled or debugged so easily.
 
798
 
 
799
        :param retcode: The status code that is expected.  Defaults to 0.  If
 
800
        None is supplied, the status code is not checked.
 
801
        """
 
802
        bzr_path = os.path.dirname(os.path.dirname(bzrlib.__file__))+'/bzr'
 
803
        args = list(args)
 
804
        process = Popen([sys.executable, bzr_path]+args, stdout=PIPE, 
 
805
                         stderr=PIPE)
 
806
        out = process.stdout.read()
 
807
        err = process.stderr.read()
 
808
        retcode = process.wait()
 
809
        supplied_retcode = kwargs.get('retcode', 0)
 
810
        if supplied_retcode is not None:
 
811
            assert supplied_retcode == retcode
 
812
        return [out, err]
501
813
 
502
814
    def check_inventory_shape(self, inv, shape):
503
815
        """Compare an inventory to a list of expected names.
668
980
        for name in shape:
669
981
            self.assert_(isinstance(name, basestring))
670
982
            if name[-1] == '/':
671
 
                transport.mkdir(urlescape(name[:-1]))
 
983
                transport.mkdir(urlutils.escape(name[:-1]))
672
984
            else:
673
985
                if line_endings == 'binary':
674
986
                    end = '\n'
676
988
                    end = os.linesep
677
989
                else:
678
990
                    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))
 
991
                content = "contents of %s%s" % (name.encode('utf-8'), end)
 
992
                transport.put(urlutils.escape(name), StringIO(content))
681
993
 
682
994
    def build_tree_contents(self, shape):
683
995
        build_tree_contents(shape)
693
1005
    def assertFileEqual(self, content, path):
694
1006
        """Fail if path does not contain 'content'."""
695
1007
        self.failUnless(osutils.lexists(path))
 
1008
        # TODO: jam 20060427 Shouldn't this be 'rb'?
696
1009
        self.assertEqualDiff(content, open(path, 'r').read())
697
1010
 
698
1011
 
774
1087
        if relpath is not None and relpath != '.':
775
1088
            if not base.endswith('/'):
776
1089
                base = base + '/'
777
 
            base = base + relpath
 
1090
            base = base + urlutils.escape(relpath)
778
1091
        return base
779
1092
 
780
1093
    def get_transport(self):
793
1106
        self.assertTrue(t.is_readonly())
794
1107
        return t
795
1108
 
796
 
    def make_branch(self, relpath):
 
1109
    def make_branch(self, relpath, format=None):
797
1110
        """Create a branch on the transport at relpath."""
798
 
        repo = self.make_repository(relpath)
 
1111
        repo = self.make_repository(relpath, format=format)
799
1112
        return repo.bzrdir.create_branch()
800
1113
 
801
 
    def make_bzrdir(self, relpath):
 
1114
    def make_bzrdir(self, relpath, format=None):
802
1115
        try:
803
1116
            url = self.get_url(relpath)
804
 
            segments = relpath.split('/')
 
1117
            mutter('relpath %r => url %r', relpath, url)
 
1118
            segments = url.split('/')
805
1119
            if segments and segments[-1] not in ('', '.'):
806
 
                parent = self.get_url('/'.join(segments[:-1]))
 
1120
                parent = '/'.join(segments[:-1])
807
1121
                t = get_transport(parent)
808
1122
                try:
809
1123
                    t.mkdir(segments[-1])
810
1124
                except errors.FileExists:
811
1125
                    pass
812
 
            return bzrlib.bzrdir.BzrDir.create(url)
 
1126
            if format is None:
 
1127
                format=bzrlib.bzrdir.BzrDirFormat.get_default_format()
 
1128
            # FIXME: make this use a single transport someday. RBC 20060418
 
1129
            return format.initialize_on_transport(get_transport(relpath))
813
1130
        except errors.UninitializableFormat:
814
 
            raise TestSkipped("Format %s is not initializable.")
 
1131
            raise TestSkipped("Format %s is not initializable." % format)
815
1132
 
816
 
    def make_repository(self, relpath, shared=False):
 
1133
    def make_repository(self, relpath, shared=False, format=None):
817
1134
        """Create a repository on our default transport at relpath."""
818
 
        made_control = self.make_bzrdir(relpath)
 
1135
        made_control = self.make_bzrdir(relpath, format=format)
819
1136
        return made_control.create_repository(shared=shared)
820
1137
 
821
 
    def make_branch_and_tree(self, relpath):
 
1138
    def make_branch_and_tree(self, relpath, format=None):
822
1139
        """Create a branch on the transport and a tree locally.
823
1140
 
824
1141
        Returns the tree.
827
1144
        # this obviously requires a format that supports branch references
828
1145
        # so check for that by checking bzrdir.BzrDirFormat.get_default_format()
829
1146
        # RBC 20060208
830
 
        b = self.make_branch(relpath)
 
1147
        b = self.make_branch(relpath, format=format)
831
1148
        try:
832
1149
            return b.bzrdir.create_workingtree()
833
1150
        except errors.NotLocalUrl:
872
1189
 
873
1190
 
874
1191
def filter_suite_by_re(suite, pattern):
875
 
    result = TestSuite()
 
1192
    result = TestUtil.TestSuite()
876
1193
    filter_re = re.compile(pattern)
877
1194
    for test in iter_suite_tests(suite):
878
1195
        if filter_re.search(test.id()):
882
1199
 
883
1200
def run_suite(suite, name='test', verbose=False, pattern=".*",
884
1201
              stop_on_failure=False, keep_output=False,
885
 
              transport=None):
 
1202
              transport=None, lsprof_timed=None):
886
1203
    TestCaseInTempDir._TEST_NAME = name
 
1204
    TestCase._gather_lsprof_in_benchmarks = lsprof_timed
887
1205
    if verbose:
888
1206
        verbosity = 2
 
1207
        pb = None
889
1208
    else:
890
1209
        verbosity = 1
 
1210
        pb = progress.ProgressBar()
891
1211
    runner = TextTestRunner(stream=sys.stdout,
892
1212
                            descriptions=0,
893
 
                            verbosity=verbosity)
 
1213
                            verbosity=verbosity,
 
1214
                            keep_output=keep_output,
 
1215
                            pb=pb)
894
1216
    runner.stop_on_failure=stop_on_failure
895
1217
    if pattern != '.*':
896
1218
        suite = filter_suite_by_re(suite, pattern)
897
1219
    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
1220
    return result.wasSuccessful()
912
1221
 
913
1222
 
914
1223
def selftest(verbose=False, pattern=".*", stop_on_failure=True,
915
1224
             keep_output=False,
916
 
             transport=None):
 
1225
             transport=None,
 
1226
             test_suite_factory=None,
 
1227
             lsprof_timed=None):
917
1228
    """Run the whole test suite under the enhanced runner"""
918
1229
    global default_transport
919
1230
    if transport is None:
920
1231
        transport = default_transport
921
1232
    old_transport = default_transport
922
1233
    default_transport = transport
923
 
    suite = test_suite()
924
1234
    try:
 
1235
        if test_suite_factory is None:
 
1236
            suite = test_suite()
 
1237
        else:
 
1238
            suite = test_suite_factory()
925
1239
        return run_suite(suite, 'testbzr', verbose=verbose, pattern=pattern,
926
1240
                     stop_on_failure=stop_on_failure, keep_output=keep_output,
927
 
                     transport=transport)
 
1241
                     transport=transport,
 
1242
                     lsprof_timed=lsprof_timed)
928
1243
    finally:
929
1244
        default_transport = old_transport
930
1245
 
931
1246
 
932
 
 
933
1247
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 = [ \
 
1248
    """Build and return TestSuite for the whole of bzrlib.
 
1249
    
 
1250
    This function can be replaced if you need to change the default test
 
1251
    suite on a global basis, but it is not encouraged.
 
1252
    """
 
1253
    testmod_names = [
940
1254
                   'bzrlib.tests.test_ancestry',
941
 
                   'bzrlib.tests.test_annotate',
942
1255
                   'bzrlib.tests.test_api',
943
1256
                   'bzrlib.tests.test_bad_files',
944
 
                   'bzrlib.tests.test_basis_inventory',
945
1257
                   'bzrlib.tests.test_branch',
 
1258
                   'bzrlib.tests.test_bundle',
946
1259
                   'bzrlib.tests.test_bzrdir',
947
1260
                   'bzrlib.tests.test_command',
948
1261
                   'bzrlib.tests.test_commit',
959
1272
                   'bzrlib.tests.test_graph',
960
1273
                   'bzrlib.tests.test_hashcache',
961
1274
                   'bzrlib.tests.test_http',
 
1275
                   'bzrlib.tests.test_http_response',
962
1276
                   'bzrlib.tests.test_identitymap',
 
1277
                   'bzrlib.tests.test_ignores',
963
1278
                   'bzrlib.tests.test_inv',
964
1279
                   'bzrlib.tests.test_knit',
965
1280
                   'bzrlib.tests.test_lockdir',
973
1288
                   'bzrlib.tests.test_nonascii',
974
1289
                   'bzrlib.tests.test_options',
975
1290
                   'bzrlib.tests.test_osutils',
 
1291
                   'bzrlib.tests.test_patch',
 
1292
                   'bzrlib.tests.test_patches',
976
1293
                   'bzrlib.tests.test_permissions',
977
1294
                   'bzrlib.tests.test_plugins',
978
1295
                   'bzrlib.tests.test_progress',
980
1297
                   'bzrlib.tests.test_repository',
981
1298
                   'bzrlib.tests.test_revision',
982
1299
                   'bzrlib.tests.test_revisionnamespaces',
983
 
                   'bzrlib.tests.test_revprops',
 
1300
                   'bzrlib.tests.test_revisiontree',
984
1301
                   'bzrlib.tests.test_rio',
985
1302
                   'bzrlib.tests.test_sampler',
986
1303
                   'bzrlib.tests.test_selftest',
988
1305
                   'bzrlib.tests.test_sftp_transport',
989
1306
                   'bzrlib.tests.test_smart_add',
990
1307
                   'bzrlib.tests.test_source',
 
1308
                   'bzrlib.tests.test_status',
991
1309
                   'bzrlib.tests.test_store',
992
1310
                   'bzrlib.tests.test_symbol_versioning',
993
1311
                   'bzrlib.tests.test_testament',
 
1312
                   'bzrlib.tests.test_textfile',
 
1313
                   'bzrlib.tests.test_textmerge',
994
1314
                   'bzrlib.tests.test_trace',
995
1315
                   'bzrlib.tests.test_transactions',
996
1316
                   'bzrlib.tests.test_transform',
997
1317
                   'bzrlib.tests.test_transport',
 
1318
                   'bzrlib.tests.test_tree',
998
1319
                   'bzrlib.tests.test_tsort',
 
1320
                   'bzrlib.tests.test_tuned_gzip',
999
1321
                   'bzrlib.tests.test_ui',
1000
1322
                   'bzrlib.tests.test_upgrade',
 
1323
                   'bzrlib.tests.test_urlutils',
1001
1324
                   'bzrlib.tests.test_versionedfile',
1002
1325
                   'bzrlib.tests.test_weave',
1003
1326
                   'bzrlib.tests.test_whitebox',
1005
1328
                   'bzrlib.tests.test_xml',
1006
1329
                   ]
1007
1330
    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()
 
1331
        'bzrlib.tests.test_transport_implementations',
 
1332
        'bzrlib.tests.test_read_bundle',
 
1333
        ]
 
1334
    suite = TestUtil.TestSuite()
 
1335
    loader = TestUtil.TestLoader()
 
1336
    suite.addTest(loader.loadTestsFromModuleNames(testmod_names))
1021
1337
    from bzrlib.transport import TransportTestProviderAdapter
1022
1338
    adapter = TransportTestProviderAdapter()
1023
1339
    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
1340
    for package in packages_to_test():
1028
1341
        suite.addTest(package.test_suite())
1029
1342
    for m in MODULES_TO_TEST:
1030
1343
        suite.addTest(loader.loadTestsFromModule(m))
1031
 
    for m in (MODULES_TO_DOCTEST):
1032
 
        suite.addTest(DocTestSuite(m))
 
1344
    for m in MODULES_TO_DOCTEST:
 
1345
        suite.addTest(doctest.DocTestSuite(m))
1033
1346
    for name, plugin in bzrlib.plugin.all_plugins().items():
1034
1347
        if getattr(plugin, 'test_suite', None) is not None:
1035
1348
            suite.addTest(plugin.test_suite())
1038
1351
 
1039
1352
def adapt_modules(mods_list, adapter, loader, suite):
1040
1353
    """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
 
1354
    for test in iter_suite_tests(loader.loadTestsFromModuleNames(mods_list)):
 
1355
        suite.addTests(adapter.adapt(test))