Viewing file: TestCoverage.py (4.45 KB) -rw-r--r-- Select action/file-type: (+) | (+) | (+) | Code (+) | Session (+) | (+) | SDB (+) | (+) | (+) | (+) | (+) | (+) |
######################################################################## # $Header: /var/local/cvsroot/4Suite/Ft/Lib/TestSuite/TestCoverage.py,v 1.9 2005/04/07 20:05:52 jkloth Exp $ """ A class that uses Python's profiler to help TestModule know which functions have been called in a particular module.
Copyright 2004 Fourthought, Inc. (USA). Detailed license and copyright information: http://4suite.org/COPYRIGHT Project home, documentation, distributions: http://4suite.org/ """
import sys, os, inspect
class TestCoverage:
def __init__(self, moduleName, ignored=None): self.module = moduleName module = __import__(moduleName, {}, {}, ['*']) self.path = os.path.dirname(module.__file__) self.ignored = ignored or [] self.data = {} return
def _getFunctionList(self): data = {} modules = {None : None} for entry in os.listdir(self.path): module_name = inspect.getmodulename(entry) if modules.has_key(module_name): # Don't process duplicates continue
try: module = __import__(self.module + '.' + module_name, {}, {}, '*') except (ImportError, NameError): # It probably needs something else to be imported first, # but we have no easy way of knowing what, so we have to skip it. continue
for top_name,object in vars(module).items(): if object in self.ignored: continue if inspect.isfunction(object) and top_name != '_': data[object.func_code] = object elif inspect.isclass(object): # Get the methods defined on this class for name, method in inspect.getmembers(object, inspect.ismethod): if method in self.ignored: continue # Make sure this method is not a C function if name not in ['__str__', '__repr__','pprint'] and \ inspect.isfunction(method.im_func): data[method.im_func.func_code] = method
# Only watch the objects that are defined directly in this package self.data = {} for code, object in data.items(): if self.path == os.path.dirname(code.co_filename): self.data[code] = object return
def _dispatch(self, frame, event, arg): if event == 'call': fcode = frame.f_code # Any items remaining in self.data will be those not called if self.data.has_key(fcode): del self.data[fcode] return 1
def _start(self, tester): self._getFunctionList() sys.setprofile(self._dispatch) return
def _end(self, tester): # Stop watching function calls sys.setprofile(None)
modules = {} for code, object in self.data.items(): if inspect.ismethod(object): type = 'method' name = object.im_class.__name__ + '.' + object.__name__ module = object.im_class.__module__ else: type = 'function' name = object.__name__ module = object.func_globals['__name__'] if not modules.has_key(module): modules[module] = {'method' : [], 'function' : [], } modules[module][type].append((name, code.co_firstlineno))
tester.startGroup('Coverage Test') tester.startTest("Verifing called functions")
keys = modules.keys() keys.sort() for module in keys: lines = [] if modules[module]['function']: funcs = modules[module]['function'] lines.append('Functions not called in %r:' % module) funcs.sort() for name, line in funcs: lines.append(' %r on line %s' % (name, line)) if modules[module]['method']: lines.append('Methods not called in %r:' % module) meths = modules[module]['method'] meths.sort() for name, line in meths: lines.append(' %r on line %s' % (name, line)) tester.warning('\n'.join(lines)) tester.testDone() tester.groupDone() return
|