/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: Robert Collins
  • Date: 2007-07-04 08:08:13 UTC
  • mfrom: (2572 +trunk)
  • mto: This revision was merged to the branch mainline in revision 2587.
  • Revision ID: robertc@robertcollins.net-20070704080813-wzebx0r88fvwj5rq
Merge bzr.dev.

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
# Copyright (C) 2005, 2006 by Canonical Ltd
 
1
# Copyright (C) 2005, 2006, 2007 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
26
26
# general style of bzrlib.  Please continue that consistency when adding e.g.
27
27
# new assertFoo() methods.
28
28
 
 
29
import atexit
29
30
import codecs
30
31
from cStringIO import StringIO
31
32
import difflib
33
34
import errno
34
35
import logging
35
36
import os
 
37
from pprint import pformat
 
38
import random
36
39
import re
37
40
import shlex
38
41
import stat
41
44
import tempfile
42
45
import unittest
43
46
import time
44
 
 
45
 
 
46
 
from bzrlib import memorytree
 
47
import warnings
 
48
 
 
49
 
 
50
from bzrlib import (
 
51
    bzrdir,
 
52
    debug,
 
53
    errors,
 
54
    memorytree,
 
55
    osutils,
 
56
    progress,
 
57
    ui,
 
58
    urlutils,
 
59
    workingtree,
 
60
    )
47
61
import bzrlib.branch
48
 
import bzrlib.bzrdir as bzrdir
49
62
import bzrlib.commands
50
 
import bzrlib.bundle.serializer
51
 
import bzrlib.errors as errors
 
63
import bzrlib.timestamp
52
64
import bzrlib.export
53
65
import bzrlib.inventory
54
66
import bzrlib.iterablefile
61
73
from bzrlib.merge import merge_inner
62
74
import bzrlib.merge3
63
75
import bzrlib.osutils
64
 
import bzrlib.osutils as osutils
65
76
import bzrlib.plugin
66
 
import bzrlib.progress as progress
67
77
from bzrlib.revision import common_ancestor
68
78
import bzrlib.store
69
79
from bzrlib import symbol_versioning
 
80
from bzrlib.symbol_versioning import (
 
81
    deprecated_method,
 
82
    zero_eighteen,
 
83
    )
70
84
import bzrlib.trace
71
85
from bzrlib.transport import get_transport
72
86
import bzrlib.transport
73
 
from bzrlib.transport.local import LocalRelpathServer
 
87
from bzrlib.transport.local import LocalURLServer
 
88
from bzrlib.transport.memory import MemoryServer
74
89
from bzrlib.transport.readonly import ReadonlyServer
75
 
from bzrlib.trace import mutter
 
90
from bzrlib.trace import mutter, note
76
91
from bzrlib.tests import TestUtil
 
92
from bzrlib.tests.HttpServer import HttpServer
77
93
from bzrlib.tests.TestUtil import (
78
94
                          TestSuite,
79
95
                          TestLoader,
80
96
                          )
81
97
from bzrlib.tests.treeshape import build_tree_contents
82
 
import bzrlib.urlutils as urlutils
83
98
from bzrlib.workingtree import WorkingTree, WorkingTreeFormat2
84
99
 
85
 
default_transport = LocalRelpathServer
 
100
# Mark this python module as being part of the implementation
 
101
# of unittest: this gives us better tracebacks where the last
 
102
# shown frame is the test code, not our assertXYZ.
 
103
__unittest = 1
 
104
 
 
105
default_transport = LocalURLServer
86
106
 
87
107
MODULES_TO_TEST = []
88
108
MODULES_TO_DOCTEST = [
89
 
                      bzrlib.branch,
90
 
                      bzrlib.bundle.serializer,
91
 
                      bzrlib.commands,
 
109
                      bzrlib.timestamp,
92
110
                      bzrlib.errors,
93
111
                      bzrlib.export,
94
112
                      bzrlib.inventory,
96
114
                      bzrlib.lockdir,
97
115
                      bzrlib.merge3,
98
116
                      bzrlib.option,
99
 
                      bzrlib.osutils,
100
117
                      bzrlib.store,
101
 
                      bzrlib.transport,
102
118
                      ]
103
119
 
104
120
 
115
131
    import bzrlib.tests.interrepository_implementations
116
132
    import bzrlib.tests.interversionedfile_implementations
117
133
    import bzrlib.tests.intertree_implementations
 
134
    import bzrlib.tests.per_lock
118
135
    import bzrlib.tests.repository_implementations
119
136
    import bzrlib.tests.revisionstore_implementations
120
137
    import bzrlib.tests.tree_implementations
127
144
            bzrlib.tests.interrepository_implementations,
128
145
            bzrlib.tests.interversionedfile_implementations,
129
146
            bzrlib.tests.intertree_implementations,
 
147
            bzrlib.tests.per_lock,
130
148
            bzrlib.tests.repository_implementations,
131
149
            bzrlib.tests.revisionstore_implementations,
132
150
            bzrlib.tests.tree_implementations,
134
152
            ]
135
153
 
136
154
 
137
 
class _MyResult(unittest._TextTestResult):
138
 
    """Custom TestResult.
 
155
class ExtendedTestResult(unittest._TextTestResult):
 
156
    """Accepts, reports and accumulates the results of running tests.
139
157
 
140
 
    Shows output in a different format, including displaying runtime for tests.
 
158
    Compared to this unittest version this class adds support for profiling,
 
159
    benchmarking, stopping as soon as a test fails,  and skipping tests.
 
160
    There are further-specialized subclasses for different types of display.
141
161
    """
 
162
 
142
163
    stop_early = False
143
164
    
144
 
    def __init__(self, stream, descriptions, verbosity, pb=None,
145
 
                 bench_history=None):
 
165
    def __init__(self, stream, descriptions, verbosity,
 
166
                 bench_history=None,
 
167
                 num_tests=None,
 
168
                 use_numbered_dirs=False,
 
169
                 ):
146
170
        """Construct new TestResult.
147
171
 
148
172
        :param bench_history: Optionally, a writable file object to accumulate
149
173
            benchmark results.
150
174
        """
151
175
        unittest._TextTestResult.__init__(self, stream, descriptions, verbosity)
152
 
        self.pb = pb
153
176
        if bench_history is not None:
154
177
            from bzrlib.version import _get_bzr_source_tree
155
178
            src_tree = _get_bzr_source_tree()
165
188
                revision_id = ''
166
189
            bench_history.write("--date %s %s\n" % (time.time(), revision_id))
167
190
        self._bench_history = bench_history
 
191
        self.ui = ui.ui_factory
 
192
        self.num_tests = num_tests
 
193
        self.error_count = 0
 
194
        self.failure_count = 0
 
195
        self.known_failure_count = 0
 
196
        self.skip_count = 0
 
197
        self.unsupported = {}
 
198
        self.count = 0
 
199
        self.use_numbered_dirs = use_numbered_dirs
 
200
        self._overall_start_time = time.time()
168
201
    
169
202
    def extractBenchmarkTime(self, testCase):
170
203
        """Add a benchmark time for the current test case."""
180
213
                self._formatTime(self._benchmarkTime),
181
214
                self._elapsedTestTimeString())
182
215
        else:
183
 
            return "      %s" % self._elapsedTestTimeString()
 
216
            return "           %s" % self._elapsedTestTimeString()
184
217
 
185
218
    def _formatTime(self, seconds):
186
219
        """Format seconds as milliseconds with leading spaces."""
187
 
        return "%5dms" % (1000 * seconds)
 
220
        # some benchmarks can take thousands of seconds to run, so we need 8
 
221
        # places
 
222
        return "%8dms" % (1000 * seconds)
188
223
 
189
 
    def _ellipsise_unimportant_words(self, a_string, final_width,
190
 
                                   keep_start=False):
191
 
        """Add ellipses (sp?) for overly long strings.
192
 
        
193
 
        :param keep_start: If true preserve the start of a_string rather
194
 
                           than the end of it.
