[Checkins] SVN: grok/trunk/ Merge ulif-testsetup-pre0.13 branch into trunk.

Uli Fouquet uli at gnufix.de
Fri Apr 25 15:10:30 EDT 2008


Log message for revision 85730:
  Merge ulif-testsetup-pre0.13 branch into trunk.

Changed:
  U   grok/trunk/CHANGES.txt
  U   grok/trunk/setup.py
  U   grok/trunk/src/grok/testing.py
  D   grok/trunk/src/grok/tests/testsetup/basicsetup.py
  A   grok/trunk/src/grok/tests/testsetup/cave/file1.py
  A   grok/trunk/src/grok/tests/testsetup/cave/ftesting.zcml
  U   grok/trunk/src/grok/tests/testsetup/cave/notatest1.foo
  A   grok/trunk/src/grok/tests/testsetup/cave/sample.zcml
  A   grok/trunk/src/grok/tests/testsetup/cave/samplesetup1.py
  A   grok/trunk/src/grok/tests/testsetup/cave/samplesetup2.py
  A   grok/trunk/src/grok/tests/testsetup/cave/samplesetup3.py
  A   grok/trunk/src/grok/tests/testsetup/cave/samplesetup4.py
  A   grok/trunk/src/grok/tests/testsetup/cave_to_let/
  D   grok/trunk/src/grok/tests/testsetup/functionalsetup.py
  A   grok/trunk/src/grok/tests/testsetup/testsetup.py
  D   grok/trunk/src/grok/tests/testsetup/unittestsetup.py
  U   grok/trunk/versions.cfg

-=-
Modified: grok/trunk/CHANGES.txt
===================================================================
--- grok/trunk/CHANGES.txt	2008-04-25 19:06:16 UTC (rev 85729)
+++ grok/trunk/CHANGES.txt	2008-04-25 19:10:27 UTC (rev 85730)
@@ -4,9 +4,22 @@
 0.13 (unreleased)
 =================
 
-Bugs fixed
-----------
+Feature changes
+---------------
 
+* Added support for easier testsetup based on z3c.testsetup. This is a
+  more stable and more powerful implementation of
+  grok.testing.register_all_tests(). See
+
+    http://grok.zope.org/documentation/how-to/tests-with-grok-testing
+
+  for details.
+
+Bug fixes
+---------
+
+* Removed first testsetup hack from grok.testing.
+
 * Version 2.1 of z3c.autoinclude contained code that caused Grok to
   fail to start on some platforms if the system-supplied Python was
   used (at least on some versions of Ubuntu and Debian). Now include
@@ -14,11 +27,6 @@
   fix was also made on Grok 0.12 in its online versions list after
   release.
 
-Feature changes
----------------
-
-* ...
-
 0.12 (2008-04-22)
 =================
 

Modified: grok/trunk/setup.py
===================================================================
--- grok/trunk/setup.py	2008-04-25 19:06:16 UTC (rev 85729)
+++ grok/trunk/setup.py	2008-04-25 19:10:27 UTC (rev 85730)
@@ -81,5 +81,6 @@
                       'zc.catalog',
                       'z3c.flashmessage',
                       'z3c.autoinclude',
+                      'z3c.testsetup',
                       ],
 )

Modified: grok/trunk/src/grok/testing.py
===================================================================
--- grok/trunk/src/grok/testing.py	2008-04-25 19:06:16 UTC (rev 85729)
+++ grok/trunk/src/grok/testing.py	2008-04-25 19:10:27 UTC (rev 85730)
@@ -16,210 +16,27 @@
 from zope.configuration.config import ConfigurationMachine
 from martian import scan
 from grok import zcml
-
-import unittest
-from os import listdir
+import z3c.testsetup
 import os.path
-import re
-from zope.testing import doctest, cleanup
-from zope.app.testing.functional import (
-    HTTPCaller, getRootFolder, FunctionalTestSetup,
-    sync, ZCMLLayer, FunctionalDocFileSuite)
 
-class BasicTestSetup(object):
-    """A basic test setup for a package.
+class GrokTestCollector(z3c.testsetup.TestCollector):
 
-    A basic test setup is a aggregation of methods and attributes to
-    search for appropriate doctest files in a package. Its purpose is
-    to collect all basic functionality, that is needed by derived
-    classes, that do real test registration.
-    """
+    def initialize(self):
+        # inject the grok ftesting ZCML as fallback...
+        if 'zcml_config' in self.settings.keys():
+            return
+        pkg_path = os.path.dirname(self.package.__file__)
+        if os.path.isfile(os.path.join(pkg_path, 'ftesting.zcml')):
+            return
+        self.settings['zcml_config'] = os.path.join(
+            os.path.dirname(__file__), 'ftesting.zcml')
+        if 'layer_name' in self.settings.keys():
+            return
+        self.settings['layer_name'] = 'GrokFunctionalLayer'
 
-    extensions = ['.rst', '.txt']
+def register_all_tests(pkg, *args, **kw):
+    return GrokTestCollector(pkg, *args, **kw)
 
-    regexp_list = []
-
-    additional_options = {}
-
-    def __init__(self, package, filter_func=None, extensions=None, **kw):
-        self.package = package
-        self.filter_func = filter_func or self.isTestFile
-        self.extensions = extensions or self.extensions
-        self.additional_options = kw
-        return
-
-    def setUp(self, test):
-        pass
-
-    def tearDown(self, test):
-        pass
-
-    def fileContains(self, filename, regexp_list):
-        """Does a file contain lines matching every of the regular
-        expressions?
-        """
-        found_list = []
-        try:
-            for line in open(filename):
-                for regexp in regexp_list:
-                    if re.compile(regexp).match(line) and (
-                        regexp not in found_list):
-                        found_list.append(regexp)
-                if len(regexp_list) == len(found_list):
-                    break
-        except IOError:
-            # be gentle
-            pass
-        return len(regexp_list) == len(found_list)
-
-    def isTestFile(self, filepath):
-        """Return ``True`` if a file matches our expectations for a
-        doctest file.
-        """
-        if os.path.splitext(filepath)[1].lower() not in self.extensions:
-            return False
-        if not self.fileContains(filepath, self.regexp_list):
-            return False
-        return True
-
-    def isTestDirectory(self, dirpath):
-        """Check whether a given directory should be searched for tests.
-        """
-        if os.path.basename(dirpath).startswith('.'):
-            # We don't search hidden directories like '.svn'
-            return False
-        return True
-
-    def getDocTestFiles(self, dirpath=None, **kw):
-        """Find all doctest files filtered by filter_func.
-        """
-        if dirpath is None:
-            dirpath = os.path.dirname(self.package.__file__)
-        dirlist = []
-        for filename in listdir(dirpath):
-            abs_path = os.path.join(dirpath, filename)
-            if not os.path.isdir(abs_path):
-                if self.filter_func(abs_path):
-                    dirlist.append(abs_path)
-                continue
-            # Search subdirectories...
-            if not self.isTestDirectory(abs_path):
-                continue
-            subdir_files = self.getDocTestFiles(dirpath=abs_path, **kw)
-            dirlist.extend(subdir_files)
-        return dirlist
-
-
-class UnitTestSetup(BasicTestSetup):
-    """A unit test setup for packages.
-
-    A collection of methods to search for appropriate doctest files in
-    a given package. ``UnitTestSetup`` is also able to 'register' the
-    tests found and to deliver them as a ready-to-use
-    ``unittest.TestSuite`` instance.
-
-    While the functionality to search for testfiles is mostly
-    inherited from the base class, the focus here is to setup the
-    tests correctly.
-
-    See file `unittestsetup.py` in the tests/testsetup directory to
-    learn more about ``UnitTestSetup``.
-    """
-
-    optionflags = (doctest.ELLIPSIS+
-                   doctest.NORMALIZE_WHITESPACE+
-                   doctest.REPORT_NDIFF)
-
-    regexp_list = [
-        '^\s*:(T|t)est-(L|l)ayer:\s*(unit)\s*',
-        ]
-
-
-    def tearDown(self, test):
-        cleanup.cleanUp()
-
-    def getTestSuite(self):
-        docfiles = self.getDocTestFiles(package=self.package)
-        suite = unittest.TestSuite()
-        for name in docfiles:
-            if os.path.isabs(name):
-                # We get absolute pathnames, but we need relative ones...
-                common_prefix = os.path.commonprefix([self.package.__file__,
-                                                      name])
-                name = name[len(common_prefix):]
-            suite.addTest(
-                doctest.DocFileSuite(
-                name,
-                package=self.package,
-                setUp=self.setUp,
-                tearDown=self.tearDown,
-                optionflags=self.optionflags,
-                **self.additional_options
-                ))
-        return suite
-
-
-class FunctionalTestSetup(BasicTestSetup):
-    """A functional test setup for packages.
-
-    A collection of methods to search for appropriate doctest files in
-    a given package. ``FunctionalTestSetup`` is also able to
-    'register' the tests found and to deliver them as a ready-to-use
-    ``unittest.TestSuite`` instance.
-
-    While the functionality to search for testfiles is mostly
-    inherited from the base class, the focus here is to setup the
-    tests correctly.
-    """
-    ftesting_zcml = os.path.join(os.path.dirname(__file__),
-                                 'ftesting.zcml')
-    layer = ZCMLLayer(ftesting_zcml, __name__,
-                      'FunctionalLayer')
-
-    globs=dict(http=HTTPCaller(),
-               getRootFolder=getRootFolder,
-               sync=sync
-               )
-
-    optionflags = (doctest.ELLIPSIS+
-                   doctest.NORMALIZE_WHITESPACE+
-                   doctest.REPORT_NDIFF)
-
-    regexp_list = [
-        '^\s*:(T|t)est-(L|l)ayer:\s*(functional)\s*',
-        ]
-
-    def setUp(self, test):
-        FunctionalTestSetup().setUp()
-
-    def tearDown(self, test):
-        FunctionalTestSetup().tearDown()
-
-    def suiteFromFile(self, name):
-        suite = unittest.TestSuite()
-        if os.path.isabs(name):
-            # We get absolute pathnames, but we need relative ones...
-            common_prefix = os.path.commonprefix([self.package.__file__, name])
-            name = name[len(common_prefix):]
-        test = FunctionalDocFileSuite(
-            name, package=self.package,
-            setUp=self.setUp, tearDown=self.tearDown,
-            globs=self.globs,
-            optionflags=self.optionflags,
-            **self.additional_options
-            )
-        test.layer = self.layer
-        suite.addTest(test)
-        return suite
-
-    def getTestSuite(self):
-        docfiles = self.getDocTestFiles(package=self.package)
-        suite = unittest.TestSuite()
-        for name in docfiles:
-            suite.addTest(self.suiteFromFile(name))
-        return suite
-
-
 def grok(module_name):
     config = ConfigurationMachine()
     zcml.do_grok('grok.meta', config)

