/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

  • Committer: John Arbash Meinel
  • Date: 2006-08-15 04:51:11 UTC
  • mfrom: (1922 +trunk)
  • mto: This revision was merged to the branch mainline in revision 1923.
  • Revision ID: john@arbash-meinel.com-20060815045111-1b6456aa306dd777
[merge] bzr.dev 1922

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,
 
597
            'BZREMAIL': None, # may still be present in the environment
386
598
            'EMAIL': None,
387
599
        }
388
600
        self.__old_env = {}
416
628
        self._runCleanups()
417
629
        unittest.TestCase.tearDown(self)
418
630
 
 
631
    def time(self, callable, *args, **kwargs):
 
632
        """Run callable and accrue the time it takes to the benchmark time.
 
633
        
 
634
        If lsprofiling is enabled (i.e. by --lsprof-time to bzr selftest) then
 
635
        this will cause lsprofile statistics to be gathered and stored in
 
636
        self._benchcalls.
 
637
        """
 
638
        if self._benchtime is None:
 
639
            self._benchtime = 0
 
640
        start = time.time()
 
641
        try:
 
642
            if not self._gather_lsprof_in_benchmarks:
 
643
                return callable(*args, **kwargs)
 
644
            else:
 
645
                # record this benchmark
 
646
                ret, stats = bzrlib.lsprof.profile(callable, *args, **kwargs)
 
647
                stats.sort()
 
648
                self._benchcalls.append(((callable, args, kwargs), stats))
 
649
                return ret
 
650
        finally:
 
651
            self._benchtime += time.time() - start
 
652
 
419
653
    def _runCleanups(self):
420
654
        """Run registered cleanup functions. 
421
655
 
441
675
        """Shortcut that splits cmd into words, runs, and returns stdout"""
442
676
        return self.run_bzr_captured(cmd.split(), retcode=retcode)[0]
443
677
 
444
 
    def run_bzr_captured(self, argv, retcode=0):
 
678
    def run_bzr_captured(self, argv, retcode=0, encoding=None, stdin=None):
445
679
        """Invoke bzr and return (stdout, stderr).
446
680
 
447
681
        Useful for code that wants to check the contents of the
458
692
        errors, and with logging set to something approximating the
459
693
        default, so that error reporting can be checked.
460
694
 
461
 
        argv -- arguments to invoke bzr
462
 
        retcode -- expected return code, or None for don't-care.
 
695
        :param argv: arguments to invoke bzr
 
696
        :param retcode: expected return code, or None for don't-care.
 
697
        :param encoding: encoding for sys.stdout and sys.stderr
 
698
        :param stdin: A string to be used as stdin for the command.
463
699
        """
464
 
        stdout = StringIO()
465
 
        stderr = StringIO()
466
 
        self.log('run bzr: %s', ' '.join(argv))
 
700
        if encoding is None:
 
701
            encoding = bzrlib.user_encoding
 
702
        if stdin is not None:
 
703
            stdin = StringIO(stdin)
 
704
        stdout = StringIOWrapper()
 
705
        stderr = StringIOWrapper()
 
706
        stdout.encoding = encoding
 
707
        stderr.encoding = encoding
 
708
 
 
709
        self.log('run bzr: %r', argv)
467
710
        # FIXME: don't call into logging here
468
711
        handler = logging.StreamHandler(stderr)
469
 
        handler.setFormatter(bzrlib.trace.QuietFormatter())
470
712
        handler.setLevel(logging.INFO)
471
713
        logger = logging.getLogger('')
472
714
        logger.addHandler(handler)
 
715
        old_ui_factory = bzrlib.ui.ui_factory
 
716
        bzrlib.ui.ui_factory = bzrlib.tests.blackbox.TestUIFactory(
 
717
            stdout=stdout,
 
718
            stderr=stderr)
 
719
        bzrlib.ui.ui_factory.stdin = stdin
473
720
        try:
474
 
            result = self.apply_redirected(None, stdout, stderr,
 
721
            result = self.apply_redirected(stdin, stdout, stderr,
475
722
                                           bzrlib.commands.run_bzr_catch_errors,
476
723
                                           argv)
477
724
        finally:
478
725
            logger.removeHandler(handler)
 
726
            bzrlib.ui.ui_factory = old_ui_factory
 
727
 
479
728
        out = stdout.getvalue()
480
729
        err = stderr.getvalue()
481
730
        if out:
482
 
            self.log('output:\n%s', out)
 
731
            self.log('output:\n%r', out)
483
732
        if err:
484
 
            self.log('errors:\n%s', err)
 
733
            self.log('errors:\n%r', err)
485
734
        if retcode is not None:
486
 
            self.assertEquals(result, retcode)
 
735
            self.assertEquals(retcode, result)
487
736
        return out, err
488
737
 
489
738
    def run_bzr(self, *args, **kwargs):
495
744
 
496
745
        This sends the stdout/stderr results into the test's log,
497
746
        where it may be useful for debugging.  See also run_captured.
 
747
 
 
748
        :param stdin: A string to be used as stdin for the command.
498
749
        """