195
 
        """
196
 
        if keep_start:
197
 
            if len(a_string) > final_width:
198
 
                result = a_string[:final_width-3] + '...'
199
 
            else:
200
 
                result = a_string
201
 
        else:
202
 
            if len(a_string) > final_width:
203
 
                result = '...' + a_string[3-final_width:]
204
 
            else:
205
 
                result = a_string
206
 
        return result.ljust(final_width)
 
224
    def _shortened_test_description(self, test):
 
225
        what = test.id()
 
226
        what = re.sub(r'^bzrlib\.(tests|benchmarks)\.', '', what)
 
227
        return what
207
228
 
208
229
    def startTest(self, test):
209
230
        unittest.TestResult.startTest(self, test)
210
 
        # In a short description, the important words are in
211
 
        # the beginning, but in an id, the important words are
212
 
        # at the end
213
 
        SHOW_DESCRIPTIONS = False
214
 
 
215
 
        if not self.showAll and self.dots and self.pb is not None:
216
 
            final_width = 13
217
 
        else:
218
 
            final_width = osutils.terminal_width()
219
 
            final_width = final_width - 15 - 8
220
 
        what = None
221
 
        if SHOW_DESCRIPTIONS:
222
 
            what = test.shortDescription()
223
 
            if what:
224
 
                what = self._ellipsise_unimportant_words(what, final_width, keep_start=True)
225
 
        if what is None:
226
 
            what = test.id()
227
 
            if what.startswith('bzrlib.tests.'):
228
 
                what = what[13:]
229
 
            what = self._ellipsise_unimportant_words(what, final_width)
230
 
        if self.showAll:
231
 
            self.stream.write(what)
232
 
        elif self.dots and self.pb is not None:
233
 
            self.pb.update(what, self.testsRun - 1, None)
234
 
        self.stream.flush()
 
231
        self.report_test_start(test)
 
232
        test.number = self.count
235
233
        self._recordTestStartTime()
236
234
 
237
235
    def _recordTestStartTime(self):
238
236
        """Record that a test has started."""
239
237
        self._start_time = time.time()
240
238
 
 
239
    def _cleanupLogFile(self, test):
 
240
        # We can only do this if we have one of our TestCases, not if
 
241
        # we have a doctest.
 
242
        setKeepLogfile = getattr(test, 'setKeepLogfile', None)
 
243
        if setKeepLogfile is not None:
 
244
            setKeepLogfile()
 
245
 
241
246
    def addError(self, test, err):
 
247
        self.extractBenchmarkTime(test)
 
248
        self._cleanupLogFile(test)
242
249
        if isinstance(err[1], TestSkipped):
243
 
            return self.addSkipped(test, err)    
 
250
            return self.addSkipped(test, err)
 
251
        elif isinstance(err[1], UnavailableFeature):
 
252
            return self.addNotSupported(test, err[1].args[0])
244
253
        unittest.TestResult.addError(self, test, err)
245
 
        # We can only do this if we have one of our TestCases, not if
246
 
        # we have a doctest.
247
 
        setKeepLogfile = getattr(test, 'setKeepLogfile', None)
248
 
        if setKeepLogfile is not None:
249
 
            setKeepLogfile()
250
 
        self.extractBenchmarkTime(test)
251
 
        if self.showAll:
252
 
            self.stream.writeln("ERROR %s" % self._testTimeString())
253
 
        elif self.dots and self.pb is None:
254
 
            self.stream.write('E')
255
 
        elif self.dots:
256
 
            self.pb.update(self._ellipsise_unimportant_words('ERROR', 13), self.testsRun, None)
257
 
            self.pb.note(self._ellipsise_unimportant_words(
258
 
                            test.id() + ': ERROR',
259
 
                            osutils.terminal_width()))
260
 
        self.stream.flush()
 
254
        self.error_count += 1
 
255
        self.report_error(test, err)
261
256
        if self.stop_early:
262
257
            self.stop()
263
258
 
264
259
    def addFailure(self, test, err):
 
260
        self._cleanupLogFile(test)
 
261
        self.extractBenchmarkTime(test)
 
262
        if isinstance(err[1], KnownFailure):
 
263
            return self.addKnownFailure(test, err)
265
264
        unittest.TestResult.addFailure(self, test, err)
266
 
        # We can only do this if we have one of our TestCases, not if
267
 
        # we have a doctest.
268
 
        setKeepLogfile = getattr(test, 'setKeepLogfile', None)
269
 
        if setKeepLogfile is not None:
270
 
            setKeepLogfile()
271
 
        self.extractBenchmarkTime(test)
272
 
        if self.showAll:
273
 
            self.stream.writeln(" FAIL %s" % self._testTimeString())
274
 
        elif self.dots and self.pb is None:
275
 
            self.stream.write('F')
276
 
        elif self.dots:
277
 
            self.pb.update(self._ellipsise_unimportant_words('FAIL', 13), self.testsRun, None)
278
 
            self.pb.note(self._ellipsise_unimportant_words(
279
 
                            test.id() + ': FAIL',
280
 
                            osutils.terminal_width()))
281
 
        self.stream.flush()
 
265
        self.failure_count += 1
 
266
        self.report_failure(test, err)
282
267
        if self.stop_early:
283
268
            self.stop()
284
269
 
 
270
    def addKnownFailure(self, test, err):
 
271
        self.known_failure_count += 1
 
272
        self.report_known_failure(test, err)
 
273
 
 
274
    def addNotSupported(self, test, feature):
 
275
        self.unsupported.setdefault(str(feature), 0)
 
276
        self.unsupported[str(feature)] += 1
 
277
        self.report_unsupported(test, feature)
 
278
 
285
279
    def addSuccess(self, test):
286
280
        self.extractBenchmarkTime(test)
287
281
        if self._bench_history is not None:
289
283
                self._bench_history.write("%s %s\n" % (
290
284
                    self._formatTime(self._benchmarkTime),
291
285
                    test.id()))
292
 
        if self.showAll:
293
 
            self.stream.writeln('   OK %s' % self._testTimeString())
294
 
            for bench_called, stats in getattr(test, '_benchcalls', []):
295
 
                self.stream.writeln('LSProf output for %s(%s, %s)' % bench_called)
296
 
                stats.pprint(file=self.stream)
297
 
        elif self.dots and self.pb is None:
298
 
            self.stream.write('~')
299
 
        elif self.dots:
300
 
            self.pb.update(self._ellipsise_unimportant_words('OK', 13), self.testsRun, None)
301
 
        self.stream.flush()
 
286
        self.report_success(test)
302
287
        unittest.TestResult.addSuccess(self, test)
303
288
 
304
289
    def addSkipped(self, test, skip_excinfo):
305
 
        self.extractBenchmarkTime(test)
306
 
        if self.showAll:
307
 
            print >>self.stream, ' SKIP %s' % self._testTimeString()
308
 
            print >>self.stream, '     %s' % skip_excinfo[1]
309
 
        elif self.dots and self.pb is None:
310
 
            self.stream.write('S')
311
 
        elif self.dots:
312
 
            self.pb.update(self._ellipsise_unimportant_words('SKIP', 13), self.testsRun, None)
313
 
        self.stream.flush()
 
290
        self.report_skip(test, skip_excinfo)
314
291
        # seems best to treat this as success from point-of-view of unittest
315
292
        # -- it actually does nothing so it barely matters :)
316
293
        try:
325
302
    def printErrorList(self, flavour, errors):
326
303
        for test, err in errors:
327
304
            self.stream.writeln(self.separator1)
328
 
            self.stream.writeln("%s: %s" % (flavour, self.getDescription(test)))
 
305
            self.stream.write("%s: " % flavour)
 
306
            if self.use_numbered_dirs:
 
307
                self.stream.write('#%d ' % test.number)
 
308
            self.stream.writeln(self.getDescription(test))
329
309
            if getattr(test, '_get_log', None) is not None:
330
310
                print >>self.stream
331
311
                print >>self.stream, \
336
316
            self.stream.writeln(self.separator2)
337
317
            self.stream.writeln("%s" % err)
338
318
 
 
319
    def finished(self):
 
320
        pass
 
321
 
 
322
    def report_cleaning_up(self):
 
323
        pass
 
324
 
 
325
    def report_success(self, test):
 
326
        pass
 
327
 
 
328
 
 
329
class TextTestResult(ExtendedTestResult):
 
330
    """Displays progress and results of tests in text form"""
 
331
 
 
332
    def __init__(self, stream, descriptions, verbosity,
 
333
                 bench_history=None,
 
334
                 num_tests=None,
 
335
                 pb=None,
 
336
                 use_numbered_dirs=False,
 
337
                 ):
 
338
        ExtendedTestResult.__init__(self, stream, descriptions, verbosity,
 
339
            bench_history, num_tests, use_numbered_dirs)
 
340
        if pb is None:
 
341
            self.pb = self.ui.nested_progress_bar()
 
342
            self._supplied_pb = False
 
343
        else:
 
344
            self.pb = pb
 
345
            self._supplied_pb = True
 
346
        self.pb.show_pct = False
 
347
        self.pb.show_spinner = False
 
348
        self.pb.show_eta = False,
 
349
        self.pb.show_count = False
 
350
        self.pb.show_bar = False
 
351
 
 
352
    def report_starting(self):
 
353
        self.pb.update('[test 0/%d] starting...' % (self.num_tests))
 
354
 
 
355
    def _progress_prefix_text(self):
 
356
        a = '[%d' % self.count
 
357
        if self.num_tests is not None:
 
358
            a +='/%d' % self.num_tests
 
359
        a += ' in %ds' % (time.time() - self._overall_start_time)
 
360
        if self.error_count:
 
361
            a += ', %d errors' % self.error_count
 
362
        if self.failure_count:
 
363
            a += ', %d failed' % self.failure_count
 
364
        if self.known_failure_count:
 
365
            a += ', %d known failures' % self.known_failure_count
 
366
        if self.skip_count:
 
367
            a += ', %d skipped' % self.skip_count
 
368
        if self.unsupported:
 
369
            a += ', %d missing features' % len(self.unsupported)
 
370
        a += ']'
 
371
        return a
 
372
 
 
373
    def report_test_start(self, test):
 
374
        self.count += 1
 
375
        self.pb.update(
 
376
                self._progress_prefix_text()
 
377
                + ' ' 
 
378
                + self._shortened_test_description(test))
 
379
 
 
380
    def _test_description(self, test):
 
381
        if self.use_numbered_dirs:
 
382
            return '#%d %s' % (self.count,
 
383
                               self._shortened_test_description(test))
 
384
        else:
 
385
            return self._shortened_test_description(test)
 
386
 
 
387
    def report_error(self, test, err):
 
388
        self.pb.note('ERROR: %s\n    %s\n', 
 
389
            self._test_description(test),
 
390
            err[1],
 
391
            )
 
392
 
 
393
    def report_failure(self, test, err):
 
394
        self.pb.note('FAIL: %s\n    %s\n', 
 
395
            self._test_description(test),
 
396
            err[1],
 
397
            )
 
398
 
 
399
    def report_known_failure(self, test, err):
 
400
        self.pb.note('XFAIL: %s\n%s\n',
 
401
            self._test_description(test), err[1])
 
402
 
 
403
    def report_skip(self, test, skip_excinfo):
 
404
        self.skip_count += 1
 
405
        if False:
 
406
            # at the moment these are mostly not things we can fix
 
407
            # and so they just produce stipple; use the verbose reporter
 
408
            # to see them.
 
409
            if False:
 
410
                # show test and reason for skip
 
411
                self.pb.note('SKIP: %s\n    %s\n', 
 
412
                    self._shortened_test_description(test),
 
413
                    skip_excinfo[1])
 
414
            else:
 
415
                # since the class name was left behind in the still-visible
 
416
                # progress bar...
 
417
                self.pb.note('SKIP: %s', skip_excinfo[1])
 
418
 
 
419
    def report_unsupported(self, test, feature):
 
420
        """test cannot be run because feature is missing."""
 
421
                  
 
422
    def report_cleaning_up(self):
 
423
        self.pb.update('cleaning up...')
 
424
 
 
425
    def finished(self):
 
426
        if not self._supplied_pb:
 
427
            self.pb.finished()
 
428
 
 
429
 
 
430
class VerboseTestResult(ExtendedTestResult):
 
431
    """Produce long output, with one line per test run plus times"""
 
432
 
 
433
    def _ellipsize_to_right(self, a_string, final_width):
 
434
        """Truncate and pad a string, keeping the right hand side"""
 
435
        if len(a_string) > final_width:
 
436
            result = '...' + a_string[3-final_width:]
 
437
        else:
 
438
            result = a_string
 
439
        return result.ljust(final_width)
 
440
 
 
441
    def report_starting(self):
 
442
        self.stream.write('running %d tests...\n' % self.num_tests)
 
443
 
 
444
    def report_test_start(self, test):
 
445
        self.count += 1
 
446
        name = self._shortened_test_description(test)
 
447
        # width needs space for 6 char status, plus 1 for slash, plus 2 10-char
 
448
        # numbers, plus a trailing blank
 
449
        # when NUMBERED_DIRS: plus 5 chars on test number, plus 1 char on space
 
450
        if self.use_numbered_dirs:
 
451
            self.stream.write('%5d ' % self.count)
 
452
            self.stream.write(self._ellipsize_to_right(name,
 
453
                                osutils.terminal_width()-36))
 
454
        else:
 
455
            self.stream.write(self._ellipsize_to_right(name,
 
456
                                osutils.terminal_width()-30))
 
457
        self.stream.flush()
 
458
 
 
459
    def _error_summary(self, err):
 
460
        indent = ' ' * 4
 
461
        if self.use_numbered_dirs:
 
462
            indent += ' ' * 6
 
463
        return '%s%s' % (indent, err[1])
 
464
 
 
465
    def report_error(self, test, err):
 
466
        self.stream.writeln('ERROR %s\n%s'
 
467
                % (self._testTimeString(),
 
468
                   self._error_summary(err)))
 
469
 
 
470
    def report_failure(self, test, err):
 
471
        self.stream.writeln(' FAIL %s\n%s'
 
472
                % (self._testTimeString(),
 
473
                   self._error_summary(err)))
 
474
 
 
475
    def report_known_failure(self, test, err):
 
476
        self.stream.writeln('XFAIL %s\n%s'
 
477
                % (self._testTimeString(),
 
478
                   self._error_summary(err)))
 
479
 
 
480
    def report_success(self, test):
 
481
        self.stream.writeln('   OK %s' % self._testTimeString())
 
482
        for bench_called, stats in getattr(test, '_benchcalls', []):
 
483
            self.stream.writeln('LSProf output for %s(%s, %s)' % bench_called)
 
484
            stats.pprint(file=self.stream)
 
485
        # flush the stream so that we get smooth output. This verbose mode is
 
486
        # used to show the output in PQM.
 
487
        self.stream.flush()
 
488
 
 
489
    def report_skip(self, test, skip_excinfo):
 
490
        self.skip_count += 1
 
491
        self.stream.writeln(' SKIP %s\n%s'
 
492
                % (self._testTimeString(),
 
493
                   self._error_summary(skip_excinfo)))
 
494
 
 
495
    def report_unsupported(self, test, feature):
 
496
        """test cannot be run because feature is missing."""
 
497
        self.stream.writeln("NODEP %s\n    The feature '%s' is not available."
 
498
                %(self._testTimeString(), feature))
 
499
                  
 
500
 
339
501
 
340
502
class TextTestRunner(object):
341
503
    stop_on_failure = False
344
506
                 stream=sys.stderr,
345
507
                 descriptions=0,
346
508
                 verbosity=1,
347
 
                 keep_output=False,
348
 
                 pb=None,
349
 
                 bench_history=None):
 
509
                 bench_history=None,
 
510
                 use_numbered_dirs=False,
 
511
                 list_only=False
 
512
                 ):
350
513
        self.stream = unittest._WritelnDecorator(stream)
351
514
        self.descriptions = descriptions
352
515
        self.verbosity = verbosity
353
 
        self.keep_output = keep_output
354
 
        self.pb = pb
355
516
        self._bench_history = bench_history
356
 
 
357
 
    def _makeResult(self):
358
 
        result = _MyResult(self.stream,
359
 
                           self.descriptions,
360
 
                           self.verbosity,
361
 
                           pb=self.pb,
362
 
                           bench_history=self._bench_history)
363
 
        result.stop_early = self.stop_on_failure
364
 
        return result
 
517
        self.use_numbered_dirs = use_numbered_dirs
 
518
        self.list_only = list_only
365
519
 
366
520
    def run(self, test):
367
521
        "Run the given test case or test suite."
368
 
        result = self._makeResult()
369
522
        startTime = time.time()
370
 
        if self.pb is not None:
371
 
            self.pb.update('Running tests', 0, test.countTestCases())
372
 
        test.run(result)
 
523
        if self.verbosity == 1:
 
524
            result_class = TextTestResult
 
525
        elif self.verbosity >= 2:
 
526
            result_class = VerboseTestResult
 
527
        result = result_class(self.stream,
 
528
                              self.descriptions,
 
529
                              self.verbosity,
 
530
                              bench_history=self._bench_history,
 
531
                              num_tests=test.countTestCases(),
 
532
                              use_numbered_dirs=self.use_numbered_dirs,
 
533
                              )
 
534
        result.stop_early = self.stop_on_failure
 
535
        result.report_starting()
 
536
        if self.list_only:
 
537
            if self.verbosity >= 2:
 
538
                self.stream.writeln("Listing tests only ...\n")
 
539
            run = 0
 
540
            for t in iter_suite_tests(test):
 
541
                self.stream.writeln("%s" % (t.id()))
 
542
                run += 1
 
543
            actionTaken = "Listed"
 
544
        else: 
 
545
            test.run(result)
 
546
            run = result.testsRun
 
547
            actionTaken = "Ran"
373
548
        stopTime = time.time()
374
549
        timeTaken = stopTime - startTime
375
550
        result.printErrors()
376
551
        self.stream.writeln(result.separator2)
377
 
        run = result.testsRun
378
 
        self.stream.writeln("Ran %d test%s in %.3fs" %
379
 
                            (run, run != 1 and "s" or "", timeTaken))
 
552
        self.stream.writeln("%s %d test%s in %.3fs" % (actionTaken,
 
553
                            run, run != 1 and "s" or "", timeTaken))
380
554
        self.stream.writeln()
381
555
        if not result.wasSuccessful():
382
556
            self.stream.write("FAILED (")
386
560
            if errored:
387
561
                if failed: self.stream.write(", ")
388
562
                self.stream.write("errors=%d" % errored)
 
563
            if result.known_failure_count:
 
564
                if failed or errored: self.stream.write(", ")
 
565
                self.stream.write("known_failure_count=%d" %
 
566
                    result.known_failure_count)
389
567
            self.stream.writeln(")")
390
568
        else:
391
 
            self.stream.writeln("OK")
392
 
        if self.pb is not None:
393
 
            self.pb.update('Cleaning up', 0, 1)
394
 
        # This is still a little bogus, 
395
 
        # but only a little. Folk not using our testrunner will
396
 
        # have to delete their temp directories themselves.
397
 
        test_root = TestCaseInTempDir.TEST_ROOT
398
 
        if result.wasSuccessful() or not self.keep_output:
399
 
            if test_root is not None:
400
 
                # If LANG=C we probably have created some bogus paths
401
 
                # which rmtree(unicode) will fail to delete
402
 
                # so make sure we are using rmtree(str) to delete everything
403
 
                # except on win32, where rmtree(str) will fail
404
 
                # since it doesn't have the property of byte-stream paths
405
 
                # (they are either ascii or mbcs)
406
 
                if sys.platform == 'win32':
407
 
                    # make sure we are using the unicode win32 api
408
 
                    test_root = unicode(test_root)
409
 
                else:
410
 
                    test_root = test_root.encode(
411
 
                        sys.getfilesystemencoding())
412
 
                osutils.rmtree(test_root)
413
 
        else:
414
 
            if self.pb is not None:
415
 
                self.pb.note("Failed tests working directories are in '%s'\n",
416
 
                             test_root)
 
569
            if result.known_failure_count:
 
570
                self.stream.writeln("OK (known_failures=%d)" %
 
571
                    result.known_failure_count)
417
572
            else:
418
 
                self.stream.writeln(
419
 
                    "Failed tests working directories are in '%s'\n" %
420
 
                    test_root)
421
 
        TestCaseInTempDir.TEST_ROOT = None
422
 
        if self.pb is not None:
423
 
            self.pb.clear()
 
573
                self.stream.writeln("OK")
 
574
        if result.skip_count > 0:
 
575
            skipped = result.skip_count
 
576
            self.stream.writeln('%d test%s skipped' %
 
577
                                (skipped, skipped != 1 and "s" or ""))
 
578
        if result.unsupported:
 
579
            for feature, count in sorted(result.unsupported.items()):
 
580
                self.stream.writeln("Missing feature '%s' skipped %d tests." %
 
581
                    (feature, count))
 
582
        result.finished()
424
583
        return result
425
584
 
426
585
 
441
600
    """Indicates that a test was intentionally skipped, rather than failing."""
442
601
 
443
602
 
 
603
class KnownFailure(AssertionError):
 
604
    """Indicates that a test failed in a precisely expected manner.
 
