1# Copyright (c) 2004 Canonical Limited 2# Author: Robert Collins <robert.collins@canonical.com> 3# 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. 8# 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. 13# 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 17# 18 19import sys 20import logging 21import unittest 22 23 24class LogCollector(logging.Handler): 25 def __init__(self): 26 logging.Handler.__init__(self) 27 self.records=[] 28 def emit(self, record): 29 self.records.append(record.getMessage()) 30 31 32def 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 40 41 42def 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? 47 try: 48 test.visit(visitor) 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) 55 else: 56 print "unvisitable non-unittest.TestCase element %r (%r)" % (test, test.__class__) 57 58 59class 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...""" 63 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) 69 70 71class TestLoader(unittest.TestLoader): 72 """Custome TestLoader to set the right TestSuite class.""" 73 suiteClass = TestSuite 74 75class TestVisitor(object): 76 """A visitor for Tests""" 77 def visitSuite(self, aTestSuite): 78 pass 79 def visitCase(self, aTestCase): 80 pass 81