Deleted: grok/trunk/src/grok/tests/testsetup/basicsetup.py
===================================================================
--- grok/trunk/src/grok/tests/testsetup/basicsetup.py	2008-04-25 19:06:16 UTC (rev 85729)
+++ grok/trunk/src/grok/tests/testsetup/basicsetup.py	2008-04-25 19:10:27 UTC (rev 85730)
@@ -1,258 +0,0 @@
-##############################################################################
-#
-# Copyright (c) 2007 Zope Corporation and Contributors.
-# All Rights Reserved.
-#
-# This software is subject to the provisions of the Zope Public License,
-# Version 2.1 (ZPL).  A copy of the ZPL should accompany this distribution.
-# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
-# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
-# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
-# FOR A PARTICULAR PURPOSE.
-#
-##############################################################################
-"""
-================
-Basic Test Setup
-================
-
-``BasicTestSetup`` is a class to support easier setup of tests in grok
-projects. It acts merely as a container for shared functions, methods
-and attributes needed by 'real' test setups which are derived from
-it. Itself provides *no* ``getTestSuite()`` method, which is needed to
-setup real tests.
-
-A ``BasicTestSetup`` tries to find all doctest files defined in a given
-package. See `functionalsetup.py` for setting up real functional tests
-and `unittestsetup.py` for 'real' setup of unittests.
-
-For a general introduction into testing with grok see the appropriate
-howto on the grok homepage.
-
-The TestSetup classes all search and handle doctest files.
-
-All we need to setup a testsuite, is the package to search::
-
-   >>> from grok.tests.testsetup import cave
-   >>> from grok.testing import BasicTestSetup
-   >>> basic_setup = BasicTestSetup(cave)
-   >>> basic_setup
-   <grok.testing.BasicTestSetup object at 0x...>
-
-The package is stored as an instance-attribute::
-
-   >>> basic_setup.package
-   <module 'grok.tests.testsetup.cave' from ...>
-
-The ``BasicTestSetup`` serves merely as a container for attributes and
-methods needed by derived classes, that provide proper test setup.
-
-One of it's resposibilities is, to find doctest files, which is done
-by the ``getDocTestFiles()`` method. If we run this method, we
-get a list of filenames::
-
-   >>> file_list = basic_setup.getDocTestFiles()
-   >>> len(file_list)
-   4
-
-The filenames are all absolute::
-
-   >>> import os.path
-   >>> [x for x in file_list if not os.path.isabs(file_list[0])]
-   []
-
-
-Which files are found?
-----------------------
-
-By default, all .txt and .rst files are taken
-into account::
-
-   >>> exts = ['.rst', '.txt']
-   >>> [x for x in file_list if not os.path.splitext(x)[1].lower() in exts]
-   []
-
-All forms of an extension are found, regardless of whether they are
-uppercase, lowercase or mixed-case::
-
-   >>> file_list
-   [...'...file2.TXT'...]
-
-Also subdirectories are searched::
-
-   >>> file_list
-   [...'...subdirfile.txt'...]
-
-Hidden directories, however, are skipped. To check this, we look for a
-'hidden' testfile put into a hidden directory in the `cave`
-directory. We first make sure, that the hidden file really exists::
-
-   >>> cavepath = os.path.dirname(cave.__file__)
-   >>> hiddenpath = os.path.join(cavepath, '.hiddendir', 'hiddenfile.txt')
-   >>> os.path.exists(hiddenpath)
-   True
-
-And now check that it was *not* included in the file list::
-
-   >>> hiddenpath in file_list
-   False
-
-To provide a more finegrained filtering, ``BasicTestSetup`` provides a
-method ``isTestFile(filepath)``, which returns ``True`` for accepted
-files and ``False`` otherwise. This method is called for every file
-found by ``getDoctesFiles``. By default it only filters files by their
-filename extension and compares it with the instance-attribute
-``extensions``, which by default is the list ``['.rst', '.txt']``::
-
-   >>> basic_setup.extensions
-   ['.rst', '.txt']
-
-   >>> basic_setup.isTestFile('')
-   False
-
-   >>> basic_setup.isTestFile('cave.txt')
-   True
-
-   >>> basic_setup.isTestFile('cave.rst')
-   True
-
-   >>> basic_setup.isTestFile('cave.RsT')
-   True
-
-   >>> basic_setup.isTestFile('cave.foo')
-   False
-
-
-How to find a customized set of files:
---------------------------------------
-
-There are several possibilities to modify the search results of
-``getDocTestFiles()``. If it is only a matter of filename extension,
-the instance's attribute ``extensions`` can be modified::
-
-   >>> basic_setup.extensions = ['.foo']
-   >>> basic_setup.getDocTestFiles()
-   ['...notatest1.foo']
-
-If things need a more complex filtering, you can also redefine the
-filter function, which by default is the ``isTestFile()`` function as
-mentioned above.
-
-You can pass an alternative filterfunction as keyword parameter
-``filter_func`` to the ``BasicTestSetup`` constructor::
-
-   >>> def myFilter(filename):
-   ...     return filename.endswith('.txt')
-   >>> basic_setup2 = BasicTestSetup(cave, filter_func=myFilter)
-   >>> len(basic_setup2.getDocTestFiles())
-   2
-
-Note, that the filter function must accept a single parameter, which
-should contain a filepath as string and it should return a boolean
-value to indicate, whether the file given by the filepath should be
-included in the test suite or not.
-
-A different set of accepted filename extensions can also be passed to
-the constructor, using the ``extensions`` keyword::
-
-   >>> basic_setup3 = BasicTestSetup(cave, extensions=['.txt'])
-
-Note, that the extensions should alway be written with a leading dot
-and in lower case. Such we can find only .txt files::
-
-   >>> len(basic_setup3.getDocTestFiles())
-   3
-
-Now also the .TXT file was found, which was omitted in the test
-before.
-
-The set of directories, which are accepted as doctest containers, is
-defined by the ``isTestDirectory`` method, which by default only skips
-'hidden' directories, i.e. directories, that start with a dot ('.').
-
-   >>> basic_setup3.isTestDirectory('foo/bar/somdir')
-   True
-
-   >>> basic_setup3.isTestDirectory('foo/bar/.hiddendir')
-   False
-
-You can change this behaviour by deriving your own setup class and
-overwriting the method. This works also with derived classes like
-``FunctionalTestSetup``.
-
-
-Find terms in docfiles:
------------------------
-
-For convenience ``BasicTestSetup`` provides a method ``fileContains``,
-which parses the contents of a file to match a list of regular
-expressions. If every of the regular expressions in the list matched
-at least one line of the file, ``True`` is returned, ``False``
-otherwise.
-
-``fileContains`` is a helper function to search files for certain
-terms and expressions. It is implemented as a method (instead a
-standalone function), to enable developers to replace it with a more
-complex implementation that also accesses other instance attributes
-like the package or similar.
-
-File paths, that cannot be found, are silently ignored::
-
-   >>> basic_setup4 = BasicTestSetup(cave, extensions=['.foo'])
-   >>> basic_setup4.fileContains('blah', ['FOO'])
-   False
-
-We pick up an existing file path::
-
-   >>> file_list = basic_setup4.getDocTestFiles()
-   >>> len(file_list)
-   1
-
-   >>> filepath = file_list[0]
-   >>> filepath.endswith('notatest1.foo')
-   True
-
-This file contains a string 'ME GROK SMASH ZCML!!', which we can
-search for::
-
-   >>> basic_setup4.fileContains(filepath, ['ME GROK'])
-   True
-
-   >>> basic_setup4.fileContains(filepath, ['ME GROK IS DUMB'])
-   False
-
-The terms to search are handled as real regular expressions as
-provided by the ``re`` package::
-
-   >>> basic_setup4.fileContains(filepath, ['^ME (G|g)ROK.*'])
-   True
-
-We can also search for several matches::
-
-   >>> basic_setup4.fileContains(filepath, ['.*SMASH.*', '.*GROK.*'])
-   True
-
-If one of the searched terms is not found, the whole thing fails::
-
-   >>> basic_setup4.fileContains(filepath, ['.*DUMB.*', '.*GROK.*'])
-   False
-
-It does not matter, whether matches occur in the same line or in
-different ones. In the example file there is also a heading stating
-'This is not a test'. Let's check this::
-
-   >>> basic_setup4.fileContains(filepath, ['ME GROK', 'This is not'])
-   True
-
-
-Note: The evaluation of regular expressions is done without any
-modifiers. Namely the matching is case sensitive::
-
-   >>> basic_setup4.fileContains(filepath, ['me grok'])
-   False
-
-Furthermore, matches are only done against one line at a time.
-
-
-
-"""