605
 
 
606
    Such failures dont block the whole test suite from passing because they are
 
607
    indicators of partially completed code or of future work. We have an
 
608
    explicit error for them so that we can ensure that they are always visible:
 
609
    KnownFailures are always shown in the output of bzr selftest.
 
610
    """
 
611
 
 
612
 
 
613
class UnavailableFeature(Exception):
 
614
    """A feature required for this test was not available.
 
615
 
 
616
    The feature should be used to construct the exception.
 
617
    """
 
618
 
 
619
 
444
620
class CommandFailed(Exception):
445
621
    pass
446
622
 
471
647
            return setattr(self._cstring, name, val)
472
648
 
473
649
 
 
650
class TestUIFactory(ui.CLIUIFactory):
 
651
    """A UI Factory for testing.
 
652
 
 
653
    Hide the progress bar but emit note()s.
 
654
    Redirect stdin.
 
655
    Allows get_password to be tested without real tty attached.
 
656
    """
 
657
 
 
658
    def __init__(self,
 
659
                 stdout=None,
 
660
                 stderr=None,
 
661
                 stdin=None):
 
662
        super(TestUIFactory, self).__init__()
 
663
        if stdin is not None:
 
664
            # We use a StringIOWrapper to be able to test various
 
665
            # encodings, but the user is still responsible to
 
666
            # encode the string and to set the encoding attribute
 
667
            # of StringIOWrapper.
 
668
            self.stdin = StringIOWrapper(stdin)
 
669
        if stdout is None:
 
670
            self.stdout = sys.stdout
 
671
        else:
 
672
            self.stdout = stdout
 
673
        if stderr is None:
 
674
            self.stderr = sys.stderr
 
675
        else:
 
676
            self.stderr = stderr
 
677
 
 
678
    def clear(self):
 
679
        """See progress.ProgressBar.clear()."""
 
680
 
 
681
    def clear_term(self):
 
682
        """See progress.ProgressBar.clear_term()."""
 
683
 
 
684
    def clear_term(self):
 
685
        """See progress.ProgressBar.clear_term()."""
 
686
 
 
687
    def finished(self):
 
688
        """See progress.ProgressBar.finished()."""
 
689
 
 
690
    def note(self, fmt_string, *args, **kwargs):
 
691
        """See progress.ProgressBar.note()."""
 
692
        self.stdout.write((fmt_string + "\n") % args)
 
693
 
 
694
    def progress_bar(self):
 
695
        return self
 
696
 
 
697
    def nested_progress_bar(self):
 
698
        return self
 
699
 
 
700
    def update(self, message, count=None, total=None):
 
701
        """See progress.ProgressBar.update()."""
 
702
 
 
703
    def get_non_echoed_password(self, prompt):
 
704
        """Get password from stdin without trying to handle the echo mode"""
 
705
        if prompt:
 
706
            self.stdout.write(prompt.encode(self.stdout.encoding, 'replace'))
 
707
        password = self.stdin.readline()
 
708
        if not password:
 
709
            raise EOFError
 
710
        if password[-1] == '\n':
 
711
            password = password[:-1]
 
712
        return password
 
713
 
 
714
 
474
715
class TestCase(unittest.TestCase):
475
716
    """Base class for bzr unit tests.
476
717
    
506
747
        unittest.TestCase.setUp(self)
507
748
        self._cleanEnvironment()
508
749
        bzrlib.trace.disable_default_logging()
 
750
        self._silenceUI()
509
751
        self._startLogFile()
510
752
        self._benchcalls = []
511
753
        self._benchtime = None
 
754
        self._clear_hooks()
 
755
        self._clear_debug_flags()
 
756
 
 
757
    def _clear_debug_flags(self):
 
758
        """Prevent externally set debug flags affecting tests.
 
759
        
 
760
        Tests that want to use debug flags can just set them in the
 
761
        debug_flags set during setup/teardown.
 
762
        """
 
763
        self._preserved_debug_flags = set(debug.debug_flags)
 
764
        debug.debug_flags.clear()
 
765
        self.addCleanup(self._restore_debug_flags)
 
766
 
 
767
    def _clear_hooks(self):
 
768
        # prevent hooks affecting tests
 
769
        import bzrlib.branch
 
770
        import bzrlib.smart.server
 
771
        self._preserved_hooks = {
 
772
            bzrlib.branch.Branch: bzrlib.branch.Branch.hooks,
 
773
            bzrlib.smart.server.SmartTCPServer: bzrlib.smart.server.SmartTCPServer.hooks,
 
774
            }
 
775
        self.addCleanup(self._restoreHooks)
 
776
        # reset all hooks to an empty instance of the appropriate type
 
777
        bzrlib.branch.Branch.hooks = bzrlib.branch.BranchHooks()
 
778
        bzrlib.smart.server.SmartTCPServer.hooks = bzrlib.smart.server.SmartServerHooks()
 
779
 
 
780
    def _silenceUI(self):
 
781
        """Turn off UI for duration of test"""
 
782
        # by default the UI is off; tests can turn it on if they want it.
 
783
        saved = ui.ui_factory
 
784
        def _restore():
 
785
            ui.ui_factory = saved
 
786
        ui.ui_factory = ui.SilentUIFactory()
 
787
        self.addCleanup(_restore)
512
788
 
513
789
    def _ndiff_strings(self, a, b):
514
790
        """Return ndiff between two strings containing lines.
525
801
                                  charjunk=lambda x: False)
526
802
        return ''.join(difflines)
527
803
 
 
804
    def assertEqual(self, a, b, message=''):
 
805
        try:
 
806
            if a == b:
 
807
                return
 
808
        except UnicodeError, e:
 
809
            # If we can't compare without getting a UnicodeError, then
 
810
            # obviously they are different
 
811
            mutter('UnicodeError: %s', e)
 
812
        if message:
 
813
            message += '\n'
 
814
        raise AssertionError("%snot equal:\na = %s\nb = %s\n"
 
815
            % (message,
 
816
               pformat(a), pformat(b)))
 
817
 
 
818
    assertEquals = assertEqual
 
819
 
528
820
    def assertEqualDiff(self, a, b, message=None):
529
821
        """Assert two texts are equal, if not raise an exception.
530
822
        
555
847
    def assertContainsRe(self, haystack, needle_re):
556
848
        """Assert that a contains something matching a regular expression."""
557
849
        if not re.search(needle_re, haystack):