499
750
        retcode = kwargs.pop('retcode', 0)
500
 
        return self.run_bzr_captured(args, retcode)
 
751
        encoding = kwargs.pop('encoding', None)
 
752
        stdin = kwargs.pop('stdin', None)
 
753
        return self.run_bzr_captured(args, retcode=retcode, encoding=encoding, stdin=stdin)
 
754
 
 
755
    def run_bzr_decode(self, *args, **kwargs):
 
756
        if kwargs.has_key('encoding'):
 
757
            encoding = kwargs['encoding']
 
758
        else:
 
759
            encoding = bzrlib.user_encoding
 
760
        return self.run_bzr(*args, **kwargs)[0].decode(encoding)
 
761
 
 
762
    def run_bzr_error(self, error_regexes, *args, **kwargs):
 
763
        """Run bzr, and check that stderr contains the supplied regexes
 
764
        
 
765
        :param error_regexes: Sequence of regular expressions which 
 
766
            must each be found in the error output. The relative ordering
 
767
            is not enforced.
 
768
        :param args: command-line arguments for bzr
 
769
        :param kwargs: Keyword arguments which are interpreted by run_bzr
 
770
            This function changes the default value of retcode to be 3,
 
771
            since in most cases this is run when you expect bzr to fail.
 
772
        :return: (out, err) The actual output of running the command (in case you
 
773
                 want to do more inspection)
 
774
 
 
775
        Examples of use:
 
776
            # Make sure that commit is failing because there is nothing to do
 
777
            self.run_bzr_error(['no changes to commit'],
 
778
                               'commit', '-m', 'my commit comment')
 
779
            # Make sure --strict is handling an unknown file, rather than
 
780
            # giving us the 'nothing to do' error
 
781
            self.build_tree(['unknown'])
 
782
            self.run_bzr_error(['Commit refused because there are unknown files'],
 
783
                               'commit', '--strict', '-m', 'my commit comment')
 
784
        """
 
785
        kwargs.setdefault('retcode', 3)
 
786
        out, err = self.run_bzr(*args, **kwargs)
 
787
        for regex in error_regexes:
 
788
            self.assertContainsRe(err, regex)
 
789
        return out, err
 
790
 
 
791
    def run_bzr_subprocess(self, *args, **kwargs):
 
792
        """Run bzr in a subprocess for testing.
 
793
 
 
794
        This starts a new Python interpreter and runs bzr in there. 
 
795
        This should only be used for tests that have a justifiable need for
 
796
        this isolation: e.g. they are testing startup time, or signal
 
797
        handling, or early startup code, etc.  Subprocess code can't be 
 
798
        profiled or debugged so easily.
 
799
 
 
800
        :param retcode: The status code that is expected.  Defaults to 0.  If
 
801
        None is supplied, the status code is not checked.
 
802
        """
 
803
        bzr_path = os.path.dirname(os.path.dirname(bzrlib.__file__))+'/bzr'
 
804
        args = list(args)
 
805
        process = Popen([sys.executable, bzr_path]+args, stdout=PIPE, 
 
806
                         stderr=PIPE)
 
807
        out = process.stdout.read()
 
808
        err = process.stderr.read()
 
809
        retcode = process.wait()
 
810
        supplied_retcode = kwargs.get('retcode', 0)
 
811
        if supplied_retcode is not None:
 
812
            assert supplied_retcode == retcode
 
813
        return [out, err]
501
814
 
502
815
    def check_inventory_shape(self, inv, shape):
503
816
        """Compare an inventory to a list of expected names.
652
965
        shape is a sequence of file specifications.  If the final
653
966
        character is '/', a directory is created.
654
967
 
 
968
        This assumes that all the elements in the tree being built are new.
 
969
 
655
970
        This doesn't add anything to a branch.
656
971
        :param line_endings: Either 'binary' or 'native'
657
972
                             in binary mode, exact contents are written
662
977
                          VFS's. If the transport is readonly or None,
663
978
                          "." is opened automatically.
664
979
        """