Copied: grok/trunk/src/grok/tests/testsetup/cave/file1.py (from rev 85728, grok/branches/ulif-testsetup-pre0.13/src/grok/tests/testsetup/cave/file1.py)
===================================================================
--- grok/trunk/src/grok/tests/testsetup/cave/file1.py	                        (rev 0)
+++ grok/trunk/src/grok/tests/testsetup/cave/file1.py	2008-04-25 19:10:27 UTC (rev 85730)
@@ -0,0 +1,17 @@
+"""
+Tests with real TestCase objects.
+
+:Test-Layer: python
+
+"""
+
+import unittest
+
+class TestTest(unittest.TestCase):
+
+    def setUp(self):
+        pass
+
+    def testFoo(self):
+        self.assertEqual(2, 1+1)
+

Copied: grok/trunk/src/grok/tests/testsetup/cave/ftesting.zcml (from rev 85728, grok/branches/ulif-testsetup-pre0.13/src/grok/tests/testsetup/cave/ftesting.zcml)
===================================================================
--- grok/trunk/src/grok/tests/testsetup/cave/ftesting.zcml	                        (rev 0)
+++ grok/trunk/src/grok/tests/testsetup/cave/ftesting.zcml	2008-04-25 19:10:27 UTC (rev 85730)
@@ -0,0 +1,8 @@
+<configure
+   xmlns="http://namespaces.zope.org/zope"
+   i18n_domain="cave"
+   >
+
+  <!-- Just a dummy ZCML for testing -->
+
+</configure>

Modified: grok/trunk/src/grok/tests/testsetup/cave/notatest1.foo
===================================================================
--- grok/trunk/src/grok/tests/testsetup/cave/notatest1.foo	2008-04-25 19:06:16 UTC (rev 85729)
+++ grok/trunk/src/grok/tests/testsetup/cave/notatest1.foo	2008-04-25 19:10:27 UTC (rev 85730)
@@ -2,4 +2,7 @@
 This is not a test
 ==================
 
+:Test-Layer: functional
+:Test-Layer: unit
+
 ME GROK SMASH ZCML!!

Copied: grok/trunk/src/grok/tests/testsetup/cave/sample.zcml (from rev 85728, grok/branches/ulif-testsetup-pre0.13/src/grok/tests/testsetup/cave/sample.zcml)
===================================================================
--- grok/trunk/src/grok/tests/testsetup/cave/sample.zcml	                        (rev 0)
+++ grok/trunk/src/grok/tests/testsetup/cave/sample.zcml	2008-04-25 19:10:27 UTC (rev 85730)
@@ -0,0 +1,8 @@
+<configure
+   xmlns="http://namespaces.zope.org/zope"
+   i18n_domain="cave"
+   >
+
+  <!-- Just a dummy ZCML for testing -->
+
+</configure>

Copied: grok/trunk/src/grok/tests/testsetup/cave/samplesetup1.py (from rev 85728, grok/branches/ulif-testsetup-pre0.13/src/grok/tests/testsetup/cave/samplesetup1.py)
===================================================================
--- grok/trunk/src/grok/tests/testsetup/cave/samplesetup1.py	                        (rev 0)
+++ grok/trunk/src/grok/tests/testsetup/cave/samplesetup1.py	2008-04-25 19:10:27 UTC (rev 85730)
@@ -0,0 +1,10 @@
+import os.path
+from zope.app.testing.functional import ZCMLLayer
+from grok.testing import register_all_tests
+samplelayer = ZCMLLayer(
+    os.path.join(os.path.dirname(__file__), 'sample.zcml'),
+    __name__, 'CustomSampleLayer')
+test_suite = register_all_tests(
+    'grok.tests.testsetup.cave',
+    layer = samplelayer
+    )

Copied: grok/trunk/src/grok/tests/testsetup/cave/samplesetup2.py (from rev 85728, grok/branches/ulif-testsetup-pre0.13/src/grok/tests/testsetup/cave/samplesetup2.py)
===================================================================
--- grok/trunk/src/grok/tests/testsetup/cave/samplesetup2.py	                        (rev 0)
+++ grok/trunk/src/grok/tests/testsetup/cave/samplesetup2.py	2008-04-25 19:10:27 UTC (rev 85730)
@@ -0,0 +1,8 @@
+import os.path
+from grok.testing import register_all_tests
+test_suite = register_all_tests(
+    'grok.tests.testsetup.cave',
+    zcml_config = os.path.join(os.path.dirname(__file__),
+                               'sample.zcml'),
+    layer_name = 'CustomLayerFromPath')
+

Copied: grok/trunk/src/grok/tests/testsetup/cave/samplesetup3.py (from rev 85728, grok/branches/ulif-testsetup-pre0.13/src/grok/tests/testsetup/cave/samplesetup3.py)
===================================================================
--- grok/trunk/src/grok/tests/testsetup/cave/samplesetup3.py	                        (rev 0)
+++ grok/trunk/src/grok/tests/testsetup/cave/samplesetup3.py	2008-04-25 19:10:27 UTC (rev 85730)
@@ -0,0 +1,5 @@
+from grok.testing import register_all_tests
+test_suite = register_all_tests('grok.tests.testsetup.cave')
+
+
+

