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
22
from subprocess import call, Popen, PIPE
23
except ImportError, e:
25
sys.stderr.write("testbzr: sorry, this test suite requires the subprocess module\n"
26
"this is shipped with python2.4 and available separately for 2.3\n")
30
class CommandFailed(Exception):
34
class TestBase(TestCase):
35
"""Base class for bzr test cases.
37
Just defines some useful helper functions; doesn't actually test
41
# TODO: Special methods to invoke bzr, so that we can run it
42
# through a specified Python intepreter
44
OVERRIDE_PYTHON = None # to run with alternative python 'python'
50
def formcmd(self, cmd):
51
if isinstance(cmd, basestring):
56
if self.OVERRIDE_PYTHON:
57
cmd.insert(0, self.OVERRIDE_PYTHON)
59
self.log('$ %r' % cmd)
64
def runcmd(self, cmd, retcode=0):
65
"""Run one command and check the return code.
67
Returns a tuple of (stdout,stderr) strings.
69
If a single string is based, it is split into words.
70
For commands that are not simple space-separated words, please
71
pass a list instead."""
72
cmd = self.formcmd(cmd)
74
self.log('$ ' + ' '.join(cmd))
75
actual_retcode = call(cmd, stdout=self.TEST_LOG, stderr=self.TEST_LOG)
77
if retcode != actual_retcode:
78
raise CommandFailed("test failed: %r returned %d, expected %d"
79
% (cmd, actual_retcode, retcode))
82
def backtick(self, cmd, retcode=0):
83
"""Run a command and return its output"""
84
cmd = self.formcmd(cmd)
85
child = Popen(cmd, stdout=PIPE, stderr=self.TEST_LOG)
86
outd, errd = child.communicate()
88
actual_retcode = child.wait()
90
outd = outd.replace('\r', '')
92
if retcode != actual_retcode:
93
raise CommandFailed("test failed: %r returned %d, expected %d"
94
% (cmd, actual_retcode, retcode))
100
def build_tree(self, shape):
101
"""Build a test tree according to a pattern.
103
shape is a sequence of file specifications. If the final
104
character is '/', a directory is created.
106
This doesn't add anything to a branch.
108
# XXX: It's OK to just create them using forward slashes on windows?
111
assert isinstance(name, basestring)
116
print >>f, "contents of", name
121
"""Log a message to a progress file"""
122
self._log_buf = self._log_buf + str(msg) + '\n'
123
print >>self.TEST_LOG, msg
126
def check_inventory_shape(self, inv, shape):
128
Compare an inventory to a list of expected names.
130
Fail if they are not precisely equal.
133
shape = list(shape) # copy
134
for path, ie in inv.entries():
135
name = path.replace('\\', '/')
143
self.fail("expected paths not found in inventory: %r" % shape)
145
self.fail("unexpected paths found in inventory: %r" % extras)
148
def check_file_contents(self, filename, expect):
149
self.log("check contents of file %s" % filename)
150
contents = file(filename, 'r').read()
151
if contents != expect:
152
self.log("expected: %r" % expected)
153
self.log("actually: %r" % contents)
154
self.fail("contents of %s not as expected")
158
class InTempDir(TestBase):
159
"""Base class for tests run in a temporary branch."""
162
self.test_dir = os.path.join(self.TEST_ROOT, self.__class__.__name__)
163
os.mkdir(self.test_dir)
164
os.chdir(self.test_dir)
168
os.chdir(self.TEST_ROOT)
174
class _MyResult(TestResult):
178
No special behaviour for now.
180
def __init__(self, out):
182
TestResult.__init__(self)
184
def startTest(self, test):
185
# TODO: Maybe show test.shortDescription somewhere?
186
print >>self.out, '%-60.60s' % test.id(),
188
TestResult.startTest(self, test)
190
def stopTest(self, test):
192
TestResult.stopTest(self, test)
195
def addError(self, test, err):
196
print >>self.out, 'ERROR'
197
TestResult.addError(self, test, err)
198
_show_test_failure('error', test, err, self.out)
200
def addFailure(self, test, err):
201
print >>self.out, 'FAILURE'
202
TestResult.addFailure(self, test, err)
203
_show_test_failure('failure', test, err, self.out)
205
def addSuccess(self, test):
206
print >>self.out, 'OK'
207
TestResult.addSuccess(self, test)
212
from unittest import TestLoader, TestSuite
213
import bzrlib, bzrlib.store, bzrlib.inventory, bzrlib.branch, bzrlib.osutils, bzrlib.commands
215
import bzrlib.selftest.whitebox
216
import bzrlib.selftest.blackbox
217
import bzrlib.selftest.versioning
218
import bzrlib.selftest.testmerge3
219
import bzrlib.merge_core
220
from doctest import DocTestSuite
226
TestBase.BZRPATH = os.path.join(os.path.realpath(os.path.dirname(bzrlib.__path__[0])), 'bzr')
227
print '%-30s %s' % ('bzr binary', TestBase.BZRPATH)
236
# should also test bzrlib.merge_core, but they seem to be out of date with
239
for m in bzrlib.selftest.whitebox, \
240
bzrlib.selftest.versioning, \
241
bzrlib.selftest.testmerge3:
242
suite.addTest(tl.loadTestsFromModule(m))
244
for m in bzrlib.store, bzrlib.inventory, bzrlib.branch, bzrlib.osutils, \
247
suite.addTest(DocTestSuite(m))
249
suite.addTest(bzrlib.selftest.blackbox.suite())
251
# save stdout & stderr so there's no leakage from code-under-test
252
real_stdout = sys.stdout
253
real_stderr = sys.stderr
254
sys.stdout = sys.stderr = TestBase.TEST_LOG
256
result = _MyResult(real_stdout)
259
sys.stdout = real_stdout
260
sys.stderr = real_stderr
262
_show_results(result)
264
return result.wasSuccessful()
269
def _setup_test_log():
273
log_filename = os.path.abspath('testbzr.log')
274
TestBase.TEST_LOG = open(log_filename, 'wt', buffering=1) # line buffered
276
print >>TestBase.TEST_LOG, "bzr tests run at " + time.ctime()
277
print '%-30s %s' % ('test log', log_filename)
280
def _setup_test_dir():
284
TestBase.ORIG_DIR = os.getcwdu()
285
TestBase.TEST_ROOT = os.path.abspath("testbzr.tmp")
287
print '%-30s %s' % ('running tests in', TestBase.TEST_ROOT)
289
if os.path.exists(TestBase.TEST_ROOT):
290
shutil.rmtree(TestBase.TEST_ROOT)
291
os.mkdir(TestBase.TEST_ROOT)
292
os.chdir(TestBase.TEST_ROOT)
294
# make a fake bzr directory there to prevent any tests propagating
295
# up onto the source directory's real branch
296
os.mkdir(os.path.join(TestBase.TEST_ROOT, '.bzr'))
300
def _show_results(result):
302
print '%4d tests run' % result.testsRun
303
print '%4d errors' % len(result.errors)
304
print '%4d failures' % len(result.failures)
308
def _show_test_failure(kind, case, exc_info, out):
309
from traceback import print_exception
311
print >>out, '-' * 60
314
desc = case.shortDescription()
316
print >>out, ' (%s)' % desc
318
print_exception(exc_info[0], exc_info[1], exc_info[2], None, out)
320
if isinstance(case, TestBase):
322
print >>out, 'log from this test:'
323
print >>out, case._log_buf
325
print >>out, '-' * 60