558
 
            raise AssertionError('pattern "%s" not found in "%s"'
 
850
            raise AssertionError('pattern "%r" not found in "%r"'
559
851
                    % (needle_re, haystack))
560
852
 
561
853
    def assertNotContainsRe(self, haystack, needle_re):
574
866
            raise AssertionError("value(s) %r not present in container %r" % 
575
867
                                 (missing, superlist))
576
868
 
577
 
    def assertIs(self, left, right):
 
869
    def assertListRaises(self, excClass, func, *args, **kwargs):
 
870
        """Fail unless excClass is raised when the iterator from func is used.
 
871
        
 
872
        Many functions can return generators this makes sure
 
873
        to wrap them in a list() call to make sure the whole generator
 
874
        is run, and that the proper exception is raised.
 
875
        """
 
876
        try:
 
877
            list(func(*args, **kwargs))
 
878
        except excClass:
 
879
            return
 
880
        else:
 
881
            if getattr(excClass,'__name__', None) is not None:
 
882
                excName = excClass.__name__
 
883
            else:
 
884
                excName = str(excClass)
 
885
            raise self.failureException, "%s not raised" % excName
 
886
 
 
887
    def assertRaises(self, excClass, callableObj, *args, **kwargs):
 
888
        """Assert that a callable raises a particular exception.
 
889
 
 
890
        :param excClass: As for the except statement, this may be either an
 
891
            exception class, or a tuple of classes.
 
892
        :param callableObj: A callable, will be passed ``*args`` and
 
893
            ``**kwargs``.
 
894
 
 
895
        Returns the exception so that you can examine it.
 
896
        """
 
897
        try:
 
898
            callableObj(*args, **kwargs)
 
899
        except excClass, e:
 
900
            return e
 
901
        else:
 
902
            if getattr(excClass,'__name__', None) is not None:
 
903
                excName = excClass.__name__
 
904
            else:
 
905
                # probably a tuple
 
906
                excName = str(excClass)
 
907
            raise self.failureException, "%s not raised" % excName
 
908
 
 
909
    def assertIs(self, left, right, message=None):
578
910
        if not (left is right):
579
 
            raise AssertionError("%r is not %r." % (left, right))
 
911
            if message is not None:
 
912
                raise AssertionError(message)
 
913
            else:
 
914
                raise AssertionError("%r is not %r." % (left, right))
 
915
 
 
916
    def assertIsNot(self, left, right, message=None):
 
917
        if (left is right):
 
918
            if message is not None:
 
919
                raise AssertionError(message)
 
920
            else:
 
921
                raise AssertionError("%r is %r." % (left, right))
580
922
 
581
923
    def assertTransportMode(self, transport, path, mode):
582
924
        """Fail if a path does not have mode mode.
596
938
            self.fail("%r is an instance of %s rather than %s" % (
597
939
                obj, obj.__class__, kls))
598
940
 
 
941
    def expectFailure(self, reason, assertion, *args, **kwargs):
 
942
        """Invoke a test, expecting it to fail for the given reason.
 
943
 
 
944
        This is for assertions that ought to succeed, but currently fail.
 
945
        (The failure is *expected* but not *wanted*.)  Please be very precise
 
946
        about the failure you're expecting.  If a new bug is introduced,
 
947
        AssertionError should be raised, not KnownFailure.
 
948
 
 
949
        Frequently, expectFailure should be followed by an opposite assertion.
 
950
        See example below.
 
951
 
 
952
        Intended to be used with a callable that raises AssertionError as the
 
953
        'assertion' parameter.  args and kwargs are passed to the 'assertion'.
 
954
 
 
955
        Raises KnownFailure if the test fails.  Raises AssertionError if the
 
956
        test succeeds.
 
957
 
 
958
        example usage::
 
959
 
 
960
          self.expectFailure('Math is broken', self.assertNotEqual, 54,
 
961
                             dynamic_val)
 
962
          self.assertEqual(42, dynamic_val)
 
963
 
 
964
          This means that a dynamic_val of 54 will cause the test to raise
 
965
          a KnownFailure.  Once math is fixed and the expectFailure is removed,
 
966
          only a dynamic_val of 42 will allow the test to pass.  Anything other
 
967
          than 54 or 42 will cause an AssertionError.
 
968
        """
 
969
        try:
 
970
            assertion(*args, **kwargs)
 
971
        except AssertionError:
 
972
            raise KnownFailure(reason)
 
973
        else:
 
974
            self.fail('Unexpected success.  Should have failed: %s' % reason)
 
975
 
599
976
    def _capture_warnings(self, a_callable, *args, **kwargs):
600
977
        """A helper for callDeprecated and applyDeprecated.
601
978
 
603
980
        :param args: The positional arguments for the callable
604
981
        :param kwargs: The keyword arguments for the callable
605
982
        :return: A tuple (warnings, result). result is the result of calling
606
 
            a_callable(*args, **kwargs).
 
983
            a_callable(``*args``, ``**kwargs``).
607
984
        """
608
985
        local_warnings = []
609
 
        def capture_warnings(msg, cls, stacklevel=None):
 
986
        def capture_warnings(msg, cls=None, stacklevel=None):
610
987
            # we've hooked into a deprecation specific callpath,
611
988
            # only deprecations should getting sent via it.
612
989
            self.assertEqual(cls, DeprecationWarning)
622
999
    def applyDeprecated(self, deprecation_format, a_callable, *args, **kwargs):
623
1000
        """Call a deprecated callable without warning the user.
624
1001
 
 
1002
        Note that this only captures warnings raised by symbol_versioning.warn,
 
1003
        not other callers that go direct to the warning module.
 
1004
 
625
1005
        :param deprecation_format: The deprecation format that the callable
626
 
            should have been deprecated with. This is the same type as the 
627
 
            parameter to deprecated_method/deprecated_function. If the 
 
1006
            should have been deprecated with. This is the same type as the
 
1007
            parameter to deprecated_method/deprecated_function. If the
628
1008
            callable is not deprecated with this format, an assertion error
629
1009
            will be raised.
630
1010
        :param a_callable: A callable to call. This may be a bound method or
631
 
            a regular function. It will be called with *args and **kwargs.
 
1011
            a regular function. It will be called with ``*args`` and
 
1012
            ``**kwargs``.
632
1013
        :param args: The positional arguments for the callable
633
1014
        :param kwargs: The keyword arguments for the callable
634
 
        :return: The result of a_callable(*args, **kwargs)
 
1015
        :return: The result of a_callable(``*args``, ``**kwargs``)
635
1016
        """
636
1017
        call_warnings, result = self._capture_warnings(a_callable,
637
1018
            *args, **kwargs)
638
1019
        expected_first_warning = symbol_versioning.deprecation_string(
639
1020
            a_callable, deprecation_format)
640
1021
        if len(call_warnings) == 0:
641
 
            self.fail("No assertion generated by call to %s" %
 
1022
            self.fail("No deprecation warning generated by call to %s" %
642
1023
                a_callable)
643
1024
        self.assertEqual(expected_first_warning, call_warnings[0])
644
1025
        return result
651
1032
        as it allows you to simply specify the deprecation format being used
652
1033
        and will ensure that that is issued for the function being called.
653
1034
 
 
1035
        Note that this only captures warnings raised by symbol_versioning.warn,
 
1036
        not other callers that go direct to the warning module.
 
1037
 
654
1038
        :param expected: a list of the deprecation warnings expected, in order
655
1039
        :param callable: The callable to call
656
1040
        :param args: The positional arguments for the callable
703
1087
 
704
1088
    def _cleanEnvironment(self):
705
1089
        new_env = {
 
1090
            'BZR_HOME': None, # Don't inherit BZR_HOME to all the tests.
706
1091
            'HOME': os.getcwd(),
707
 
            'APPDATA': os.getcwd(),
 
1092
            'APPDATA': None,  # bzr now use Win32 API and don't rely on APPDATA
708
1093
            'BZR_EMAIL': None,
709
1094
            'BZREMAIL': None, # may still be present in the environment
710
1095
            'EMAIL': None,
711
1096
            'BZR_PROGRESS_BAR': None,
 
1097
            # Proxies
 
1098
            'http_proxy': None,
 
1099
            'HTTP_PROXY': None,
 
1100
            'https_proxy': None,
 
1101
            'HTTPS_PROXY': None,
 
1102
            'no_proxy': None,
 
1103
            'NO_PROXY': None,
 
1104
            'all_proxy': None,
 
1105
            'ALL_PROXY': None,
 
1106
            # Nobody cares about these ones AFAIK. So far at
 
1107
            # least. If you do (care), please update this comment
 
1108
            # -- vila 20061212
 
1109
            'ftp_proxy': None,
 
1110
            'FTP_PROXY': None,
 
1111
            'BZR_REMOTE_PATH': None,
712
1112
        }
713
1113
        self.__old_env = {}
714
1114
        self.addCleanup(self._restoreEnvironment)
719
1119
        """Set an environment variable, and reset it when finished."""
720
1120
        self.__old_env[name] = osutils.set_or_unset_env(name, newvalue)
721
1121
 
 
1122
    def _restore_debug_flags(self):
 
1123
        debug.debug_flags.clear()
 
1124
        debug.debug_flags.update(self._preserved_debug_flags)
 
1125
 
722
1126
    def _restoreEnvironment(self):
723
1127
        for name, value in self.__old_env.iteritems():
724
1128
            osutils.set_or_unset_env(name, value)
725
1129
 
 
1130
    def _restoreHooks(self):
 
1131
        for klass, hooks in self._preserved_hooks.items():
 
1132
            setattr(klass, 'hooks', hooks)
 
1133
 
 
1134
    def knownFailure(self, reason):
 
1135
        """This test has failed for some known reason."""
 
1136
        raise KnownFailure(reason)
 
1137
 
 
1138
    def run(self, result=None):
 
1139
        if result is None: result = self.defaultTestResult()
 
1140
        for feature in getattr(self, '_test_needs_features', []):
 
1141
            if not feature.available():
 
1142
                result.startTest(self)
 
1143
                if getattr(result, 'addNotSupported', None):
 
1144
                    result.addNotSupported(self, feature)
 
1145
                else:
 
1146
                    result.addSuccess(self)
 
1147
                result.stopTest(self)
 
1148
                return
 
1149
        return unittest.TestCase.run(self, result)
 
1150
 
726
1151
    def tearDown(self):
727
1152
        self._runCleanups()
728
1153
        unittest.TestCase.tearDown(self)
756
1181
        """
757
1182
        # TODO: Perhaps this should keep running cleanups even if 
758
1183
        # one of them fails?
759
 
        for cleanup_fn in reversed(self._cleanups):
760
 
            cleanup_fn()
 
1184
 
 
1185
        # Actually pop the cleanups from the list so tearDown running
 
1186
        # twice is safe (this happens for skipped tests).
 
1187
        while self._cleanups:
 
1188
            self._cleanups.pop()()
761
1189
 
762
1190
    def log(self, *args):
763
1191
        mutter(*args)
779
1207
                logfile.close()
780
1208
            if not keep_log_file:
781
1209
                self._log_contents = log_contents
782
 
                os.remove(self._log_file_name)
 
1210
                try:
 
1211
                    os.remove(self._log_file_name)
 
1212
                except OSError, e:
 
1213
                    if sys.platform == 'win32' and e.errno == errno.EACCES:
 
1214
                        print >>sys.stderr, ('Unable to delete log file '
 
1215
                                             ' %r' % self._log_file_name)
 
1216
                    else:
 
1217
                        raise
783
1218
            return log_contents
784
1219
        else:
785
1220
            return "DELETED log file to reduce memory footprint"
786
1221
 
 
1222
    @deprecated_method(zero_eighteen)
787
1223
    def capture(self, cmd, retcode=0):
788
1224
        """Shortcut that splits cmd into words, runs, and returns stdout"""
789
1225
        return self.run_bzr_captured(cmd.split(), retcode=retcode)[0]
790
1226
 
 
1227
    def requireFeature(self, feature):
 
1228
        """This test requires a specific feature is available.
 
1229
 
 
1230
        :raises UnavailableFeature: When feature is not available.
 
1231
        """
 
1232
        if not feature.available():
 
1233
            raise UnavailableFeature(feature)
 
1234
 
 
1235
    @deprecated_method(zero_eighteen)
791
1236
    def run_bzr_captured(self, argv, retcode=0, encoding=None, stdin=None,
792
1237
                         working_dir=None):
793
1238
        """Invoke bzr and return (stdout, stderr).
794
1239
 
795
 
        Useful for code that wants to check the contents of the
796
 
        output, the way error messages are presented, etc.
797
 
 
798
 
        This should be the main method for tests that want to exercise the
799
 
        overall behavior of the bzr application (rather than a unit test
800
 
        or a functional test of the library.)
801
 
 
802
 
        Much of the old code runs bzr by forking a new copy of Python, but
803
 
        that is slower, harder to debug, and generally not necessary.
804
 
 
805
 
        This runs bzr through the interface that catches and reports
806
 
        errors, and with logging set to something approximating the
807
 
        default, so that error reporting can be checked.
808
 
 
809
 
        :param argv: arguments to invoke bzr
810
 
        :param retcode: expected return code, or None for don't-care.
811
 
        :param encoding: encoding for sys.stdout and sys.stderr
 
1240
        Don't call this method, just use run_bzr() which is equivalent.
 
1241
 
 
1242
        :param argv: Arguments to invoke bzr.  This may be either a 
 
1243
            single string, in which case it is split by shlex into words, 
 
1244
            or a list of arguments.
 
1245
        :param retcode: Expected return code, or None for don't-care.
 
1246
        :param encoding: Encoding for sys.stdout and sys.stderr
812
1247
        :param stdin: A string to be used as stdin for the command.
813
1248
        :param working_dir: Change to this directory before running
814
1249
        """
 
1250
        return self._run_bzr_autosplit(argv, retcode=retcode,
 
1251
                encoding=encoding, stdin=stdin, working_dir=working_dir,
 
1252
                )
 
1253
 
 
1254
    def _run_bzr_autosplit(self, args, retcode, encoding, stdin,
 
1255
            working_dir):
 
1256
        """Run bazaar command line, splitting up a string command line."""
 
1257
        if isinstance(args, basestring):
 
1258
            args = list(shlex.split(args))
 
1259
        return self._run_bzr_core(args, retcode=retcode,
 
1260
                encoding=encoding, stdin=stdin, working_dir=working_dir,
 
1261
                )
 
1262
 
 
1263
    def _run_bzr_core(self, args, retcode, encoding, stdin,
 
1264
            working_dir):
815
1265
        if encoding is None:
816
1266
            encoding = bzrlib.user_encoding
817
 
        if stdin is not None:
818
 
            stdin = StringIO(stdin)
819
1267
        stdout = StringIOWrapper()
820
1268
        stderr = StringIOWrapper()
821
1269
        stdout.encoding = encoding
822
1270
        stderr.encoding = encoding
823
1271
 
824
 
        self.log('run bzr: %r', argv)
 
1272
        self.log('run bzr: %r', args)
825
1273
        # FIXME: don't call into logging here
826
1274
        handler = logging.StreamHandler(stderr)
827
1275
        handler.setLevel(logging.INFO)
828
1276
        logger = logging.getLogger('')
829
1277
        logger.addHandler(handler)
830
 
        old_ui_factory = bzrlib.ui.ui_factory
831
 
        bzrlib.ui.ui_factory = bzrlib.tests.blackbox.TestUIFactory(
832
 
            stdout=stdout,
833
 
            stderr=stderr)
834
 
        bzrlib.ui.ui_factory.stdin = stdin
 
1278
        old_ui_factory = ui.ui_factory
 
1279
        ui.ui_factory = TestUIFactory(stdin=stdin, stdout=stdout, stderr=stderr)
835
1280
 
836
1281
        cwd = None
837
1282
        if working_dir is not None:
839
1284
            os.chdir(working_dir)
840
1285
 
841
1286
        try:
842
 
            result = self.apply_redirected(stdin, stdout, stderr,
843
 
                                           bzrlib.commands.run_bzr_catch_errors,
844
 
                                           argv)
 
1287
            result = self.apply_redirected(ui.ui_factory.stdin,
 
1288
                stdout, stderr,
 
1289
                bzrlib.commands.run_bzr_catch_errors,
 
1290
                args)
845
1291
        finally:
846
1292
            logger.removeHandler(handler)
847
 
            bzrlib.ui.ui_factory = old_ui_factory
 
1293
            ui.ui_factory = old_ui_factory
848
1294
            if cwd is not None:
849
1295
                os.chdir(cwd)
850
1296
 
855
1301
        if err:
856
1302
            self.log('errors:\n%r', err)
857
1303
        if retcode is not None:
858
 
            self.assertEquals(retcode, result)
 
1304
            self.assertEquals(retcode, result,
 
1305
                              message='Unexpected return code')
859
1306
        return out, err
860
1307
 
861
1308
    def run_bzr(self, *args, **kwargs):
862
1309
        """Invoke bzr, as if it were run from the command line.
863
1310
 
 
1311
        The argument list should not include the bzr program name - the
 
1312
        first argument is normally the bzr command.  Arguments may be
 
1313
        passed in three ways:
 
1314
 
 
1315
        1- A list of strings, eg ["commit", "a"].  This is recommended
 
1316
        when the command contains whitespace or metacharacters, or 
 
1317
        is built up at run time.
 
1318
 
 
1319
        2- A single string, eg "add a".  This is the most convenient 
 
1320
        for hardcoded commands.
 
1321
 
 
1322
        3- Several varargs parameters, eg run_bzr("add", "a").  
 
1323
        This is not recommended for new code.
 
1324
 
 
1325
        This runs bzr through the interface that catches and reports
 
1326
        errors, and with logging set to something approximating the
 
1327
        default, so that error reporting can be checked.
 
1328
 
864
1329
        This should be the main method for tests that want to exercise the
865
1330
        overall behavior of the bzr application (rather than a unit test
866
1331
        or a functional test of the library.)
868
1333
        This sends the stdout/stderr results into the test's log,
869
1334
        where it may be useful for debugging.  See also run_captured.
870
1335
 
871
 
        :param stdin: A string to be used as stdin for the command.
 
1336
        :keyword stdin: A string to be used as stdin for the command.
 
1337
        :keyword retcode: The status code the command should return;
 
1338
            default 0.
 
1339
        :keyword working_dir: The directory to run the command in
 
1340
        :keyword error_regexes: A list of expected error messages.  If
 
1341
            specified they must be seen in the error output of the command.
872
1342
        """
873
1343
        retcode = kwargs.pop('retcode', 0)
874
1344
        encoding = kwargs.pop('encoding', None)
875
1345
        stdin = kwargs.pop('stdin', None)
876
1346
        working_dir = kwargs.pop('working_dir', None)
877
 
        return self.run_bzr_captured(args, retcode=retcode, encoding=encoding,
878
 
                                     stdin=stdin, working_dir=working_dir)
 
1347
        error_regexes = kwargs.pop('error_regexes', [])
 
1348
 
 
1349
        if len(args) == 1:
 
1350
            if isinstance(args[0], (list, basestring)):
 
1351
                args = args[0]
 
1352
        else:
 
1353
            ## symbol_versioning.warn(zero_eighteen % "passing varargs to run_bzr",
 
1354
            ##         DeprecationWarning, stacklevel=2)
 
1355
            # not done yet, because too many tests would need to  be updated -
 
1356
            # but please don't do this in new code.  -- mbp 20070626
 
1357
            pass
 
1358
 
 
1359
        out, err = self._run_bzr_autosplit(args=args,
 
1360
            retcode=retcode,
 
1361
            encoding=encoding, stdin=stdin, working_dir=working_dir,
 
1362
            )
 
1363
 
 
1364
        for regex in error_regexes:
 
1365
            self.assertContainsRe(err, regex)
 
1366
        return out, err
879
1367
 
880
1368
    def run_bzr_decode(self, *args, **kwargs):
881
1369
        if 'encoding' in kwargs:
886
1374
 
887
1375
    def run_bzr_error(self, error_regexes, *args, **kwargs):
888
1376
        """Run bzr, and check that stderr contains the supplied regexes
889
 
        
890
 
        :param error_regexes: Sequence of regular expressions which 
 
1377
 
 
1378
        :param error_regexes: Sequence of regular expressions which
891
1379
            must each be found in the error output. The relative ordering
892
1380
            is not enforced.
893
1381
        :param args: command-line arguments for bzr
894
1382
        :param kwargs: Keyword arguments which are interpreted by run_bzr
895
1383
            This function changes the default value of retcode to be 3,
896
1384
            since in most cases this is run when you expect bzr to fail.
897
 
        :return: (out, err) The actual output of running the command (in case you
898
 
                 want to do more inspection)
899
 
 
900
 
        Examples of use:
 
1385
        :return: (out, err) The actual output of running the command (in case
 
1386
            you want to do more inspection)
 
1387
 
 
1388
        Examples of use::
 
1389
 
901
1390
            # Make sure that commit is failing because there is nothing to do
902
1391
            self.run_bzr_error(['no changes to commit'],
903
1392
                               'commit', '-m', 'my commit comment')
908
1397
                               'commit', '--strict', '-m', 'my commit comment')
909
1398
        """
910
1399
        kwargs.setdefault('retcode', 3)
911
 
        out, err = self.run_bzr(*args, **kwargs)
912
 
        for regex in error_regexes:
913
 
            self.assertContainsRe(err, regex)
 
1400
        out, err = self.run_bzr(error_regexes=error_regexes, *args, **kwargs)
914
1401
        return out, err
915
1402
 
916
1403
    def run_bzr_subprocess(self, *args, **kwargs):
922
1409
        handling, or early startup code, etc.  Subprocess code can't be 
923
1410
        profiled or debugged so easily.
924
1411
 
925
 
        :param retcode: The status code that is expected.  Defaults to 0.  If
 
1412
        :keyword retcode: The status code that is expected.  Defaults to 0.  If
926
1413
            None is supplied, the status code is not checked.
927
 
        :param env_changes: A dictionary which lists changes to environment
 
1414
        :keyword env_changes: A dictionary which lists changes to environment
928
1415
            variables. A value of None will unset the env variable.
929
1416
            The values must be strings. The change will only occur in the
930
1417
            child, so you don't need to fix the environment after running.
931
 
        :param universal_newlines: Convert CRLF => LF
 
1418
        :keyword universal_newlines: Convert CRLF => LF
 
1419
        :keyword allow_plugins: By default the subprocess is run with
 
1420
            --no-plugins to ensure test reproducibility. Also, it is possible
 
1421
            for system-wide plugins to create unexpected output on stderr,
 
1422
            which can cause unnecessary test failures.
932
1423
        """
933
1424
        env_changes = kwargs.get('env_changes', {})
934
1425
        working_dir = kwargs.get('working_dir', None)
 
1426
        allow_plugins = kwargs.get('allow_plugins', False)
935
1427
        process = self.start_bzr_subprocess(args, env_changes=env_changes,
936
 
                                            working_dir=working_dir)
 
1428
                                            working_dir=working_dir,
 
1429
                                            allow_plugins=allow_plugins)
937
1430
        # We distinguish between retcode=None and retcode not passed.
938
1431
        supplied_retcode = kwargs.get('retcode', 0)
939
1432
        return self.finish_bzr_subprocess(process, retcode=supplied_retcode,
942
1435
 
943
1436
    def start_bzr_subprocess(self, process_args, env_changes=None,
944
1437
                             skip_if_plan_to_signal=False,
945
 
                             working_dir=None):
 
1438
                             working_dir=None,
 
1439
                             allow_plugins=False):
946
1440
        """Start bzr in a subprocess for testing.
947
1441
 
948
1442
        This starts a new Python interpreter and runs bzr in there.
952
1446
        profiled or debugged so easily.
953
1447
 
954
1448
        :param process_args: a list of arguments to pass to the bzr executable,
955
 
            for example `['--version']`.
 
1449
            for example ``['--version']``.
956
1450
        :param env_changes: A dictionary which lists changes to environment
957
1451
            variables. A value of None will unset the env variable.
958
1452
            The values must be strings. The change will only occur in the
959
1453
            child, so you don't need to fix the environment after running.
960
1454
        :param skip_if_plan_to_signal: raise TestSkipped when true and os.kill
961
1455
            is not available.
 
1456
        :param allow_plugins: If False (default) pass --no-plugins to bzr.
962
1457
 
963
1458
        :returns: Popen object for the started process.
964
1459
        """
990
1485
            # so we will avoid using it on all platforms, just to
991
1486
            # make sure the code path is used, and we don't break on win32
992
1487
            cleanup_environment()
993
 
            process = Popen([sys.executable, bzr_path] + list(process_args),
994
 
                             stdin=PIPE, stdout=PIPE, stderr=PIPE)
 
1488
            command = [sys.executable, bzr_path]
 
1489
            if not allow_plugins:
 
1490
                command.append('--no-plugins')
 
1491
            command.extend(process_args)
 
1492
            process = self._popen(command, stdin=PIPE, stdout=PIPE, stderr=PIPE)
995
1493
        finally:
996
1494
            restore_environment()
997
1495
            if cwd is not None:
999
1497
 
1000
1498
        return process
1001
1499
 
 
1500
    def _popen(self, *args, **kwargs):
 
1501
        """Place a call to Popen.
 
1502
 
 
1503
        Allows tests to override this method to intercept the calls made to
 
1504
        Popen for introspection.
 
1505
        """
 
1506
        return Popen(*args, **kwargs)
 
1507
 
1002
1508
    def get_bzr_path(self):
1003
1509
        """Return the path of the 'bzr' executable for this test suite."""
1004
1510
        bzr_path = os.path.dirname(os.path.dirname(bzrlib.__file__))+'/bzr'
1044
1550
        shape = list(shape)             # copy
1045
1551
        for path, ie in inv.entries():
1046
1552
            name = path.replace('\\', '/')
1047
 
            if ie.kind == 'dir':
 
1553
            if ie.kind == 'directory':
1048
1554
                name = name + '/'
1049
1555
            if name in shape:
1050
1556
                shape.remove(name)
1087
1593
            sys.stderr = real_stderr
1088
1594
            sys.stdin = real_stdin
1089
1595
 
1090
 
    @symbol_versioning.deprecated_method(symbol_versioning.zero_eleven)
1091
 
    def merge(self, branch_from, wt_to):
1092
 
        """A helper for tests to do a ui-less merge.
1093
 
 
1094
 
        This should move to the main library when someone has time to integrate
1095
 
        it in.
1096
 
        """
1097
 
        # minimal ui-less merge.
1098
 
        wt_to.branch.fetch(branch_from)
1099
 
        base_rev = common_ancestor(branch_from.last_revision(),
1100
 
                                   wt_to.branch.last_revision(),
1101
 
                                   wt_to.branch.repository)
1102
 
        merge_inner(wt_to.branch, branch_from.basis_tree(),
1103
 
                    wt_to.branch.repository.revision_tree(base_rev),
1104
 
                    this_tree=wt_to)
1105
 
        wt_to.add_parent_tree_id(branch_from.last_revision())
1106
 
 
1107
 
 
1108
 
BzrTestBase = TestCase
 
1596
    def reduceLockdirTimeout(self):
 
1597
        """Reduce the default lock timeout for the duration of the test, so that
 
1598
        if LockContention occurs during a test, it does so quickly.
 
1599
 
 
1600
        Tests that expect to provoke LockContention errors should call this.
 
1601
        """
 
1602
        orig_timeout = bzrlib.lockdir._DEFAULT_TIMEOUT_SECONDS
 
1603
        def resetTimeout():
 
1604
            bzrlib.lockdir._DEFAULT_TIMEOUT_SECONDS = orig_timeout
 
1605
        self.addCleanup(resetTimeout)
 
1606
        bzrlib.lockdir._DEFAULT_TIMEOUT_SECONDS = 0
 
1607
 
 
1608
 
 
1609
class TestCaseWithMemoryTransport(TestCase):
 
1610
    """Common test class for tests that do not need disk resources.
 
1611
 
 
1612
    Tests that need disk resources should derive from TestCaseWithTransport.
 
1613
 
 
1614
    TestCaseWithMemoryTransport sets the TEST_ROOT variable for all bzr tests.
 
1615
 
 
1616
    For TestCaseWithMemoryTransport the test_home_dir is set to the name of
 
1617
    a directory which does not exist. This serves to help ensure test isolation
 
1618
    is preserved. test_dir is set to the TEST_ROOT, as is cwd, because they
 
1619
    must exist. However, TestCaseWithMemoryTransport does not offer local
 
1620
    file defaults for the transport in tests, nor does it obey the command line
 
1621
    override, so tests that accidentally write to the common directory should
 
1622
    be rare.
 
1623
 
 
1624
    :cvar TEST_ROOT: Directory containing all temporary directories, plus
 
1625
    a .bzr directory that stops us ascending higher into the filesystem.
 
1626
    """
 
1627
 
 
1628
    TEST_ROOT = None
 
1629
    _TEST_NAME = 'test'
 
1630
 
 
1631
    def __init__(self, methodName='runTest'):
 
1632
        # allow test parameterisation after test construction and before test
 
1633
        # execution. Variables that the parameteriser sets need to be 
 
1634
        # ones that are not set by setUp, or setUp will trash them.
 
1635
        super(TestCaseWithMemoryTransport, self).__init__(methodName)
 
1636
        self.vfs_transport_factory = default_transport
 
1637
        self.transport_server = None
 
1638
        self.transport_readonly_server = None
 
1639
        self.__vfs_server = None
 
1640
 
 
1641
    def get_transport(self):
 
1642
        """Return a writeable transport for the test scratch space"""
 
1643
        t = get_transport(self.get_url())
 
1644
        self.assertFalse(t.is_readonly())
 
1645
        return t
 
1646
 
 
1647
    def get_readonly_transport(self):
 
1648
        """Return a readonly transport for the test scratch space
 
1649
        
 
1650
        This can be used to test that operations which should only need
 
1651
        readonly access in fact do not try to write.
 
1652
        """
 
1653
        t = get_transport(self.get_readonly_url())
 
1654
        self.assertTrue(t.is_readonly())
 
1655
        return t
 
1656
 
 
1657
    def create_transport_readonly_server(self):
 
1658
        """Create a transport server from class defined at init.
 
1659
 
 
1660
        This is mostly a hook for daughter classes.
 
1661
        """
 
1662
        return self.transport_readonly_server()
 
1663
 
 
1664
    def get_readonly_server(self):
 
1665
        """Get the server instance for the readonly transport
 
1666
 
 
1667
        This is useful for some tests with specific servers to do diagnostics.
 
1668
        """
 
1669
        if self.__readonly_server is None:
 
1670
            if self.transport_readonly_server is None:
 
1671
                # readonly decorator requested
 
1672
                # bring up the server
 
1673
                self.__readonly_server = ReadonlyServer()
 
1674
                self.__readonly_server.setUp(self.get_vfs_only_server())
 
1675
            else:
 
1676
                self.__readonly_server = self.create_transport_readonly_server()
 
1677
                self.__readonly_server.setUp(self.get_vfs_only_server())
 
1678
            self.addCleanup(self.__readonly_server.tearDown)
 
1679
        return self.__readonly_server
 
1680
 
 
1681
    def get_readonly_url(self, relpath=None):
 
1682
        """Get a URL for the readonly transport.
 
1683
 
 
1684
        This will either be backed by '.' or a decorator to the transport 
 
1685
        used by self.get_url()
 
1686
        relpath provides for clients to get a path relative to the base url.
 
1687
        These should only be downwards relative, not upwards.
 
1688
        """
 
1689
        base = self.get_readonly_server().get_url()
 
1690
        if relpath is not None:
 
1691
            if not base.endswith('/'):
 
1692
                base = base + '/'
 
1693
            base = base + relpath
 
1694
        return base
 
1695
 
 
1696
    def get_vfs_only_server(self):
 
1697
        """Get the vfs only read/write server instance.
 
1698
 
 
1699
        This is useful for some tests with specific servers that need
 
1700
        diagnostics.
 
1701
 
 
1702
        For TestCaseWithMemoryTransport this is always a MemoryServer, and there
 
1703
        is no means to override it.
 
1704
        """
 
1705
        if self.__vfs_server is None:
 
1706
            self.__vfs_server = MemoryServer()
 
1707
            self.__vfs_server.setUp()
 
1708
            self.addCleanup(self.__vfs_server.tearDown)
 
1709
        return self.__vfs_server
 
1710
 
 
1711
    def get_server(self):
 
1712
        """Get the read/write server instance.
 
1713
 
 
1714
        This is useful for some tests with specific servers that need
 
1715
        diagnostics.
 
1716
 
 
1717
        This is built from the self.transport_server factory. If that is None,
 
1718
        then the self.get_vfs_server is returned.
 
1719
        """
 
1720
        if self.__server is None:
 
1721
            if self.transport_server is None or self.transport_server is self.vfs_transport_factory:
 
1722
                return self.get_vfs_only_server()
 
1723
            else:
 
1724
                # bring up a decorated means of access to the vfs only server.
 
1725
                self.__server = self.transport_server()
 
1726
                try:
 
1727
                    self.__server.setUp(self.get_vfs_only_server())
 
1728
                except TypeError, e:
 
1729
                    # This should never happen; the try:Except here is to assist
 
1730
                    # developers having to update code rather than seeing an
 
1731
                    # uninformative TypeError.
 
1732
                    raise Exception, "Old server API in use: %s, %s" % (self.__server, e)
 
1733
            self.addCleanup(self.__server.tearDown)
 
1734
        return self.__server
 
1735
 
 
1736
    def _adjust_url(self, base, relpath):
 
1737
        """Get a URL (or maybe a path) for the readwrite transport.
 
1738
 
 
1739
        This will either be backed by '.' or to an equivalent non-file based
 
1740
        facility.
 
1741
        relpath provides for clients to get a path relative to the base url.
 
1742
        These should only be downwards relative, not upwards.
 
1743
        """
 
1744
        if relpath is not None and relpath != '.':
 
1745
            if not base.endswith('/'):
 
1746
                base = base + '/'
 
1747
            # XXX: Really base should be a url; we did after all call
 
1748
            # get_url()!  But sometimes it's just a path (from
 
1749
            # LocalAbspathServer), and it'd be wrong to append urlescaped data
 
1750
            # to a non-escaped local path.
 
1751
            if base.startswith('./') or base.startswith('/'):
 
1752
                base += relpath
 
1753
            else:
 
1754
                base += urlutils.escape(relpath)
 
1755
        return base
 
1756
 
 
1757
    def get_url(self, relpath=None):
 
1758
        """Get a URL (or maybe a path) for the readwrite transport.
 
1759
 
 
1760
        This will either be backed by '.' or to an equivalent non-file based
 
1761
        facility.
 
1762
        relpath provides for clients to get a path relative to the base url.
 
1763
        These should only be downwards relative, not upwards.
 
1764
        """
 
1765
        base = self.get_server().get_url()
 
1766
        return self._adjust_url(base, relpath)
 
1767
 
 
1768
    def get_vfs_only_url(self, relpath=None):
 
1769
        """Get a URL (or maybe a path for the plain old vfs transport.
 
1770
 
 
1771
        This will never be a smart protocol.  It always has all the
 
1772
        capabilities of the local filesystem, but it might actually be a
 
1773
        MemoryTransport or some other similar virtual filesystem.
 
1774
 
 
1775
        This is the backing transport (if any) of the server returned by
 
1776
        get_url and get_readonly_url.
 
1777
 
 
1778
        :param relpath: provides for clients to get a path relative to the base
 
1779
            url.  These should only be downwards relative, not upwards.
 
1780
        :return: A URL
 
1781
        """
 
1782
        base = self.get_vfs_only_server().get_url()
 
1783
        return self._adjust_url(base, relpath)
 
1784
 
 
1785
    def _make_test_root(self):
 
1786
        if TestCaseWithMemoryTransport.TEST_ROOT is not None:
 
1787
            return
 
1788
        root = tempfile.mkdtemp(prefix='testbzr-', suffix='.tmp')
 
1789
        TestCaseWithMemoryTransport.TEST_ROOT = root
 
1790
        
 
1791
        # make a fake bzr directory there to prevent any tests propagating
 
1792
        # up onto the source directory's real branch
 
1793
        bzrdir.BzrDir.create_standalone_workingtree(root)
 
1794
 
 
1795
        # The same directory is used by all tests, and we're not specifically
 
1796
        # told when all tests are finished.  This will do.
 
1797
        atexit.register(_rmtree_temp_dir, root)
 
1798
 
 
1799
    def makeAndChdirToTestDir(self):
 
1800
        """Create a temporary directories for this one test.
 
1801
        
 
1802
        This must set self.test_home_dir and self.test_dir and chdir to
 
1803
        self.test_dir.
 
1804
        
 
1805
        For TestCaseWithMemoryTransport we chdir to the TEST_ROOT for this test.
 
1806
        """
 
1807
        os.chdir(TestCaseWithMemoryTransport.TEST_ROOT)
 
1808
        self.test_dir = TestCaseWithMemoryTransport.TEST_ROOT
 
1809
        self.test_home_dir = self.test_dir + "/MemoryTransportMissingHomeDir"
 
1810
        
 
1811
    def make_branch(self, relpath, format=None):
 
1812
        """Create a branch on the transport at relpath."""
 
1813
        repo = self.make_repository(relpath, format=format)
 
1814
        return repo.bzrdir.create_branch()
 
1815
 
 
1816
    def make_bzrdir(self, relpath, format=None):
 
1817
        try:
 
1818
            # might be a relative or absolute path
 
1819
            maybe_a_url = self.get_url(relpath)
 
1820
            segments = maybe_a_url.rsplit('/', 1)
 
1821
            t = get_transport(maybe_a_url)
 
1822
            if len(segments) > 1 and segments[-1] not in ('', '.'):
 
1823
                t.ensure_base()
 
1824
            if format is None:
 
1825
                format = 'default'
 
1826
            if isinstance(format, basestring):
 
1827
                format = bzrdir.format_registry.make_bzrdir(format)
 
1828
            return format.initialize_on_transport(t)
 
1829
        except errors.UninitializableFormat:
 
1830
            raise TestSkipped("Format %s is not initializable." % format)
 
1831
 
 
1832
    def make_repository(self, relpath, shared=False, format=None):
 
1833
        """Create a repository on our default transport at relpath.
 
1834
        
 
1835
        Note that relpath must be a relative path, not a full url.
 
1836
        """
 
1837
        # FIXME: If you create a remoterepository this returns the underlying
 
1838
        # real format, which is incorrect.  Actually we should make sure that 
 
1839
        # RemoteBzrDir returns a RemoteRepository.
 
1840
        # maybe  mbp 20070410
 
1841
        made_control = self.make_bzrdir(relpath, format=format)
 
1842
        return made_control.create_repository(shared=shared)
 
1843
 
 
1844
    def make_branch_and_memory_tree(self, relpath, format=None):
 
1845
        """Create a branch on the default transport and a MemoryTree for it."""
 
1846
        b = self.make_branch(relpath, format=format)
 
1847
        return memorytree.MemoryTree.create_on_branch(b)
 
1848
 
 
1849
    def overrideEnvironmentForTesting(self):
 
1850
        os.environ['HOME'] = self.test_home_dir
 
1851
        os.environ['BZR_HOME'] = self.test_home_dir
 
1852
        
 
1853
    def setUp(self):
 
1854
        super(TestCaseWithMemoryTransport, self).setUp()
 
1855
        self._make_test_root()
 
1856
        _currentdir = os.getcwdu()
 
1857
        def _leaveDirectory():
 
1858
            os.chdir(_currentdir)
 
1859
        self.addCleanup(_leaveDirectory)
 
1860
        self.makeAndChdirToTestDir()
 
1861
        self.overrideEnvironmentForTesting()
 
1862
        self.__readonly_server = None
 
1863
        self.__server = None
 
1864
        self.reduceLockdirTimeout()
1109
1865
 
1110
1866
     
1111
 
class TestCaseInTempDir(TestCase):
 
1867
class TestCaseInTempDir(TestCaseWithMemoryTransport):
1112
1868
    """Derived class that runs a test within a temporary directory.
1113
1869
 
1114
1870
    This is useful for tests that need to create a branch, etc.
1118
1874
    All test cases create their own directory within that.  If the
1119
1875
    tests complete successfully, the directory is removed.
1120
1876
 
1121
 
    InTempDir is an old alias for FunctionalTestCase.
 
1877
    :ivar test_base_dir: The path of the top-level directory for this 
 
1878
    test, which contains a home directory and a work directory.
 
1879
 
 
1880
    :ivar test_home_dir: An initially empty directory under test_base_dir
 
1881
    which is used as $HOME for this test.
 
1882
 
 
1883
    :ivar test_dir: A directory under test_base_dir used as the current
 
1884
    directory when the test proper is run.
1122
1885
    """
1123
1886
 
1124
 
    TEST_ROOT = None
1125
 
    _TEST_NAME = 'test'
1126
1887
    OVERRIDE_PYTHON = 'python'
 
1888
    use_numbered_dirs = False
1127
1889
 
1128
1890
    def check_file_contents(self, filename, expect):
1129
1891
        self.log("check contents of file %s" % filename)
1133
1895
            self.log("actually: %r" % contents)
1134
1896
            self.fail("contents of %s not as expected" % filename)
1135
1897
 
1136
 
    def _make_test_root(self):
1137
 
        if TestCaseInTempDir.TEST_ROOT is not None:
1138
 
            return
1139
 
        i = 0
1140
 
        while True:
1141
 
            root = u'test%04d.tmp' % i
1142
 
            try:
1143
 
                os.mkdir(root)
1144
 
            except OSError, e:
1145
 
                if e.errno == errno.EEXIST:
1146
 
                    i += 1
1147
 
                    continue
1148
 
                else:
1149
 
                    raise
1150
 
            # successfully created
1151
 
            TestCaseInTempDir.TEST_ROOT = osutils.abspath(root)
1152
 
            break
1153
 
        # make a fake bzr directory there to prevent any tests propagating
1154
 
        # up onto the source directory's real branch
1155
 
        bzrdir.BzrDir.create_standalone_workingtree(TestCaseInTempDir.TEST_ROOT)
1156
 
 
1157
 
    def setUp(self):
1158
 
        super(TestCaseInTempDir, self).setUp()
1159
 
        self._make_test_root()
1160
 
        _currentdir = os.getcwdu()
1161
 
        # shorten the name, to avoid test failures due to path length
1162
 
        short_id = self.id().replace('bzrlib.tests.', '') \
1163
 
                   .replace('__main__.', '')[-100:]
1164
 
        # it's possible the same test class is run several times for
1165
 
        # parameterized tests, so make sure the names don't collide.  
1166
 
        i = 0
1167
 
        while True:
1168
 
            if i > 0:
1169
 
                candidate_dir = '%s/%s.%d' % (self.TEST_ROOT, short_id, i)
1170
 
            else:
1171
 
                candidate_dir = '%s/%s' % (self.TEST_ROOT, short_id)
1172
 
            if os.path.exists(candidate_dir):
1173
 
                i = i + 1
1174
 
                continue
1175
 
            else:
1176
 
                os.mkdir(candidate_dir)
1177
 
                self.test_home_dir = candidate_dir + '/home'
1178
 
                os.mkdir(self.test_home_dir)
1179
 
                self.test_dir = candidate_dir + '/work'
1180
 
                os.mkdir(self.test_dir)
1181
 
                os.chdir(self.test_dir)
1182
 
                break
1183
 
        os.environ['HOME'] = self.test_home_dir
1184
 
        os.environ['APPDATA'] = self.test_home_dir
1185
 
        def _leaveDirectory():
1186
 
            os.chdir(_currentdir)
1187
 
        self.addCleanup(_leaveDirectory)
 
1898
    def makeAndChdirToTestDir(self):
 
1899
        """See TestCaseWithMemoryTransport.makeAndChdirToTestDir().
1188
1900
        
1189
 
    def build_tree(self, shape, line_endings='native', transport=None):
 
1901
        For TestCaseInTempDir we create a temporary directory based on the test
 
1902
        name and then create two subdirs - test and home under it.
 
1903
        """
 
1904
        # create a directory within the top level test directory
 
1905
        candidate_dir = tempfile.mkdtemp(dir=self.TEST_ROOT)
 
1906
        # now create test and home directories within this dir
 
1907
        self.test_base_dir = candidate_dir
 
1908
        self.test_home_dir = self.test_base_dir + '/home'
 
1909
        os.mkdir(self.test_home_dir)
 
1910
        self.test_dir = self.test_base_dir + '/work'
 
1911
        os.mkdir(self.test_dir)
 
1912
        os.chdir(self.test_dir)
 
1913
        # put name of test inside
 
1914
        f = file(self.test_base_dir + '/name', 'w')
 
1915
        try:
 
1916
            f.write(self.id())
 
1917
        finally:
 
1918
            f.close()
 
1919
        self.addCleanup(self.deleteTestDir)
 
1920
 
 
1921
    def deleteTestDir(self):
 
1922
        os.chdir(self.TEST_ROOT)
 
1923
        _rmtree_temp_dir(self.test_base_dir)
 
1924
 
 
1925
    def build_tree(self, shape, line_endings='binary', transport=None):
1190
1926
        """Build a test tree according to a pattern.
1191
1927
 
1192
1928
        shape is a sequence of file specifications.  If the final
1195
1931
        This assumes that all the elements in the tree being built are new.
1196
1932
 
1197
1933
        This doesn't add anything to a branch.
 
1934
 
1198
1935
        :param line_endings: Either 'binary' or 'native'
1199
 
                             in binary mode, exact contents are written
1200
 
                             in native mode, the line endings match the
1201
 
                             default platform endings.
1202
 
 
1203
 
        :param transport: A transport to write to, for building trees on 
1204
 
                          VFS's. If the transport is readonly or None,
1205
 
                          "." is opened automatically.
 
1936
            in binary mode, exact contents are written in native mode, the
 
1937
            line endings match the default platform endings.
 
1938
        :param transport: A transport to write to, for building trees on VFS's.
 
1939
            If the transport is readonly or None, "." is opened automatically.
 
1940
        :return: None
1206
1941
        """
1207
1942
        # It's OK to just create them using forward slashes on windows.
1208
1943
        if transport is None or transport.is_readonly():
1217
1952
                elif line_endings == 'native':
1218
1953
                    end = os.linesep
1219
1954
                else:
1220
 
                    raise errors.BzrError('Invalid line ending request %r' % (line_endings,))
 
1955
                    raise errors.BzrError(
 
1956
                        'Invalid line ending request %r' % line_endings)
1221
1957
                content = "contents of %s%s" % (name.encode('utf-8'), end)
1222
 
                # Technically 'put()' is the right command. However, put
1223
 
                # uses an AtomicFile, which requires an extra rename into place
1224
 
                # As long as the files didn't exist in the past, append() will
1225
 
                # do the same thing as put()
1226
 
                # On jam's machine, make_kernel_like_tree is:
1227
 
                #   put:    4.5-7.5s (averaging 6s)
1228
 
                #   append: 2.9-4.5s
1229
 
                #   put_non_atomic: 2.9-4.5s
1230
1958
                transport.put_bytes_non_atomic(urlutils.escape(name), content)
1231
1959
 
1232
1960
    def build_tree_contents(self, shape):
1233
1961
        build_tree_contents(shape)
1234
1962
 
 
1963
    def assertFileEqual(self, content, path):
 
1964
        """Fail if path does not contain 'content'."""
 
1965
        self.failUnlessExists(path)
 
1966
        f = file(path, 'rb')
 
1967
        try:
 
1968
            s = f.read()
 
1969
        finally:
 
1970
            f.close()
 
1971
        self.assertEqualDiff(content, s)
 
1972
 
1235
1973
    def failUnlessExists(self, path):
1236
 
        """Fail unless path, which may be abs or relative, exists."""
1237
 
        self.failUnless(osutils.lexists(path))
 
1974
        """Fail unless path or paths, which may be abs or relative, exist."""
 
1975
        if not isinstance(path, basestring):
 
1976
            for p in path:
 
1977
                self.failUnlessExists(p)
 
1978
        else:
 
1979
            self.failUnless(osutils.lexists(path),path+" does not exist")
1238
1980
 
1239
1981
    def failIfExists(self, path):
1240
 
        """Fail if path, which may be abs or relative, exists."""
1241
 
        self.failIf(osutils.lexists(path))
1242
 
        
1243
 
    def assertFileEqual(self, content, path):
1244
 
        """Fail if path does not contain 'content'."""
1245
 
        self.failUnless(osutils.lexists(path))
1246
 
        # TODO: jam 20060427 Shouldn't this be 'rb'?
1247
 
        self.assertEqualDiff(content, open(path, 'r').read())
 
1982
        """Fail if path or paths, which may be abs or relative, exist."""
 
1983
        if not isinstance(path, basestring):
 
1984
            for p in path:
 
1985
                self.failIfExists(p)
 
1986
        else:
 
1987
            self.failIf(osutils.lexists(path),path+" exists")
 
1988
 
 
1989
    def assertInWorkingTree(self,path,root_path='.',tree=None):
 
1990
        """Assert whether path or paths are in the WorkingTree"""
 
1991
        if tree is None:
 
1992
            tree = workingtree.WorkingTree.open(root_path)
 
1993
        if not isinstance(path, basestring):
 
1994
            for p in path:
 
1995
                self.assertInWorkingTree(p,tree=tree)
 
1996
        else:
 
1997
            self.assertIsNot(tree.path2id(path), None,
 
1998
                path+' not in working tree.')
 
1999
 
 
2000
    def assertNotInWorkingTree(self,path,root_path='.',tree=None):
 
2001
        """Assert whether path or paths are not in the WorkingTree"""
 
2002
        if tree is None:
 
2003
            tree = workingtree.WorkingTree.open(root_path)
 
2004
        if not isinstance(path, basestring):
 
2005
            for p in path:
 
2006
                self.assertNotInWorkingTree(p,tree=tree)
 
2007
        else:
 
2008
            self.assertIs(tree.path2id(path), None, path+' in working tree.')
1248
2009
 
1249
2010
 
1250
2011
class TestCaseWithTransport(TestCaseInTempDir):
1261
2022
    readwrite one must both define get_url() as resolving to os.getcwd().
1262
2023
    """
1263
2024
 
1264
 
    def __init__(self, methodName='testMethod'):
1265
 
        super(TestCaseWithTransport, self).__init__(methodName)
1266
 
        self.__readonly_server = None
1267
 
        self.__server = None
1268
 
        self.transport_server = default_transport
1269
 
        self.transport_readonly_server = None
1270
 
 
1271
 
    def get_readonly_url(self, relpath=None):
1272
 
        """Get a URL for the readonly transport.
1273
 
 
1274
 
        This will either be backed by '.' or a decorator to the transport 
1275
 
        used by self.get_url()
1276
 
        relpath provides for clients to get a path relative to the base url.
1277
 
        These should only be downwards relative, not upwards.
1278
 
        """
1279
 
        base = self.get_readonly_server().get_url()
1280
 
        if relpath is not None:
1281
 
            if not base.endswith('/'):
1282
 
                base = base + '/'
1283
 
            base = base + relpath
1284
 
        return base
1285
 
 
1286
 
    def get_readonly_server(self):
1287
 
        """Get the server instance for the readonly transport
1288
 
 
1289
 
        This is useful for some tests with specific servers to do diagnostics.
1290
 
        """
1291
 
        if self.__readonly_server is None:
1292
 
            if self.transport_readonly_server is None:
1293
 
                # readonly decorator requested
1294
 
                # bring up the server
1295
 
                self.get_url()
1296
 
                self.__readonly_server = ReadonlyServer()
1297
 
                self.__readonly_server.setUp(self.__server)
1298
 
            else:
1299
 
                self.__readonly_server = self.transport_readonly_server()
1300
 
                self.__readonly_server.setUp()
1301
 
            self.addCleanup(self.__readonly_server.tearDown)
1302
 
        return self.__readonly_server
1303
 
 
1304
 
    def get_server(self):
1305
 
        """Get the read/write server instance.
 
2025
    def get_vfs_only_server(self):
 
2026
        """See TestCaseWithMemoryTransport.
1306
2027
 
1307
2028
        This is useful for some tests with specific servers that need
1308
2029
        diagnostics.
1309
2030
        """
1310
 
        if self.__server is None:
1311
 
            self.__server = self.transport_server()
1312
 
            self.__server.setUp()
1313
 
            self.addCleanup(self.__server.tearDown)
1314
 
        return self.__server
1315
 
 
1316
 
    def get_url(self, relpath=None):
1317
 
        """Get a URL (or maybe a path) for the readwrite transport.
1318
 
 
1319
 
        This will either be backed by '.' or to an equivalent non-file based
1320
 
        facility.
1321
 
        relpath provides for clients to get a path relative to the base url.
1322
 
        These should only be downwards relative, not upwards.
1323
 
        """
1324
 
        base = self.get_server().get_url()
1325
 
        if relpath is not None and relpath != '.':
1326
 
            if not base.endswith('/'):
1327
 
                base = base + '/'
1328
 
            # XXX: Really base should be a url; we did after all call
1329
 
            # get_url()!  But sometimes it's just a path (from
1330
 
            # LocalAbspathServer), and it'd be wrong to append urlescaped data
1331
 
            # to a non-escaped local path.
1332
 
            if base.startswith('./') or base.startswith('/'):
1333
 
                base += relpath
1334
 
            else:
1335
 
                base += urlutils.escape(relpath)
1336
 
        return base
1337
 
 
1338
 
    def get_transport(self):
1339
 
        """Return a writeable transport for the test scratch space"""
1340
 
        t = get_transport(self.get_url())
1341
 
        self.assertFalse(t.is_readonly())
1342
 
        return t
1343
 
 
1344
 
    def get_readonly_transport(self):
1345
 
        """Return a readonly transport for the test scratch space
1346
 
        
1347
 
        This can be used to test that operations which should only need
1348
 
        readonly access in fact do not try to write.
1349
 
        """
1350
 
        t = get_transport(self.get_readonly_url())
1351
 
        self.assertTrue(t.is_readonly())
1352
 
        return t
1353
 
 
1354
 
    def make_branch(self, relpath, format=None):
1355
 
        """Create a branch on the transport at relpath."""
1356
 
        repo = self.make_repository(relpath, format=format)
1357
 
        return repo.bzrdir.create_branch()
1358
 
 
1359
 
    def make_bzrdir(self, relpath, format=None):
1360
 
        try:
1361
 
            # might be a relative or absolute path
1362
 
            maybe_a_url = self.get_url(relpath)
1363
 
            segments = maybe_a_url.rsplit('/', 1)
1364
 
            t = get_transport(maybe_a_url)
1365
 
            if len(segments) > 1 and segments[-1] not in ('', '.'):
1366
 
                try:
1367
 
                    t.mkdir('.')
1368
 
                except errors.FileExists:
1369
 
                    pass
1370
 
            if format is None:
1371
 
                format = bzrlib.bzrdir.BzrDirFormat.get_default_format()
1372
 
            return format.initialize_on_transport(t)
1373
 
        except errors.UninitializableFormat:
1374
 
            raise TestSkipped("Format %s is not initializable." % format)
1375
 
 
1376
 
    def make_repository(self, relpath, shared=False, format=None):
1377
 
        """Create a repository on our default transport at relpath."""
1378
 
        made_control = self.make_bzrdir(relpath, format=format)
1379
 
        return made_control.create_repository(shared=shared)
1380
 
 
1381
 
    def make_branch_and_memory_tree(self, relpath):
1382
 
        """Create a branch on the default transport and a MemoryTree for it."""
1383
 
        b = self.make_branch(relpath)
1384
 
        return memorytree.MemoryTree.create_on_branch(b)
 
2031
        if self.__vfs_server is None:
 
2032
            self.__vfs_server = self.vfs_transport_factory()
 
2033
            self.__vfs_server.setUp()
 
2034
            self.addCleanup(self.__vfs_server.tearDown)
 
2035
        return self.__vfs_server
1385
2036
 
1386
2037
    def make_branch_and_tree(self, relpath, format=None):
1387
2038
        """Create a branch on the transport and a tree locally.
1388
2039
 
1389
2040
        If the transport is not a LocalTransport, the Tree can't be created on
1390
 
        the transport.  In that case the working tree is created in the local
1391
 
        directory, and the returned tree's branch and repository will also be
1392
 
        accessed locally.
1393
 
 
1394
 
        This will fail if the original default transport for this test
1395
 
        case wasn't backed by the working directory, as the branch won't
1396
 
        be on disk for us to open it.  
 
2041
        the transport.  In that case if the vfs_transport_factory is
 
2042
        LocalURLServer the working tree is created in the local
 
2043
        directory backing the transport, and the returned tree's branch and
 
2044
        repository will also be accessed locally. Otherwise a lightweight
 
2045
        checkout is created and returned.
1397
2046
 
1398
2047
        :param format: The BzrDirFormat.
1399
2048
        :returns: the WorkingTree.
1407
2056
            return b.bzrdir.create_workingtree()
1408
2057
        except errors.NotLocalUrl:
1409
2058
            # We can only make working trees locally at the moment.  If the
1410
 
            # transport can't support them, then reopen the branch on a local
1411
 
            # transport, and create the working tree there.  
1412
 
            #
1413
 
            # Possibly we should instead keep
1414
 
            # the non-disk-backed branch and create a local checkout?
1415
 
            bd = bzrdir.BzrDir.open(relpath)
1416
 
            return bd.create_workingtree()
 
2059
            # transport can't support them, then we keep the non-disk-backed
 
2060
            # branch and create a local checkout.
 
2061
            if self.vfs_transport_factory is LocalURLServer:
 
2062
                # the branch is colocated on disk, we cannot create a checkout.
 
2063
                # hopefully callers will expect this.
 
2064
                local_controldir= bzrdir.BzrDir.open(self.get_vfs_only_url(relpath))
 
2065
                return local_controldir.create_workingtree()
 
2066
            else:
 
2067
                return b.create_checkout(relpath, lightweight=True)
1417
2068
 
1418
2069
    def assertIsDirectory(self, relpath, transport):
1419
2070
        """Assert that relpath within transport is a directory.
1430
2081
            self.fail("path %s is not a directory; has mode %#o"
1431
2082
                      % (relpath, mode))
1432
2083
 
 
2084
    def assertTreesEqual(self, left, right):
 
2085
        """Check that left and right have the same content and properties."""
 
2086
        # we use a tree delta to check for equality of the content, and we
 
2087
        # manually check for equality of other things such as the parents list.
 
2088
        self.assertEqual(left.get_parent_ids(), right.get_parent_ids())
 
2089
        differences = left.changes_from(right)
 
2090
        self.assertFalse(differences.has_changed(),
 
2091
            "Trees %r and %r are different: %r" % (left, right, differences))
 
2092
 
 
2093
    def setUp(self):
 
2094
        super(TestCaseWithTransport, self).setUp()
 
2095
        self.__vfs_server = None
 
2096
 
1433
2097
 
1434
2098
class ChrootedTestCase(TestCaseWithTransport):
1435
2099
    """A support class that provides readonly urls outside the local namespace.
1445
2109
 
1446
2110
    def setUp(self):
1447
2111
        super(ChrootedTestCase, self).setUp()
1448
 
        if not self.transport_server == bzrlib.transport.memory.MemoryServer:
1449
 
            self.transport_readonly_server = bzrlib.transport.http.HttpServer
1450
 
 
1451
 
 
1452
 
def filter_suite_by_re(suite, pattern):
1453
 
    result = TestUtil.TestSuite()
 
2112
        if not self.vfs_transport_factory == MemoryServer:
 
2113
            self.transport_readonly_server = HttpServer
 
2114
 
 
2115
 
 
2116
def filter_suite_by_re(suite, pattern, exclude_pattern=None,
 
2117
                       random_order=False):
 
2118
    """Create a test suite by filtering another one.
 
2119
    
 
2120
    :param suite:           the source suite
 
2121
    :param pattern:         pattern that names must match
 
2122
    :param exclude_pattern: pattern that names must not match, if any
 
2123
    :param random_order:    if True, tests in the new suite will be put in
 
2124
                            random order
 
2125
    :returns: the newly created suite
 
2126
    """ 
 
2127
    return sort_suite_by_re(suite, pattern, exclude_pattern,
 
2128
        random_order, False)
 
2129
 
 
2130
 
 
2131
def sort_suite_by_re(suite, pattern, exclude_pattern=None,
 
2132
                     random_order=False, append_rest=True):
 
2133
    """Create a test suite by sorting another one.
 
2134
    
 
2135
    :param suite:           the source suite
 
2136
    :param pattern:         pattern that names must match in order to go
 
2137
                            first in the new suite
 
2138
    :param exclude_pattern: pattern that names must not match, if any
 
2139
    :param random_order:    if True, tests in the new suite will be put in
 
2140
                            random order
 
2141
    :param append_rest:     if False, pattern is a strict filter and not
 
2142
                            just an ordering directive
 
2143
    :returns: the newly created suite
 
2144
    """ 
 
2145
    first = []
 
2146
    second = []
1454
2147
    filter_re = re.compile(pattern)
 
2148
    if exclude_pattern is not None:
 
2149
        exclude_re = re.compile(exclude_pattern)
1455
2150
    for test in iter_suite_tests(suite):
1456
 
        if filter_re.search(test.id()):
1457
 
            result.addTest(test)
1458
 
    return result
 
2151
        test_id = test.id()
 
2152
        if exclude_pattern is None or not exclude_re.search(test_id):
 
2153
            if filter_re.search(test_id):
 
2154
                first.append(test)
 
2155
            elif append_rest:
 
2156
                second.append(test)
 
2157
    if random_order:
 
2158
        random.shuffle(first)
 
2159
        random.shuffle(second)
 
2160
    return TestUtil.TestSuite(first + second)
1459
2161
 
1460
2162
 
1461
2163
def run_suite(suite, name='test', verbose=False, pattern=".*",
1462
 
              stop_on_failure=False, keep_output=False,
1463
 
              transport=None, lsprof_timed=None, bench_history=None):
1464
 
    TestCaseInTempDir._TEST_NAME = name
 
2164
              stop_on_failure=False,
 
2165
              transport=None, lsprof_timed=None, bench_history=None,
 
2166
              matching_tests_first=None,
 
2167
              numbered_dirs=None,
 
2168
              list_only=False,
 
2169
              random_seed=None,
 
2170
              exclude_pattern=None,
 
2171
              ):
 
2172
    use_numbered_dirs = bool(numbered_dirs)
 
2173
 
1465
2174
    TestCase._gather_lsprof_in_benchmarks = lsprof_timed
 
2175
    if numbered_dirs is not None:
 
2176
        TestCaseInTempDir.use_numbered_dirs = use_numbered_dirs
1466
2177
    if verbose:
1467
2178
        verbosity = 2
1468
 
        pb = None
1469
2179
    else:
1470
2180
        verbosity = 1
1471
 
        pb = progress.ProgressBar()
1472
2181
    runner = TextTestRunner(stream=sys.stdout,
1473
2182
                            descriptions=0,
1474
2183
                            verbosity=verbosity,
1475
 
                            keep_output=keep_output,
1476
 
                            pb=pb,
1477
 
                            bench_history=bench_history)
 
2184
                            bench_history=bench_history,
 
2185
                            use_numbered_dirs=use_numbered_dirs,
 
2186
                            list_only=list_only,
 
2187
                            )