Copied: grok/trunk/src/grok/tests/testsetup/cave/samplesetup4.py (from rev 85728, grok/branches/ulif-testsetup-pre0.13/src/grok/tests/testsetup/cave/samplesetup4.py)
===================================================================
--- grok/trunk/src/grok/tests/testsetup/cave/samplesetup4.py	                        (rev 0)
+++ grok/trunk/src/grok/tests/testsetup/cave/samplesetup4.py	2008-04-25 19:10:27 UTC (rev 85730)
@@ -0,0 +1,5 @@
+from grok.testing import register_all_tests
+test_suite = register_all_tests('grok.tests.testsetup.cave_to_let')
+
+
+

Copied: grok/trunk/src/grok/tests/testsetup/cave_to_let (from rev 85728, grok/branches/ulif-testsetup-pre0.13/src/grok/tests/testsetup/cave_to_let)

Deleted: grok/trunk/src/grok/tests/testsetup/functionalsetup.py
===================================================================
--- grok/trunk/src/grok/tests/testsetup/functionalsetup.py	2008-04-25 19:06:16 UTC (rev 85729)
+++ grok/trunk/src/grok/tests/testsetup/functionalsetup.py	2008-04-25 19:10:27 UTC (rev 85730)
@@ -1,280 +0,0 @@
-##############################################################################
-#
-# Copyright (c) 2007 Zope Corporation and Contributors.
-# All Rights Reserved.
-#
-# This software is subject to the provisions of the Zope Public License,
-# Version 2.1 (ZPL).  A copy of the ZPL should accompany this distribution.
-# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
-# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
-# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
-# FOR A PARTICULAR PURPOSE.
-#
-##############################################################################
-"""
-=====================
-Functional Test Setup
-=====================
-
-``FunctionalTestSetup`` helps to find and setup functional doctests
-contained in a package. The most important method therefore might be
-``getTestSuite()``, which searches a given package for doctest files
-and returns all tests found as a suite of functional tests.
-
-The work is done mainly in two stages:
-
-1) The package is searched for appropriate docfiles, based on the
-   settings of instcance attributes.
-
-2) The tests contained in the found docfiles are setup as functional
-   tests and added to a ``unittest.TestSuite`` instance.
-
-There are plenty of default values active, if you use instances of
-this class without further modifications. Therefore we will first
-discuss the default behaviour and afterwards show, how you can modify
-this behaviour to suit your special expectations on the tests.
-
-
-Setting up a simple test suite
-------------------------------
-
-We want to register the tests contained in the local ``cave``
-package. This has to be imported first, because we need the package as
-a parameter for the testseupt constructor::
-
-   >>> from grok.tests.testsetup import cave
-
-Using the ``FunctionalTestSetup`` then is easy::
-
-   >>> from grok.testing import FunctionalTestSetup
-   >>> setup = FunctionalTestSetup(cave)
-   >>> setup
-   <grok.testing.FunctionalTestSetup object at 0x...>   
-
-This setup is ready for use::
-
-   >>> suite = setup.getTestSuite()
-   >>> suite
-   <unittest.TestSuite tests=[...]>
-
-To sum it up, writing a test setup for a grok project now can be that
-short::
-
-   import unittest
-   import grok
-   import cave
-   def test_suite():
-       setup = grok.testing.FunctionalTestSetup(cave)
-       return setup.getTestSuite()
-   if __name__ == '__main__':
-       unittest.main(default='test_suite')
-
-This will find all .rst and .txt files in the package that provide a
-certain signature (see below), register the contained tests as
-functional tests and run them as part of a `unittest.TestSuite`.
-
-
-FunctionalTestSetup default values
-----------------------------------
-
-Understanding the defaults is important, because the default values
-are driving the whole process of finding and registering the test.
-
-
-Which files are found by default?
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-
-Basically, all files are accepted that
-
-1) reside inside the package passed to the constructor. This includes
-   subdirectories.
-
-2) have a filename extension `.txt` or `.rst` (uppercase, lowercase
-   etc. does not matter).
-
-3) are *not* located inside a 'hidden' directory (i.e. a directory
-   starting with a dot ('.'). Also subdirectories of 'hidden'
-   directories are skipped.
-
-4) contain a ReStructured Text meta-marker somewhere, that defines the
-   file as a functional test explicitly::
-
-       :Test-Layer: functional
-
-   This means: there *must* be a line like the above one in the
-   doctest file. The term might be preceeded or followed by whitspace
-   characters (spaces, tabs).
-
-Only files, that meet all four conditions are searched for functional
-doctests. You can modify this behaviour of course, which will be
-explained below in detail.
-
-
-What options are set by default?
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-
-Many options can be set, when registering functional doctests. When
-using the default set of options, the following values are set::
-
-* The setup-instance's ``setUp``-method is set as the ``setUp``
-  function.
-
-* The setup-instance's ``tearDown``-method is set as the ``tearDown``
-  function.
-  
-     >>> setup.setUp
-     <bound method FunctionalTestSetup.setUp of
-      <grok.testing.FunctionalTestSetup object at 0x...>>
-
-* The setup-instance's `globs` attribute is passed as the `globs`
-  parameter. By default `globs` is a dictionary of functions, that
-  should be'globally' available during testruns and it contains::
-
-     >>> setup.globs
-     {'http': <zope.app.testing.functional.HTTPCaller object at 0x...>,
-      'sync': <function sync at 0x...>,
-      'getRootFolder': <function getRootFolder at 0x...>}
-
-  The functions `sync` and `getRootFolder` are provided by
-  `zope.app.testing.functional`.
-
-* The setup-instance's `optionsflags` attribute is passed. It
-  includes by default the following doctest constants:
-
-     >>> from zope.testing import doctest
-     >>> setup.optionflags == (doctest.ELLIPSIS+
-     ...                       doctest.NORMALIZE_WHITESPACE |
-     ...                       doctest.REPORT_NDIFF)
-     True
-
-* Furthermore, additional keyword parameters are passed, which were
-  set when calling the constructor. These keywords are stored in the
-  setup object as `additional_options`. Those are empty by default::
-
-     >>> setup.additional_options
-     {}
-
-Because functional tests require a ZCML layer, that defines a ZCML
-setup for the tests, we provide a layer, that is driven by the file
-`ftesting.zcml`, which comes with grok. The layer is accessible as the
-setup instance attribute `layer`::
-
-   >>> setup.layer
-   <zope.app.testing.functional.ZCMLLayer instance at 0x...>
-
-   >>> setup.layer.config_file
-   '...ftesting.zcml'
-
-   
-
-No other options/parameters are set by default.
-
-
-Customizing functional test setup:
-----------------------------------
-
-You can modify the behaviour of grok.testing.FunctionalTestSetup such,
-that a different set of files is registered and/or the found tests are
-registered with a different set of parameters/options. We will first
-discuss modifying the set of files to be searched.
-
-
-Customizing the doctest file search:
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-
-The searching of appropriate doctest files is basically done by the
-base class `BasicTestSetup`. Its purpose is to determine the set of
-files in a package, that contain functional tests. See the testfile
-`basicsetup.py` to learn more about the procedure.
-
-The functional test setup, however, provides a special
-`isDocTestFile()` method, which does additional checking. Namely it
-checks for the existance of the above mentioned ReStructured Text
-meta-marker::
-
-    `:Test-Layer: functional`
-
-This is determined by a list of regular expressions, which is also
-available as an object attribute::
-
-    >>> setup.regexp_list
-    ['^\\\\s*:(T|t)est-(L|l)ayer:\\\\s*(functional)\\\\s*']
-
-This is the default value of functional test setups.
-
-There are two files in the `cave` subpackage, which include that
-marker. We can get the list of test files using
-`getDocTestFiles()``::
-
-    >>> testfile_list = setup.getDocTestFiles()
-    >>> testfile_list.sort()
-    >>> testfile_list
-    ['...file1.txt', '...subdirfile.txt']
-
-    >>> len(testfile_list)
-    2
-
-The ``isTestFile()`` method of our setup object did the filtering
-here::
-
-    >>> setup.isTestFile(testfile_list[0])
-    True
-
-The file file1.rst does not contain a functional test marker::
-
-    >>> import os.path
-    >>> path = os.path.join(os.path.dirname(cave.__file__),
-    ...                     'test1.rst')
-    >>> setup.isTestFile(path)
-    False
-
-The `regexp_list` attribute of a ``FunctionalTestSetup`` contains a
-list of regular expressions, of which each one must at least match one
-line of a searched file to be accepted. If you want to include files
-with different marker-strings, just change this attribute. The value
-will influence behaviour of the `isTestFile()``, ``getDocTestFiles()``
-and ``getTestSuite()`` methods.
-
-If you need more complex checks here, you can derive your customized
-test setup class and overwrite ``isTestFile()``.
-
-See `basicsetup.py` for further methods how to modify test file
-search, for example by choosing another set of accepted filename
-extensions.
-
-
-Customizing the functional test setup
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-
-To customize the setup of your tests, just modify the appropriate
-attributes as explained before.
-
-To setup a different setUp or tearDown function, you can define a
-derived class, that overwrites these methods.
-
-A convenient way to pass keyword parameters to the test setup, which
-do not appear in the attributes, is passing these keywords (and the
-values) to the constructor::
-
-    >>> encoded_setup = FunctionalTestSetup(cave,
-    ...                                     encoding='utf-8')
-
-This will read all doctests 'utf-8' encoded, which allow umlauts and
-similar chars in tests. Note, however, that you can archieve this very
-special behaviour also by writing an appropriate encoding string in
-the head of the doctest file.
-
-All keywords passed to the constructor (except 'filter_func' and
-'extensions') are also given to each individual test setup 'as-is'.
-
-Alternatively you can also modify the `additional_options` dictionary
-of a ``FunctionalTestSetup`` object.
-
-    >>> encoded_setup.additional_options
-    {'encoding': 'utf-8'}
-
-    >>> encoded_setup.additional_options['encoding'] = 'latin1'
-
-
-
-"""

