Finalized integration of coverage.py within the Appy framework.

This commit is contained in:
Gaetan Delannay 2009-12-03 16:45:05 +01:00
parent 01487db688
commit c3f5cfc9cd
5 changed files with 66 additions and 32 deletions

View file

@ -1,5 +1,5 @@
# ------------------------------------------------------------------------------
import os, os.path, sys, parser, symbol, token
import os, os.path, sys, parser, symbol, token, types
from appy.gen import Type, State, Config, Tool, Flavour
from appy.gen.descriptors import *
from appy.gen.utils import produceNiceMessage
@ -150,6 +150,7 @@ class Generator:
self.initialize()
self.config = Config.getDefault()
self.modulesWithTests = set()
self.totalNumberOfTests = 0
def determineAppyType(self, klass):
'''Is p_klass an Appy class ? An Appy workflow? None of this ?
@ -172,10 +173,23 @@ class Generator:
return res
def containsTests(self, moduleOrClass):
'''Does p_moduleOrClass contain doctests?'''
if moduleOrClass.__doc__ and (moduleOrClass.__doc__.find('>>>') != -1):
return True
return False
'''Returns True if p_moduleOrClass contains doctests. This method also
counts tests and updates self.totalNumberOfTests.'''
res = False
docString = moduleOrClass.__doc__
if docString and (docString.find('>>>') != -1):
self.totalNumberOfTests += 1
res = True
# Count also docstring in methods
if type(moduleOrClass) == types.ClassType:
for name, elem in moduleOrClass.__dict__.iteritems():
if type(elem) in (staticmethod, classmethod):
elem = elem.__get__(name)
if hasattr(elem, '__doc__') and elem.__doc__ and \
(elem.__doc__.find('>>>') != -1):
res = True
self.totalNumberOfTests += 1
return res
IMPORT_ERROR = 'Warning: error while importing module %s (%s)'
SYNTAX_ERROR = 'Warning: error while parsing module %s (%s)'
@ -320,5 +334,8 @@ class Generator:
for classDescr in self.classes: self.generateClass(classDescr)
for wfDescr in self.workflows: self.generateWorkflow(wfDescr)
self.finalize()
print 'Done.'
msg = ''
if self.totalNumberOfTests:
msg = ' (number of tests found: %d)' % self.totalNumberOfTests
print 'Done%s.' % msg
# ------------------------------------------------------------------------------

View file

@ -325,6 +325,7 @@ class Generator(AbstractGenerator):
imports.append(importDef)
repls = self.repls.copy()
repls['imports'] = '\n'.join(imports)
repls['totalNumberOfTests'] = self.totalNumberOfTests
self.copyFile('__init__.py', repls)
def generateInstall(self):

View file

@ -32,7 +32,6 @@ class TestMixin:
# absence of names beginning with other chars than "__".
for elem in moduleObj.__dict__.iterkeys():
if not elem.startswith('__'):
print 'Element found in this module!!!', moduleObj, elem
res.append(moduleObj)
break
# Include sub-modules if any
@ -49,7 +48,8 @@ class TestMixin:
res += self.getNonEmptySubModules(subModuleName)
return res
def getCovFolder(self):
@staticmethod
def getCovFolder():
'''Returns the folder where to put the coverage folder if needed.'''
for arg in sys.argv:
if arg.startswith('[coverage'):
@ -68,28 +68,18 @@ def beforeTest(test):
test.createUser('admin', ('Member','Manager'))
test.login('admin')
g['t'] = g['test']
# Must we perform test coverage ?
covFolder = test.getCovFolder()
if covFolder:
try:
print 'COV!!!!', covFolder
import coverage
app = getattr(cfg, g['tool'].o.getAppName())
from coverage import coverage
cov = coverage()
g['cov'] = cov
g['covFolder'] = covFolder
cov.start()
except ImportError:
print 'You must install the "coverage" product.'
def afterTest(test):
'''Is executed after every test.'''
g = test.globs
if g.has_key('covFolder'):
cov = g['cov']
appName = g['tool'].o.getAppName()
exec 'from Products.%s import cov, covFolder, totalNumberOfTests, ' \
'countTest' % appName
countTest()
exec 'from Products.%s import numberOfExecutedTests' % appName
if cov and (numberOfExecutedTests == totalNumberOfTests):
cov.stop()
# Dumps the coverage report
appModules = test.getNonEmptySubModules(g['tool'].o.getAppName())
cov.html_report(directory=g['covFolder'], morfs=appModules)
appModules = test.getNonEmptySubModules(appName)
cov.html_report(directory=covFolder, morfs=appModules)
# ------------------------------------------------------------------------------

View file

@ -1,4 +1,30 @@
<!codeHeader!>
# Test coverage-related stuff --------------------------------------------------
import sys
from appy.gen.plone25.mixins.TestMixin import TestMixin
covFolder = TestMixin.getCovFolder()
# The previous method checks in sys.argv whether Zope was lauched for performing
# coverage tests or not.
cov = None # The main Coverage instance as created by the coverage program.
totalNumberOfTests = <!totalNumberOfTests!>
numberOfExecutedTests = 0
if covFolder:
try:
import coverage
from coverage import coverage
cov = coverage()
cov.start()
except ImportError:
print 'COVERAGE KO! The "coverage" program is not installed. You can ' \
'download it from http://nedbatchelder.com/code/coverage.' \
'\nHit <enter> to execute the test suite without coverage.'
sys.stdin.readline()
def countTest():
global numberOfExecutedTests
numberOfExecutedTests += 1
# ------------------------------------------------------------------------------
from config import *
import logging
try:
@ -13,6 +39,7 @@ from Products.Archetypes import listTypes
from appy.gen.plone25.installer import ZopeInstaller
logger = logging.getLogger(PROJECTNAME)
# Zope-level installation of the generated product. ----------------------------
def initialize(context):
<!imports!>
# I need to do those imports here; else, types and add permissions will not
@ -21,3 +48,4 @@ def initialize(context):
<!applicationName!>Tool.<!applicationName!>Tool,
DEFAULT_ADD_CONTENT_PERMISSION, ADD_CONTENT_PERMISSIONS,
logger, globals()).install()
# ------------------------------------------------------------------------------

View file

@ -613,12 +613,10 @@ class XmlComparator:
i += 1
if line and (line[0] != ' '):
if not atLeastOneDiff:
if report:
report.say('Difference(s) detected between files '\
'%s and %s:' % (self.fileNameA, self.fileNameB),
encoding='utf-8')
else:
print 'Differences:'
msg = 'Difference(s) detected between files %s and %s:' % \
(self.fileNameA, self.fileNameB)
if report: report.say(msg, encoding='utf-8')
else: print msg
atLeastOneDiff = True
if not lastLinePrinted:
if report: report.say('...')