1478
2188
    runner.stop_on_failure=stop_on_failure
1479
 
    if pattern != '.*':
1480
 
        suite = filter_suite_by_re(suite, pattern)
 
2189
    # Initialise the random number generator and display the seed used.
 
2190
    # We convert the seed to a long to make it reuseable across invocations.
 
2191
    random_order = False
 
2192
    if random_seed is not None:
 
2193
        random_order = True
 
2194
        if random_seed == "now":
 
2195
            random_seed = long(time.time())
 
2196
        else:
 
2197
            # Convert the seed to a long if we can
 
2198
            try:
 
2199
                random_seed = long(random_seed)
 
2200
            except:
 
2201
                pass
 
2202
        runner.stream.writeln("Randomizing test order using seed %s\n" %
 
2203
            (random_seed))
 
2204
        random.seed(random_seed)
 
2205
    # Customise the list of tests if requested
 
2206
    if pattern != '.*' or exclude_pattern is not None or random_order:
 
2207
        if matching_tests_first:
 
2208
            suite = sort_suite_by_re(suite, pattern, exclude_pattern,
 
2209
                random_order)
 
2210
        else:
 
2211
            suite = filter_suite_by_re(suite, pattern, exclude_pattern,
 
2212
                random_order)
1481
2213
    result = runner.run(suite)