665
 
        # XXX: It's OK to just create them using forward slashes on windows?
 
980
        # It's OK to just create them using forward slashes on windows.
666
981
        if transport is None or transport.is_readonly():
667
982
            transport = get_transport(".")
668
983
        for name in shape:
669
984
            self.assert_(isinstance(name, basestring))
670
985
            if name[-1] == '/':
671
 
                transport.mkdir(urlescape(name[:-1]))
 
986
                transport.mkdir(urlutils.escape(name[:-1]))
672
987
            else:
673
988
                if line_endings == 'binary':
674
989
                    end = '\n'
676
991
                    end = os.linesep
677
992
                else:
678
993
                    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))
 
994
                content = "contents of %s%s" % (name.encode('utf-8'), end)
 
995
                # Technically 'put()' is the right command. However, put
 
996
                # uses an AtomicFile, which requires an extra rename into place
 
997
                # As long as the files didn't exist in the past, append() will
 
998
                # do the same thing as put()
 
999
                # On jam's machine, make_kernel_like_tree is:
 
1000
                #   put:    4.5-7.5s (averaging 6s)
 
1001
                #   append: 2.9-4.5s
 
1002
                transport.append(urlutils.escape(name), StringIO(content))
681
1003
 
682
1004
    def build_tree_contents(self, shape):
683
1005
        build_tree_contents(shape)
693
1015
    def assertFileEqual(self, content, path):
694
1016
        """Fail if path does not contain 'content'."""
695
1017
        self.failUnless(osutils.lexists(path))
 
1018
        # TODO: jam 20060427 Shouldn't this be 'rb'?
696
1019
        self.assertEqualDiff(content, open(path, 'r').read())
697
1020
 
698
1021
 
774
1097
        if relpath is not None and relpath != '.':
775
1098
            if not base.endswith('/'):
776
1099
                base = base + '/'
777
 
            base = base + relpath
 
1100
            base = base + urlutils.escape(relpath)
778
1101
        return base
779
1102
 
780
1103
    def get_transport(self):
793
1116
        self.assertTrue(t.is_readonly())
794
1117
        return t
795
1118
 
796
 
    def make_branch(self, relpath):
 
1119
    def make_branch(self, relpath, format=None):
797
1120
        """Create a branch on the transport at relpath."""
798
 
        repo = self.make_repository(relpath)
 
1121
        repo = self.make_repository(relpath, format=format)
799
1122
        return repo.bzrdir.create_branch()
800
1123
 
801
 
    def make_bzrdir(self, relpath):
 
1124
    def make_bzrdir(self, relpath, format=None):
802
1125
        try:
803
1126
            url = self.get_url(relpath)
804
 
            segments = relpath.split('/')
 
1127
            mutter('relpath %r => url %r', relpath, url)
 
1128
            segments = url.split('/')
805
1129
            if segments and segments[-1] not in ('', '.'):
806
 
                parent = self.get_url('/'.join(segments[:-1]))
 
1130
                parent = '/'.join(segments[:-1])
807
1131
                t = get_transport(parent)
808
1132
                try:
809
1133
                    t.mkdir(segments[-1])
810
1134
                except errors.FileExists:
811
1135
                    pass
812
 
            return bzrlib.bzrdir.BzrDir.create(url)
 
1136
            if format is None:
 
1137
                format=bzrlib.bzrdir.BzrDirFormat.get_default_format()
 
1138
            # FIXME: make this use a single transport someday. RBC 20060418
 
1139
            return format.initialize_on_transport(get_transport(relpath))
813
1140
        except errors.UninitializableFormat:
814
 
            raise TestSkipped("Format %s is not initializable.")
 
1141
            raise TestSkipped("Format %s is not initializable." % format)
815
1142
 
816
 
    def make_repository(self, relpath, shared=False):
 
1143
    def make_repository(self, relpath, shared=False, format=None):
817
1144
        """Create a repository on our default transport at relpath."""
818
 
        made_control = self.make_bzrdir(relpath)
 
1145
        made_control = self.make_bzrdir(relpath, format=format)
819
1146
        return made_control.create_repository(shared=shared)
820
1147
 
821
 
    def make_branch_and_tree(self, relpath):
 
1148
    def make_branch_and_tree(self, relpath, format=None):
