diff --git a/gen/generator.py b/gen/generator.py index 0179f57..d42bedb 100755 --- a/gen/generator.py +++ b/gen/generator.py @@ -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 # ------------------------------------------------------------------------------ diff --git a/gen/plone25/generator.py b/gen/plone25/generator.py index e17f7d3..ed44802 100644 --- a/gen/plone25/generator.py +++ b/gen/plone25/generator.py @@ -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): diff --git a/gen/plone25/mixins/TestMixin.py b/gen/plone25/mixins/TestMixin.py index b305911..265dcc7 100644 --- a/gen/plone25/mixins/TestMixin.py +++ b/gen/plone25/mixins/TestMixin.py @@ -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) # ------------------------------------------------------------------------------ diff --git a/gen/plone25/templates/__init__.py b/gen/plone25/templates/__init__.py index 6439b1f..e4229c5 100644 --- a/gen/plone25/templates/__init__.py +++ b/gen/plone25/templates/__init__.py @@ -1,4 +1,30 @@ +# 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 = +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 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): # I need to do those imports here; else, types and add permissions will not @@ -21,3 +48,4 @@ def initialize(context): Tool.Tool, DEFAULT_ADD_CONTENT_PERMISSION, ADD_CONTENT_PERMISSIONS, logger, globals()).install() +# ------------------------------------------------------------------------------ diff --git a/shared/xml_parser.py b/shared/xml_parser.py index 0095499..77de4f2 100755 --- a/shared/xml_parser.py +++ b/shared/xml_parser.py @@ -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('...')