1482
2214
    return result.wasSuccessful()
1483
2215
 
1484
2216
 
1485
2217
def selftest(verbose=False, pattern=".*", stop_on_failure=True,
1486
 
             keep_output=False,
1487
2218
             transport=None,
1488
2219
             test_suite_factory=None,
1489
2220
             lsprof_timed=None,
1490
 
             bench_history=None):
 
2221
             bench_history=None,
 
2222
             matching_tests_first=None,
 
2223
             numbered_dirs=None,
 
2224
             list_only=False,
 
2225
             random_seed=None,
 
2226
             exclude_pattern=None):
1491
2227
    """Run the whole test suite under the enhanced runner"""
1492
2228
    # XXX: Very ugly way to do this...
1493
2229
    # Disable warning about old formats because we don't want it to disturb
1506
2242
        else:
1507
2243
            suite = test_suite_factory()
1508
2244
        return run_suite(suite, 'testbzr', verbose=verbose, pattern=pattern,
1509
 
                     stop_on_failure=stop_on_failure, keep_output=keep_output,
 
2245
                     stop_on_failure=stop_on_failure,
1510
2246
                     transport=transport,
1511
2247
                     lsprof_timed=lsprof_timed,
1512
 
                     bench_history=bench_history)
 
2248
                     bench_history=bench_history,
 