822
1149
        """Create a branch on the transport and a tree locally.
823
1150
 
824
1151
        Returns the tree.
827
1154
        # this obviously requires a format that supports branch references
828
1155
        # so check for that by checking bzrdir.BzrDirFormat.get_default_format()
829
1156
        # RBC 20060208
830
 
        b = self.make_branch(relpath)
 
1157
        b = self.make_branch(relpath, format=format)
831
1158
        try:
832
1159
            return b.bzrdir.create_workingtree()
833
1160
        except errors.NotLocalUrl:
872
1199
 
873
1200
 
874
1201
def filter_suite_by_re(suite, pattern):
875
 
    result = TestSuite()
 
1202
    result = TestUtil.TestSuite()
876
1203
    filter_re = re.compile(pattern)
877
1204
    for test in iter_suite_tests(suite):
878
1205
        if filter_re.search(test.id()):
882
1209
 
883
1210
def run_suite(suite, name='test', verbose=False, pattern=".*",
884
1211
              stop_on_failure=False, keep_output=False,
885
 
              transport=None):
 
1212
              transport=None, lsprof_timed=None):
886
1213
    TestCaseInTempDir._TEST_NAME = name
 
1214
    TestCase._gather_lsprof_in_benchmarks = lsprof_timed
887
1215
    if verbose:
888
1216
        verbosity = 2
 
1217
        pb = None
889
1218
    else:
890
1219
        verbosity = 1
 
1220
        pb = progress.ProgressBar()
891
1221
    runner = TextTestRunner(stream=sys.stdout,
892
1222
                            descriptions=0,
893
 
                            verbosity=verbosity)
 
1223
                            verbosity=verbosity,
 
1224
                            keep_output=keep_output,
 
1225
                            pb=pb)
894
1226
    runner.stop_on_failure=stop_on_failure
895
1227
    if pattern != '.*':
896
1228
        suite = filter_suite_by_re(suite, pattern)
897
1229
    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
1230
    return result.wasSuccessful()
912
1231
 
913
1232
 
914
1233
def selftest(verbose=False, pattern=".*", stop_on_failure=True,
915
1234
             keep_output=False,
916
 
             transport=None):
 
1235
             transport=None,
 
1236
             test_suite_factory=None,
 
1237
             lsprof_timed=None):
917
1238
    """Run the whole test suite under the enhanced runner"""
 
1239
    # XXX: Very ugly way to do this...
 
1240
    # Disable warning about old formats because we don't want it to disturb
 
1241
    # any blackbox tests.
 
1242
    from bzrlib import repository
 
1243
    repository._deprecation_warning_done = True
 
1244
 
918
1245
    global default_transport
919
1246
    if transport is None:
920
1247
        transport = default_transport
921
1248
    old_transport = default_transport
922
1249
    default_transport = transport
923
 
    suite = test_suite()
924
1250
    try:
 
1251
        if test_suite_factory is None:
 
1252
            suite = test_suite()
 
1253
        else:
 
1254
            suite = test_suite_factory()
925
1255
        return run_suite(suite, 'testbzr', verbose=verbose, pattern=pattern,
926
1256
                     stop_on_failure=stop_on_failure, keep_output=keep_output,
927
 
                     transport=transport)
 
1257
                     transport=transport,
 
1258
                     lsprof_timed=lsprof_timed)
928
1259
    finally:
929
1260
        default_transport = old_transport
930
1261
 
931
1262
 
932
 
 
933
1263
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 = [ \
 
1264
    """Build and return TestSuite for the whole of bzrlib.
 
1265
    
 
1266
    This function can be replaced if you need to change the default test
 
1267
    suite on a global basis, but it is not encouraged.
 
