1
# Copyright (C) 2005 by Canonical Ltd
3
# This program is free software; you can redistribute it and/or modify
4
# it under the terms of the GNU General Public License as published by
5
# the Free Software Foundation; either version 2 of the License, or
6
# (at your option) any later version.
8
# This program is distributed in the hope that it will be useful,
9
# but WITHOUT ANY WARRANTY; without even the implied warranty of
10
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11
# GNU General Public License for more details.
13
# You should have received a copy of the GNU General Public License
14
# along with this program; if not, write to the Free Software
15
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
18
from unittest import TestResult, TestCase
20
def _need_subprocess():
21
sys.stderr.write("sorry, this test suite requires the subprocess module\n"
22
"this is shipped with python2.4 and available separately for 2.3\n")
25
class CommandFailed(Exception):
30
class TestSkipped(Exception):
31
"""Indicates that a test was intentionally skipped, rather than failing."""
35
class TestBase(TestCase):
36
"""Base class for bzr test cases.
38
Just defines some useful helper functions; doesn't actually test
42
# TODO: Special methods to invoke bzr, so that we can run it
43
# through a specified Python intepreter
45
OVERRIDE_PYTHON = None # to run with alternative python 'python'
52
super(TestBase, self).setUp()
53
self.log("%s setup" % self.id())
57
super(TestBase, self).tearDown()
58
self.log("%s teardown" % self.id())
62
def formcmd(self, cmd):
63
if isinstance(cmd, basestring):
68
if self.OVERRIDE_PYTHON:
69
cmd.insert(0, self.OVERRIDE_PYTHON)
71
self.log('$ %r' % cmd)
76
def runcmd(self, cmd, retcode=0):
77
"""Run one command and check the return code.
79
Returns a tuple of (stdout,stderr) strings.
81
If a single string is based, it is split into words.
82
For commands that are not simple space-separated words, please
83
pass a list instead."""
85
from subprocess import call, Popen, PIPE
86
except ImportError, e:
91
cmd = self.formcmd(cmd)
93
self.log('$ ' + ' '.join(cmd))
94
actual_retcode = call(cmd, stdout=self.TEST_LOG, stderr=self.TEST_LOG)
96
if retcode != actual_retcode:
97
raise CommandFailed("test failed: %r returned %d, expected %d"
98
% (cmd, actual_retcode, retcode))
101
def backtick(self, cmd, retcode=0):
102
"""Run a command and return its output"""
104
from subprocess import call, Popen, PIPE
105
except ImportError, e:
109
cmd = self.formcmd(cmd)
110
child = Popen(cmd, stdout=PIPE, stderr=self.TEST_LOG)
111
outd, errd = child.communicate()
113
actual_retcode = child.wait()
115
outd = outd.replace('\r', '')
117
if retcode != actual_retcode:
118
raise CommandFailed("test failed: %r returned %d, expected %d"
119
% (cmd, actual_retcode, retcode))
125
def build_tree(self, shape):
126
"""Build a test tree according to a pattern.
128
shape is a sequence of file specifications. If the final
129
character is '/', a directory is created.
131
This doesn't add anything to a branch.
133
# XXX: It's OK to just create them using forward slashes on windows?
136
assert isinstance(name, basestring)
141
print >>f, "contents of", name
146
"""Log a message to a progress file"""
147
self._log_buf = self._log_buf + str(msg) + '\n'
148
print >>self.TEST_LOG, msg
151
def check_inventory_shape(self, inv, shape):
153
Compare an inventory to a list of expected names.
155
Fail if they are not precisely equal.
158
shape = list(shape) # copy
159
for path, ie in inv.entries():
160
name = path.replace('\\', '/')
168
self.fail("expected paths not found in inventory: %r" % shape)
170
self.fail("unexpected paths found in inventory: %r" % extras)
173
def check_file_contents(self, filename, expect):
174
self.log("check contents of file %s" % filename)
175
contents = file(filename, 'r').read()
176
if contents != expect:
177
self.log("expected: %r" % expected)
178
self.log("actually: %r" % contents)
179
self.fail("contents of %s not as expected")
183
class InTempDir(TestBase):
184
"""Base class for tests run in a temporary branch."""
187
self.test_dir = os.path.join(self.TEST_ROOT, self.__class__.__name__)
188
os.mkdir(self.test_dir)
189
os.chdir(self.test_dir)
193
os.chdir(self.TEST_ROOT)
199
class _MyResult(TestResult):
203
No special behaviour for now.
205
def __init__(self, out):
207
TestResult.__init__(self)
209
def startTest(self, test):
210
# TODO: Maybe show test.shortDescription somewhere?
211
print >>self.out, '%-60.60s' % test.id(),
213
TestResult.startTest(self, test)
215
def stopTest(self, test):
217
TestResult.stopTest(self, test)
220
def addError(self, test, err):
221
print >>self.out, 'ERROR'
222
TestResult.addError(self, test, err)
223
_show_test_failure('error', test, err, self.out)
225
def addFailure(self, test, err):
226
print >>self.out, 'FAILURE'
227
TestResult.addFailure(self, test, err)
228
_show_test_failure('failure', test, err, self.out)
230
def addSuccess(self, test):
231
print >>self.out, 'OK'
232
TestResult.addSuccess(self, test)
237
from unittest import TestLoader, TestSuite
239
import bzrlib.selftest.whitebox
240
import bzrlib.selftest.blackbox
241
import bzrlib.selftest.versioning
242
from doctest import DocTestSuite
251
for m in bzrlib.selftest.whitebox, \
252
bzrlib.selftest.versioning:
253
suite.addTest(tl.loadTestsFromModule(m))
255
for m in bzrlib.store, bzrlib.inventory, bzrlib.branch, bzrlib.osutils, \
257
suite.addTest(DocTestSuite(m))
259
suite.addTest(bzrlib.selftest.blackbox.suite())
261
return run_suite(suite)
264
def run_suite(suite):
274
# save stdout & stderr so there's no leakage from code-under-test
275
real_stdout = sys.stdout
276
real_stderr = sys.stderr
277
sys.stdout = sys.stderr = TestBase.TEST_LOG
279
result = _MyResult(real_stdout)
282
sys.stdout = real_stdout
283
sys.stderr = real_stderr
285
_show_results(result)
287
return result.wasSuccessful()
291
def _setup_test_log():
295
log_filename = os.path.abspath('test.log')
296
TestBase.TEST_LOG = open(log_filename, 'wt', buffering=1) # line buffered
298
print >>TestBase.TEST_LOG, "tests run at " + time.ctime()
299
print '%-30s %s' % ('test log', log_filename)
302
def _setup_test_dir():
306
TestBase.ORIG_DIR = os.getcwdu()
307
TestBase.TEST_ROOT = os.path.abspath("test.tmp")
309
print '%-30s %s' % ('running tests in', TestBase.TEST_ROOT)
311
if os.path.exists(TestBase.TEST_ROOT):
312
shutil.rmtree(TestBase.TEST_ROOT)
313
os.mkdir(TestBase.TEST_ROOT)
314
os.chdir(TestBase.TEST_ROOT)
316
# make a fake bzr directory there to prevent any tests propagating
317
# up onto the source directory's real branch
318
os.mkdir(os.path.join(TestBase.TEST_ROOT, '.bzr'))
322
def _show_results(result):
324
print '%4d tests run' % result.testsRun
325
print '%4d errors' % len(result.errors)
326
print '%4d failures' % len(result.failures)
330
def _show_test_failure(kind, case, exc_info, out):
331
from traceback import print_exception
333
print >>out, '-' * 60
336
desc = case.shortDescription()
338
print >>out, ' (%s)' % desc
340
print_exception(exc_info[0], exc_info[1], exc_info[2], None, out)
342
if isinstance(case, TestBase):
344
print >>out, 'log from this test:'
345
print >>out, case._log_buf
347
print >>out, '-' * 60