Copied: grok/trunk/src/grok/tests/testsetup/testsetup.py (from rev 85728, grok/branches/ulif-testsetup-pre0.13/src/grok/tests/testsetup/testsetup.py)
===================================================================
--- grok/trunk/src/grok/tests/testsetup/testsetup.py	                        (rev 0)
+++ grok/trunk/src/grok/tests/testsetup/testsetup.py	2008-04-25 19:10:27 UTC (rev 85730)
@@ -0,0 +1,602 @@
+##############################################################################
+#
+# Copyright (c) 2008 Zope Corporation and Contributors.
+# All Rights Reserved.
+#
+# This software is subject to the provisions of the Zope Public License,
+# Version 2.1 (ZPL).  A copy of the ZPL should accompany this distribution.
+# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
+# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
+# FOR A PARTICULAR PURPOSE.
+#
+##############################################################################
+"""
+Tests for testsetups in grok.testing
+************************************
+
+The grok testing support provides a z3c.testsetup which should suit
+most grokprojects. Main parts of this support are
+
+- a grok.testing.register_all_tests() function that registers all
+  marked tests found in a package and
+
+- a TestGetter, that is reusable in own projects.
+
+We will discuss both in the following sections.
+
+grok.testing.register_all_tests(<pkg>)
+======================================
+
+A function that requires a package and delivers a callable which, if
+called without arguments, returns a test suite with all tests of all
+doctestfiles (functional *and* unit doctests) and Python tests found
+in the given package.
+
+With this function you can setup tests like this::
+
+   import grok
+   test_suite = grok.testing.register_all_tests('cave')
+
+In standard grokprojects, this should find all files and modules, that
+have a .txt or .rst filename extension (doctests) or are regular
+Python modules (Python tests). Only those tests are found, that
+provide a certain marker string (see below).
+
+To modify the default values (described below), you can pass
+(optional) keyword parameters. The complete syntax is::
+
+   grok.testing.register_all_tests(
+      <pkg_or_dotted_name>,
+      filter_func = <function>,
+      ffilter_func = <function>,
+      ufilter_func = <function>,
+      pfilter_func = <function>,
+      extensions = <list_of_filename_extenstions>,
+      fextensions = <list_of_filename_extenstions>,
+      uextensions = <list_of_filename_extenstions>
+      regexp_list = <list_of_regular_expression_terms>,
+      uregexp_list = <list_of_regular_expression_terms>,
+      fregexp_list = <list_of_regular_expression_terms>,
+      pregexp_list = <list_of_regular_expression_terms>,
+      encoding = <string_with_encoding_specifier>,
+      checker = <output_checker>,
+      globs = <dict_of_globals>,
+      fglobs = <dict_of_globals>,
+      uglobs = <dict_of_globals>,
+      setup = <function>,
+      fsetup = <function>,
+      usetup = <function>,
+      teardown = <function>,
+      fteardown = <function>,
+      uteardown = <function>,
+      optionflags = <optionflags>,
+      foptionflags = <optionflags>,
+      uoptionflags = <optionflags>,
+      zcml_config = <path_to_zcml_config_file>,
+      layer_name = <string>,
+      layer = <complete_zcml_layer>)
+
+where all parameters (except the first one) are optional. Those
+options that are preceeded by 'u', 'f', or 'p' affect only unit
+doctests, functional doctests or Python tests respectively.
+
+The work of the function is done in two steps:
+
+1) Doctestfiles and Python modules with tests are collected and
+
+2) the tests contained in them are registered with the given values or
+   default values.
+
+We will discuss the default values and how to modify the behaviour of
+both steps.
+
+
+A simple test setup with register_all_tests()
+---------------------------------------------
+
+The `register_all_tests()` function must be called with a package as
+first argument. This package can be given in 'dotted name' notation::
+
+   >>> import grok
+   >>> setup = grok.testing.register_all_tests(
+   ...             'grok.tests.testsetup.cave')
+   >>> setup
+   <grok.testing.GrokTestCollector object at 0x...>
+
+Alternatively, we can pass the 'real' package, which requires to
+import it before::
+
+   >>> from grok.tests.testsetup import cave
+   >>> setup = grok.testing.register_all_tests(cave)
+   >>> setup
+   <grok.testing.GrokTestCollector object at 0x...>
+
+In both cases we get a `GrokTestCollector` which is a callable, that
+returns a ``unittest.TestSuite`` upon being called::
+
+   >>> suite = setup()
+   >>> suite
+   <unittest.TestSuite tests=[...]>
+
+We import a function of the z3c.testsetup to list the set of included
+testfiles/modules::
+
+   >>> from z3c.testsetup.tests.test_testsetup import get_basenames_from_suite
+   >>> get_basenames_from_suite(suite)
+   ['file1.py', 'file1.rst', 'file1.txt', 'subdirfile.txt']
+   
+These are files/modules located in the ``cave`` package. If you look
+into these files, you will see, that `file1.py` is a normal Pyhton
+testmodule, `file1.rst` contains unitdoctests and both .txt-files
+are functional doctest files.
+
+There are some more files in the `cave` package, which also contain
+tests. Why haven't they been found? A doctestfile or module must meet
+certain requirements to be accepted.
+
+
+Which files/modules are found by default?
+-----------------------------------------
+
+Basically, all files/modules are found that
+
+1) reside inside the package passed to the function. This includes
+   subdirectories/subpackages.
+
+2) have a filename extension `.txt` or `.rst` (uppercase, lowercase
+   etc. does not matter) if they should be registered as unit or
+   functional doctests. Python tests are always looked up in regular
+   Python modules.
+
+3) are *not* located inside a 'hidden' directory (i.e. a directory
+   starting with a dot ('.'). Also subdirectories of 'hidden'
+   directories are skipped. Python tests are only found, if the
+   subpackage they are in is a real subpackage (the directory itself
+   and all parent directories inside the root package must have an
+   `__init__.py`).
+
+4) contain a ReStructured Text meta-marker somewhere, that defines the
+   file as a functional or unit doctest or Python test explicitly.
+
+   For functional doctests, the file must contain::
+   
+       :Test-Layer: functional
+
+   For unit doctests the file must contain::
+
+       :Test-Layer: functional
+
+   Python test modules must provide a module docstring that contains::
+
+       :Test-Layer: python
+
+   This means: there *must* be a line like the above one in the
+   doctest file or python modules. The terms might be preceeded or
+   followed by whitspace characters (spaces, tabs).
+
+All this is the default behaviour.
+
+
+Customize the set of files/modules found
+----------------------------------------
+
+If we want to grab a different set of doctest files and/or modules, we
+can use three options:
+
+1) Pass an `extensions` parameter (doctests only):
+
+     This by default is the list ``['.txt', '.rst']. If we want to
+     search .foo files too, then we can do it like this::
+
+        >>> setup = grok.testing.register_all_tests(
+        ...     cave, extensions=['.foo'])
+
+     Note, that the behaviour is not cummulative. We have to give the
+     complete list. This will result in a different set of files
+     found::
+
+        >>> suite = setup()
+        >>> get_basenames_from_suite(suite)
+        ['file1.py', 'notatest1.foo', 'notatest1.foo']
+
+     This result may look surprisingly, but is correct. The `file1.py`
+     module was included, because Python tests are not affected by the
+     `extensions` option and `file1.py` is a Python test. The
+     `notatest1.foo` file appears twice, because it was once
+     registered as a unit test and once as a functional test (yes,
+     this is possible although it might not make too much sense in
+     reality).
+
+     To modify only the selection of functional doctests, you can pass
+     the `fextensions` option::
+
+        >>> setup = grok.testing.register_all_tests(
+        ...     cave, fextensions=['.foo'])
+
+     Now .txt and .rst files will be searched for unit doctests and
+     .foo files for functional doctests::
+
+        >>> suite = setup()
+        >>> get_basenames_from_suite(suite)
+        ['file1.py', 'file1.rst', 'notatest1.foo']
+
+     If we provide an `<x>extensions` parameter and an `extensions`
+     parameter, the more specific one will override the more general
+     one. If for example we use::
+
+        >>> setup = grok.testing.register_all_tests(
+        ...     cave, extensions=['.foo'], fextensions=['.txt'])
+
+     then all unitdoctests with filename extension .foo will be found
+     and all functional doctests in .txt files::
+
+        >>> suite=setup()
+        >>> get_basenames_from_suite(suite)
+        ['file1.py', 'file1.txt', 'notatest1.foo', 'subdirfile.txt']
+
+     Python tests are not affected by the `extensions` parameter. But
+     to be clear: you can search for doctests (and find them!) in
+     Python files. See `Doctests in Python modules`_ below.
+
+2) Pass an `regexp_list` parameter:
+
+     The `regexp_list` parameter determins, which terms we want to
+     search for in potential doctest files and modules. By default the
+     'Test-Layer' terms mentioned above are used.
+
+     To set a required term for one specific test type (unitdoctest,
+     functional doctests or Python tests), you can use the
+     `uregexp_list`, `fregexp_list` and `pregexp_list` keywords
+     respectively.
+
+     If you use the `regexp_list` parameter only, all kinds of tests
+     require the same term. That is normally not what you want, but
+     works::
+
+        >>> setup = grok.testing.register_all_tests(
+        ...     cave, regexp_list = [':Test-Layer:'])
+        >>> suite = setup()
+        >>> get_basenames_from_suite(suite)
+        ['file1.py', 'file1.rst', 'file1.rst', 'file1.txt',
+        'file1.txt', 'subdirfile.txt', 'subdirfile.txt']
+
+     Here the .txt and .rst files were registered twice, once as a
+     unit doctest and once as a functional doctest.
+
+     Normally you want to set a special marker for one type of
+     tests. We require the unit doctest marker for functional doctests
+     now::
+     
+        >>> setup = grok.testing.register_all_tests(
+        ...     cave, fregexp_list = [':Test-Layer: unit'])
+        >>> suite = setup()
+        >>> get_basenames_from_suite(suite)
+        ['file1.py', 'file1.rst', 'file1.rst']
+
+     The file `file1.rst` was now registered as a functional doctest
+     as well.
+
+     As you see, regexp_lists are lists. They match (accept) a file
+     iff each of the expressions of the list could be found in a line
+     of a considered file.
+
+     For example the string ':Test-Layer:' can be found in many test
+     files. But the additional string 'TestCase' appears only in the
+     file1.py file in the cave package::
+
+        >>> setup = grok.testing.register_all_tests(
+        ...     cave, regexp_list = ['.*:Test-Layer:.*',
+        ...                          '.*TestCase.*'])
+        >>> suite = setup()
+        >>> get_basenames_from_suite(suite)
+        ['file1.py']
+
+3) Pass a `filter_func` parameter:
+
+     This keyword expects an callable, which can be called with a file
+     path as argument. It should return `True` or `False`. We define
+     an example function::
+
+        >>> import os.path
+        >>> def myfilter(path):
+        ...     if os.path.basename(path).startswith('subdir'):
+        ...         return True
+        ...     return False
+
+     This function accepts all filenames that start with 'subdir',
+     which matches exactly one file in our example cave. Let's see the
+     results::
+
+        >>> setup = grok.testing.register_all_tests(
+        ...     cave, filter_func = myfilter)
+        >>> suite = setup()
+        >>> get_basenames_from_suite(suite)
+        ['file1.py', 'subdirfile.txt', 'subdirfile.txt']
+
+     Again we see the one Python module. The module search is not
+     affected by `filter_func`. Use `pfilter_func` instead::
+
+        >>> def mypfilter(module):
+        ...     basename = os.path.basename(module.__file__)
+        ...     if basename.startswith('subdirfile'):
+        ...         return True
+        ...     return False
+
+        >>> setup = grok.testing.register_all_tests(
+        ...     cave, pfilter_func = mypfilter)
+        >>> suite = setup()
+        >>> get_basenames_from_suite(suite)
+        ['file1.rst', 'file1.txt', 'subdirfile.txt']
+
+     Unit and functional dotests can be selected specifically by using
+     `ufilter_func` or `ffilter_func` respectively.
+
+     Note, that using a custom `filter_func` will disable filename
+     extension filtering. You have to implement it yourself in this
+     case. Therefore also the `regexp_list` parameter will have no
+     effect when you define your own filter functions.
+
+
+Customizing the setup of single tests
+-------------------------------------
+
+The other keyword parameters of `register_all_tests()` influence not
+the set of files handled, but the manner in which each individual test
+is set up.
+
+The descriptions here will be somewhat short, because testing of such
+stuff requires a more complex test setup. But the behaviour is (with
+one exception described below) like the behaviour of the original
+z3c.testsetup.register_all_tests() function. See
+
+  http://svn.zope.org/z3c.testsetup/trunk/z3c/testsetup/testrunner.txt
+
+and
+
+  http://svn.zope.org/z3c.testsetup/trunk/z3c/testsetup/README.txt
+
+for some examples in action.
+
+The difference from original behaviour is the default value of the
+layer for functional doctests. We will therefore start with it.
+
+* `zcml_config`, `layer_name` and `layer`:
+
+    `zcml_config`: a string with a filesystem path to a ZCML layer,
+    that should be used during functional doctests.
+
+    `layer_name`: a string with an arbitrary name for the file
+    identified by the `zcml_config` file. The layer name is only used,
+    if a `zcml_config` is set. Default is: `FunctionalLayer`.
+
+    `layer`: a ready to use zope.testing.functional.ZCMLLayer object.
+
+    Functional doctests need a layer to set up some framework stuff
+    like registering of principals etc. The grok.register_all_tests()
+    function will lookup a few places for such a file or, if the
+    `zcml_config` keyword is passed, take this. The order is like
+    this:
+
+      1) if `layer` is set, take that. This overrides any
+         `zcml_config` given.
+
+      2) if `zcml_config` is set, lookup the file, setup a layer with
+         that file and take that.
+
+      3) if a file `ftesting.zcml` exists in the root of the package
+         scanned for tests, register and take that.
+
+      4) as fallback take the `ftesting.zcml` from the `grok`
+         package. This is the only difference from the original
+         z3c.testsetup behaviour, which takes another file as fallback
+         solution.
+
+    We will now simulate each of this four cases. For this purpose we
+    will call testrunners that collect and run tests in the `cave` and
+    the `cave_to_let` package.
+
+    In `samplesetup1.py` in the cave package is a testsetup, that
+    defines an own test layer and passes it as `layer` parameter. We
+    dump the file contents here::
+
+       >>> cavepath = os.path.join(os.path.dirname(__file__), 'cave')
+       >>> setupfile = os.path.join(cavepath, 'samplesetup1.py')
+       >>> print open(setupfile).read()
+       import os.path
+       from zope.app.testing.functional import ZCMLLayer
+       from grok.testing import register_all_tests
+       samplelayer = ZCMLLayer(
+           os.path.join(os.path.dirname(__file__), 'sample.zcml'),
+           __name__, 'CustomSampleLayer')
+       test_suite = register_all_tests(
+           'grok.tests.testsetup.cave',
+           layer = samplelayer
+           )
+
+    Note, that here a custom ZCML layer is defined, based on the file
+    `sample.zcml`. Now we setup a testrunner, that will read exactly
+    this file. We configure it such, that it runs only functional
+    tests::
+
+       >>> import sys
+       >>> old_sysargv = sys.argv # store
+       >>> defaults = [
+       ...     '--path', cavepath,
+       ...     '--tests-pattern', '^samplesetup1$',
+       ...     ]
+       >>> sys.argv = 'test -f '.split()
+       >>> from zope.testing import testrunner
+
+    The testrunner is ready. Let's start it::
+
+       >>> testrunner.run(defaults)
+       Running samplesetup1.CustomSampleLayer tests:
+         Set up samplesetup1.CustomSampleLayer in ... seconds.
+         Ran 2 tests with 0 failures and 0 errors in ... seconds.
+       Tearing down left over layers:
+         Tear down samplesetup1.CustomSampleLayer ... not supported
+       False
+
+    We see, that the custom layer was used. The `False` at the end
+    indicates, that the testrun was finished without any failures.
+
+    Now let's do the same, but give a path to the ZCML file instead of
+    a fully configured layer. For this we use `samplesetup2` from the
+    cave package::
+
+       >>> setupfile = os.path.join(cavepath, 'samplesetup2.py')
+       >>> print open(setupfile).read()
+       import os.path
+       from grok.testing import register_all_tests
+       test_suite = register_all_tests(
+           'grok.tests.testsetup.cave',
+           zcml_config = os.path.join(os.path.dirname(__file__),
+                                      'sample.zcml'),
+           layer_name = 'CustomLayerFromPath')
+
+    If we feed this setup to a testrunner, we get the following::
+
+       >>> defaults = [
+       ...     '--path', cavepath,
+       ...     '--tests-pattern', '^samplesetup2$',
+       ...     ]
+       >>> sys.argv = 'test -f '.split()
+       >>> testrunner.run(defaults)
+       Running grok.tests.testsetup.cave.CustomLayerFromPath tests:
+         Set up grok.tests.testsetup.cave.CustomLayerFromPath in ... seconds.
+         Ran 2 tests with 0 failures and 0 errors in ... seconds.
+       Tearing down left over layers:
+         Tear down grok.tests.testsetup.cave.CustomLayerFromPath ...
+       not supported
+       False
+
+    Apparently the CustomLayerFromPath was found and registered.
+
+    Now we will use the default value. The `cave` package provides an
+    (empty) `ftesting.zcml` which should be found and registered, when
+    no other option was given.
+
+    The file `samplesetup3.py` will do so::
+
+       >>> setupfile = os.path.join(cavepath, 'samplesetup3.py')
+       >>> print open(setupfile).read()
+       from grok.testing import register_all_tests
+       test_suite = register_all_tests('grok.tests.testsetup.cave')
+
+    This test setup has only two lines, but is perfectly valid. Will
+    it register the right thing?
+    
+       >>> defaults = [
+       ...     '--path', cavepath,
+       ...     '--tests-pattern', '^samplesetup3$',
+       ...     ]
+       >>> sys.argv = 'test -f '.split()
+       >>> testrunner.run(defaults)
+       Running grok.tests.testsetup.cave.FunctionalLayer tests:
+         Set up grok.tests.testsetup.cave.FunctionalLayer in ... seconds.
+         Ran 2 tests with 0 failures and 0 errors in ... seconds.
+       Tearing down left over layers:
+         Tear down grok.tests.testsetup.cave.FunctionalLayer ...
+       not supported
+       False
+
+    The ftesting.zcml layer from the cave package was used
+    automatically. The name `FunctionalLayer` is the default for such
+    cases. It can be overriden by passing the `layer_name` keyword.
+
+    Now, the last layer test.
+
+    In `samplesetup4.py` in the cave package, there is another
+    testsetup, which is as short as the last one, but registers tests
+    for the `cave_to_let` package, which contrary to the `cave`
+    package does not provide an `ftesting.zcml`. It looks like this::
+
+       >>> setupfile = os.path.join(cavepath, 'samplesetup4.py')
+       >>> print open(setupfile).read()
+       from grok.testing import register_all_tests
+       test_suite = register_all_tests('grok.tests.testsetup.cave_to_let')
+
+    Obviously, the only difference is the 'cave_to_let' package
+    registered. Let's run it::
+
+       >>> defaults = [
+       ...     '--path', cavepath,
+       ...     '--tests-pattern', '^samplesetup4$',
+       ...     ]
+       >>> sys.argv = 'test -f '.split()
+       >>> testrunner.run(defaults)
+       Running grok.tests.testsetup.cave_to_let.GrokFunctionalLayer tests:
+         Set up grok.tests.testsetup.cave_to_let.GrokFunctionalLayer in ... seconds.
+         Ran 1 tests with 0 failures and 0 errors in ... seconds.
+       Tearing down left over layers:
+         Tear down grok.tests.testsetup.cave_to_let.GrokFunctionalLayer ... not supported
+       False
+
+    So, the `GrokFunctionalLayer` was used as fallback, because the
+    `cave_to_let` package has no own ftesting.zcml. Note also, that
+    here the testsetup was put into a location out of the package
+    tested. A testsetup does not have to be part of the package it
+    tests.
+
+       >>> sys.argv = old_sysargv # restore old values
+
+Doctests in Python modules
+==========================
+
+or: what the heck are those 'Python tests' after all?
+
+That a file with tests is a Python module, does not mean
+automatically, that it is a Python test in the sense of
+z3c.testsetup. Instead many packages contain Python files, that
+contain **doctests** and not real Python tests. The file you are
+reading is an example for such a module with doctests.
+
+A real python test modules defines tests as follows::
+
+    '''
+    Tests with real TestCase objects.
+
+    :Test-Layer: python
+
+    '''
+
+    import unittest
+
+    class TestTest(unittest.TestCase):
+
+        def setUp(self):
+            pass
+
+        def testFoo(self):
+            self.assertEqual(2, 1+1)
+
+while a doctestfile with .py filename extension might look like this::
+
+    '''
+    Doctests in a Python module.
+
+    :Test-Layer: functional
+
+    This file contains a lot of examples::
+
+       >>> 1+1
+       2
+
+    Another example::
+
+       >>> 1+2
+       3
+    
+    '''
+    # Setup stuff...
+    class MyTestClass:
+        pass
+
+You can also define doctests in functions and classes of a regular
+Python module. The single tests will be collected as well and setup as
+doctests, as long as .py files are accepted and the file contains the
+required marker string somewhere in the file.
+
+
+"""