2249
                     matching_tests_first=matching_tests_first,
 
2250
                     numbered_dirs=numbered_dirs,
 
2251
                     list_only=list_only,
 
2252
                     random_seed=random_seed,
 
2253
                     exclude_pattern=exclude_pattern)
1513
2254
    finally:
1514
2255
        default_transport = old_transport
1515
2256
 
1522
2263
    """
1523
2264
    testmod_names = [
1524
2265
                   'bzrlib.tests.test_ancestry',
 
2266
                   'bzrlib.tests.test_annotate',
1525
2267
                   'bzrlib.tests.test_api',
1526
2268
                   'bzrlib.tests.test_atomicfile',
1527
2269
                   'bzrlib.tests.test_bad_files',
1528
2270
                   'bzrlib.tests.test_branch',
 
2271
                   'bzrlib.tests.test_branchbuilder',
 
2272
                   'bzrlib.tests.test_bugtracker',
1529
2273
                   'bzrlib.tests.test_bundle',
1530
2274
                   'bzrlib.tests.test_bzrdir',
1531
2275
                   'bzrlib.tests.test_cache_utf8',
1532
 
                   'bzrlib.tests.test_command',
 
2276
                   'bzrlib.tests.test_commands',
1533
2277
                   'bzrlib.tests.test_commit',
1534
2278
                   'bzrlib.tests.test_commit_merge',
1535
2279
                   'bzrlib.tests.test_config',
1536
2280
                   'bzrlib.tests.test_conflicts',
 
2281
                   'bzrlib.tests.test_pack',
 
2282
                   'bzrlib.tests.test_counted_lock',
1537
2283
                   'bzrlib.tests.test_decorators',
 
2284
                   'bzrlib.tests.test_delta',
 
2285
                   'bzrlib.tests.test_deprecated_graph',
1538
2286
                   'bzrlib.tests.test_diff',
1539
 
                   'bzrlib.tests.test_doc_generate',
 
2287
                   'bzrlib.tests.test_dirstate',
1540
2288
                   'bzrlib.tests.test_errors',
1541
2289
                   'bzrlib.tests.test_escaped_store',
 
2290
                   'bzrlib.tests.test_extract',
1542
2291
                   'bzrlib.tests.test_fetch',
1543
2292
                   'bzrlib.tests.test_ftp_transport',
 
2293
                   'bzrlib.tests.test_generate_docs',
 
2294
                   'bzrlib.tests.test_generate_ids',
 
2295
                   'bzrlib.tests.test_globbing',
1544
2296
                   'bzrlib.tests.test_gpg',
1545
2297
                   'bzrlib.tests.test_graph',
1546
2298
                   'bzrlib.tests.test_hashcache',
 
2299
                   'bzrlib.tests.test_help',
 
2300
                   'bzrlib.tests.test_hooks',
1547
2301
                   'bzrlib.tests.test_http',
1548
2302
                   'bzrlib.tests.test_http_response',
 
2303
                   'bzrlib.tests.test_https_ca_bundle',
1549
2304
                   'bzrlib.tests.test_identitymap',
1550
2305
                   'bzrlib.tests.test_ignores',
 
2306
                   'bzrlib.tests.test_info',
1551
2307
                   'bzrlib.tests.test_inv',
1552
2308
                   'bzrlib.tests.test_knit',
1553
2309
                   'bzrlib.tests.test_lazy_import',
 
2310
                   'bzrlib.tests.test_lazy_regex',
1554
2311
                   'bzrlib.tests.test_lockdir',
1555
2312
                   'bzrlib.tests.test_lockable_files',
1556
2313
                   'bzrlib.tests.test_log',
 
2314
                   'bzrlib.tests.test_lsprof',
1557
2315
                   'bzrlib.tests.test_memorytree',
1558
2316
                   'bzrlib.tests.test_merge',
1559
2317
                   'bzrlib.tests.test_merge3',
1560
2318
                   'bzrlib.tests.test_merge_core',
 
2319
                   'bzrlib.tests.test_merge_directive',
1561
2320
                   'bzrlib.tests.test_missing',
1562
2321
                   'bzrlib.tests.test_msgeditor',
1563
2322
                   'bzrlib.tests.test_nonascii',
1564
2323
                   'bzrlib.tests.test_options',
1565
2324
                   'bzrlib.tests.test_osutils',
 
2325
                   'bzrlib.tests.test_osutils_encodings',
1566
2326
                   'bzrlib.tests.test_patch',
1567
2327
                   'bzrlib.tests.test_patches',
1568
2328
                   'bzrlib.tests.test_permissions',
1569
2329
                   'bzrlib.tests.test_plugins',
1570
2330
                   'bzrlib.tests.test_progress',
1571
2331
                   'bzrlib.tests.test_reconcile',
 
2332
                   'bzrlib.tests.test_registry',
 
2333
                   'bzrlib.tests.test_remote',
1572
2334
                   'bzrlib.tests.test_repository',
1573
2335
                   'bzrlib.tests.test_revert',
1574
2336
                   'bzrlib.tests.test_revision',
1579
2341
                   'bzrlib.tests.test_selftest',
1580
2342
                   'bzrlib.tests.test_setup',
1581
2343
                   'bzrlib.tests.test_sftp_transport',
 
2344
                   'bzrlib.tests.test_smart',
1582
2345
                   'bzrlib.tests.test_smart_add',
1583
2346
                   'bzrlib.tests.test_smart_transport',
 
2347
                   'bzrlib.tests.test_smtp_connection',
1584
2348
                   'bzrlib.tests.test_source',
 
2349
                   'bzrlib.tests.test_ssh_transport',
1585
2350
                   'bzrlib.tests.test_status',
1586
2351
                   'bzrlib.tests.test_store',
 
2352
                   'bzrlib.tests.test_strace',
 
2353
                   'bzrlib.tests.test_subsume',
1587
2354
                   'bzrlib.tests.test_symbol_versioning',
 
2355
                   'bzrlib.tests.test_tag',
1588
2356
                   'bzrlib.tests.test_testament',
1589
2357
                   'bzrlib.tests.test_textfile',
1590
2358
                   'bzrlib.tests.test_textmerge',
 
2359
                   'bzrlib.tests.test_timestamp',
1591
2360
                   'bzrlib.tests.test_trace',
1592
2361
                   'bzrlib.tests.test_transactions',
1593
2362
                   'bzrlib.tests.test_transform',
1605
2374
                   'bzrlib.tests.test_weave',
1606
2375
                   'bzrlib.tests.test_whitebox',
1607
2376
                   'bzrlib.tests.test_workingtree',
 
2377
                   'bzrlib.tests.test_workingtree_4',
 
2378
                   'bzrlib.tests.test_wsgi',
1608
2379
                   'bzrlib.tests.test_xml',
1609
2380
                   ]
1610
2381
    test_transport_implementations = [
1614
2385
    suite = TestUtil.TestSuite()
1615
2386
    loader = TestUtil.TestLoader()
1616
2387
    suite.addTest(loader.loadTestsFromModuleNames(testmod_names))
1617
 
    from bzrlib.transport import TransportTestProviderAdapter
 
2388
    from bzrlib.tests.test_transport_implementations import TransportTestProviderAdapter
1618
2389
    adapter = TransportTestProviderAdapter()
1619
2390
    adapt_modules(test_transport_implementations, adapter, loader, suite)
1620
2391
    for package in packages_to_test():
1622
2393
    for m in MODULES_TO_TEST:
1623
2394
        suite.addTest(loader.loadTestsFromModule(m))
1624
2395
    for m in MODULES_TO_DOCTEST:
1625
 
        suite.addTest(doctest.DocTestSuite(m))
 
2396
        try:
 
2397
            suite.addTest(doctest.DocTestSuite(m))
 
2398
        except ValueError, e:
 
2399
            print '**failed to get doctest for: %s\n%s' %(m,e)
 
2400
            raise
1626
2401
    for name, plugin in bzrlib.plugin.all_plugins().items():
1627
2402
        if getattr(plugin, 'test_suite', None) is not None:
1628
 
            suite.addTest(plugin.test_suite())
 
2403
            default_encoding = sys.getdefaultencoding()
 
2404
            try:
 
2405
                plugin_suite = plugin.test_suite()
 
2406
            except ImportError, e:
 
2407
                bzrlib.trace.warning(
 
2408
                    'Unable to test plugin "%s": %s', name, e)
 
2409
            else:
 
2410
                suite.addTest(plugin_suite)
 
2411
            if default_encoding != sys.getdefaultencoding():
 
2412
                bzrlib.trace.warning(
 
2413
                    'Plugin "%s" tried to reset default encoding to: %s', name,
 
2414
                    sys.getdefaultencoding())
 
2415
                reload(sys)
 
2416
                sys.setdefaultencoding(default_encoding)
1629
2417
    return suite
1630
2418
 
1631
2419
 
1633
2421
    """Adapt the modules in mods_list using adapter and add to suite."""
1634
2422
    for test in iter_suite_tests(loader.loadTestsFromModuleNames(mods_list)):
1635
2423
        suite.addTests(adapter.adapt(test))
 
2424
 
 
2425
 
 
2426
def _rmtree_temp_dir(dirname):
 
2427
    # If LANG=C we probably have created some bogus paths
 
2428
    # which rmtree(unicode) will fail to delete
 
2429
    # so make sure we are using rmtree(str) to delete everything
 
2430
    # except on win32, where rmtree(str) will fail
 
2431
    # since it doesn't have the property of byte-stream paths
 
2432
    # (they are either ascii or mbcs)
 
2433
    if sys.platform == 'win32':
 
2434
        # make sure we are using the unicode win32 api
 
2435
        dirname = unicode(dirname)
 
2436
    else:
 
2437
        dirname = dirname.encode(sys.getfilesystemencoding())
 
2438
    try:
 
2439
        osutils.rmtree(dirname)
 
2440
    except OSError, e:
 
2441
        if sys.platform == 'win32' and e.errno == errno.EACCES:
 
2442
            print >>sys.stderr, ('Permission denied: '
 
2443
                                 'unable to remove testing dir '
 
2444
                                 '%s' % os.path.basename(dirname))
 
2445
        else:
 
2446
            raise
 
2447
 
 
2448
 
 
2449
def clean_selftest_output(root=None, quiet=False):
 
2450
    """Remove all selftest output directories from root directory.
 
