55
56
# XXX: Not used yet
58
class TestCase(unittest.TestCase):
59
"""Base class for bzr unit tests.
61
Tests that need access to disk resources should subclass
62
FunctionalTestCase not TestCase.
65
# TODO: Special methods to invoke bzr, so that we can run it
66
# through a specified Python intepreter
68
OVERRIDE_PYTHON = None # to run with alternative python 'python'
71
def apply_redirected(self, stdin=None, stdout=None, stderr=None,
72
a_callable=None, *args, **kwargs):
73
"""Call callable with redirected std io pipes.
75
Returns the return code."""
76
from StringIO import StringIO
77
if not callable(a_callable):
78
raise ValueError("a_callable must be callable.")
82
stdout = self.TEST_LOG
84
stderr = self.TEST_LOG
85
real_stdin = sys.stdin
86
real_stdout = sys.stdout
87
real_stderr = sys.stderr
93
result = a_callable(*args, **kwargs)
95
sys.stdout = real_stdout
96
sys.stderr = real_stderr
97
sys.stdin = real_stdin
101
super(TestCase, self).setUp()
102
# setup a temporary log for the test
104
self.TEST_LOG = tempfile.NamedTemporaryFile(mode='wt', bufsize=0)
105
self.log("%s setup" % self.id())
108
self.log("%s teardown" % self.id())
110
super(TestCase, self).tearDown()
113
"""Log a message to a progress file"""
114
print >>self.TEST_LOG, msg
116
def check_inventory_shape(self, inv, shape):
118
Compare an inventory to a list of expected names.
120
Fail if they are not precisely equal.
123
shape = list(shape) # copy
124
for path, ie in inv.entries():
125
name = path.replace('\\', '/')
133
self.fail("expected paths not found in inventory: %r" % shape)
135
self.fail("unexpected paths found in inventory: %r" % extras)
138
"""Get the log the test case used. This can only be called once,
139
after which an exception will be raised.
141
self.TEST_LOG.flush()
142
log = open(self.TEST_LOG.name, 'rt').read()
143
self.TEST_LOG.close()
147
class FunctionalTestCase(TestCase):
148
"""Base class for tests that perform function testing - running bzr,
149
using files on disk, and similar activities.
151
InTempDir is an old alias for FunctionalTestCase.
157
def check_file_contents(self, filename, expect):
158
self.log("check contents of file %s" % filename)
159
contents = file(filename, 'r').read()
160
if contents != expect:
161
self.log("expected: %r" % expect)
162
self.log("actually: %r" % contents)
163
self.fail("contents of %s not as expected")
165
def _make_test_root(self):
170
if FunctionalTestCase.TEST_ROOT is not None:
172
FunctionalTestCase.TEST_ROOT = os.path.abspath(
173
tempfile.mkdtemp(suffix='.tmp',
174
prefix=self._TEST_NAME + '-',
177
# make a fake bzr directory there to prevent any tests propagating
178
# up onto the source directory's real branch
179
os.mkdir(os.path.join(FunctionalTestCase.TEST_ROOT, '.bzr'))
182
super(FunctionalTestCase, self).setUp()
184
self._make_test_root()
185
self._currentdir = os.getcwdu()
186
self.test_dir = os.path.join(self.TEST_ROOT, self.id())
187
os.mkdir(self.test_dir)
188
os.chdir(self.test_dir)
192
os.chdir(self._currentdir)
193
super(FunctionalTestCase, self).tearDown()
195
def formcmd(self, cmd):
196
if isinstance(cmd, basestring):
199
cmd[0] = self.BZRPATH
200
if self.OVERRIDE_PYTHON:
201
cmd.insert(0, self.OVERRIDE_PYTHON)
202
self.log('$ %r' % cmd)
205
def runcmd(self, cmd, retcode=0):
206
"""Run one command and check the return code.
208
Returns a tuple of (stdout,stderr) strings.
210
If a single string is based, it is split into words.
211
For commands that are not simple space-separated words, please
212
pass a list instead."""
215
from subprocess import call
216
except ImportError, e:
219
cmd = self.formcmd(cmd)
220
self.log('$ ' + ' '.join(cmd))
221
actual_retcode = call(cmd, stdout=self.TEST_LOG, stderr=self.TEST_LOG)
222
if retcode != actual_retcode:
223
raise CommandFailed("test failed: %r returned %d, expected %d"
224
% (cmd, actual_retcode, retcode))
226
def backtick(self, cmd, retcode=0):
227
"""Run a command and return its output"""
230
from subprocess import Popen, PIPE
231
except ImportError, e:
234
cmd = self.formcmd(cmd)
235
child = Popen(cmd, stdout=PIPE, stderr=self.TEST_LOG)
236
outd, errd = child.communicate()
238
actual_retcode = child.wait()
239
outd = outd.replace('\r', '')
240
if retcode != actual_retcode:
241
raise CommandFailed("test failed: %r returned %d, expected %d"
242
% (cmd, actual_retcode, retcode))
245
def build_tree(self, shape):
246
"""Build a test tree according to a pattern.
248
shape is a sequence of file specifications. If the final
249
character is '/', a directory is created.
251
This doesn't add anything to a branch.
253
# XXX: It's OK to just create them using forward slashes on windows?
256
assert isinstance(name, basestring)
261
print >>f, "contents of", name
264
InTempDir = FunctionalTestCase
60
class EarlyStoppingTestResultAdapter(object):
61
"""An adapter for TestResult to stop at the first first failure or error"""
63
def __init__(self, result):
66
def addError(self, test, err):
67
self._result.addError(test, err)
70
def addFailure(self, test, err):
71
self._result.addFailure(test, err)
74
def __getattr__(self, name):
75
return getattr(self._result, name)
77
def __setattr__(self, name, value):
79
object.__setattr__(self, name, value)
80
return setattr(self._result, name, value)
267
83
class _MyResult(unittest._TextTestResult):
313
129
class TextTestRunner(unittest.TextTestRunner):
315
131
def _makeResult(self):
316
return _MyResult(self.stream, self.descriptions, self.verbosity)
319
def run_suite(suite, name='test', verbose=False):
132
result = _MyResult(self.stream, self.descriptions, self.verbosity)
133
return EarlyStoppingTestResultAdapter(result)
136
class filteringVisitor(TestUtil.TestVisitor):
137
"""I accruse all the testCases I visit that pass a regexp filter on id
141
def __init__(self, filter):
143
TestUtil.TestVisitor.__init__(self)
145
self.filter=re.compile(filter)
148
"""answer the suite we are building"""
149
if self._suite is None:
150
self._suite=TestUtil.TestSuite()
153
def visitCase(self, aCase):
154
if self.filter.match(aCase.id()):
155
self.suite().addTest(aCase)
158
def run_suite(suite, name='test', verbose=False, pattern=".*"):
321
FunctionalTestCase._TEST_NAME = name
160
from bzrlib.selftest import TestCaseInTempDir
161
TestCaseInTempDir._TEST_NAME = name