1268
    """
 
1269
    testmod_names = [
940
1270
                   'bzrlib.tests.test_ancestry',
941
 
                   'bzrlib.tests.test_annotate',
942
1271
                   'bzrlib.tests.test_api',
 
1272
                   'bzrlib.tests.test_atomicfile',
943
1273
                   'bzrlib.tests.test_bad_files',
944
 
                   'bzrlib.tests.test_basis_inventory',
945
1274
                   'bzrlib.tests.test_branch',
 
1275
                   'bzrlib.tests.test_bundle',
946
1276
                   'bzrlib.tests.test_bzrdir',
947
1277
                   'bzrlib.tests.test_command',
948
1278
                   'bzrlib.tests.test_commit',
959
1289
                   'bzrlib.tests.test_graph',
960
1290
                   'bzrlib.tests.test_hashcache',
961
1291
                   'bzrlib.tests.test_http',
 
1292
                   'bzrlib.tests.test_http_response',
962
1293
                   'bzrlib.tests.test_identitymap',
 
1294
                   'bzrlib.tests.test_ignores',
963
1295
                   'bzrlib.tests.test_inv',
964
1296
                   'bzrlib.tests.test_knit',
965
1297
                   'bzrlib.tests.test_lockdir',
973
1305
                   'bzrlib.tests.test_nonascii',
974
1306
                   'bzrlib.tests.test_options',
975
1307
                   'bzrlib.tests.test_osutils',
 
1308
                   'bzrlib.tests.test_patch',
 
1309
                   'bzrlib.tests.test_patches',
976
1310
                   'bzrlib.tests.test_permissions',
977
1311
                   'bzrlib.tests.test_plugins',
978
1312
                   'bzrlib.tests.test_progress',
980
1314
                   'bzrlib.tests.test_repository',
981
1315
                   'bzrlib.tests.test_revision',
982
1316
                   'bzrlib.tests.test_revisionnamespaces',
983
 
                   'bzrlib.tests.test_revprops',
 
1317
                   'bzrlib.tests.test_revisiontree',
984
1318
                   'bzrlib.tests.test_rio',
985
1319
                   'bzrlib.tests.test_sampler',
986
1320
                   'bzrlib.tests.test_selftest',
988
1322
                   'bzrlib.tests.test_sftp_transport',
989
1323
                   'bzrlib.tests.test_smart_add',
990
1324
                   'bzrlib.tests.test_source',
 
1325
                   'bzrlib.tests.test_status',
991
1326
                   'bzrlib.tests.test_store',
992
1327
                   'bzrlib.tests.test_symbol_versioning',
993
1328
                   'bzrlib.tests.test_testament',
 
1329
                   'bzrlib.tests.test_textfile',
 
1330
                   'bzrlib.tests.test_textmerge',
994
1331
                   'bzrlib.tests.test_trace',
995
1332
                   'bzrlib.tests.test_transactions',
996
1333
                   'bzrlib.tests.test_transform',
997
1334
                   'bzrlib.tests.test_transport',
 
1335
                   'bzrlib.tests.test_tree',
998
1336
                   'bzrlib.tests.test_tsort',
 
1337
                   'bzrlib.tests.test_tuned_gzip',
999
1338
                   'bzrlib.tests.test_ui',
1000
1339
                   'bzrlib.tests.test_upgrade',
 
1340
                   'bzrlib.tests.test_urlutils',
1001
1341
                   'bzrlib.tests.test_versionedfile',
1002
1342
                   'bzrlib.tests.test_weave',
1003
1343
                   'bzrlib.tests.test_whitebox',
1005
1345
                   'bzrlib.tests.test_xml',
1006
1346
                   ]
1007
1347
    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()
 
1348
        'bzrlib.tests.test_transport_implementations',
 
1349
        'bzrlib.tests.test_read_bundle',
 
1350
        ]
 
1351
    suite = TestUtil.TestSuite()
 
1352
    loader = TestUtil.TestLoader()
 
1353
    suite.addTest(loader.loadTestsFromModuleNames(testmod_names))
1021
1354
    from bzrlib.transport import TransportTestProviderAdapter
1022
1355
    adapter = TransportTestProviderAdapter()
1023
1356
    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
1357
    for package in packages_to_test():
1028
1358
        suite.addTest(package.test_suite())
1029
1359
    for m in MODULES_TO_TEST:
1030
1360
        suite.addTest(loader.loadTestsFromModule(m))
1031
 
    for m in (MODULES_TO_DOCTEST):
1032
 
        suite.addTest(DocTestSuite(m))
 
1361
    for m in MODULES_TO_DOCTEST:
 
1362
        suite.addTest(doctest.DocTestSuite(m))
1033
1363
    for name, plugin in bzrlib.plugin.all_plugins().items():
1034
1364
        if getattr(plugin, 'test_suite', None) is not None:
1035
1365
            suite.addTest(plugin.test_suite())
1038
1368
 
1039
1369
def adapt_modules(mods_list, adapter, loader, suite):
1040
1370
    """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
 
1371
    for test in iter_suite_tests(loader.loadTestsFromModuleNames(mods_list)):
 
1372
        suite.addTests(adapter.adapt(test))