2451
 
 
2452
    :param  root:   root directory for clean
 
2453
                    (if ommitted or None then clean current directory).
 
2454
    :param  quiet:  suppress report about deleting directories
 
2455
    """
 
2456
    import re
 
2457
    re_dir = re.compile(r'''test\d\d\d\d\.tmp''')
 
2458
    if root is None:
 
2459
        root = u'.'
 
2460
    for i in os.listdir(root):
 
2461
        if os.path.isdir(i) and re_dir.match(i):
 
2462
            if not quiet:
 
2463
                print 'delete directory:', i
 
2464
            _rmtree_temp_dir(i)
 
2465
 
 
2466
 
 
2467
class Feature(object):
 
2468
    """An operating system Feature."""
 
2469
 
 
2470
    def __init__(self):
 
2471
        self._available = None
 
2472
 
 
2473
    def available(self):
 
2474
        """Is the feature available?
 
2475
 
 
2476
        :return: True if the feature is available.
 
2477
        """
 
2478
        if self._available is None:
 
2479
            self._available = self._probe()
 
2480
        return self._available
 
2481
 
 
2482
    def _probe(self):
 
2483
        """Implement this method in concrete features.
 
2484
 
 
2485
        :return: True if the feature is available.
 
2486
        """
 
2487
        raise NotImplementedError
 
2488
 
 
2489
    def __str__(self):
 
2490
        if getattr(self, 'feature_name', None):
 
2491
            return self.feature_name()
 
2492
        return self.__class__.__name__
 
2493
 
 
2494
 
 
2495
class TestScenarioApplier(object):
 
2496
    """A tool to apply scenarios to tests."""
 
2497
 
 
2498
    def adapt(self, test):
 
2499
        """Return a TestSuite containing a copy of test for each scenario."""
 
2500
        result = unittest.TestSuite()
 
2501
        for scenario in self.scenarios:
 
2502
            result.addTest(self.adapt_test_to_scenario(test, scenario))
 
2503
        return result
 
2504
 
 
2505
    def adapt_test_to_scenario(self, test, scenario):
 
2506
        """Copy test and apply scenario to it.
 
2507
 
 
2508
        :param test: A test to adapt.
 
2509
        :param scenario: A tuple describing the scenarion.
 
2510
            The first element of the tuple is the new test id.
 
2511
            The second element is a dict containing attributes to set on the
 
2512
            test.
 
2513
        :return: The adapted test.
 
2514
        """
 
2515
        from copy import deepcopy
 
2516
        new_test = deepcopy(test)
 
2517
        for name, value in scenario[1].items():
 
2518
            setattr(new_test, name, value)
 
2519
        new_id = "%s(%s)" % (new_test.id(), scenario[0])
 
2520
        new_test.id = lambda: new_id
 
2521
        return new_test