[Pkg-bazaar-commits] ./bzr/unstable r841: - Start splitting bzr-independent parts of the test framework into
Martin Pool
mbp at sourcefrog.net
Fri Apr 10 08:13:40 UTC 2009
------------------------------------------------------------
revno: 841
committer: Martin Pool <mbp at sourcefrog.net>
timestamp: Wed 2005-07-06 14:40:52 +1000
message:
- Start splitting bzr-independent parts of the test framework into
testsweet.py
added:
testsweet.py
modified:
bzrlib/selftest/__init__.py
-------------- next part --------------
=== modified file 'bzrlib/selftest/__init__.py'
--- a/bzrlib/selftest/__init__.py 2005-07-06 04:20:14 +0000
+++ b/bzrlib/selftest/__init__.py 2005-07-06 04:40:52 +0000
@@ -15,207 +15,7 @@
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
-from unittest import TestResult, TestCase
-
-class CommandFailed(Exception):
- pass
-
-
-class TestBase(TestCase):
- """Base class for bzr test cases.
-
- Just defines some useful helper functions; doesn't actually test
- anything.
- """
-
- # TODO: Special methods to invoke bzr, so that we can run it
- # through a specified Python intepreter
-
- OVERRIDE_PYTHON = None # to run with alternative python 'python'
- BZRPATH = 'bzr'
-
- _log_buf = ""
-
-
- def formcmd(self, cmd):
- if isinstance(cmd, basestring):
- cmd = cmd.split()
-
- if cmd[0] == 'bzr':
- cmd[0] = self.BZRPATH
- if self.OVERRIDE_PYTHON:
- cmd.insert(0, self.OVERRIDE_PYTHON)
-
- self.log('$ %r' % cmd)
-
- return cmd
-
-
- def runcmd(self, cmd, retcode=0):
- """Run one command and check the return code.
-
- Returns a tuple of (stdout,stderr) strings.
-
- If a single string is based, it is split into words.
- For commands that are not simple space-separated words, please
- pass a list instead."""
- try:
- import shutil
- from subprocess import call
- except ImportError, e:
- import sys
- sys.stderr.write("testbzr: sorry, this test suite requires the subprocess module\n"
- "this is shipped with python2.4 and available separately for 2.3\n")
- raise
-
-
- cmd = self.formcmd(cmd)
-
- self.log('$ ' + ' '.join(cmd))
- actual_retcode = call(cmd, stdout=self.TEST_LOG, stderr=self.TEST_LOG)
-
- if retcode != actual_retcode:
- raise CommandFailed("test failed: %r returned %d, expected %d"
- % (cmd, actual_retcode, retcode))
-
-
- def backtick(self, cmd, retcode=0):
- """Run a command and return its output"""
- try:
- import shutil
- from subprocess import Popen, PIPE
- except ImportError, e:
- import sys
- sys.stderr.write("testbzr: sorry, this test suite requires the subprocess module\n"
- "this is shipped with python2.4 and available separately for 2.3\n")
- raise
-
-
- cmd = self.formcmd(cmd)
- child = Popen(cmd, stdout=PIPE, stderr=self.TEST_LOG)
- outd, errd = child.communicate()
- self.log(outd)
- actual_retcode = child.wait()
-
- outd = outd.replace('\r', '')
-
- if retcode != actual_retcode:
- raise CommandFailed("test failed: %r returned %d, expected %d"
- % (cmd, actual_retcode, retcode))
-
- return outd
-
-
-
- def build_tree(self, shape):
- """Build a test tree according to a pattern.
-
- shape is a sequence of file specifications. If the final
- character is '/', a directory is created.
-
- This doesn't add anything to a branch.
- """
- # XXX: It's OK to just create them using forward slashes on windows?
- import os
- for name in shape:
- assert isinstance(name, basestring)
- if name[-1] == '/':
- os.mkdir(name[:-1])
- else:
- f = file(name, 'wt')
- print >>f, "contents of", name
- f.close()
-
-
- def log(self, msg):
- """Log a message to a progress file"""
- self._log_buf = self._log_buf + str(msg) + '\n'
- print >>self.TEST_LOG, msg
-
-
- def check_inventory_shape(self, inv, shape):
- """
- Compare an inventory to a list of expected names.
-
- Fail if they are not precisely equal.
- """
- extras = []
- shape = list(shape) # copy
- for path, ie in inv.entries():
- name = path.replace('\\', '/')
- if ie.kind == 'dir':
- name = name + '/'
- if name in shape:
- shape.remove(name)
- else:
- extras.append(name)
- if shape:
- self.fail("expected paths not found in inventory: %r" % shape)
- if extras:
- self.fail("unexpected paths found in inventory: %r" % extras)
-
-
- def check_file_contents(self, filename, expect):
- self.log("check contents of file %s" % filename)
- contents = file(filename, 'r').read()
- if contents != expect:
- self.log("expected: %r" % expected)
- self.log("actually: %r" % contents)
- self.fail("contents of %s not as expected")
-
-
-
-class InTempDir(TestBase):
- """Base class for tests run in a temporary branch."""
- def setUp(self):
- import os
- self.test_dir = os.path.join(self.TEST_ROOT, self.__class__.__name__)
- os.mkdir(self.test_dir)
- os.chdir(self.test_dir)
-
- def tearDown(self):
- import os
- os.chdir(self.TEST_ROOT)
-
-
-
-
-
-class _MyResult(TestResult):
- """
- Custom TestResult.
-
- No special behaviour for now.
- """
- def __init__(self, out):
- self.out = out
- TestResult.__init__(self)
-
- def startTest(self, test):
- # TODO: Maybe show test.shortDescription somewhere?
- print >>self.out, '%-60.60s' % test.id(),
- self.out.flush()
- TestResult.startTest(self, test)
-
- def stopTest(self, test):
- # print
- TestResult.stopTest(self, test)
-
-
- def addError(self, test, err):
- print >>self.out, 'ERROR'
- TestResult.addError(self, test, err)
- _show_test_failure('error', test, err, self.out)
-
- def addFailure(self, test, err):
- print >>self.out, 'FAILURE'
- TestResult.addFailure(self, test, err)
- _show_test_failure('failure', test, err, self.out)
-
- def addSuccess(self, test):
- print >>self.out, 'OK'
- TestResult.addSuccess(self, test)
-
+from testsweet import TestBase, run_suite, InTempDir
def selftest():
@@ -236,8 +36,6 @@
TestBase.BZRPATH = os.path.join(os.path.realpath(os.path.dirname(bzrlib.__path__[0])), 'bzr')
print '%-30s %s' % ('bzr binary', TestBase.BZRPATH)
- _setup_test_log()
- _setup_test_dir()
print
suite = TestSuite()
@@ -258,80 +56,7 @@
suite.addTest(bzrlib.selftest.blackbox.suite())
- # save stdout & stderr so there's no leakage from code-under-test
- real_stdout = sys.stdout
- real_stderr = sys.stderr
- sys.stdout = sys.stderr = TestBase.TEST_LOG
- try:
- result = _MyResult(real_stdout)
- suite.run(result)
- finally:
- sys.stdout = real_stdout
- sys.stderr = real_stderr
-
- _show_results(result)
-
- return result.wasSuccessful()
-
-
-
-
-def _setup_test_log():
- import time
- import os
-
- log_filename = os.path.abspath('testbzr.log')
- TestBase.TEST_LOG = open(log_filename, 'wt', buffering=1) # line buffered
-
- print >>TestBase.TEST_LOG, "bzr tests run at " + time.ctime()
- print '%-30s %s' % ('test log', log_filename)
-
-
-def _setup_test_dir():
- import os
- import shutil
-
- TestBase.ORIG_DIR = os.getcwdu()
- TestBase.TEST_ROOT = os.path.abspath("testbzr.tmp")
-
- print '%-30s %s' % ('running tests in', TestBase.TEST_ROOT)
-
- if os.path.exists(TestBase.TEST_ROOT):
- shutil.rmtree(TestBase.TEST_ROOT)
- os.mkdir(TestBase.TEST_ROOT)
- os.chdir(TestBase.TEST_ROOT)
-
- # make a fake bzr directory there to prevent any tests propagating
- # up onto the source directory's real branch
- os.mkdir(os.path.join(TestBase.TEST_ROOT, '.bzr'))
-
-
-
-def _show_results(result):
- print
- print '%4d tests run' % result.testsRun
- print '%4d errors' % len(result.errors)
- print '%4d failures' % len(result.failures)
-
-
-
-def _show_test_failure(kind, case, exc_info, out):
- from traceback import print_exception
-
- print >>out, '-' * 60
- print >>out, case
-
- desc = case.shortDescription()
- if desc:
- print >>out, ' (%s)' % desc
-
- print_exception(exc_info[0], exc_info[1], exc_info[2], None, out)
-
- if isinstance(case, TestBase):
- print >>out
- print >>out, 'log from this test:'
- print >>out, case._log_buf
-
- print >>out, '-' * 60
-
+ return run_suite(suite)
+
+
=== added file 'testsweet.py'
--- a/testsweet.py 1970-01-01 00:00:00 +0000
+++ b/testsweet.py 2005-07-06 04:40:52 +0000
@@ -0,0 +1,346 @@
+# Copyright (C) 2005 by Canonical Ltd
+
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+
+
+"""Enhanced layer on unittest.
+
+This does several things:
+
+* nicer reporting as tests run
+
+* test code can log messages into a buffer that is recorded to disk
+ and displayed if the test fails
+
+* tests can be run in a separate directory, which is useful for code that
+ wants to create files
+
+* utilities to run external commands and check their return code
+ and/or output
+
+Test cases should normally subclass TestBase. The test runner should
+call runsuite().
+
+This is meant to become independent of bzr, though that's not quite
+true yet.
+"""
+
+
+from unittest import TestResult, TestCase
+
+def _need_subprocess():
+ sys.stderr.write("sorry, this test suite requires the subprocess module\n"
+ "this is shipped with python2.4 and available separately for 2.3\n")
+
+
+class CommandFailed(Exception):
+ pass
+
+
+
+class TestSkipped(Exception):
+ """Indicates that a test was intentionally skipped, rather than failing."""
+ # XXX: Not used yet
+
+
+class TestBase(TestCase):
+ """Base class for bzr test cases.
+
+ Just defines some useful helper functions; doesn't actually test
+ anything.
+ """
+
+ # TODO: Special methods to invoke bzr, so that we can run it
+ # through a specified Python intepreter
+
+ OVERRIDE_PYTHON = None # to run with alternative python 'python'
+ BZRPATH = 'bzr'
+
+ _log_buf = ""
+
+
+ def setUp(self):
+ super(TestBase, self).setUp()
+ self.log("%s setup" % self.id())
+
+
+ def tearDown(self):
+ super(TestBase, self).tearDown()
+ self.log("%s teardown" % self.id())
+ self.log('')
+
+
+ def formcmd(self, cmd):
+ if isinstance(cmd, basestring):
+ cmd = cmd.split()
+
+ if cmd[0] == 'bzr':
+ cmd[0] = self.BZRPATH
+ if self.OVERRIDE_PYTHON:
+ cmd.insert(0, self.OVERRIDE_PYTHON)
+
+ self.log('$ %r' % cmd)
+
+ return cmd
+
+
+ def runcmd(self, cmd, retcode=0):
+ """Run one command and check the return code.
+
+ Returns a tuple of (stdout,stderr) strings.
+
+ If a single string is based, it is split into words.
+ For commands that are not simple space-separated words, please
+ pass a list instead."""
+ try:
+ import shutil
+ from subprocess import call
+ except ImportError, e:
+ _need_subprocess()
+ raise
+
+
+ cmd = self.formcmd(cmd)
+
+ self.log('$ ' + ' '.join(cmd))
+ actual_retcode = call(cmd, stdout=self.TEST_LOG, stderr=self.TEST_LOG)
+
+ if retcode != actual_retcode:
+ raise CommandFailed("test failed: %r returned %d, expected %d"
+ % (cmd, actual_retcode, retcode))
+
+
+ def backtick(self, cmd, retcode=0):
+ """Run a command and return its output"""
+ try:
+ import shutil
+ from subprocess import Popen, PIPE
+ except ImportError, e:
+ _need_subprocess()
+ raise
+
+ cmd = self.formcmd(cmd)
+ child = Popen(cmd, stdout=PIPE, stderr=self.TEST_LOG)
+ outd, errd = child.communicate()
+ self.log(outd)
+ actual_retcode = child.wait()
+
+ outd = outd.replace('\r', '')
+
+ if retcode != actual_retcode:
+ raise CommandFailed("test failed: %r returned %d, expected %d"
+ % (cmd, actual_retcode, retcode))
+
+ return outd
+
+
+
+ def build_tree(self, shape):
+ """Build a test tree according to a pattern.
+
+ shape is a sequence of file specifications. If the final
+ character is '/', a directory is created.
+
+ This doesn't add anything to a branch.
+ """
+ # XXX: It's OK to just create them using forward slashes on windows?
+ import os
+ for name in shape:
+ assert isinstance(name, basestring)
+ if name[-1] == '/':
+ os.mkdir(name[:-1])
+ else:
+ f = file(name, 'wt')
+ print >>f, "contents of", name
+ f.close()
+
+
+ def log(self, msg):
+ """Log a message to a progress file"""
+ self._log_buf = self._log_buf + str(msg) + '\n'
+ print >>self.TEST_LOG, msg
+
+
+ def check_inventory_shape(self, inv, shape):
+ """
+ Compare an inventory to a list of expected names.
+
+ Fail if they are not precisely equal.
+ """
+ extras = []
+ shape = list(shape) # copy
+ for path, ie in inv.entries():
+ name = path.replace('\\', '/')
+ if ie.kind == 'dir':
+ name = name + '/'
+ if name in shape:
+ shape.remove(name)
+ else:
+ extras.append(name)
+ if shape:
+ self.fail("expected paths not found in inventory: %r" % shape)
+ if extras:
+ self.fail("unexpected paths found in inventory: %r" % extras)
+
+
+ def check_file_contents(self, filename, expect):
+ self.log("check contents of file %s" % filename)
+ contents = file(filename, 'r').read()
+ if contents != expect:
+ self.log("expected: %r" % expected)
+ self.log("actually: %r" % contents)
+ self.fail("contents of %s not as expected")
+
+
+
+class InTempDir(TestBase):
+ """Base class for tests run in a temporary branch."""
+ def setUp(self):
+ import os
+ self.test_dir = os.path.join(self.TEST_ROOT, self.__class__.__name__)
+ os.mkdir(self.test_dir)
+ os.chdir(self.test_dir)
+
+ def tearDown(self):
+ import os
+ os.chdir(self.TEST_ROOT)
+
+
+
+
+
+class _MyResult(TestResult):
+ """
+ Custom TestResult.
+
+ No special behaviour for now.
+ """
+ def __init__(self, out):
+ self.out = out
+ TestResult.__init__(self)
+
+ def startTest(self, test):
+ # TODO: Maybe show test.shortDescription somewhere?
+ print >>self.out, '%-60.60s' % test.id(),
+ self.out.flush()
+ TestResult.startTest(self, test)
+
+ def stopTest(self, test):
+ # print
+ TestResult.stopTest(self, test)
+
+
+ def addError(self, test, err):
+ print >>self.out, 'ERROR'
+ TestResult.addError(self, test, err)
+ _show_test_failure('error', test, err, self.out)
+
+ def addFailure(self, test, err):
+ print >>self.out, 'FAILURE'
+ TestResult.addFailure(self, test, err)
+ _show_test_failure('failure', test, err, self.out)
+
+ def addSuccess(self, test):
+ print >>self.out, 'OK'
+ TestResult.addSuccess(self, test)
+
+
+
+def run_suite(suite, name="test"):
+ import os
+ import shutil
+ import time
+ import sys
+
+ _setup_test_log(name)
+ _setup_test_dir(name)
+ print
+
+ # save stdout & stderr so there's no leakage from code-under-test
+ real_stdout = sys.stdout
+ real_stderr = sys.stderr
+ sys.stdout = sys.stderr = TestBase.TEST_LOG
+ try:
+ result = _MyResult(real_stdout)
+ suite.run(result)
+ finally:
+ sys.stdout = real_stdout
+ sys.stderr = real_stderr
+
+ _show_results(result)
+
+ return result.wasSuccessful()
+
+
+
+def _setup_test_log(name):
+ import time
+ import os
+
+ log_filename = os.path.abspath(name + '.log')
+ TestBase.TEST_LOG = open(log_filename, 'wt', buffering=1) # line buffered
+
+ print >>TestBase.TEST_LOG, "tests run at " + time.ctime()
+ print '%-30s %s' % ('test log', log_filename)
+
+
+def _setup_test_dir(name):
+ import os
+ import shutil
+
+ TestBase.ORIG_DIR = os.getcwdu()
+ TestBase.TEST_ROOT = os.path.abspath(name + '.tmp')
+
+ print '%-30s %s' % ('running tests in', TestBase.TEST_ROOT)
+
+ if os.path.exists(TestBase.TEST_ROOT):
+ shutil.rmtree(TestBase.TEST_ROOT)
+ os.mkdir(TestBase.TEST_ROOT)
+ os.chdir(TestBase.TEST_ROOT)
+
+ # make a fake bzr directory there to prevent any tests propagating
+ # up onto the source directory's real branch
+ os.mkdir(os.path.join(TestBase.TEST_ROOT, '.bzr'))
+
+
+
+def _show_results(result):
+ print
+ print '%4d tests run' % result.testsRun
+ print '%4d errors' % len(result.errors)
+ print '%4d failures' % len(result.failures)
+
+
+
+def _show_test_failure(kind, case, exc_info, out):
+ from traceback import print_exception
+
+ print >>out, '-' * 60
+ print >>out, case
+
+ desc = case.shortDescription()
+ if desc:
+ print >>out, ' (%s)' % desc
+
+ print_exception(exc_info[0], exc_info[1], exc_info[2], None, out)
+
+ if isinstance(case, TestBase):
+ print >>out
+ print >>out, 'log from this test:'
+ print >>out, case._log_buf
+
+ print >>out, '-' * 60
+
+
More information about the Pkg-bazaar-commits
mailing list