Deleted: grok/trunk/src/grok/tests/testsetup/unittestsetup.py
===================================================================
--- grok/trunk/src/grok/tests/testsetup/unittestsetup.py	2008-04-25 19:06:16 UTC (rev 85729)
+++ grok/trunk/src/grok/tests/testsetup/unittestsetup.py	2008-04-25 19:10:27 UTC (rev 85730)
@@ -1,252 +0,0 @@
-##############################################################################
-#
-# Copyright (c) 2007 Zope Corporation and Contributors.
-# All Rights Reserved.
-#
-# This software is subject to the provisions of the Zope Public License,
-# Version 2.1 (ZPL).  A copy of the ZPL should accompany this distribution.
-# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
-# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
-# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
-# FOR A PARTICULAR PURPOSE.
-#
-##############################################################################
-"""
-===============
-Unit Test Setup
-===============
-
-``UnitTestSetup`` helps to find and setup unit doctests contained in a
-package. The most important method therefore might be
-``getTestSuite()``, which searches a given package for doctest files
-and returns all tests found as a suite of unit tests.
-
-The work is done mainly in two stages:
-
-1) The package is searched for appropriate docfiles, based on the
-   settings of instcance attributes.
-
-2) The tests contained in the found docfiles are setup as unit tests
-   and added to a ``unittest.TestSuite`` instance.
-
-There are plenty of default values active, if you use instances of
-this class without further modifications. Therefore we will first
-discuss the default behaviour and afterwards show, how you can modify
-this behaviour to suit your special expectations on the tests.
-
-
-Setting up a simple test suite
-------------------------------
-
-We want to register the tests contained in the local ``cave``
-package. This has to be imported first, because we need the package as
-a parameter for the testseupt constructor::
-
-   >>> from grok.tests.testsetup import cave
-
-Using the ``UnitTestSetup`` then is easy::
-
-   >>> from grok.testing import UnitTestSetup
-   >>> setup = UnitTestSetup(cave)
-   >>> setup
-   <grok.testing.UnitTestSetup object at 0x...>   
-
-This setup is ready for use::
-
-   >>> suite = setup.getTestSuite()
-   >>> suite
-   <unittest.TestSuite tests=[...]>
-
-To sum it up, writing a test setup for a grok project now can be that
-short::
-
-   import unittest
-   import grok
-   import cave
-   def test_suite():
-       setup = grok.testing.UnitTestSetup(cave)
-       return setup.getTestSuite()
-   if __name__ == '__main__':
-       unittest.main(default='test_suite')
-
-This will find all .rst and .txt files in the package that provide a
-certain signature (see below), register the contained tests as unit
-tests and run them as part of a `unittest.TestSuite`.
-
-
-UnitTestSetup default values
-----------------------------
-
-Understanding the defaults is important, because the default values
-are driving the whole process of finding and registering the test.
-
-
-Which files are found by default?
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-
-Basically, all files are accepted that
-
-1) reside inside the package passed to the constructor. This includes
-   subdirectories.
-
-2) have a filename extension `.txt` or `.rst` (uppercase, lowercase
-   etc. does not matter).
-
-3) are *not* located inside a 'hidden' directory (i.e. a directory
-   starting with a dot ('.'). Also subdirectories of 'hidden'
-   directories are skipped.
-
-4) contain a ReStructured Text meta-marker somewhere, that defines the
-   file as a unit test (and not: functional test) explicitly::
-
-       :Test-Layer: unit
-
-   This means: there *must* be a line like the above one in the
-   doctest file. The term might be preceeded or followed by whitspace
-   characters (spaces, tabs).
-
-Only files, that meet all four conditions are searched for unit
-doctests. You can modify this behaviour of course, which will be
-explained below in detail.
-
-
-What options are set by default?
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-
-Many options can be set, when registering unit doctests. When using
-the default set of options, the following values are set::
-
-* The setup-instance's ``setUp``-method is set as the ``setUp``
-  function.
-
-* The setup-instance's ``tearDown``-method is set as the ``tearDown``
-  function.
-  
-     >>> setup.setUp
-     <bound method UnitTestSetup.setUp of
-      <grok.testing.UnitTestSetup object at 0x...>>
-
-* The setup-instance's `optionsflags` attribute is passed. It
-  includes by default the following doctest constants:
-
-     >>> from zope.testing import doctest
-     >>> setup.optionflags == (doctest.ELLIPSIS+
-     ...                       doctest.NORMALIZE_WHITESPACE |
-     ...                       doctest.REPORT_NDIFF)
-     True
-
-* Furthermore, additional keyword parameters are passed, which were
-  set when calling the constructor. These keywords are stored in the
-  setup object as `additional_options`. Those are empty by default::
-
-     >>> setup.additional_options
-     {}
-
-No other options/parameters are set by default.
-
-
-Customizing unit test setup:
-----------------------------
-
-You can modify the behaviour of grok.testing.UnitTestSetup such, that
-a different set of files is registered and/or the found tests are
-registered with a different set of parameters/options. We will first
-discuss modifying the set of files to be searched.
-
-
-Customizing the doctest file search:
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-
-The searching of appropriate doctest files is basically done by the
-base class `BasicTestSetup`. Its purpose is to determine the set of
-files in a package, that contain unit tests. See the testfile
-`basicsetup.py` to learn more about the procedure.
-
-The unit test setup, however, requires that files contain the above
-mentioned ReStructured Text meta-marker::
-
-    `:Test-Layer: unit`
-
-This is determined by a list of regular expressions, which is also
-available as an object attribute::
-
-    >>> setup.regexp_list
-    ['^\\\\s*:(T|t)est-(L|l)ayer:\\\\s*(unit)\\\\s*']
-
-This is the default value of unit test setups.
-
-There is one file in the `cave` subpackage, which includes that
-marker. We can get the list of test files using
-`getDocTestFiles()``::
-
-    >>> testfile_list = setup.getDocTestFiles()
-    >>> testfile_list
-    ['...file1.rst']
-
-    >>> len(testfile_list)
-    1
-
-The ``isTestFile()`` method of our setup object did the filtering
-here::
-
-    >>> setup.isTestFile(testfile_list[0])
-    True
-
-The file file1.txt does not contain a unit test marker::
-
-    >>> import os.path
-    >>> path = os.path.join(os.path.dirname(cave.__file__),
-    ...                     'test1.txt')
-    >>> setup.isTestFile(path)
-    False
-
-The `regexp_list` attribute of a ``UnitTestSetup`` contains a
-list of regular expressions, of which each one must at least match one
-line of a searched file to be accepted. If you want to include files
-with different marker-strings, just change this attribute. The value
-will influence behaviour of the `isTestFile()``, ``getDocTestFiles()``
-and ``getTestSuite()`` methods.
-
-If you need more complex checks here, you can derive your customized
-test setup class and overwrite ``isTestFile()``.
-
-See `basicsetup.py` for further methods how to modify test file
-search, for example by choosing another set of accepted filename
-extensions.
-
-
-Customizing the unit test setup
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-
-To customize the setup of your tests, just modify the appropriate
-attributes as explained before.
-
-To setup a different setUp or tearDown function, you can define a
-derived class, that overwrites these methods.
-
-A convenient way to pass keyword parameters to the test setup, which
-do not appear in the attributes, is passing these keywords (and the
-values) to the constructor::
-
-    >>> encoded_setup = UnitTestSetup(cave,
-    ...                               encoding='utf-8')
-
-This will read all doctests 'utf-8' encoded, which allow umlauts and
-similar chars in tests. Note, however, that you can archieve this very
-special behaviour also by writing an appropriate encoding string in
-the head of the doctest file.
-
-All keywords passed to the constructor (except 'filter_func' and
-'extensions') are also given to each individual test setup 'as-is'.
-
-Alternatively you can also modify the `additional_options` dictionary
-of a ``UnitTestSetup`` object.
-
-    >>> encoded_setup.additional_options
-    {'encoding': 'utf-8'}
-
-    >>> encoded_setup.additional_options['encoding'] = 'latin1'
-
-
-
-"""

Modified: grok/trunk/versions.cfg
===================================================================
--- grok/trunk/versions.cfg	2008-04-25 19:06:16 UTC (rev 85729)
+++ grok/trunk/versions.cfg	2008-04-25 19:10:27 UTC (rev 85730)
@@ -9,6 +9,7 @@
 simplejson = 1.7.1
 z3c.autoinclude = 0.2.2
 z3c.flashmessage = 1.0b2
+z3c.testsetup = 0.2.1
 zc.catalog = 1.2b
 ZConfig = 2.5
 zdaemon = 2.0.0



More information about the Checkins mailing list