1
# Copyright (C) 2004, 2005, 2006 Canonical Ltd
2
# Author: Robert Collins <robert.collins@canonical.com>
4
# This program is free software; you can redistribute it and/or modify
5
# it under the terms of the GNU General Public License as published by
6
# the Free Software Foundation; either version 2 of the License, or
7
# (at your option) any later version.
9
# This program is distributed in the hope that it will be useful,
10
# but WITHOUT ANY WARRANTY; without even the implied warranty of
11
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12
# GNU General Public License for more details.
14
# You should have received a copy of the GNU General Public License
15
# along with this program; if not, write to the Free Software
16
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
24
class LogCollector(logging.Handler):
26
logging.Handler.__init__(self)
28
def emit(self, record):
29
self.records.append(record.getMessage())
32
def makeCollectingLogger():
33
"""I make a logger instance that collects its logs for programmatic analysis
34
-> (logger, collector)"""
35
logger=logging.Logger("collector")
36
handler=LogCollector()
37
handler.setFormatter(logging.Formatter("%(levelname)s: %(message)s"))
38
logger.addHandler(handler)
39
return logger, handler
42
def visitTests(suite, visitor):
43
"""A foreign method for visiting the tests in a test suite."""
44
for test in suite._tests:
45
#Abusing types to avoid monkey patching unittest.TestCase.
46
# Maybe that would be better?
49
except AttributeError:
50
if isinstance(test, unittest.TestCase):
51
visitor.visitCase(test)
52
elif isinstance(test, unittest.TestSuite):
53
visitor.visitSuite(test)
54
visitTests(test, visitor)
56
print "unvisitable non-unittest.TestCase element %r (%r)" % (test, test.__class__)
59
class TestSuite(unittest.TestSuite):
60
"""I am an extended TestSuite with a visitor interface.
61
This is primarily to allow filtering of tests - and suites or
62
more in the future. An iterator of just tests wouldn't scale..."""
64
def visit(self, visitor):
65
"""visit the composite. Visiting is depth-first.
66
current callbacks are visitSuite and visitCase."""
67
visitor.visitSuite(self)
68
visitTests(self, visitor)
71
class TestLoader(unittest.TestLoader):
72
"""Custom TestLoader to address some quirks in the stock python one."""
73
suiteClass = TestSuite
75
def loadTestsFromModuleNames(self, names):
76
"""use a custom means to load tests from modules.
78
There is an undesirable glitch in the python TestLoader where a
79
import error is ignore. We think this can be solved by ensuring the
80
requested name is resolvable, if its not raising the original error.
82
result = self.suiteClass()
84
_load_module_by_name(name)
85
result.addTests(self.loadTestsFromName(name))
89
def _load_module_by_name(mod_name):
90
parts = mod_name.split('.')
91
module = __import__(mod_name)
93
# for historical reasons python returns the top-level module even though
94
# it loads the submodule; we need to walk down to get the one we want.
96
module = getattr(module, parts.pop(0))
100
class TestVisitor(object):
101
"""A visitor for Tests"""
102
def visitSuite(self, aTestSuite):
104
def visitCase(self, aTestCase):