From 2efe607f06e80a0f737d4c520ed3b95e446fac06 Mon Sep 17 00:00:00 2001 From: chaoflow Date: Fri, 9 Jan 2009 13:38:56 +0000 Subject: [PATCH] paula.testing: tests pass, no app dep, currently no zcml git-svn-id: https://svn.plone.org/svn/collective/paula/trunk@78689 db7f04ef-aaf3-0310-a811-c281ed44c4ad --- paula.testing/setup.py | 3 +- paula.testing/src/paula/testing/README.txt | 23 +- paula.testing/src/paula/testing/__init__.py | 12 - paula.testing/src/paula/testing/mock.py | 11 +- .../paula/testing/no_package/no_package_file.py | 0 .../paula/testing/no_package/no_package_file2.py | 0 .../paula/testing/no_package/no_package_file3.py | 0 paula.testing/src/paula/testing/not_searched.txt | 4 + paula.testing/src/paula/testing/testing.py | 384 ++++++++------------- paula.testing/src/paula/testing/tests.py | 28 +- paula.testing/src/paula/testing/utils.py | 77 ++++- 11 files changed, 243 insertions(+), 299 deletions(-) create mode 100644 paula.testing/src/paula/testing/no_package/no_package_file.py create mode 100644 paula.testing/src/paula/testing/no_package/no_package_file2.py create mode 100644 paula.testing/src/paula/testing/no_package/no_package_file3.py create mode 100644 paula.testing/src/paula/testing/not_searched.txt rewrite paula.testing/src/paula/testing/testing.py (74%) diff --git a/paula.testing/setup.py b/paula.testing/setup.py index 99cb5c8..cdd3b1a 100644 --- a/paula.testing/setup.py +++ b/paula.testing/setup.py @@ -21,7 +21,7 @@ setup(name='paula.testing', keywords='', author='Florian Friesdorf', author_email='flo@chaoflow.net', - url='https://chaoflow.net/projects/gsoc2008/z3membrane-ldap', + url='https://chaoflow.net/projects/paula', license='AGPL', packages = find_packages('src'), package_dir = {'': 'src'}, @@ -31,7 +31,6 @@ setup(name='paula.testing', install_requires=[ 'setuptools', # -*- Extra requirements: -*- - 'zope.app.testing', 'zope.component', 'zope.testing', ], diff --git a/paula.testing/src/paula/testing/README.txt b/paula.testing/src/paula/testing/README.txt index 6a64c8e..6f69a01 100644 --- a/paula.testing/src/paula/testing/README.txt +++ b/paula.testing/src/paula/testing/README.txt @@ -1,13 +1,28 @@ +Check that all tests are found + + >>> from paula.testing.utils import saneimport, pkgpath, recursedir + >>> from paula.testing.utils import ispackagedir + >>> from paula.testing.testing import scanfordoctest + >>> pkg = saneimport('paula.testing') + >>> path = pkgpath(pkg) + >>> l1 = recursedir(path,cond=ispackagedir,filefilter=scanfordoctest) + >>> interact( locals()) + + A sample integration test, our zcml should have been loaded - >>> from paula.testing.module import ISomeObjectUtility +XXX: currently not - >>> u = getUtility(ISomeObjectUtility) - >>> u.name - 'some object utility' +# >>> from paula.testing.module import ISomeObjectUtility + +# >>> u = getUtility(ISomeObjectUtility) +# >>> u.name +# 'some object utility' Thx to jensens you can get an interactive prompt in your tests (waiting to be packaged as an egg!) >>> interact( locals() ) + + diff --git a/paula.testing/src/paula/testing/__init__.py b/paula.testing/src/paula/testing/__init__.py index b40dc8a..6830203 100644 --- a/paula.testing/src/paula/testing/__init__.py +++ b/paula.testing/src/paula/testing/__init__.py @@ -22,16 +22,4 @@ __docformat__ = "plaintext" from paula.testing.testing import get_test_suite from paula.testing.testing import test_globs -from paula.testing.testing import SuiteGenerator from paula.testing.testing import setUp, tearDown -from paula.testing.testing import my_import -try: - from paula.testing.plonetesting import setup_package - from paula.testing.plonetesting import setupPloneSite - from paula.testing.plonetesting import PloneTestCase - from paula.testing.plonetesting import FunctionalTestCase - from paula.testing.plonetesting import PanelTestCase - from paula.testing.plonetesting import KSSTestCase -except ImportError: - # no plone testing possible - pass diff --git a/paula.testing/src/paula/testing/mock.py b/paula.testing/src/paula/testing/mock.py index bbb0ff4..9ab54ed 100644 --- a/paula.testing/src/paula/testing/mock.py +++ b/paula.testing/src/paula/testing/mock.py @@ -22,7 +22,7 @@ __docformat__ = "plaintext" import types -from zope.interface import alsoProvides +from zope.interface import alsoProvides, implements, Interface class Mock(object): """a mock object that carries desired interfaces @@ -48,16 +48,17 @@ class Mock(object): True """ implements(Interface) + def __init__(self, **kws): try: - alsoProvides = kws['alsoProvides'] + alsoprovides = kws['alsoProvides'] except KeyError: pass else: - if type alsoProvides is types.TupleType: - alsoProvides(self, *alsoProvides) + if type(alsoprovides) is types.TupleType: + alsoProvides(self, *alsoprovides) else: - alsoProvides(self, alsoProvides) + alsoProvides(self, alsoprovides) del kws['alsoProvides'] for k,v in kws.items(): diff --git a/paula.testing/src/paula/testing/no_package/no_package_file.py b/paula.testing/src/paula/testing/no_package/no_package_file.py new file mode 100644 index 0000000..e69de29 diff --git a/paula.testing/src/paula/testing/no_package/no_package_file2.py b/paula.testing/src/paula/testing/no_package/no_package_file2.py new file mode 100644 index 0000000..e69de29 diff --git a/paula.testing/src/paula/testing/no_package/no_package_file3.py b/paula.testing/src/paula/testing/no_package/no_package_file3.py new file mode 100644 index 0000000..e69de29 diff --git a/paula.testing/src/paula/testing/not_searched.txt b/paula.testing/src/paula/testing/not_searched.txt new file mode 100644 index 0000000..d52a845 --- /dev/null +++ b/paula.testing/src/paula/testing/not_searched.txt @@ -0,0 +1,4 @@ +This file is not scanned as there is no corresponding .py + + >>> True + False diff --git a/paula.testing/src/paula/testing/testing.py b/paula.testing/src/paula/testing/testing.py dissimilarity index 74% index fc0926d..b2ed29b 100644 --- a/paula.testing/src/paula/testing/testing.py +++ b/paula.testing/src/paula/testing/testing.py @@ -1,249 +1,135 @@ -# Copyright (c) 2008 by Florian Friesdorf -# -# GNU Affero General Public License (AGPL) -# -# This program is free software; you can redistribute it and/or modify -# it under the terms of the GNU Affero General Public License as -# published by the Free Software Foundation; either version 3 of the -# License, or (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU Affero General Public License for more details. -# -# You should have received a copy of the GNU Affero General Public -# License along with this program. If not, see -# . -""" -""" -__author__ = "Florian Friesdorf " -__docformat__ = "plaintext" - -import os -import os.path -import types -import unittest - -from zope.app.testing.functional import ZCMLLayer, FunctionalDocFileSuite -from zope.component import testing - -from zope.testing import doctest -from zope.testing import doctestunit - -from paula.testing.utils import saneimport, hasdoctests -from paula.testing.globs import test_globs - -optionflags = \ - doctest.REPORT_ONLY_FIRST_FAILURE + \ - doctest.ELLIPSIS + \ - doctest.NORMALIZE_WHITESPACE - - -def setUp(test): - """We can use this to set up anything that needs to be available for - each test. It is run before each test, i.e. for each docstring that - contains doctests. - - Look at the Python unittest and doctest module documentation to learn - more about how to prepare state and pass it into various tests. - """ - testing.setUp(test) - - -def tearDown(test): - """ - """ - testing.tearDown(test) - -# ------------------------------------------------------------------------ - -def recurse(*args): - """ - returns all doctests found within the modules passed in *args - - That is: - - modules containing doctests - - text files named after modules, containing doctests - - For paula.testing itself, recurse should find 9 modules containing tests: - - >>> to_test = recurse('paula.testing') - >>> len(to_test) - 9 - """ - result = [] - for modname in args: - # import module and append to result, iff it contains doctests - mod = saneimport(modname) - if hasdoctests(mod): - result.append(mod) - - # Check module vs package - realmodname = mod.__file__.replace('.pyc','').replace('.py','') - if not realmodname.endswith('__init__'): - # a module, not a package, we can stop recursing here - continue - - # list package contents and evtl. recurse further - dirname = os.path.dirname(mod.__file__) - dirlist = os.listdir(dirname) - for item in dirlist: - fullpath = os.path.join(dirname, item) - # skip, if neither directory nor .py file nor txt file - if not os.path.isdir(fullpath): - if not item.endswith('.py')): - continue - - # skip directories, that are not packages - if os.path.isdir(fullpath) and not \ - os.path.isfile(os.path.join(fullpath, '__init__.py')): - continue - - # get rid of .py ending - x = x.replace('.py','') - - # skip if it starts with a dot - if x.startswith('.'): - continue - - # skip __init__.py, it _is_ the current package, which was - # added above: result += [mod] - if x == "__init__": - continue - - # don't test tests/ and tests.py, XXX: why not? - #if x == "tests": - # continue - - mod_name = '%s.%s' % (name, x) - result += recurse(mod_name) - return result - - -def doctestsuite(mod): - return doctestunit.DocTestSuite(mod, - setUp=setUp, tearDown=tearDown, - optionflags=optionflags - ) - -def testsuite(*args): - """ - """ - testsuites = [] - for pkgname in args: - mod = saneimport(pkgname) - if hasdoctests(mod): - testsuites.append(doctestsuite(mod)) - - # Only recurse for packages, for modules continue with next loop - if not '__init__' in mod.__file__: - continue - - - XXX - - if txtfile: - if not hasdoctests(txtfile): - return [] - - testsuite = doctestunit.DocFileSuite( txtfile - package=pkgname, - setUp=setUp, tearDown=tearDown, - optionflags=optionflags - ) - return testsuite - - - -# XXX: this could be moved inside the SuiteGenerator -def get_test_suite(pkg_name, tests=[]): - """construct a test suite for a package - - recurses through a package and returns a test suite consisting of all - doctest found + the tests passed as argument - """ - def testsuite(x): - if type(x) == types.ModuleType: - return doctestunit.DocTestSuite(x, - setUp=setUp, tearDown=tearDown, - optionflags=optionflags - ) - - if type(x) == types.StringTypes: - return doctestunit.DocFileSuite( XXX - package=XXX, - setUp=setUp, tearDown=tearDown, - optionflags=optionflags - ) - def fulltestsuite(): - to_test = recurse(pkg_name,) - testsuites = [testsuite(x) for x in to_test] - for x in to_test: - test = doctestunit.DocFileSuite( XXX - package=XXX, - setUp=setUp, tearDown=tearDown, - optionflags=optionflags - ) - unit_tests.append(test) - - test_suite = unittest.TestSuite(unit_tests + tests) - return test_suite - - return fulltestsuite - - -# TestSuite/Cases loading ftesting.zcml -# taken from a zopeproject generated testing.py - thank you - -#ftesting_zcml = os.path.join(os.path.dirname(__file__), 'ftesting.zcml') -#FunctionalLayer = ZCMLLayer(ftesting_zcml, __name__, 'FunctionalLayer') - -class SuiteGenerator(object): - """ - """ - def __init__(self, package_name): - self.package_name = package_name - self.package = my_import(package_name) - self.package_dir = os.path.dirname(self.package.__file__) - self.ftesting_zcml = os.path.join(self.package_dir, 'ftesting.zcml') - try: - self.FunctionalLayer = ZCMLLayer( - self.ftesting_zcml, - package_name, - 'FunctionalLayer', - allow_teardown=True, - ) - except TypeError: - self.FunctionalLayer = ZCMLLayer( - self.ftesting_zcml, - package_name, - 'FunctionalLayer', - ) - - @property - def FunctionalDocFileSuite(self): - - def myFunctionalDocFileSuite(path, **kw): - if not 'package' in kw: - kw['package'] = self.package_name - suite = FunctionalDocFileSuite(path, globs=test_globs, **kw) - suite.layer = self.FunctionalLayer - return suite - - return myFunctionalDocFileSuite - - - -# we currently don't care about these - -#class FunctionalTestCase(FunctionalTestCase): -# layer = FunctionalLayer - - -#def FunctionalDocTestSuite(module=None, **kw): -# module = doctest._normalize_module(module) -# suite = FunctionalDocTestSuite(module, globs=test_globs, **kw) -# suite.layer = FunctionalLayer -# return suite - +# Copyright (c) 2008 by Florian Friesdorf +# +# GNU Affero General Public License (AGPL) +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU Affero General Public License as +# published by the Free Software Foundation; either version 3 of the +# License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Affero General Public License for more details. +# +# You should have received a copy of the GNU Affero General Public +# License along with this program. If not, see +# . +""" +""" +__author__ = "Florian Friesdorf " +__docformat__ = "plaintext" + +import os +import os.path +import types +import unittest + +from zope.component import testing + +from zope.testing import doctest +from zope.testing import doctestunit + +from paula.testing.utils import hasdoctests +from paula.testing.utils import ispackagedir +from paula.testing.utils import pkgpath +from paula.testing.utils import recursedir +from paula.testing.utils import saneimport + +from paula.testing.globs import test_globs + +optionflags = \ + doctest.REPORT_ONLY_FIRST_FAILURE + \ + doctest.ELLIPSIS + \ + doctest.NORMALIZE_WHITESPACE + + +def setUp(test): + """We can use this to set up anything that needs to be available for + each test. It is run before each test, i.e. for each docstring that + contains doctests. + + Look at the Python unittest and doctest module documentation to learn + more about how to prepare state and pass it into various tests. + """ + testing.setUp(test) + for k,v in test_globs.items(): + test.globs[k] = v + +def tearDown(test): + """ + """ + testing.tearDown(test) + +def scanfordoctest(file): + """Decides whether a file should be scanned for doctests + + - all .py files + - all .txt files for which a .py file exists + """ + # XXX: not reimplemented + # # skip if it starts with a dot + # if item.startswith('.'): + # continue + + if file.endswith('.py'): + return hasdoctests(file) + + if file.endswith('.txt'): + pyfile = file.replace('.txt','.py') + if os.path.isfile(pyfile): + return hasdoctests(file) + + return False + + +def get_test_suite(pkgname, files=[]): + """construct a test suite for a package + + test suite will contain all doctests found somewhere in the package and + the tests passed as argument + + 1. get root folder for package + 2. recurse and find everything that might contain a doctest + 3. create the test suite + + """ + + def testsuite(doctestfile): + if doctestfile.endswith('.txt'): + doctest = doctestunit.DocFileSuite(doctestfile, + package=pkgname, + setUp=setUp, tearDown=tearDown, + optionflags=optionflags, + ) + return doctest + + if doctestfile.endswith('.py'): + module = doctestfile.replace('.py','').replace(os.sep, '.') + module = '.'.join((pkgname, module,)) + module = saneimport(module) + doctest = doctestunit.DocTestSuite(module, + setUp=setUp, tearDown=tearDown, + optionflags=optionflags, + ) + return doctest + + def fulltestsuite(): + """ + """ + pkg = saneimport(pkgname) + path = pkgpath(pkg) + + doctestfiles = recursedir( + path, + cond=ispackagedir, + filefilter=scanfordoctest, + ) + # make relative to pkg path + doctestfiles = [x[len(path)+1:] for x in doctestfiles] + doctests = [testsuite(x) for x in doctestfiles+files] + + test_suite = unittest.TestSuite(doctests) + return test_suite + + return fulltestsuite diff --git a/paula.testing/src/paula/testing/tests.py b/paula.testing/src/paula/testing/tests.py index f800381..47d71e3 100644 --- a/paula.testing/src/paula/testing/tests.py +++ b/paula.testing/src/paula/testing/tests.py @@ -8,33 +8,25 @@ """ import unittest -#from zope.testing import doctestunit +from zope.testing import doctestunit #from zope.component.testing import setUp -from paula.testing import get_test_suite, SuiteGenerator +from paula.testing import get_test_suite +from paula.testing import setUp, tearDown # XXX: this could be derived from __name__, but then it would not work, # if being called as __main__ (see bottom) - is that needed? # eventually we could then derive it from path?! from config import PACKAGE_NAME -sg = SuiteGenerator(PACKAGE_NAME) +# File to test, relative to the package root +# all .py files are found +# all .txt files with corresponding .py file are found +files = [ + 'README.txt' + ] -tests = [ - # doctests in all submodules of the package are found by paula.testing - - # doctests in files need to be declared - #doctestunit.DocFileSuite( 'README.txt', - # package=PACKAGE_NAME, setUp=pt.setUp, tearDown=pt.tearDown - # ), - - # functional doctests in files, don't pass setUp/tearDown, except if you - # really know what you are doing... - sg.FunctionalDocFileSuite('README.txt') - - ] - -test_suite = get_test_suite(PACKAGE_NAME, tests) +test_suite = get_test_suite(PACKAGE_NAME, files) if __name__ == '__main__': unittest.main(defaultTest='test_suite') diff --git a/paula.testing/src/paula/testing/utils.py b/paula.testing/src/paula/testing/utils.py index b34eca0..eaa6b7b 100644 --- a/paula.testing/src/paula/testing/utils.py +++ b/paula.testing/src/paula/testing/utils.py @@ -20,18 +20,77 @@ __author__ = "Florian Friesdorf " __docformat__ = "plaintext" +import os +from paula.testing.interact import interact + +def hasdoctests(file): + """Check whether a file has doctests + """ + for line in open(file): + if line.lstrip().startswith('>>>'): + return True + + +def ispackagedir(path): + initfile = os.path.join(path, '__init__.py') + result = os.path.isfile(initfile) + return result + + +def pkgpath(pkg): + """Returns the path to a imported package + + >>> from paula.testing.utils import saneimport + >>> from paula.testing.utils import pkgpath + >>> pkg = saneimport('paula.testing') + >>> pkgpath(pkg).split(os.sep)[-2:] + ['paula', 'testing'] + """ + path = pkg.__file__.replace('.pyc','').replace('.py','') + if not path.endswith('__init__'): + raise ValueError + path = path.replace(os.sep+'__init__', '') + if path.endswith(os.sep): + raise ValueError + return path + + +def recursedir(path, cond=lambda x: True, filefilter=lambda x: True): + """Recurses a directory structure and returns all contained files + + Optionally a condition can be given that must be met in order to recurse + into a directory. The condition is a function that takes the directory as + argument and returns either True or False. + + >>> from paula.testing.utils import saneimport + >>> from paula.testing.utils import recursedir + >>> from paula.testing.utils import pkgpath + >>> from paula.testing.utils import ispackagedir + >>> pkg = saneimport('paula.testing') + >>> l1 = recursedir(pkgpath(pkg)) + >>> l1 = filter(lambda x: not x.endswith('.swp'), l1) + >>> len(l1) + 35 + >>> l2 = recursedir(pkgpath(pkg), cond=ispackagedir) + >>> l2 = filter(lambda x: not x.endswith('.swp'), l2) + >>> len(l2) + 33 + """ + files=[] + ls = os.listdir(path) + for item in ls: + fullpath = os.path.join(path, item) + if os.path.isdir(fullpath) and cond(fullpath): + files += recursedir(fullpath,cond,filefilter) + continue + if filefilter(fullpath): + files.append(fullpath) + return files + + def saneimport(name): mod = __import__(name) components = name.split('.') for x in components[1:]: mod = getattr(mod, x) return mod - -def hasdoctests(mod): - """Check whether a module has doctests - """ - pyfile = mod.__file__.replace('.pyc','.py') - for line in open(pyfile): - if line.lstrip().startswith('>>>'): - return True - -- 2.11.4.GIT