Finalized integration of coverage.py within the Appy framework.
This commit is contained in:
parent
01487db688
commit
c3f5cfc9cd
|
@ -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
|
||||
# ------------------------------------------------------------------------------
|
||||
|
|
|
@ -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):
|
||||
|
|
|
@ -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)
|
||||
# ------------------------------------------------------------------------------
|
||||
|
|
|
@ -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()
|
||||
# ------------------------------------------------------------------------------
|
||||
|
|
|
@ -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('...')
|
||||
|
|
Loading…
Reference in a new issue