[Zope3-checkins] SVN: zope.testing/trunk/ Two new features at once:

Jim Fulton jim at zope.com
Tue May 24 16:29:23 EDT 2005


Log message for revision 30492:
  Two new features at once:
  
  - renormalizing module for using regular expressions to normalize
    expected and actual outputs to deal with variable data such as 
    addresses, times, and paths
  
  - Initial cut at new test runner.  Have documentation and tests for
    basic features for selecting and running tests and for displaying
    errors.
  
  (Documentation and tests for advanced features will come as I have
    time.)
  

Changed:
  U   zope.testing/trunk/src/zope/testing/doctest.py
  A   zope.testing/trunk/src/zope/testing/renormalizing.py
  A   zope.testing/trunk/src/zope/testing/testrunner-ex/
  A   zope.testing/trunk/src/zope/testing/testrunner-ex/README.txt
  A   zope.testing/trunk/src/zope/testing/testrunner-ex/sample1/
  A   zope.testing/trunk/src/zope/testing/testrunner-ex/sample1/__init__.py
  A   zope.testing/trunk/src/zope/testing/testrunner-ex/sample1/sample11/
  A   zope.testing/trunk/src/zope/testing/testrunner-ex/sample1/sample11/__init__.py
  A   zope.testing/trunk/src/zope/testing/testrunner-ex/sample1/sample11/sampletests/
  A   zope.testing/trunk/src/zope/testing/testrunner-ex/sample1/sample11/sampletests.py
  A   zope.testing/trunk/src/zope/testing/testrunner-ex/sample1/sample12/
  A   zope.testing/trunk/src/zope/testing/testrunner-ex/sample1/sample12/__init__.py
  A   zope.testing/trunk/src/zope/testing/testrunner-ex/sample1/sample12/sampletests/
  A   zope.testing/trunk/src/zope/testing/testrunner-ex/sample1/sample13/
  A   zope.testing/trunk/src/zope/testing/testrunner-ex/sample1/sample13/__init__.py
  A   zope.testing/trunk/src/zope/testing/testrunner-ex/sample1/sample13/sampletests.py
  A   zope.testing/trunk/src/zope/testing/testrunner-ex/sample1/sampletests/
  A   zope.testing/trunk/src/zope/testing/testrunner-ex/sample1/sampletests/__init__.py
  A   zope.testing/trunk/src/zope/testing/testrunner-ex/sample1/sampletests/test1.py
  A   zope.testing/trunk/src/zope/testing/testrunner-ex/sample1/sampletests/test11.py
  A   zope.testing/trunk/src/zope/testing/testrunner-ex/sample1/sampletests/test111.py
  A   zope.testing/trunk/src/zope/testing/testrunner-ex/sample1/sampletests/test112.py
  A   zope.testing/trunk/src/zope/testing/testrunner-ex/sample1/sampletests/test12.py
  A   zope.testing/trunk/src/zope/testing/testrunner-ex/sample1/sampletests/test121.py
  A   zope.testing/trunk/src/zope/testing/testrunner-ex/sample1/sampletests/test122.py
  A   zope.testing/trunk/src/zope/testing/testrunner-ex/sample1/sampletests/test_one.py
  A   zope.testing/trunk/src/zope/testing/testrunner-ex/sample1/sampletestsf.py
  A   zope.testing/trunk/src/zope/testing/testrunner-ex/sample2/
  A   zope.testing/trunk/src/zope/testing/testrunner-ex/sample2/__init__.py
  A   zope.testing/trunk/src/zope/testing/testrunner-ex/sample2/e.txt
  A   zope.testing/trunk/src/zope/testing/testrunner-ex/sample2/sample21/
  A   zope.testing/trunk/src/zope/testing/testrunner-ex/sample2/sample21/__init__.py
  A   zope.testing/trunk/src/zope/testing/testrunner-ex/sample2/sample21/sampletests.py
  A   zope.testing/trunk/src/zope/testing/testrunner-ex/sample2/sample22/
  A   zope.testing/trunk/src/zope/testing/testrunner-ex/sample2/sample22/__init__.py
  A   zope.testing/trunk/src/zope/testing/testrunner-ex/sample2/sample22/sampletests/
  A   zope.testing/trunk/src/zope/testing/testrunner-ex/sample2/sample23/
  A   zope.testing/trunk/src/zope/testing/testrunner-ex/sample2/sample23/__init__.py
  A   zope.testing/trunk/src/zope/testing/testrunner-ex/sample2/sampletests/
  A   zope.testing/trunk/src/zope/testing/testrunner-ex/sample2/sampletests/__init__.py
  A   zope.testing/trunk/src/zope/testing/testrunner-ex/sample2/sampletests/test_1.py
  A   zope.testing/trunk/src/zope/testing/testrunner-ex/sample2/sampletests/testone.py
  A   zope.testing/trunk/src/zope/testing/testrunner-ex/sample2/sampletests_e.py
  A   zope.testing/trunk/src/zope/testing/testrunner-ex/sample2/sampletests_f.py
  A   zope.testing/trunk/src/zope/testing/testrunner-ex/sample3/
  A   zope.testing/trunk/src/zope/testing/testrunner-ex/sample3/__init__.py
  A   zope.testing/trunk/src/zope/testing/testrunner-ex/sample3/sample31/
  A   zope.testing/trunk/src/zope/testing/testrunner-ex/sample3/sample31/__init__.py
  A   zope.testing/trunk/src/zope/testing/testrunner-ex/sample3/sample32/
  A   zope.testing/trunk/src/zope/testing/testrunner-ex/sample3/sample32/__init__.py
  A   zope.testing/trunk/src/zope/testing/testrunner-ex/sample3/sample33/
  A   zope.testing/trunk/src/zope/testing/testrunner-ex/sample3/sample33/__init__.py
  A   zope.testing/trunk/src/zope/testing/testrunner-ex/sample3/sampletests.py
  A   zope.testing/trunk/src/zope/testing/testrunner-ex/samplelayers.py
  A   zope.testing/trunk/src/zope/testing/testrunner-ex/sampletests/
  A   zope.testing/trunk/src/zope/testing/testrunner-ex/sampletests/__init__.py
  A   zope.testing/trunk/src/zope/testing/testrunner-ex/sampletests/test1.py
  A   zope.testing/trunk/src/zope/testing/testrunner-ex/sampletests/test11.py
  A   zope.testing/trunk/src/zope/testing/testrunner-ex/sampletests/test111.py
  A   zope.testing/trunk/src/zope/testing/testrunner-ex/sampletests/test112.py
  A   zope.testing/trunk/src/zope/testing/testrunner-ex/sampletests/test12.py
  A   zope.testing/trunk/src/zope/testing/testrunner-ex/sampletests/test121.py
  A   zope.testing/trunk/src/zope/testing/testrunner-ex/sampletests/test122.py
  A   zope.testing/trunk/src/zope/testing/testrunner-ex/sampletests/test_one.py
  A   zope.testing/trunk/src/zope/testing/testrunner-ex/sampletests.txt
  A   zope.testing/trunk/src/zope/testing/testrunner-ex/sampletestsf.py
  A   zope.testing/trunk/src/zope/testing/testrunner-ex/sampletestsl.txt
  A   zope.testing/trunk/src/zope/testing/testrunner.py
  A   zope.testing/trunk/src/zope/testing/testrunner.txt
  U   zope.testing/trunk/src/zope/testing/tests.py
  A   zope.testing/trunk/test.py

-=-
Modified: zope.testing/trunk/src/zope/testing/doctest.py
===================================================================
--- zope.testing/trunk/src/zope/testing/doctest.py	2005-05-24 20:28:14 UTC (rev 30491)
+++ zope.testing/trunk/src/zope/testing/doctest.py	2005-05-24 20:28:53 UTC (rev 30492)
@@ -2130,7 +2130,11 @@
             
     return count or 1
             
-    
+
+class DocTestFailureException(AssertionError):
+    """Use custom exception for doctest unit test failures
+    """
+
 class DocTestCase(unittest.TestCase):
 
     def __init__(self, test, optionflags=0, setUp=None, tearDown=None,
@@ -2162,6 +2166,8 @@
 
         test.globs.clear()
 
+    failureException = DocTestFailureException
+
     def runTest(self):
         test = self._dt_test
         old = sys.stdout

Added: zope.testing/trunk/src/zope/testing/renormalizing.py
===================================================================
--- zope.testing/trunk/src/zope/testing/renormalizing.py	2005-05-24 20:28:14 UTC (rev 30491)
+++ zope.testing/trunk/src/zope/testing/renormalizing.py	2005-05-24 20:28:53 UTC (rev 30492)
@@ -0,0 +1,221 @@
+##############################################################################
+#
+# Copyright (c) 2004 Zope Corporation and Contributors.
+# All Rights Reserved.
+#
+# This software is subject to the provisions of the Zope Public License,
+# Version 2.0 (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.
+#
+##############################################################################
+r"""Regular expression pattern normalizing output checker
+
+The pattern-normalizing output checker extends the default output
+checker with an option to normalize expected an actual output.
+
+You specify a sequence of patterns and replacements.  The replacements
+are applied to the expected and actual outputs before calling the
+default outputs checker.  Let's look at an example.  In this example,
+we have some times and addresses:
+
+    >>> want = '''\
+    ... <object object at 0xb7f14438>
+    ... completed in 1.234 seconds.
+    ... <BLANKLINE>
+    ... <object object at 0xb7f14440>
+    ... completed in 123.234 seconds.
+    ... <BLANKLINE>
+    ... <object object at 0xb7f14448>
+    ... completed in .234 seconds.
+    ... <BLANKLINE>
+    ... <object object at 0xb7f14450>
+    ... completed in 1.234 seconds.
+    ... <BLANKLINE>
+    ... '''
+
+    >>> got = '''\
+    ... <object object at 0xb7f14458>
+    ... completed in 1.235 seconds.
+    ... 
+    ... <object object at 0xb7f14460>
+    ... completed in 123.233 seconds.
+    ... 
+    ... <object object at 0xb7f14468>
+    ... completed in .231 seconds.
+    ... 
+    ... <object object at 0xb7f14470>
+    ... completed in 1.23 seconds.
+    ... 
+    ... '''
+
+We may wish to consider these two strings to match, even though they
+differ in actual addresses and times.  The default output checker will
+consider them different:
+
+    >>> doctest.OutputChecker().check_output(want, got, 0)
+    False
+
+We'll use the RENormalizing to normalize both the
+wanted and gotten strings to ignore differences in times and addresses:
+
+    >>> import re
+    >>> checker = RENormalizing([
+    ...    (re.compile('[0-9]*[.][0-9]* seconds'), '<SOME NUMBER OF> seconds'),
+    ...    (re.compile('at 0x[0-9a-f]+'), 'at <SOME ADDRESS>'),
+    ...    ])
+
+    >>> checker.check_output(want, got, 0)
+    True
+
+Usual OutputChecker options work as exected:
+
+    >>> want_ellided = '''\
+    ... <object object at 0xb7f14438>
+    ... completed in 1.234 seconds.
+    ... ...
+    ... <object object at 0xb7f14450>
+    ... completed in 1.234 seconds.
+    ... <BLANKLINE>
+    ... '''
+    
+    >>> checker.check_output(want_ellided, got, 0)
+    False
+    
+    >>> checker.check_output(want, got, doctest.ELLIPSIS)
+    True
+
+When we get differencs, we output them with normalized text:
+
+    >>> source = '''\
+    ... >>> do_something()
+    ... <object object at 0xb7f14438>
+    ... completed in 1.234 seconds.
+    ... ...
+    ... <object object at 0xb7f14450>
+    ... completed in 1.234 seconds.
+    ... <BLANKLINE>
+    ... '''
+
+    >>> example = doctest.Example(source, want_ellided)
+
+    >>> print checker.output_difference(example, got, 0)
+    Expected:
+        <object object at <SOME ADDRESS>>
+        completed in <SOME NUMBER OF> seconds.
+        ...
+        <object object at <SOME ADDRESS>>
+        completed in <SOME NUMBER OF> seconds.
+        <BLANKLINE>
+    Got:
+        <object object at <SOME ADDRESS>>
+        completed in <SOME NUMBER OF> seconds.
+        <BLANKLINE>
+        <object object at <SOME ADDRESS>>
+        completed in <SOME NUMBER OF> seconds.
+        <BLANKLINE>
+        <object object at <SOME ADDRESS>>
+        completed in <SOME NUMBER OF> seconds.
+        <BLANKLINE>
+        <object object at <SOME ADDRESS>>
+        completed in <SOME NUMBER OF> seconds.
+        <BLANKLINE>
+    <BLANKLINE>
+
+    >>> print checker.output_difference(example, got,
+    ...                                 doctest.REPORT_NDIFF)
+    Differences (ndiff with -expected +actual):
+        - <object object at <SOME ADDRESS>>
+        - completed in <SOME NUMBER OF> seconds.
+        - ...
+          <object object at <SOME ADDRESS>>
+          completed in <SOME NUMBER OF> seconds.
+          <BLANKLINE>
+        + <object object at <SOME ADDRESS>>
+        + completed in <SOME NUMBER OF> seconds.
+        + <BLANKLINE>
+        + <object object at <SOME ADDRESS>>
+        + completed in <SOME NUMBER OF> seconds.
+        + <BLANKLINE>
+        + <object object at <SOME ADDRESS>>
+        + completed in <SOME NUMBER OF> seconds.
+        + <BLANKLINE>
+    <BLANKLINE>
+
+    If the wanted text is empty, however, we don't transform the
+    actual output. This is usful when writing tests.  We leave the
+    expected output empty, run the test, and use the actual output ad
+    expected, after reviewing it.
+
+    >>> source = '''\
+    ... '''
+
+    >>> example = doctest.Example(source, '\n')
+    >>> print checker.output_difference(example, got, 0)
+    Expected:
+    <BLANKLINE>
+    Got:
+        <object object at 0xb7f14458>
+        completed in 1.235 seconds.
+        <BLANKLINE>
+        <object object at 0xb7f14460>
+        completed in 123.233 seconds.
+        <BLANKLINE>
+        <object object at 0xb7f14468>
+        completed in .231 seconds.
+        <BLANKLINE>
+        <object object at 0xb7f14470>
+        completed in 1.23 seconds.
+        <BLANKLINE>
+    <BLANKLINE>    
+
+$Id$
+"""
+
+import doctest
+
+class RENormalizing(doctest.OutputChecker):
+    """Pattern-normalizing outout checker
+    """
+
+    def __init__(self, patterns):
+        self.patterns = patterns
+
+    def check_output(self, want, got, optionflags):
+        if got == want:
+            return True
+
+        for pattern, repl in self.patterns:
+            want = pattern.sub(repl, want)
+            got = pattern.sub(repl, got)
+
+        return doctest.OutputChecker.check_output(self, want, got, optionflags)
+
+    def output_difference(self, example, got, optionflags):
+
+        want = example.want
+
+        # If want is empty, use original outputter. This is useful
+        # when setting up tests for the first time.  In that case, we
+        # generally use the differencer to display output, which we evaluate
+        # by hand.
+        if not want.strip():
+            return doctest.OutputChecker.output_difference(
+                self, example, got, optionflags)
+        
+        # Dang, this isn't as easy to override as we might wish        
+        original = want
+        
+        for pattern, repl in self.patterns:
+            want = pattern.sub(repl, want)
+            got = pattern.sub(repl, got)
+
+        # temporarily hack example with normalized want:
+        example.want = want
+        result = doctest.OutputChecker.output_difference(
+            self, example, got, optionflags)
+        example.want = original
+
+        return result

Added: zope.testing/trunk/src/zope/testing/testrunner-ex/README.txt
===================================================================
--- zope.testing/trunk/src/zope/testing/testrunner-ex/README.txt	2005-05-24 20:28:14 UTC (rev 30491)
+++ zope.testing/trunk/src/zope/testing/testrunner-ex/README.txt	2005-05-24 20:28:53 UTC (rev 30492)
@@ -0,0 +1,2 @@
+This directory and it's subdirectories contains example tests for
+testing the test runner, testrunner.py.

Added: zope.testing/trunk/src/zope/testing/testrunner-ex/sample1/__init__.py
===================================================================
--- zope.testing/trunk/src/zope/testing/testrunner-ex/sample1/__init__.py	2005-05-24 20:28:14 UTC (rev 30491)
+++ zope.testing/trunk/src/zope/testing/testrunner-ex/sample1/__init__.py	2005-05-24 20:28:53 UTC (rev 30492)
@@ -0,0 +1 @@
+#

Added: zope.testing/trunk/src/zope/testing/testrunner-ex/sample1/sample11/__init__.py
===================================================================
--- zope.testing/trunk/src/zope/testing/testrunner-ex/sample1/sample11/__init__.py	2005-05-24 20:28:14 UTC (rev 30491)
+++ zope.testing/trunk/src/zope/testing/testrunner-ex/sample1/sample11/__init__.py	2005-05-24 20:28:53 UTC (rev 30492)
@@ -0,0 +1 @@
+#

Added: zope.testing/trunk/src/zope/testing/testrunner-ex/sample1/sample11/sampletests.py
===================================================================
--- zope.testing/trunk/src/zope/testing/testrunner-ex/sample1/sample11/sampletests.py	2005-05-24 20:28:14 UTC (rev 30491)
+++ zope.testing/trunk/src/zope/testing/testrunner-ex/sample1/sample11/sampletests.py	2005-05-24 20:28:53 UTC (rev 30492)
@@ -0,0 +1,123 @@
+##############################################################################
+#
+# Copyright (c) 2003 Zope Corporation and Contributors.
+# All Rights Reserved.
+#
+# This software is subject to the provisions of the Zope Public License,
+# Version 2.0 (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.
+#
+##############################################################################
+
+import unittest
+from zope.testing import doctest
+
+x=0
+y=0
+z=0
+
+class TestA(unittest.TestCase):
+    def setUp(self):
+        global x
+        x = 1
+    def tearDown(self):
+        global x
+        x = 0
+    def test_x1(self):
+        self.assertEqual(x, 1)
+    def test_y0(self):
+        self.assertEqual(y, 0)
+    def test_z0(self):
+        self.assertEqual(z, 0)
+
+class TestA3(unittest.TestCase):
+
+    level = 3
+    
+    def setUp(self):
+        global x
+        x = 1
+    def tearDown(self):
+        global x
+        x = 0
+    def test_x1(self):
+        self.assertEqual(x, 1)
+    def test_y0(self):
+        self.assertEqual(y, 0)
+    def test_z0(self):
+        self.assertEqual(z, 0)
+
+class TestB(unittest.TestCase):
+    def setUp(self):
+        global y
+        y = 1
+    def tearDown(self):
+        global y
+        y = 0
+    def test_y1(self):
+        self.assertEqual(y, 1)
+    def test_x0(self):
+        self.assertEqual(x, 0)
+    def test_z0(self):
+        self.assertEqual(z, 0)
+
+class TestB2(unittest.TestCase):
+    level = 2
+    
+    def setUp(self):
+        global y
+        y = 1
+    def tearDown(self):
+        global y
+        y = 0
+    def test_y1(self):
+        self.assertEqual(y, 1)
+    def test_x0(self):
+        self.assertEqual(x, 0)
+    def test_z0(self):
+        self.assertEqual(z, 0)
+
+
+class TestNotMuch(unittest.TestCase):
+    def test_1(self):
+        pass
+    def test_2(self):
+        pass
+    def test_3(self):
+        pass
+
+def setUp(test):
+    test.globs['z'] = 1
+
+def test_y0(self):
+    """
+    >>> y
+    0
+    """
+
+def test_x0(self):
+    """
+    >>> x
+    0
+    """
+
+def test_z1(self):
+    """
+    >>> z
+    1
+    """
+
+def test_suite():
+    suite = unittest.TestSuite()
+    suite.addTest(unittest.makeSuite(TestA))
+    suite.addTest(unittest.makeSuite(TestA3))
+    suite.addTest(unittest.makeSuite(TestB))
+    suite.addTest(unittest.makeSuite(TestB2))
+    suite.addTest(unittest.makeSuite(TestNotMuch))
+    suite.addTest(doctest.DocTestSuite(setUp=setUp))
+    suite.addTest(doctest.DocFileSuite('../../sampletests.txt',
+                                       setUp=setUp))
+    return suite

Added: zope.testing/trunk/src/zope/testing/testrunner-ex/sample1/sample12/__init__.py
===================================================================
--- zope.testing/trunk/src/zope/testing/testrunner-ex/sample1/sample12/__init__.py	2005-05-24 20:28:14 UTC (rev 30491)
+++ zope.testing/trunk/src/zope/testing/testrunner-ex/sample1/sample12/__init__.py	2005-05-24 20:28:53 UTC (rev 30492)
@@ -0,0 +1 @@
+#

Added: zope.testing/trunk/src/zope/testing/testrunner-ex/sample1/sample13/__init__.py
===================================================================
--- zope.testing/trunk/src/zope/testing/testrunner-ex/sample1/sample13/__init__.py	2005-05-24 20:28:14 UTC (rev 30491)
+++ zope.testing/trunk/src/zope/testing/testrunner-ex/sample1/sample13/__init__.py	2005-05-24 20:28:53 UTC (rev 30492)
@@ -0,0 +1 @@
+#

Added: zope.testing/trunk/src/zope/testing/testrunner-ex/sample1/sample13/sampletests.py
===================================================================
--- zope.testing/trunk/src/zope/testing/testrunner-ex/sample1/sample13/sampletests.py	2005-05-24 20:28:14 UTC (rev 30491)
+++ zope.testing/trunk/src/zope/testing/testrunner-ex/sample1/sample13/sampletests.py	2005-05-24 20:28:53 UTC (rev 30492)
@@ -0,0 +1,88 @@
+##############################################################################
+#
+# Copyright (c) 2003 Zope Corporation and Contributors.
+# All Rights Reserved.
+#
+# This software is subject to the provisions of the Zope Public License,
+# Version 2.0 (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.
+#
+##############################################################################
+
+import unittest
+from zope.testing import doctest
+
+x=0
+y=0
+z=0
+
+class TestA(unittest.TestCase):
+    def setUp(self):
+        global x
+        x = 1
+    def tearDown(self):
+        global x
+        x = 0
+    def test_x1(self):
+        self.assertEqual(x, 1)
+    def test_y0(self):
+        self.assertEqual(y, 0)
+    def test_z0(self):
+        self.assertEqual(z, 0)
+
+class TestB(unittest.TestCase):
+    def setUp(self):
+        global y
+        y = 1
+    def tearDown(self):
+        global y
+        y = 0
+    def test_y1(self):
+        self.assertEqual(y, 1)
+    def test_x0(self):
+        self.assertEqual(x, 0)
+    def test_z0(self):
+        self.assertEqual(z, 0)
+
+
+class TestNotMuch(unittest.TestCase):
+    def test_1(self):
+        pass
+    def test_2(self):
+        pass
+    def test_3(self):
+        pass
+
+def setUp(test):
+    test.globs['z'] = 1
+
+def test_y0(self):
+    """
+    >>> y
+    0
+    """
+
+def test_x0(self):
+    """
+    >>> x
+    0
+    """
+
+def test_z1(self):
+    """
+    >>> z
+    1
+    """
+
+def test_suite():
+    suite = unittest.TestSuite()
+    suite.addTest(unittest.makeSuite(TestA))
+    suite.addTest(unittest.makeSuite(TestB))
+    suite.addTest(unittest.makeSuite(TestNotMuch))
+    suite.addTest(doctest.DocTestSuite(setUp=setUp))
+    suite.addTest(doctest.DocFileSuite('../../sampletests.txt',
+                                       setUp=setUp))
+    return suite

Added: zope.testing/trunk/src/zope/testing/testrunner-ex/sample1/sampletests/__init__.py
===================================================================
--- zope.testing/trunk/src/zope/testing/testrunner-ex/sample1/sampletests/__init__.py	2005-05-24 20:28:14 UTC (rev 30491)
+++ zope.testing/trunk/src/zope/testing/testrunner-ex/sample1/sampletests/__init__.py	2005-05-24 20:28:53 UTC (rev 30492)
@@ -0,0 +1 @@
+#

Added: zope.testing/trunk/src/zope/testing/testrunner-ex/sample1/sampletests/test1.py
===================================================================
--- zope.testing/trunk/src/zope/testing/testrunner-ex/sample1/sampletests/test1.py	2005-05-24 20:28:14 UTC (rev 30491)
+++ zope.testing/trunk/src/zope/testing/testrunner-ex/sample1/sampletests/test1.py	2005-05-24 20:28:53 UTC (rev 30492)
@@ -0,0 +1,88 @@
+##############################################################################
+#
+# Copyright (c) 2003 Zope Corporation and Contributors.
+# All Rights Reserved.
+#
+# This software is subject to the provisions of the Zope Public License,
+# Version 2.0 (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.
+#
+##############################################################################
+
+import unittest
+from zope.testing import doctest
+
+x=0
+y=0
+z=0
+
+class TestA(unittest.TestCase):
+    def setUp(self):
+        global x
+        x = 1
+    def tearDown(self):
+        global x
+        x = 0
+    def test_x1(self):
+        self.assertEqual(x, 1)
+    def test_y0(self):
+        self.assertEqual(y, 0)
+    def test_z0(self):
+        self.assertEqual(z, 0)
+
+class TestB(unittest.TestCase):
+    def setUp(self):
+        global y
+        y = 1
+    def tearDown(self):
+        global y
+        y = 0
+    def test_y1(self):
+        self.assertEqual(y, 1)
+    def test_x0(self):
+        self.assertEqual(x, 0)
+    def test_z0(self):
+        self.assertEqual(z, 0)
+
+
+class TestNotMuch(unittest.TestCase):
+    def test_1(self):
+        pass
+    def test_2(self):
+        pass
+    def test_3(self):
+        pass
+
+def setUp(test):
+    test.globs['z'] = 1
+
+def test_y0(self):
+    """
+    >>> y
+    0
+    """
+
+def test_x0(self):
+    """
+    >>> x
+    0
+    """
+
+def test_z1(self):
+    """
+    >>> z
+    1
+    """
+
+def test_suite():
+    suite = unittest.TestSuite()
+    suite.addTest(unittest.makeSuite(TestA))
+    suite.addTest(unittest.makeSuite(TestB))
+    suite.addTest(unittest.makeSuite(TestNotMuch))
+    suite.addTest(doctest.DocTestSuite(setUp=setUp))
+    suite.addTest(doctest.DocFileSuite('../../sampletests.txt',
+                                       setUp=setUp))
+    return suite

Added: zope.testing/trunk/src/zope/testing/testrunner-ex/sample1/sampletests/test11.py
===================================================================
--- zope.testing/trunk/src/zope/testing/testrunner-ex/sample1/sampletests/test11.py	2005-05-24 20:28:14 UTC (rev 30491)
+++ zope.testing/trunk/src/zope/testing/testrunner-ex/sample1/sampletests/test11.py	2005-05-24 20:28:53 UTC (rev 30492)
@@ -0,0 +1,127 @@
+##############################################################################
+#
+# Copyright (c) 2003 Zope Corporation and Contributors.
+# All Rights Reserved.
+#
+# This software is subject to the provisions of the Zope Public License,
+# Version 2.0 (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.
+#
+##############################################################################
+
+import unittest
+from zope.testing import doctest
+import samplelayers
+
+layername = 'samplelayers.Layer11'
+layer = samplelayers.Layer11
+
+x=0
+y=0
+z=0
+
+class TestA(unittest.TestCase):
+    layer = layername
+        
+    def setUp(self):
+        global x
+        x = 1
+    def tearDown(self):
+        global x
+        x = 0
+    def test_x1(self):
+        self.assertEqual(x, 1)
+        self.assertEqual(samplelayers.layer, layer.layer)
+        self.assertEqual(samplelayers.layerx, layer.layerx)
+    def test_y0(self):
+        self.assertEqual(y, 0)
+        self.assertEqual(samplelayers.layer, layer.layer)
+        self.assertEqual(samplelayers.layerx, layer.layerx)
+    def test_z0(self):
+        self.assertEqual(z, 0)
+        self.assertEqual(samplelayers.layer, layer.layer)
+        self.assertEqual(samplelayers.layerx, layer.layerx)
+
+class TestB(unittest.TestCase):
+    layer = layername
+
+    def setUp(self):
+        global y
+        y = 1
+    def tearDown(self):
+        global y
+        y = 0
+    def test_y1(self):
+        self.assertEqual(y, 1)
+        self.assertEqual(samplelayers.layer, layer.layer)
+        self.assertEqual(samplelayers.layerx, layer.layerx)
+    def test_x0(self):
+        self.assertEqual(x, 0)
+        self.assertEqual(samplelayers.layer, layer.layer)
+        self.assertEqual(samplelayers.layerx, layer.layerx)
+    def test_z0(self):
+        self.assertEqual(z, 0)
+        self.assertEqual(samplelayers.layer, layer.layer)
+        self.assertEqual(samplelayers.layerx, layer.layerx)
+
+
+class TestNotMuch(unittest.TestCase):
+    layer = layername
+
+    def test_1(self):
+        self.assertEqual(samplelayers.layer, layer.layer)
+        self.assertEqual(samplelayers.layerx, layer.layerx)
+    def test_2(self):
+        self.assertEqual(samplelayers.layer, layer.layer)
+        self.assertEqual(samplelayers.layerx, layer.layerx)
+    def test_3(self):
+        self.assertEqual(samplelayers.layer, layer.layer)
+        self.assertEqual(samplelayers.layerx, layer.layerx)
+
+def setUp(test):
+    test.globs['z'] = 1
+    test.globs['layer'] = layer.layer
+    test.globs['layerx'] = layer.layerx
+
+def test_y0(self):
+    """
+    >>> y
+    0
+
+    >>> (layer == samplelayers.layer), (layerx == samplelayers.layerx)
+    (True, True)
+    """
+
+def test_x0(self):
+    """
+    >>> x
+    0
+
+    >>> (layer == samplelayers.layer), (layerx == samplelayers.layerx)
+    (True, True)
+    """
+
+def test_z1(self):
+    """
+    >>> z
+    1
+
+    >>> (layer == samplelayers.layer), (layerx == samplelayers.layerx)
+    (True, True)
+    """
+
+def test_suite():
+    suite = unittest.TestSuite()
+    suite.addTest(unittest.makeSuite(TestA))
+    suite.addTest(unittest.makeSuite(TestB))
+    suite.addTest(unittest.makeSuite(TestNotMuch))
+    s = doctest.DocTestSuite(setUp=setUp)
+    s.layer = layer
+    suite.addTest(s)
+    s = doctest.DocFileSuite('../../sampletestsl.txt', setUp=setUp)
+    s.layer = layer
+    suite.addTest(s)
+    return suite

Added: zope.testing/trunk/src/zope/testing/testrunner-ex/sample1/sampletests/test111.py
===================================================================
--- zope.testing/trunk/src/zope/testing/testrunner-ex/sample1/sampletests/test111.py	2005-05-24 20:28:14 UTC (rev 30491)
+++ zope.testing/trunk/src/zope/testing/testrunner-ex/sample1/sampletests/test111.py	2005-05-24 20:28:53 UTC (rev 30492)
@@ -0,0 +1,127 @@
+##############################################################################
+#
+# Copyright (c) 2003 Zope Corporation and Contributors.
+# All Rights Reserved.
+#
+# This software is subject to the provisions of the Zope Public License,
+# Version 2.0 (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.
+#
+##############################################################################
+
+import unittest
+from zope.testing import doctest
+import samplelayers
+
+layername = 'samplelayers.Layer111'
+layer = samplelayers.Layer111
+
+x=0
+y=0
+z=0
+
+class TestA(unittest.TestCase):
+    layer = layername
+        
+    def setUp(self):
+        global x
+        x = 1
+    def tearDown(self):
+        global x
+        x = 0
+    def test_x1(self):
+        self.assertEqual(x, 1)
+        self.assertEqual(samplelayers.layer, layer.layer)
+        self.assertEqual(samplelayers.layerx, layer.layerx)
+    def test_y0(self):
+        self.assertEqual(y, 0)
+        self.assertEqual(samplelayers.layer, layer.layer)
+        self.assertEqual(samplelayers.layerx, layer.layerx)
+    def test_z0(self):
+        self.assertEqual(z, 0)
+        self.assertEqual(samplelayers.layer, layer.layer)
+        self.assertEqual(samplelayers.layerx, layer.layerx)
+
+class TestB(unittest.TestCase):
+    layer = layername
+
+    def setUp(self):
+        global y
+        y = 1
+    def tearDown(self):
+        global y
+        y = 0
+    def test_y1(self):
+        self.assertEqual(y, 1)
+        self.assertEqual(samplelayers.layer, layer.layer)
+        self.assertEqual(samplelayers.layerx, layer.layerx)
+    def test_x0(self):
+        self.assertEqual(x, 0)
+        self.assertEqual(samplelayers.layer, layer.layer)
+        self.assertEqual(samplelayers.layerx, layer.layerx)
+    def test_z0(self):
+        self.assertEqual(z, 0)
+        self.assertEqual(samplelayers.layer, layer.layer)
+        self.assertEqual(samplelayers.layerx, layer.layerx)
+
+
+class TestNotMuch(unittest.TestCase):
+    layer = layername
+
+    def test_1(self):
+        self.assertEqual(samplelayers.layer, layer.layer)
+        self.assertEqual(samplelayers.layerx, layer.layerx)
+    def test_2(self):
+        self.assertEqual(samplelayers.layer, layer.layer)
+        self.assertEqual(samplelayers.layerx, layer.layerx)
+    def test_3(self):
+        self.assertEqual(samplelayers.layer, layer.layer)
+        self.assertEqual(samplelayers.layerx, layer.layerx)
+
+def setUp(test):
+    test.globs['z'] = 1
+    test.globs['layer'] = layer.layer
+    test.globs['layerx'] = layer.layerx
+
+def test_y0(self):
+    """
+    >>> y
+    0
+
+    >>> (layer == samplelayers.layer), (layerx == samplelayers.layerx)
+    (True, True)
+    """
+
+def test_x0(self):
+    """
+    >>> x
+    0
+
+    >>> (layer == samplelayers.layer), (layerx == samplelayers.layerx)
+    (True, True)
+    """
+
+def test_z1(self):
+    """
+    >>> z
+    1
+
+    >>> (layer == samplelayers.layer), (layerx == samplelayers.layerx)
+    (True, True)
+    """
+
+def test_suite():
+    suite = unittest.TestSuite()
+    suite.addTest(unittest.makeSuite(TestA))
+    suite.addTest(unittest.makeSuite(TestB))
+    suite.addTest(unittest.makeSuite(TestNotMuch))
+    s = doctest.DocTestSuite(setUp=setUp)
+    s.layer = layer
+    suite.addTest(s)
+    s = doctest.DocFileSuite('../../sampletestsl.txt', setUp=setUp)
+    s.layer = layer
+    suite.addTest(s)
+    return suite

Added: zope.testing/trunk/src/zope/testing/testrunner-ex/sample1/sampletests/test112.py
===================================================================
--- zope.testing/trunk/src/zope/testing/testrunner-ex/sample1/sampletests/test112.py	2005-05-24 20:28:14 UTC (rev 30491)
+++ zope.testing/trunk/src/zope/testing/testrunner-ex/sample1/sampletests/test112.py	2005-05-24 20:28:53 UTC (rev 30492)
@@ -0,0 +1,128 @@
+##############################################################################
+#
+# Copyright (c) 2003 Zope Corporation and Contributors.
+# All Rights Reserved.
+#
+# This software is subject to the provisions of the Zope Public License,
+# Version 2.0 (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.
+#
+##############################################################################
+
+import unittest
+from zope.testing import doctest
+import samplelayers
+
+layername = 'samplelayers.Layer112'
+layer = samplelayers.Layer112
+
+
+x=0
+y=0
+z=0
+
+class TestA(unittest.TestCase):
+    layer = layername
+        
+    def setUp(self):
+        global x
+        x = 1
+    def tearDown(self):
+        global x
+        x = 0
+    def test_x1(self):
+        self.assertEqual(x, 1)
+        self.assertEqual(samplelayers.layer, layer.layer)
+        self.assertEqual(samplelayers.layerx, layer.layerx)
+    def test_y0(self):
+        self.assertEqual(y, 0)
+        self.assertEqual(samplelayers.layer, layer.layer)
+        self.assertEqual(samplelayers.layerx, layer.layerx)
+    def test_z0(self):
+        self.assertEqual(z, 0)
+        self.assertEqual(samplelayers.layer, layer.layer)
+        self.assertEqual(samplelayers.layerx, layer.layerx)
+
+class TestB(unittest.TestCase):
+    layer = layername
+
+    def setUp(self):
+        global y
+        y = 1
+    def tearDown(self):
+        global y
+        y = 0
+    def test_y1(self):
+        self.assertEqual(y, 1)
+        self.assertEqual(samplelayers.layer, layer.layer)
+        self.assertEqual(samplelayers.layerx, layer.layerx)
+    def test_x0(self):
+        self.assertEqual(x, 0)
+        self.assertEqual(samplelayers.layer, layer.layer)
+        self.assertEqual(samplelayers.layerx, layer.layerx)
+    def test_z0(self):
+        self.assertEqual(z, 0)
+        self.assertEqual(samplelayers.layer, layer.layer)
+        self.assertEqual(samplelayers.layerx, layer.layerx)
+
+
+class TestNotMuch(unittest.TestCase):
+    layer = layername
+
+    def test_1(self):
+        self.assertEqual(samplelayers.layer, layer.layer)
+        self.assertEqual(samplelayers.layerx, layer.layerx)
+    def test_2(self):
+        self.assertEqual(samplelayers.layer, layer.layer)
+        self.assertEqual(samplelayers.layerx, layer.layerx)
+    def test_3(self):
+        self.assertEqual(samplelayers.layer, layer.layer)
+        self.assertEqual(samplelayers.layerx, layer.layerx)
+
+def setUp(test):
+    test.globs['z'] = 1
+    test.globs['layer'] = layer.layer
+    test.globs['layerx'] = layer.layerx
+
+def test_y0(self):
+    """
+    >>> y
+    0
+
+    >>> (layer == samplelayers.layer), (layerx == samplelayers.layerx)
+    (True, True)
+    """
+
+def test_x0(self):
+    """
+    >>> x
+    0
+
+    >>> (layer == samplelayers.layer), (layerx == samplelayers.layerx)
+    (True, True)
+    """
+
+def test_z1(self):
+    """
+    >>> z
+    1
+
+    >>> (layer == samplelayers.layer), (layerx == samplelayers.layerx)
+    (True, True)
+    """
+
+def test_suite():
+    suite = unittest.TestSuite()
+    suite.addTest(unittest.makeSuite(TestA))
+    suite.addTest(unittest.makeSuite(TestB))
+    suite.addTest(unittest.makeSuite(TestNotMuch))
+    s = doctest.DocTestSuite(setUp=setUp)
+    s.layer = layer
+    suite.addTest(s)
+    s = doctest.DocFileSuite('../../sampletestsl.txt', setUp=setUp)
+    s.layer = layer
+    suite.addTest(s)
+    return suite

Added: zope.testing/trunk/src/zope/testing/testrunner-ex/sample1/sampletests/test12.py
===================================================================
--- zope.testing/trunk/src/zope/testing/testrunner-ex/sample1/sampletests/test12.py	2005-05-24 20:28:14 UTC (rev 30491)
+++ zope.testing/trunk/src/zope/testing/testrunner-ex/sample1/sampletests/test12.py	2005-05-24 20:28:53 UTC (rev 30492)
@@ -0,0 +1,127 @@
+##############################################################################
+#
+# Copyright (c) 2003 Zope Corporation and Contributors.
+# All Rights Reserved.
+#
+# This software is subject to the provisions of the Zope Public License,
+# Version 2.0 (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.
+#
+##############################################################################
+
+import unittest
+from zope.testing import doctest
+import samplelayers
+
+layername = 'samplelayers.Layer12'
+layer = samplelayers.Layer12
+
+x=0
+y=0
+z=0
+
+class TestA(unittest.TestCase):
+    layer = layername
+        
+    def setUp(self):
+        global x
+        x = 1
+    def tearDown(self):
+        global x
+        x = 0
+    def test_x1(self):
+        self.assertEqual(x, 1)
+        self.assertEqual(samplelayers.layer, layer.layer)
+        self.assertEqual(samplelayers.layerx, layer.layerx)
+    def test_y0(self):
+        self.assertEqual(y, 0)
+        self.assertEqual(samplelayers.layer, layer.layer)
+        self.assertEqual(samplelayers.layerx, layer.layerx)
+    def test_z0(self):
+        self.assertEqual(z, 0)
+        self.assertEqual(samplelayers.layer, layer.layer)
+        self.assertEqual(samplelayers.layerx, layer.layerx)
+
+class TestB(unittest.TestCase):
+    layer = layername
+
+    def setUp(self):
+        global y
+        y = 1
+    def tearDown(self):
+        global y
+        y = 0
+    def test_y1(self):
+        self.assertEqual(y, 1)
+        self.assertEqual(samplelayers.layer, layer.layer)
+        self.assertEqual(samplelayers.layerx, layer.layerx)
+    def test_x0(self):
+        self.assertEqual(x, 0)
+        self.assertEqual(samplelayers.layer, layer.layer)
+        self.assertEqual(samplelayers.layerx, layer.layerx)
+    def test_z0(self):
+        self.assertEqual(z, 0)
+        self.assertEqual(samplelayers.layer, layer.layer)
+        self.assertEqual(samplelayers.layerx, layer.layerx)
+
+
+class TestNotMuch(unittest.TestCase):
+    layer = layername
+
+    def test_1(self):
+        self.assertEqual(samplelayers.layer, layer.layer)
+        self.assertEqual(samplelayers.layerx, layer.layerx)
+    def test_2(self):
+        self.assertEqual(samplelayers.layer, layer.layer)
+        self.assertEqual(samplelayers.layerx, layer.layerx)
+    def test_3(self):
+        self.assertEqual(samplelayers.layer, layer.layer)
+        self.assertEqual(samplelayers.layerx, layer.layerx)
+
+def setUp(test):
+    test.globs['z'] = 1
+    test.globs['layer'] = layer.layer
+    test.globs['layerx'] = layer.layerx
+
+def test_y0(self):
+    """
+    >>> y
+    0
+
+    >>> (layer == samplelayers.layer), (layerx == samplelayers.layerx)
+    (True, True)
+    """
+
+def test_x0(self):
+    """
+    >>> x
+    0
+
+    >>> (layer == samplelayers.layer), (layerx == samplelayers.layerx)
+    (True, True)
+    """
+
+def test_z1(self):
+    """
+    >>> z
+    1
+
+    >>> (layer == samplelayers.layer), (layerx == samplelayers.layerx)
+    (True, True)
+    """
+
+def test_suite():
+    suite = unittest.TestSuite()
+    suite.addTest(unittest.makeSuite(TestA))
+    suite.addTest(unittest.makeSuite(TestB))
+    suite.addTest(unittest.makeSuite(TestNotMuch))
+    s = doctest.DocTestSuite(setUp=setUp)
+    s.layer = layer
+    suite.addTest(s)
+    s = doctest.DocFileSuite('../../sampletestsl.txt', setUp=setUp)
+    s.layer = layer
+    suite.addTest(s)
+    return suite

Added: zope.testing/trunk/src/zope/testing/testrunner-ex/sample1/sampletests/test121.py
===================================================================
--- zope.testing/trunk/src/zope/testing/testrunner-ex/sample1/sampletests/test121.py	2005-05-24 20:28:14 UTC (rev 30491)
+++ zope.testing/trunk/src/zope/testing/testrunner-ex/sample1/sampletests/test121.py	2005-05-24 20:28:53 UTC (rev 30492)
@@ -0,0 +1,127 @@
+##############################################################################
+#
+# Copyright (c) 2003 Zope Corporation and Contributors.
+# All Rights Reserved.
+#
+# This software is subject to the provisions of the Zope Public License,
+# Version 2.0 (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.
+#
+##############################################################################
+
+import unittest
+from zope.testing import doctest
+import samplelayers
+
+layername = 'samplelayers.Layer121'
+layer = samplelayers.Layer121
+
+x=0
+y=0
+z=0
+
+class TestA(unittest.TestCase):
+    layer = layername
+        
+    def setUp(self):
+        global x
+        x = 1
+    def tearDown(self):
+        global x
+        x = 0
+    def test_x1(self):
+        self.assertEqual(x, 1)
+        self.assertEqual(samplelayers.layer, layer.layer)
+        self.assertEqual(samplelayers.layerx, layer.layerx)
+    def test_y0(self):
+        self.assertEqual(y, 0)
+        self.assertEqual(samplelayers.layer, layer.layer)
+        self.assertEqual(samplelayers.layerx, layer.layerx)
+    def test_z0(self):
+        self.assertEqual(z, 0)
+        self.assertEqual(samplelayers.layer, layer.layer)
+        self.assertEqual(samplelayers.layerx, layer.layerx)
+
+class TestB(unittest.TestCase):
+    layer = layername
+
+    def setUp(self):
+        global y
+        y = 1
+    def tearDown(self):
+        global y
+        y = 0
+    def test_y1(self):
+        self.assertEqual(y, 1)
+        self.assertEqual(samplelayers.layer, layer.layer)
+        self.assertEqual(samplelayers.layerx, layer.layerx)
+    def test_x0(self):
+        self.assertEqual(x, 0)
+        self.assertEqual(samplelayers.layer, layer.layer)
+        self.assertEqual(samplelayers.layerx, layer.layerx)
+    def test_z0(self):
+        self.assertEqual(z, 0)
+        self.assertEqual(samplelayers.layer, layer.layer)
+        self.assertEqual(samplelayers.layerx, layer.layerx)
+
+
+class TestNotMuch(unittest.TestCase):
+    layer = layername
+
+    def test_1(self):
+        self.assertEqual(samplelayers.layer, layer.layer)
+        self.assertEqual(samplelayers.layerx, layer.layerx)
+    def test_2(self):
+        self.assertEqual(samplelayers.layer, layer.layer)
+        self.assertEqual(samplelayers.layerx, layer.layerx)
+    def test_3(self):
+        self.assertEqual(samplelayers.layer, layer.layer)
+        self.assertEqual(samplelayers.layerx, layer.layerx)
+
+def setUp(test):
+    test.globs['z'] = 1
+    test.globs['layer'] = layer.layer
+    test.globs['layerx'] = layer.layerx
+
+def test_y0(self):
+    """
+    >>> y
+    0
+
+    >>> (layer == samplelayers.layer), (layerx == samplelayers.layerx)
+    (True, True)
+    """
+
+def test_x0(self):
+    """
+    >>> x
+    0
+
+    >>> (layer == samplelayers.layer), (layerx == samplelayers.layerx)
+    (True, True)
+    """
+
+def test_z1(self):
+    """
+    >>> z
+    1
+
+    >>> (layer == samplelayers.layer), (layerx == samplelayers.layerx)
+    (True, True)
+    """
+
+def test_suite():
+    suite = unittest.TestSuite()
+    suite.addTest(unittest.makeSuite(TestA))
+    suite.addTest(unittest.makeSuite(TestB))
+    suite.addTest(unittest.makeSuite(TestNotMuch))
+    s = doctest.DocTestSuite(setUp=setUp)
+    s.layer = layer
+    suite.addTest(s)
+    s = doctest.DocFileSuite('../../sampletestsl.txt', setUp=setUp)
+    s.layer = layer
+    suite.addTest(s)
+    return suite

Added: zope.testing/trunk/src/zope/testing/testrunner-ex/sample1/sampletests/test122.py
===================================================================
--- zope.testing/trunk/src/zope/testing/testrunner-ex/sample1/sampletests/test122.py	2005-05-24 20:28:14 UTC (rev 30491)
+++ zope.testing/trunk/src/zope/testing/testrunner-ex/sample1/sampletests/test122.py	2005-05-24 20:28:53 UTC (rev 30492)
@@ -0,0 +1,127 @@
+##############################################################################
+#
+# Copyright (c) 2003 Zope Corporation and Contributors.
+# All Rights Reserved.
+#
+# This software is subject to the provisions of the Zope Public License,
+# Version 2.0 (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.
+#
+##############################################################################
+
+import unittest
+from zope.testing import doctest
+import samplelayers
+
+layername = 'samplelayers.Layer122'
+layer = samplelayers.Layer122
+
+x=0
+y=0
+z=0
+
+class TestA(unittest.TestCase):
+    layer = layername
+        
+    def setUp(self):
+        global x
+        x = 1
+    def tearDown(self):
+        global x
+        x = 0
+    def test_x1(self):
+        self.assertEqual(x, 1)
+        self.assertEqual(samplelayers.layer, layer.layer)
+        self.assertEqual(samplelayers.layerx, layer.layerx)
+    def test_y0(self):
+        self.assertEqual(y, 0)
+        self.assertEqual(samplelayers.layer, layer.layer)
+        self.assertEqual(samplelayers.layerx, layer.layerx)
+    def test_z0(self):
+        self.assertEqual(z, 0)
+        self.assertEqual(samplelayers.layer, layer.layer)
+        self.assertEqual(samplelayers.layerx, layer.layerx)
+
+class TestB(unittest.TestCase):
+    layer = layername
+
+    def setUp(self):
+        global y
+        y = 1
+    def tearDown(self):
+        global y
+        y = 0
+    def test_y1(self):
+        self.assertEqual(y, 1)
+        self.assertEqual(samplelayers.layer, layer.layer)
+        self.assertEqual(samplelayers.layerx, layer.layerx)
+    def test_x0(self):
+        self.assertEqual(x, 0)
+        self.assertEqual(samplelayers.layer, layer.layer)
+        self.assertEqual(samplelayers.layerx, layer.layerx)
+    def test_z0(self):
+        self.assertEqual(z, 0)
+        self.assertEqual(samplelayers.layer, layer.layer)
+        self.assertEqual(samplelayers.layerx, layer.layerx)
+
+
+class TestNotMuch(unittest.TestCase):
+    layer = layername
+
+    def test_1(self):
+        self.assertEqual(samplelayers.layer, layer.layer)
+        self.assertEqual(samplelayers.layerx, layer.layerx)
+    def test_2(self):
+        self.assertEqual(samplelayers.layer, layer.layer)
+        self.assertEqual(samplelayers.layerx, layer.layerx)
+    def test_3(self):
+        self.assertEqual(samplelayers.layer, layer.layer)
+        self.assertEqual(samplelayers.layerx, layer.layerx)
+
+def setUp(test):
+    test.globs['z'] = 1
+    test.globs['layer'] = layer.layer
+    test.globs['layerx'] = layer.layerx
+
+def test_y0(self):
+    """
+    >>> y
+    0
+
+    >>> (layer == samplelayers.layer), (layerx == samplelayers.layerx)
+    (True, True)
+    """
+
+def test_x0(self):
+    """
+    >>> x
+    0
+
+    >>> (layer == samplelayers.layer), (layerx == samplelayers.layerx)
+    (True, True)
+    """
+
+def test_z1(self):
+    """
+    >>> z
+    1
+
+    >>> (layer == samplelayers.layer), (layerx == samplelayers.layerx)
+    (True, True)
+    """
+
+def test_suite():
+    suite = unittest.TestSuite()
+    suite.addTest(unittest.makeSuite(TestA))
+    suite.addTest(unittest.makeSuite(TestB))
+    suite.addTest(unittest.makeSuite(TestNotMuch))
+    s = doctest.DocTestSuite(setUp=setUp)
+    s.layer = layer
+    suite.addTest(s)
+    s = doctest.DocFileSuite('../../sampletestsl.txt', setUp=setUp)
+    s.layer = layer
+    suite.addTest(s)
+    return suite

Added: zope.testing/trunk/src/zope/testing/testrunner-ex/sample1/sampletests/test_one.py
===================================================================
--- zope.testing/trunk/src/zope/testing/testrunner-ex/sample1/sampletests/test_one.py	2005-05-24 20:28:14 UTC (rev 30491)
+++ zope.testing/trunk/src/zope/testing/testrunner-ex/sample1/sampletests/test_one.py	2005-05-24 20:28:53 UTC (rev 30492)
@@ -0,0 +1,88 @@
+##############################################################################
+#
+# Copyright (c) 2003 Zope Corporation and Contributors.
+# All Rights Reserved.
+#
+# This software is subject to the provisions of the Zope Public License,
+# Version 2.0 (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.
+#
+##############################################################################
+
+import unittest
+from zope.testing import doctest
+
+x=0
+y=0
+z=0
+
+class TestA(unittest.TestCase):
+    def setUp(self):
+        global x
+        x = 1
+    def tearDown(self):
+        global x
+        x = 0
+    def test_x1(self):
+        self.assertEqual(x, 1)
+    def test_y0(self):
+        self.assertEqual(y, 0)
+    def test_z0(self):
+        self.assertEqual(z, 0)
+
+class TestB(unittest.TestCase):
+    def setUp(self):
+        global y
+        y = 1
+    def tearDown(self):
+        global y
+        y = 0
+    def test_y1(self):
+        self.assertEqual(y, 1)
+    def test_x0(self):
+        self.assertEqual(x, 0)
+    def test_z0(self):
+        self.assertEqual(z, 0)
+
+
+class TestNotMuch(unittest.TestCase):
+    def test_1(self):
+        pass
+    def test_2(self):
+        pass
+    def test_3(self):
+        pass
+
+def setUp(test):
+    test.globs['z'] = 1
+
+def test_y0(self):
+    """
+    >>> y
+    0
+    """
+
+def test_x0(self):
+    """
+    >>> x
+    0
+    """
+
+def test_z1(self):
+    """
+    >>> z
+    1
+    """
+
+def test_suite():
+    suite = unittest.TestSuite()
+    suite.addTest(unittest.makeSuite(TestA))
+    suite.addTest(unittest.makeSuite(TestB))
+    suite.addTest(unittest.makeSuite(TestNotMuch))
+    suite.addTest(doctest.DocTestSuite(setUp=setUp))
+    suite.addTest(doctest.DocFileSuite('../../sampletests.txt',
+                                       setUp=setUp))
+    return suite

Added: zope.testing/trunk/src/zope/testing/testrunner-ex/sample1/sampletestsf.py
===================================================================
--- zope.testing/trunk/src/zope/testing/testrunner-ex/sample1/sampletestsf.py	2005-05-24 20:28:14 UTC (rev 30491)
+++ zope.testing/trunk/src/zope/testing/testrunner-ex/sample1/sampletestsf.py	2005-05-24 20:28:53 UTC (rev 30492)
@@ -0,0 +1,88 @@
+##############################################################################
+#
+# Copyright (c) 2003 Zope Corporation and Contributors.
+# All Rights Reserved.
+#
+# This software is subject to the provisions of the Zope Public License,
+# Version 2.0 (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.
+#
+##############################################################################
+
+import unittest
+from zope.testing import doctest
+
+x=0
+y=0
+z=0
+
+class TestA(unittest.TestCase):
+    def setUp(self):
+        global x
+        x = 1
+    def tearDown(self):
+        global x
+        x = 0
+    def test_x1(self):
+        self.assertEqual(x, 1)
+    def test_y0(self):
+        self.assertEqual(y, 0)
+    def test_z0(self):
+        self.assertEqual(z, 0)
+
+class TestB(unittest.TestCase):
+    def setUp(self):
+        global y
+        y = 1
+    def tearDown(self):
+        global y
+        y = 0
+    def test_y1(self):
+        self.assertEqual(y, 1)
+    def test_x0(self):
+        self.assertEqual(x, 0)
+    def test_z0(self):
+        self.assertEqual(z, 0)
+
+
+class TestNotMuch(unittest.TestCase):
+    def test_1(self):
+        pass
+    def test_2(self):
+        pass
+    def test_3(self):
+        pass
+
+def setUp(test):
+    test.globs['z'] = 1
+
+def test_y0(self):
+    """
+    >>> y
+    0
+    """
+
+def test_x0(self):
+    """
+    >>> x
+    0
+    """
+
+def test_z1(self):
+    """
+    >>> z
+    1
+    """
+
+def test_suite():
+    suite = unittest.TestSuite()
+    suite.addTest(unittest.makeSuite(TestA))
+    suite.addTest(unittest.makeSuite(TestB))
+    suite.addTest(unittest.makeSuite(TestNotMuch))
+    suite.addTest(doctest.DocTestSuite(setUp=setUp))
+    suite.addTest(doctest.DocFileSuite('../sampletests.txt',
+                                       setUp=setUp))
+    return suite

Added: zope.testing/trunk/src/zope/testing/testrunner-ex/sample2/__init__.py
===================================================================
--- zope.testing/trunk/src/zope/testing/testrunner-ex/sample2/__init__.py	2005-05-24 20:28:14 UTC (rev 30491)
+++ zope.testing/trunk/src/zope/testing/testrunner-ex/sample2/__init__.py	2005-05-24 20:28:53 UTC (rev 30492)
@@ -0,0 +1 @@
+#

Added: zope.testing/trunk/src/zope/testing/testrunner-ex/sample2/e.txt
===================================================================
--- zope.testing/trunk/src/zope/testing/testrunner-ex/sample2/e.txt	2005-05-24 20:28:14 UTC (rev 30491)
+++ zope.testing/trunk/src/zope/testing/testrunner-ex/sample2/e.txt	2005-05-24 20:28:53 UTC (rev 30492)
@@ -0,0 +1,4 @@
+    >>> def f():
+    ...     return x
+   
+    >>> f()

Added: zope.testing/trunk/src/zope/testing/testrunner-ex/sample2/sample21/__init__.py
===================================================================
--- zope.testing/trunk/src/zope/testing/testrunner-ex/sample2/sample21/__init__.py	2005-05-24 20:28:14 UTC (rev 30491)
+++ zope.testing/trunk/src/zope/testing/testrunner-ex/sample2/sample21/__init__.py	2005-05-24 20:28:53 UTC (rev 30492)
@@ -0,0 +1 @@
+#

Added: zope.testing/trunk/src/zope/testing/testrunner-ex/sample2/sample21/sampletests.py
===================================================================
--- zope.testing/trunk/src/zope/testing/testrunner-ex/sample2/sample21/sampletests.py	2005-05-24 20:28:14 UTC (rev 30491)
+++ zope.testing/trunk/src/zope/testing/testrunner-ex/sample2/sample21/sampletests.py	2005-05-24 20:28:53 UTC (rev 30492)
@@ -0,0 +1,88 @@
+##############################################################################
+#
+# Copyright (c) 2003 Zope Corporation and Contributors.
+# All Rights Reserved.
+#
+# This software is subject to the provisions of the Zope Public License,
+# Version 2.0 (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.
+#
+##############################################################################
+
+import unittest
+from zope.testing import doctest
+
+x=0
+y=0
+z=0
+
+class TestA(unittest.TestCase):
+    def setUp(self):
+        global x
+        x = 1
+    def tearDown(self):
+        global x
+        x = 0
+    def test_x1(self):
+        self.assertEqual(x, 1)
+    def test_y0(self):
+        self.assertEqual(y, 0)
+    def test_z0(self):
+        self.assertEqual(z, 0)
+
+class TestB(unittest.TestCase):
+    def setUp(self):
+        global y
+        y = 1
+    def tearDown(self):
+        global y
+        y = 0
+    def test_y1(self):
+        self.assertEqual(y, 1)
+    def test_x0(self):
+        self.assertEqual(x, 0)
+    def test_z0(self):
+        self.assertEqual(z, 0)
+
+
+class TestNotMuch(unittest.TestCase):
+    def test_1(self):
+        pass
+    def test_2(self):
+        pass
+    def test_3(self):
+        pass
+
+def setUp(test):
+    test.globs['z'] = 1
+
+def test_y0(self):
+    """
+    >>> y
+    0
+    """
+
+def test_x0(self):
+    """
+    >>> x
+    0
+    """
+
+def test_z1(self):
+    """
+    >>> z
+    1
+    """
+
+def test_suite():
+    suite = unittest.TestSuite()
+    suite.addTest(unittest.makeSuite(TestA))
+    suite.addTest(unittest.makeSuite(TestB))
+    suite.addTest(unittest.makeSuite(TestNotMuch))
+    suite.addTest(doctest.DocTestSuite(setUp=setUp))
+    suite.addTest(doctest.DocFileSuite('../../sampletests.txt',
+                                       setUp=setUp))
+    return suite

Added: zope.testing/trunk/src/zope/testing/testrunner-ex/sample2/sample22/__init__.py
===================================================================
--- zope.testing/trunk/src/zope/testing/testrunner-ex/sample2/sample22/__init__.py	2005-05-24 20:28:14 UTC (rev 30491)
+++ zope.testing/trunk/src/zope/testing/testrunner-ex/sample2/sample22/__init__.py	2005-05-24 20:28:53 UTC (rev 30492)
@@ -0,0 +1 @@
+#

Added: zope.testing/trunk/src/zope/testing/testrunner-ex/sample2/sample23/__init__.py
===================================================================
--- zope.testing/trunk/src/zope/testing/testrunner-ex/sample2/sample23/__init__.py	2005-05-24 20:28:14 UTC (rev 30491)
+++ zope.testing/trunk/src/zope/testing/testrunner-ex/sample2/sample23/__init__.py	2005-05-24 20:28:53 UTC (rev 30492)
@@ -0,0 +1 @@
+#

Added: zope.testing/trunk/src/zope/testing/testrunner-ex/sample2/sampletests/__init__.py
===================================================================
--- zope.testing/trunk/src/zope/testing/testrunner-ex/sample2/sampletests/__init__.py	2005-05-24 20:28:14 UTC (rev 30491)
+++ zope.testing/trunk/src/zope/testing/testrunner-ex/sample2/sampletests/__init__.py	2005-05-24 20:28:53 UTC (rev 30492)
@@ -0,0 +1 @@
+#

Added: zope.testing/trunk/src/zope/testing/testrunner-ex/sample2/sampletests/test_1.py
===================================================================
--- zope.testing/trunk/src/zope/testing/testrunner-ex/sample2/sampletests/test_1.py	2005-05-24 20:28:14 UTC (rev 30491)
+++ zope.testing/trunk/src/zope/testing/testrunner-ex/sample2/sampletests/test_1.py	2005-05-24 20:28:53 UTC (rev 30492)
@@ -0,0 +1,88 @@
+##############################################################################
+#
+# Copyright (c) 2003 Zope Corporation and Contributors.
+# All Rights Reserved.
+#
+# This software is subject to the provisions of the Zope Public License,
+# Version 2.0 (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.
+#
+##############################################################################
+
+import unittest
+from zope.testing import doctest
+
+x=0
+y=0
+z=0
+
+class TestA(unittest.TestCase):
+    def setUp(self):
+        global x
+        x = 1
+    def tearDown(self):
+        global x
+        x = 0
+    def test_x1(self):
+        self.assertEqual(x, 1)
+    def test_y0(self):
+        self.assertEqual(y, 0)
+    def test_z0(self):
+        self.assertEqual(z, 0)
+
+class TestB(unittest.TestCase):
+    def setUp(self):
+        global y
+        y = 1
+    def tearDown(self):
+        global y
+        y = 0
+    def test_y1(self):
+        self.assertEqual(y, 1)
+    def test_x0(self):
+        self.assertEqual(x, 0)
+    def test_z0(self):
+        self.assertEqual(z, 0)
+
+
+class TestNotMuch(unittest.TestCase):
+    def test_1(self):
+        pass
+    def test_2(self):
+        pass
+    def test_3(self):
+        pass
+
+def setUp(test):
+    test.globs['z'] = 1
+
+def test_y0(self):
+    """
+    >>> y
+    0
+    """
+
+def test_x0(self):
+    """
+    >>> x
+    0
+    """
+
+def test_z1(self):
+    """
+    >>> z
+    1
+    """
+
+def test_suite():
+    suite = unittest.TestSuite()
+    suite.addTest(unittest.makeSuite(TestA))
+    suite.addTest(unittest.makeSuite(TestB))
+    suite.addTest(unittest.makeSuite(TestNotMuch))
+    suite.addTest(doctest.DocTestSuite(setUp=setUp))
+    suite.addTest(doctest.DocFileSuite('../../sampletests.txt',
+                                       setUp=setUp))
+    return suite

Added: zope.testing/trunk/src/zope/testing/testrunner-ex/sample2/sampletests/testone.py
===================================================================
--- zope.testing/trunk/src/zope/testing/testrunner-ex/sample2/sampletests/testone.py	2005-05-24 20:28:14 UTC (rev 30491)
+++ zope.testing/trunk/src/zope/testing/testrunner-ex/sample2/sampletests/testone.py	2005-05-24 20:28:53 UTC (rev 30492)
@@ -0,0 +1,88 @@
+##############################################################################
+#
+# Copyright (c) 2003 Zope Corporation and Contributors.
+# All Rights Reserved.
+#
+# This software is subject to the provisions of the Zope Public License,
+# Version 2.0 (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.
+#
+##############################################################################
+
+import unittest
+from zope.testing import doctest
+
+x=0
+y=0
+z=0
+
+class TestA(unittest.TestCase):
+    def setUp(self):
+        global x
+        x = 1
+    def tearDown(self):
+        global x
+        x = 0
+    def test_x1(self):
+        self.assertEqual(x, 1)
+    def test_y0(self):
+        self.assertEqual(y, 0)
+    def test_z0(self):
+        self.assertEqual(z, 0)
+
+class TestB(unittest.TestCase):
+    def setUp(self):
+        global y
+        y = 1
+    def tearDown(self):
+        global y
+        y = 0
+    def test_y1(self):
+        self.assertEqual(y, 1)
+    def test_x0(self):
+        self.assertEqual(x, 0)
+    def test_z0(self):
+        self.assertEqual(z, 0)
+
+
+class TestNotMuch(unittest.TestCase):
+    def test_1(self):
+        pass
+    def test_2(self):
+        pass
+    def test_3(self):
+        pass
+
+def setUp(test):
+    test.globs['z'] = 1
+
+def test_y0(self):
+    """
+    >>> y
+    0
+    """
+
+def test_x0(self):
+    """
+    >>> x
+    0
+    """
+
+def test_z1(self):
+    """
+    >>> z
+    1
+    """
+
+def test_suite():
+    suite = unittest.TestSuite()
+    suite.addTest(unittest.makeSuite(TestA))
+    suite.addTest(unittest.makeSuite(TestB))
+    suite.addTest(unittest.makeSuite(TestNotMuch))
+    suite.addTest(doctest.DocTestSuite(setUp=setUp))
+    suite.addTest(doctest.DocFileSuite('../../sampletests.txt',
+                                       setUp=setUp))
+    return suite

Added: zope.testing/trunk/src/zope/testing/testrunner-ex/sample2/sampletests_e.py
===================================================================
--- zope.testing/trunk/src/zope/testing/testrunner-ex/sample2/sampletests_e.py	2005-05-24 20:28:14 UTC (rev 30491)
+++ zope.testing/trunk/src/zope/testing/testrunner-ex/sample2/sampletests_e.py	2005-05-24 20:28:53 UTC (rev 30492)
@@ -0,0 +1,56 @@
+##############################################################################
+#
+# Copyright (c) 2003 Zope Corporation and Contributors.
+# All Rights Reserved.
+#
+# This software is subject to the provisions of the Zope Public License,
+# Version 2.0 (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.
+#
+##############################################################################
+
+import unittest
+from zope.testing import doctest
+
+def f():
+    g()
+
+def g():
+    x = 1
+    x = x + 1
+    x = y + 1
+    x = x + 1
+
+
+def eek(self):
+    """
+    >>> f()
+    1
+    """
+
+class Test(unittest.TestCase):
+
+    def test1(self):
+        pass
+
+    def test2(self):
+        pass
+
+    def test3(self):
+        f()
+
+    def test4(self):
+        pass
+
+    def test5(self):
+        pass
+        
+def test_suite():
+    suite = unittest.TestSuite()
+    suite.addTest(doctest.DocTestSuite())
+    suite.addTest(unittest.makeSuite(Test))
+    suite.addTest(doctest.DocFileSuite('e.txt'))
+    return suite

Added: zope.testing/trunk/src/zope/testing/testrunner-ex/sample2/sampletests_f.py
===================================================================
--- zope.testing/trunk/src/zope/testing/testrunner-ex/sample2/sampletests_f.py	2005-05-24 20:28:14 UTC (rev 30491)
+++ zope.testing/trunk/src/zope/testing/testrunner-ex/sample2/sampletests_f.py	2005-05-24 20:28:53 UTC (rev 30492)
@@ -0,0 +1,24 @@
+##############################################################################
+#
+# Copyright (c) 2003 Zope Corporation and Contributors.
+# All Rights Reserved.
+#
+# This software is subject to the provisions of the Zope Public License,
+# Version 2.0 (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.
+#
+##############################################################################
+
+import unittest
+from zope.testing import doctest
+
+class Test(unittest.TestCase):
+
+    def test(self):
+        self.assertEqual(1,0)
+        
+def test_suite():
+    return unittest.makeSuite(Test)

Added: zope.testing/trunk/src/zope/testing/testrunner-ex/sample3/__init__.py
===================================================================
--- zope.testing/trunk/src/zope/testing/testrunner-ex/sample3/__init__.py	2005-05-24 20:28:14 UTC (rev 30491)
+++ zope.testing/trunk/src/zope/testing/testrunner-ex/sample3/__init__.py	2005-05-24 20:28:53 UTC (rev 30492)
@@ -0,0 +1 @@
+#

Added: zope.testing/trunk/src/zope/testing/testrunner-ex/sample3/sample31/__init__.py
===================================================================
--- zope.testing/trunk/src/zope/testing/testrunner-ex/sample3/sample31/__init__.py	2005-05-24 20:28:14 UTC (rev 30491)
+++ zope.testing/trunk/src/zope/testing/testrunner-ex/sample3/sample31/__init__.py	2005-05-24 20:28:53 UTC (rev 30492)
@@ -0,0 +1 @@
+#

Added: zope.testing/trunk/src/zope/testing/testrunner-ex/sample3/sample32/__init__.py
===================================================================
--- zope.testing/trunk/src/zope/testing/testrunner-ex/sample3/sample32/__init__.py	2005-05-24 20:28:14 UTC (rev 30491)
+++ zope.testing/trunk/src/zope/testing/testrunner-ex/sample3/sample32/__init__.py	2005-05-24 20:28:53 UTC (rev 30492)
@@ -0,0 +1 @@
+#

Added: zope.testing/trunk/src/zope/testing/testrunner-ex/sample3/sample33/__init__.py
===================================================================
--- zope.testing/trunk/src/zope/testing/testrunner-ex/sample3/sample33/__init__.py	2005-05-24 20:28:14 UTC (rev 30491)
+++ zope.testing/trunk/src/zope/testing/testrunner-ex/sample3/sample33/__init__.py	2005-05-24 20:28:53 UTC (rev 30492)
@@ -0,0 +1 @@
+#

Added: zope.testing/trunk/src/zope/testing/testrunner-ex/sample3/sampletests.py
===================================================================
--- zope.testing/trunk/src/zope/testing/testrunner-ex/sample3/sampletests.py	2005-05-24 20:28:14 UTC (rev 30491)
+++ zope.testing/trunk/src/zope/testing/testrunner-ex/sample3/sampletests.py	2005-05-24 20:28:53 UTC (rev 30492)
@@ -0,0 +1,88 @@
+##############################################################################
+#
+# Copyright (c) 2003 Zope Corporation and Contributors.
+# All Rights Reserved.
+#
+# This software is subject to the provisions of the Zope Public License,
+# Version 2.0 (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.
+#
+##############################################################################
+
+import unittest
+from zope.testing import doctest
+
+x=0
+y=0
+z=0
+
+class TestA(unittest.TestCase):
+    def setUp(self):
+        global x
+        x = 1
+    def tearDown(self):
+        global x
+        x = 0
+    def test_x1(self):
+        self.assertEqual(x, 1)
+    def test_y0(self):
+        self.assertEqual(y, 0)
+    def test_z0(self):
+        self.assertEqual(z, 0)
+
+class TestB(unittest.TestCase):
+    def setUp(self):
+        global y
+        y = 1
+    def tearDown(self):
+        global y
+        y = 0
+    def test_y1(self):
+        self.assertEqual(y, 1)
+    def test_x0(self):
+        self.assertEqual(x, 0)
+    def test_z0(self):
+        self.assertEqual(z, 0)
+
+
+class TestNotMuch(unittest.TestCase):
+    def test_1(self):
+        pass
+    def test_2(self):
+        pass
+    def test_3(self):
+        pass
+
+def setUp(test):
+    test.globs['z'] = 1
+
+def test_y0(self):
+    """
+    >>> y
+    0
+    """
+
+def test_x0(self):
+    """
+    >>> x
+    0
+    """
+
+def test_z1(self):
+    """
+    >>> z
+    1
+    """
+
+def test_suite():
+    suite = unittest.TestSuite()
+    suite.addTest(unittest.makeSuite(TestA))
+    suite.addTest(unittest.makeSuite(TestB))
+    suite.addTest(unittest.makeSuite(TestNotMuch))
+    suite.addTest(doctest.DocTestSuite(setUp=setUp))
+    suite.addTest(doctest.DocFileSuite('../sampletests.txt',
+                                       setUp=setUp))
+    return suite

Added: zope.testing/trunk/src/zope/testing/testrunner-ex/samplelayers.py
===================================================================
--- zope.testing/trunk/src/zope/testing/testrunner-ex/samplelayers.py	2005-05-24 20:28:14 UTC (rev 30491)
+++ zope.testing/trunk/src/zope/testing/testrunner-ex/samplelayers.py	2005-05-24 20:28:53 UTC (rev 30492)
@@ -0,0 +1,130 @@
+##############################################################################
+#
+# Copyright (c) 2004 Zope Corporation and Contributors.
+# All Rights Reserved.
+#
+# This software is subject to the provisions of the Zope Public License,
+# Version 2.0 (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.
+#
+##############################################################################
+"""Sample test layers
+
+$Id$
+"""
+
+layer = '0' # Internal to samples. Not part of layer API
+layerx = '0'
+
+class Layer1:
+    # Internal to samples. Not part of layer API:
+    layer = '1'
+    base = '0'
+    layerx = '0'
+    
+    def setUp(self):
+        global layer
+        if layer != self.base:
+            raise ValueError("Bad layer, %s, for %s." % (layer, self))
+        layer = self.layer
+    setUp = classmethod(setUp)
+
+    def tearDown(self):
+        global layer
+        if layer != self.layer:
+            raise ValueError("Bad layer, %s, for %s." % (layer, self))
+        layer = self.base
+    tearDown = classmethod(tearDown)
+
+class Layerx:
+    layerx = '1' # Internal to samples. Not part of layer API
+    basex = '0'
+    
+    def setUp(self):
+        global layerx
+        if layerx != self.basex:
+            raise ValueError("Bad layerx, %s, for %s." % (layerx, self))
+        layerx = self.layerx
+    setUp = classmethod(setUp)
+
+    def tearDown(self):
+        global layerx
+        if layerx != self.layerx:
+            raise ValueError("Bad layerx, %s, for %s." % (layerx, self))
+        layerx = self.basex
+    tearDown = classmethod(tearDown)
+
+class Layer11(Layer1):
+    layer = '11' # Internal to samples. Not part of layer API
+    base  = '1'  # Internal to samples. Not part of layer API
+
+class Layer12(Layer1):
+    layer = '12' # Internal to samples. Not part of layer API
+    base  = '1'  # Internal to samples. Not part of layer API
+
+class Layer111(Layerx, Layer11):
+    layer = '111' # Internal to samples. Not part of layer API
+    base  = '11'  # Internal to samples. Not part of layer API
+    layerx = '2' # Internal to samples. Not part of layer API
+    basex = '1'
+
+    def setUp(self):
+        global layer
+        if layer != self.base:
+            raise ValueError("Bad layer, %s, for %s." % (layer, self))
+        layer = self.layer
+        global layerx
+        if layerx != self.basex:
+            raise ValueError("Bad layerx, %s, for %s." % (layerx, self))
+        layerx = self.layerx
+    setUp = classmethod(setUp)
+
+    def tearDown(self):
+        global layer
+        if layer != self.layer:
+            raise ValueError("Bad layer, %s, for %s." % (layer, self))
+        layer = self.base
+        global layerx
+        if layerx != self.layerx:
+            raise ValueError("Bad layerx, %s, for %s." % (layerx, self))
+        layerx = self.basex
+    tearDown = classmethod(tearDown)
+
+class Layer121(Layer12):
+    layer = '121' # Internal to samples. Not part of layer API
+    base  = '12'  # Internal to samples. Not part of layer API
+
+class Layer112(Layerx, Layer11):
+    layer = '112' # Internal to samples. Not part of layer API
+    base  = '11'  # Internal to samples. Not part of layer API
+    layerx = '2' # Internal to samples. Not part of layer API
+    basex = '1'
+
+    def setUp(self):
+        global layer
+        if layer != self.base:
+            raise ValueError("Bad layer, %s, for %s." % (layer, self))
+        layer = self.layer
+        global layerx
+        if layerx != self.basex:
+            raise ValueError("Bad layerx, %s, for %s." % (layerx, self))
+        layerx = self.layerx
+    setUp = classmethod(setUp)
+
+    def tearDown(self):
+        global layer
+        if layer != self.layer:
+            raise ValueError("Bad layer, %s, for %s." % (layer, self))
+        layer = self.base
+        global layerx
+        if layerx != self.layerx:
+            raise ValueError("Bad layerx, %s, for %s." % (layerx, self))
+        layerx = self.basex
+    tearDown = classmethod(tearDown)
+
+class Layer122(Layer12):
+    layer = '122' # Internal to samples. Not part of layer API
+    base  = '12'  # Internal to samples. Not part of layer API

Added: zope.testing/trunk/src/zope/testing/testrunner-ex/sampletests/__init__.py
===================================================================
--- zope.testing/trunk/src/zope/testing/testrunner-ex/sampletests/__init__.py	2005-05-24 20:28:14 UTC (rev 30491)
+++ zope.testing/trunk/src/zope/testing/testrunner-ex/sampletests/__init__.py	2005-05-24 20:28:53 UTC (rev 30492)
@@ -0,0 +1 @@
+#

Added: zope.testing/trunk/src/zope/testing/testrunner-ex/sampletests/test1.py
===================================================================
--- zope.testing/trunk/src/zope/testing/testrunner-ex/sampletests/test1.py	2005-05-24 20:28:14 UTC (rev 30491)
+++ zope.testing/trunk/src/zope/testing/testrunner-ex/sampletests/test1.py	2005-05-24 20:28:53 UTC (rev 30492)
@@ -0,0 +1,88 @@
+##############################################################################
+#
+# Copyright (c) 2003 Zope Corporation and Contributors.
+# All Rights Reserved.
+#
+# This software is subject to the provisions of the Zope Public License,
+# Version 2.0 (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.
+#
+##############################################################################
+
+import unittest
+from zope.testing import doctest
+
+x=0
+y=0
+z=0
+
+class TestA(unittest.TestCase):
+    def setUp(self):
+        global x
+        x = 1
+    def tearDown(self):
+        global x
+        x = 0
+    def test_x1(self):
+        self.assertEqual(x, 1)
+    def test_y0(self):
+        self.assertEqual(y, 0)
+    def test_z0(self):
+        self.assertEqual(z, 0)
+
+class TestB(unittest.TestCase):
+    def setUp(self):
+        global y
+        y = 1
+    def tearDown(self):
+        global y
+        y = 0
+    def test_y1(self):
+        self.assertEqual(y, 1)
+    def test_x0(self):
+        self.assertEqual(x, 0)
+    def test_z0(self):
+        self.assertEqual(z, 0)
+
+
+class TestNotMuch(unittest.TestCase):
+    def test_1(self):
+        pass
+    def test_2(self):
+        pass
+    def test_3(self):
+        pass
+
+def setUp(test):
+    test.globs['z'] = 1
+
+def test_y0(self):
+    """
+    >>> y
+    0
+    """
+
+def test_x0(self):
+    """
+    >>> x
+    0
+    """
+
+def test_z1(self):
+    """
+    >>> z
+    1
+    """
+
+def test_suite():
+    suite = unittest.TestSuite()
+    suite.addTest(unittest.makeSuite(TestA))
+    suite.addTest(unittest.makeSuite(TestB))
+    suite.addTest(unittest.makeSuite(TestNotMuch))
+    suite.addTest(doctest.DocTestSuite(setUp=setUp))
+    suite.addTest(doctest.DocFileSuite('../sampletests.txt',
+                                       setUp=setUp))
+    return suite

Added: zope.testing/trunk/src/zope/testing/testrunner-ex/sampletests/test11.py
===================================================================
--- zope.testing/trunk/src/zope/testing/testrunner-ex/sampletests/test11.py	2005-05-24 20:28:14 UTC (rev 30491)
+++ zope.testing/trunk/src/zope/testing/testrunner-ex/sampletests/test11.py	2005-05-24 20:28:53 UTC (rev 30492)
@@ -0,0 +1,127 @@
+##############################################################################
+#
+# Copyright (c) 2003 Zope Corporation and Contributors.
+# All Rights Reserved.
+#
+# This software is subject to the provisions of the Zope Public License,
+# Version 2.0 (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.
+#
+##############################################################################
+
+import unittest
+from zope.testing import doctest
+import samplelayers
+
+layername = 'samplelayers.Layer11'
+layer = samplelayers.Layer11
+
+x=0
+y=0
+z=0
+
+class TestA(unittest.TestCase):
+    layer = layername
+        
+    def setUp(self):
+        global x
+        x = 1
+    def tearDown(self):
+        global x
+        x = 0
+    def test_x1(self):
+        self.assertEqual(x, 1)
+        self.assertEqual(samplelayers.layer, layer.layer)
+        self.assertEqual(samplelayers.layerx, layer.layerx)
+    def test_y0(self):
+        self.assertEqual(y, 0)
+        self.assertEqual(samplelayers.layer, layer.layer)
+        self.assertEqual(samplelayers.layerx, layer.layerx)
+    def test_z0(self):
+        self.assertEqual(z, 0)
+        self.assertEqual(samplelayers.layer, layer.layer)
+        self.assertEqual(samplelayers.layerx, layer.layerx)
+
+class TestB(unittest.TestCase):
+    layer = layername
+
+    def setUp(self):
+        global y
+        y = 1
+    def tearDown(self):
+        global y
+        y = 0
+    def test_y1(self):
+        self.assertEqual(y, 1)
+        self.assertEqual(samplelayers.layer, layer.layer)
+        self.assertEqual(samplelayers.layerx, layer.layerx)
+    def test_x0(self):
+        self.assertEqual(x, 0)
+        self.assertEqual(samplelayers.layer, layer.layer)
+        self.assertEqual(samplelayers.layerx, layer.layerx)
+    def test_z0(self):
+        self.assertEqual(z, 0)
+        self.assertEqual(samplelayers.layer, layer.layer)
+        self.assertEqual(samplelayers.layerx, layer.layerx)
+
+
+class TestNotMuch(unittest.TestCase):
+    layer = layername
+
+    def test_1(self):
+        self.assertEqual(samplelayers.layer, layer.layer)
+        self.assertEqual(samplelayers.layerx, layer.layerx)
+    def test_2(self):
+        self.assertEqual(samplelayers.layer, layer.layer)
+        self.assertEqual(samplelayers.layerx, layer.layerx)
+    def test_3(self):
+        self.assertEqual(samplelayers.layer, layer.layer)
+        self.assertEqual(samplelayers.layerx, layer.layerx)
+
+def setUp(test):
+    test.globs['z'] = 1
+    test.globs['layer'] = layer.layer
+    test.globs['layerx'] = layer.layerx
+
+def test_y0(self):
+    """
+    >>> y
+    0
+
+    >>> (layer == samplelayers.layer), (layerx == samplelayers.layerx)
+    (True, True)
+    """
+
+def test_x0(self):
+    """
+    >>> x
+    0
+
+    >>> (layer == samplelayers.layer), (layerx == samplelayers.layerx)
+    (True, True)
+    """
+
+def test_z1(self):
+    """
+    >>> z
+    1
+
+    >>> (layer == samplelayers.layer), (layerx == samplelayers.layerx)
+    (True, True)
+    """
+
+def test_suite():
+    suite = unittest.TestSuite()
+    suite.addTest(unittest.makeSuite(TestA))
+    suite.addTest(unittest.makeSuite(TestB))
+    suite.addTest(unittest.makeSuite(TestNotMuch))
+    s = doctest.DocTestSuite(setUp=setUp)
+    s.layer = layer
+    suite.addTest(s)
+    s = doctest.DocFileSuite('../sampletestsl.txt', setUp=setUp)
+    s.layer = layer
+    suite.addTest(s)
+    return suite

Added: zope.testing/trunk/src/zope/testing/testrunner-ex/sampletests/test111.py
===================================================================
--- zope.testing/trunk/src/zope/testing/testrunner-ex/sampletests/test111.py	2005-05-24 20:28:14 UTC (rev 30491)
+++ zope.testing/trunk/src/zope/testing/testrunner-ex/sampletests/test111.py	2005-05-24 20:28:53 UTC (rev 30492)
@@ -0,0 +1,127 @@
+##############################################################################
+#
+# Copyright (c) 2003 Zope Corporation and Contributors.
+# All Rights Reserved.
+#
+# This software is subject to the provisions of the Zope Public License,
+# Version 2.0 (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.
+#
+##############################################################################
+
+import unittest
+from zope.testing import doctest
+import samplelayers
+
+layername = 'samplelayers.Layer111'
+layer = samplelayers.Layer111
+
+x=0
+y=0
+z=0
+
+class TestA(unittest.TestCase):
+    layer = layername
+        
+    def setUp(self):
+        global x
+        x = 1
+    def tearDown(self):
+        global x
+        x = 0
+    def test_x1(self):
+        self.assertEqual(x, 1)
+        self.assertEqual(samplelayers.layer, layer.layer)
+        self.assertEqual(samplelayers.layerx, layer.layerx)
+    def test_y0(self):
+        self.assertEqual(y, 0)
+        self.assertEqual(samplelayers.layer, layer.layer)
+        self.assertEqual(samplelayers.layerx, layer.layerx)
+    def test_z0(self):
+        self.assertEqual(z, 0)
+        self.assertEqual(samplelayers.layer, layer.layer)
+        self.assertEqual(samplelayers.layerx, layer.layerx)
+
+class TestB(unittest.TestCase):
+    layer = layername
+
+    def setUp(self):
+        global y
+        y = 1
+    def tearDown(self):
+        global y
+        y = 0
+    def test_y1(self):
+        self.assertEqual(y, 1)
+        self.assertEqual(samplelayers.layer, layer.layer)
+        self.assertEqual(samplelayers.layerx, layer.layerx)
+    def test_x0(self):
+        self.assertEqual(x, 0)
+        self.assertEqual(samplelayers.layer, layer.layer)
+        self.assertEqual(samplelayers.layerx, layer.layerx)
+    def test_z0(self):
+        self.assertEqual(z, 0)
+        self.assertEqual(samplelayers.layer, layer.layer)
+        self.assertEqual(samplelayers.layerx, layer.layerx)
+
+
+class TestNotMuch(unittest.TestCase):
+    layer = layername
+
+    def test_1(self):
+        self.assertEqual(samplelayers.layer, layer.layer)
+        self.assertEqual(samplelayers.layerx, layer.layerx)
+    def test_2(self):
+        self.assertEqual(samplelayers.layer, layer.layer)
+        self.assertEqual(samplelayers.layerx, layer.layerx)
+    def test_3(self):
+        self.assertEqual(samplelayers.layer, layer.layer)
+        self.assertEqual(samplelayers.layerx, layer.layerx)
+
+def setUp(test):
+    test.globs['z'] = 1
+    test.globs['layer'] = layer.layer
+    test.globs['layerx'] = layer.layerx
+
+def test_y0(self):
+    """
+    >>> y
+    0
+
+    >>> (layer == samplelayers.layer), (layerx == samplelayers.layerx)
+    (True, True)
+    """
+
+def test_x0(self):
+    """
+    >>> x
+    0
+
+    >>> (layer == samplelayers.layer), (layerx == samplelayers.layerx)
+    (True, True)
+    """
+
+def test_z1(self):
+    """
+    >>> z
+    1
+
+    >>> (layer == samplelayers.layer), (layerx == samplelayers.layerx)
+    (True, True)
+    """
+
+def test_suite():
+    suite = unittest.TestSuite()
+    suite.addTest(unittest.makeSuite(TestA))
+    suite.addTest(unittest.makeSuite(TestB))
+    suite.addTest(unittest.makeSuite(TestNotMuch))
+    s = doctest.DocTestSuite(setUp=setUp)
+    s.layer = layer
+    suite.addTest(s)
+    s = doctest.DocFileSuite('../sampletestsl.txt', setUp=setUp)
+    s.layer = layer
+    suite.addTest(s)
+    return suite

Added: zope.testing/trunk/src/zope/testing/testrunner-ex/sampletests/test112.py
===================================================================
--- zope.testing/trunk/src/zope/testing/testrunner-ex/sampletests/test112.py	2005-05-24 20:28:14 UTC (rev 30491)
+++ zope.testing/trunk/src/zope/testing/testrunner-ex/sampletests/test112.py	2005-05-24 20:28:53 UTC (rev 30492)
@@ -0,0 +1,128 @@
+##############################################################################
+#
+# Copyright (c) 2003 Zope Corporation and Contributors.
+# All Rights Reserved.
+#
+# This software is subject to the provisions of the Zope Public License,
+# Version 2.0 (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.
+#
+##############################################################################
+
+import unittest
+from zope.testing import doctest
+import samplelayers
+
+layername = 'samplelayers.Layer112'
+layer = samplelayers.Layer112
+
+
+x=0
+y=0
+z=0
+
+class TestA(unittest.TestCase):
+    layer = layername
+        
+    def setUp(self):
+        global x
+        x = 1
+    def tearDown(self):
+        global x
+        x = 0
+    def test_x1(self):
+        self.assertEqual(x, 1)
+        self.assertEqual(samplelayers.layer, layer.layer)
+        self.assertEqual(samplelayers.layerx, layer.layerx)
+    def test_y0(self):
+        self.assertEqual(y, 0)
+        self.assertEqual(samplelayers.layer, layer.layer)
+        self.assertEqual(samplelayers.layerx, layer.layerx)
+    def test_z0(self):
+        self.assertEqual(z, 0)
+        self.assertEqual(samplelayers.layer, layer.layer)
+        self.assertEqual(samplelayers.layerx, layer.layerx)
+
+class TestB(unittest.TestCase):
+    layer = layername
+
+    def setUp(self):
+        global y
+        y = 1
+    def tearDown(self):
+        global y
+        y = 0
+    def test_y1(self):
+        self.assertEqual(y, 1)
+        self.assertEqual(samplelayers.layer, layer.layer)
+        self.assertEqual(samplelayers.layerx, layer.layerx)
+    def test_x0(self):
+        self.assertEqual(x, 0)
+        self.assertEqual(samplelayers.layer, layer.layer)
+        self.assertEqual(samplelayers.layerx, layer.layerx)
+    def test_z0(self):
+        self.assertEqual(z, 0)
+        self.assertEqual(samplelayers.layer, layer.layer)
+        self.assertEqual(samplelayers.layerx, layer.layerx)
+
+
+class TestNotMuch(unittest.TestCase):
+    layer = layername
+
+    def test_1(self):
+        self.assertEqual(samplelayers.layer, layer.layer)
+        self.assertEqual(samplelayers.layerx, layer.layerx)
+    def test_2(self):
+        self.assertEqual(samplelayers.layer, layer.layer)
+        self.assertEqual(samplelayers.layerx, layer.layerx)
+    def test_3(self):
+        self.assertEqual(samplelayers.layer, layer.layer)
+        self.assertEqual(samplelayers.layerx, layer.layerx)
+
+def setUp(test):
+    test.globs['z'] = 1
+    test.globs['layer'] = layer.layer
+    test.globs['layerx'] = layer.layerx
+
+def test_y0(self):
+    """
+    >>> y
+    0
+
+    >>> (layer == samplelayers.layer), (layerx == samplelayers.layerx)
+    (True, True)
+    """
+
+def test_x0(self):
+    """
+    >>> x
+    0
+
+    >>> (layer == samplelayers.layer), (layerx == samplelayers.layerx)
+    (True, True)
+    """
+
+def test_z1(self):
+    """
+    >>> z
+    1
+
+    >>> (layer == samplelayers.layer), (layerx == samplelayers.layerx)
+    (True, True)
+    """
+
+def test_suite():
+    suite = unittest.TestSuite()
+    suite.addTest(unittest.makeSuite(TestA))
+    suite.addTest(unittest.makeSuite(TestB))
+    suite.addTest(unittest.makeSuite(TestNotMuch))
+    s = doctest.DocTestSuite(setUp=setUp)
+    s.layer = layer
+    suite.addTest(s)
+    s = doctest.DocFileSuite('../sampletestsl.txt', setUp=setUp)
+    s.layer = layer
+    suite.addTest(s)
+    return suite

Added: zope.testing/trunk/src/zope/testing/testrunner-ex/sampletests/test12.py
===================================================================
--- zope.testing/trunk/src/zope/testing/testrunner-ex/sampletests/test12.py	2005-05-24 20:28:14 UTC (rev 30491)
+++ zope.testing/trunk/src/zope/testing/testrunner-ex/sampletests/test12.py	2005-05-24 20:28:53 UTC (rev 30492)
@@ -0,0 +1,127 @@
+##############################################################################
+#
+# Copyright (c) 2003 Zope Corporation and Contributors.
+# All Rights Reserved.
+#
+# This software is subject to the provisions of the Zope Public License,
+# Version 2.0 (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.
+#
+##############################################################################
+
+import unittest
+from zope.testing import doctest
+import samplelayers
+
+layername = 'samplelayers.Layer12'
+layer = samplelayers.Layer12
+
+x=0
+y=0
+z=0
+
+class TestA(unittest.TestCase):
+    layer = layername
+        
+    def setUp(self):
+        global x
+        x = 1
+    def tearDown(self):
+        global x
+        x = 0
+    def test_x1(self):
+        self.assertEqual(x, 1)
+        self.assertEqual(samplelayers.layer, layer.layer)
+        self.assertEqual(samplelayers.layerx, layer.layerx)
+    def test_y0(self):
+        self.assertEqual(y, 0)
+        self.assertEqual(samplelayers.layer, layer.layer)
+        self.assertEqual(samplelayers.layerx, layer.layerx)
+    def test_z0(self):
+        self.assertEqual(z, 0)
+        self.assertEqual(samplelayers.layer, layer.layer)
+        self.assertEqual(samplelayers.layerx, layer.layerx)
+
+class TestB(unittest.TestCase):
+    layer = layername
+
+    def setUp(self):
+        global y
+        y = 1
+    def tearDown(self):
+        global y
+        y = 0
+    def test_y1(self):
+        self.assertEqual(y, 1)
+        self.assertEqual(samplelayers.layer, layer.layer)
+        self.assertEqual(samplelayers.layerx, layer.layerx)
+    def test_x0(self):
+        self.assertEqual(x, 0)
+        self.assertEqual(samplelayers.layer, layer.layer)
+        self.assertEqual(samplelayers.layerx, layer.layerx)
+    def test_z0(self):
+        self.assertEqual(z, 0)
+        self.assertEqual(samplelayers.layer, layer.layer)
+        self.assertEqual(samplelayers.layerx, layer.layerx)
+
+
+class TestNotMuch(unittest.TestCase):
+    layer = layername
+
+    def test_1(self):
+        self.assertEqual(samplelayers.layer, layer.layer)
+        self.assertEqual(samplelayers.layerx, layer.layerx)
+    def test_2(self):
+        self.assertEqual(samplelayers.layer, layer.layer)
+        self.assertEqual(samplelayers.layerx, layer.layerx)
+    def test_3(self):
+        self.assertEqual(samplelayers.layer, layer.layer)
+        self.assertEqual(samplelayers.layerx, layer.layerx)
+
+def setUp(test):
+    test.globs['z'] = 1
+    test.globs['layer'] = layer.layer
+    test.globs['layerx'] = layer.layerx
+
+def test_y0(self):
+    """
+    >>> y
+    0
+
+    >>> (layer == samplelayers.layer), (layerx == samplelayers.layerx)
+    (True, True)
+    """
+
+def test_x0(self):
+    """
+    >>> x
+    0
+
+    >>> (layer == samplelayers.layer), (layerx == samplelayers.layerx)
+    (True, True)
+    """
+
+def test_z1(self):
+    """
+    >>> z
+    1
+
+    >>> (layer == samplelayers.layer), (layerx == samplelayers.layerx)
+    (True, True)
+    """
+
+def test_suite():
+    suite = unittest.TestSuite()
+    suite.addTest(unittest.makeSuite(TestA))
+    suite.addTest(unittest.makeSuite(TestB))
+    suite.addTest(unittest.makeSuite(TestNotMuch))
+    s = doctest.DocTestSuite(setUp=setUp)
+    s.layer = layer
+    suite.addTest(s)
+    s = doctest.DocFileSuite('../sampletestsl.txt', setUp=setUp)
+    s.layer = layer
+    suite.addTest(s)
+    return suite

Added: zope.testing/trunk/src/zope/testing/testrunner-ex/sampletests/test121.py
===================================================================
--- zope.testing/trunk/src/zope/testing/testrunner-ex/sampletests/test121.py	2005-05-24 20:28:14 UTC (rev 30491)
+++ zope.testing/trunk/src/zope/testing/testrunner-ex/sampletests/test121.py	2005-05-24 20:28:53 UTC (rev 30492)
@@ -0,0 +1,127 @@
+##############################################################################
+#
+# Copyright (c) 2003 Zope Corporation and Contributors.
+# All Rights Reserved.
+#
+# This software is subject to the provisions of the Zope Public License,
+# Version 2.0 (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.
+#
+##############################################################################
+
+import unittest
+from zope.testing import doctest
+import samplelayers
+
+layername = 'samplelayers.Layer121'
+layer = samplelayers.Layer121
+
+x=0
+y=0
+z=0
+
+class TestA(unittest.TestCase):
+    layer = layername
+        
+    def setUp(self):
+        global x
+        x = 1
+    def tearDown(self):
+        global x
+        x = 0
+    def test_x1(self):
+        self.assertEqual(x, 1)
+        self.assertEqual(samplelayers.layer, layer.layer)
+        self.assertEqual(samplelayers.layerx, layer.layerx)
+    def test_y0(self):
+        self.assertEqual(y, 0)
+        self.assertEqual(samplelayers.layer, layer.layer)
+        self.assertEqual(samplelayers.layerx, layer.layerx)
+    def test_z0(self):
+        self.assertEqual(z, 0)
+        self.assertEqual(samplelayers.layer, layer.layer)
+        self.assertEqual(samplelayers.layerx, layer.layerx)
+
+class TestB(unittest.TestCase):
+    layer = layername
+
+    def setUp(self):
+        global y
+        y = 1
+    def tearDown(self):
+        global y
+        y = 0
+    def test_y1(self):
+        self.assertEqual(y, 1)
+        self.assertEqual(samplelayers.layer, layer.layer)
+        self.assertEqual(samplelayers.layerx, layer.layerx)
+    def test_x0(self):
+        self.assertEqual(x, 0)
+        self.assertEqual(samplelayers.layer, layer.layer)
+        self.assertEqual(samplelayers.layerx, layer.layerx)
+    def test_z0(self):
+        self.assertEqual(z, 0)
+        self.assertEqual(samplelayers.layer, layer.layer)
+        self.assertEqual(samplelayers.layerx, layer.layerx)
+
+
+class TestNotMuch(unittest.TestCase):
+    layer = layername
+
+    def test_1(self):
+        self.assertEqual(samplelayers.layer, layer.layer)
+        self.assertEqual(samplelayers.layerx, layer.layerx)
+    def test_2(self):
+        self.assertEqual(samplelayers.layer, layer.layer)
+        self.assertEqual(samplelayers.layerx, layer.layerx)
+    def test_3(self):
+        self.assertEqual(samplelayers.layer, layer.layer)
+        self.assertEqual(samplelayers.layerx, layer.layerx)
+
+def setUp(test):
+    test.globs['z'] = 1
+    test.globs['layer'] = layer.layer
+    test.globs['layerx'] = layer.layerx
+
+def test_y0(self):
+    """
+    >>> y
+    0
+
+    >>> (layer == samplelayers.layer), (layerx == samplelayers.layerx)
+    (True, True)
+    """
+
+def test_x0(self):
+    """
+    >>> x
+    0
+
+    >>> (layer == samplelayers.layer), (layerx == samplelayers.layerx)
+    (True, True)
+    """
+
+def test_z1(self):
+    """
+    >>> z
+    1
+
+    >>> (layer == samplelayers.layer), (layerx == samplelayers.layerx)
+    (True, True)
+    """
+
+def test_suite():
+    suite = unittest.TestSuite()
+    suite.addTest(unittest.makeSuite(TestA))
+    suite.addTest(unittest.makeSuite(TestB))
+    suite.addTest(unittest.makeSuite(TestNotMuch))
+    s = doctest.DocTestSuite(setUp=setUp)
+    s.layer = layer
+    suite.addTest(s)
+    s = doctest.DocFileSuite('../sampletestsl.txt', setUp=setUp)
+    s.layer = layer
+    suite.addTest(s)
+    return suite

Added: zope.testing/trunk/src/zope/testing/testrunner-ex/sampletests/test122.py
===================================================================
--- zope.testing/trunk/src/zope/testing/testrunner-ex/sampletests/test122.py	2005-05-24 20:28:14 UTC (rev 30491)
+++ zope.testing/trunk/src/zope/testing/testrunner-ex/sampletests/test122.py	2005-05-24 20:28:53 UTC (rev 30492)
@@ -0,0 +1,127 @@
+##############################################################################
+#
+# Copyright (c) 2003 Zope Corporation and Contributors.
+# All Rights Reserved.
+#
+# This software is subject to the provisions of the Zope Public License,
+# Version 2.0 (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.
+#
+##############################################################################
+
+import unittest
+from zope.testing import doctest
+import samplelayers
+
+layername = 'samplelayers.Layer122'
+layer = samplelayers.Layer122
+
+x=0
+y=0
+z=0
+
+class TestA(unittest.TestCase):
+    layer = layername
+        
+    def setUp(self):
+        global x
+        x = 1
+    def tearDown(self):
+        global x
+        x = 0
+    def test_x1(self):
+        self.assertEqual(x, 1)
+        self.assertEqual(samplelayers.layer, layer.layer)
+        self.assertEqual(samplelayers.layerx, layer.layerx)
+    def test_y0(self):
+        self.assertEqual(y, 0)
+        self.assertEqual(samplelayers.layer, layer.layer)
+        self.assertEqual(samplelayers.layerx, layer.layerx)
+    def test_z0(self):
+        self.assertEqual(z, 0)
+        self.assertEqual(samplelayers.layer, layer.layer)
+        self.assertEqual(samplelayers.layerx, layer.layerx)
+
+class TestB(unittest.TestCase):
+    layer = layername
+
+    def setUp(self):
+        global y
+        y = 1
+    def tearDown(self):
+        global y
+        y = 0
+    def test_y1(self):
+        self.assertEqual(y, 1)
+        self.assertEqual(samplelayers.layer, layer.layer)
+        self.assertEqual(samplelayers.layerx, layer.layerx)
+    def test_x0(self):
+        self.assertEqual(x, 0)
+        self.assertEqual(samplelayers.layer, layer.layer)
+        self.assertEqual(samplelayers.layerx, layer.layerx)
+    def test_z0(self):
+        self.assertEqual(z, 0)
+        self.assertEqual(samplelayers.layer, layer.layer)
+        self.assertEqual(samplelayers.layerx, layer.layerx)
+
+
+class TestNotMuch(unittest.TestCase):
+    layer = layername
+
+    def test_1(self):
+        self.assertEqual(samplelayers.layer, layer.layer)
+        self.assertEqual(samplelayers.layerx, layer.layerx)
+    def test_2(self):
+        self.assertEqual(samplelayers.layer, layer.layer)
+        self.assertEqual(samplelayers.layerx, layer.layerx)
+    def test_3(self):
+        self.assertEqual(samplelayers.layer, layer.layer)
+        self.assertEqual(samplelayers.layerx, layer.layerx)
+
+def setUp(test):
+    test.globs['z'] = 1
+    test.globs['layer'] = layer.layer
+    test.globs['layerx'] = layer.layerx
+
+def test_y0(self):
+    """
+    >>> y
+    0
+
+    >>> (layer == samplelayers.layer), (layerx == samplelayers.layerx)
+    (True, True)
+    """
+
+def test_x0(self):
+    """
+    >>> x
+    0
+
+    >>> (layer == samplelayers.layer), (layerx == samplelayers.layerx)
+    (True, True)
+    """
+
+def test_z1(self):
+    """
+    >>> z
+    1
+
+    >>> (layer == samplelayers.layer), (layerx == samplelayers.layerx)
+    (True, True)
+    """
+
+def test_suite():
+    suite = unittest.TestSuite()
+    suite.addTest(unittest.makeSuite(TestA))
+    suite.addTest(unittest.makeSuite(TestB))
+    suite.addTest(unittest.makeSuite(TestNotMuch))
+    s = doctest.DocTestSuite(setUp=setUp)
+    s.layer = layer
+    suite.addTest(s)
+    s = doctest.DocFileSuite('../sampletestsl.txt', setUp=setUp)
+    s.layer = layer
+    suite.addTest(s)
+    return suite

Added: zope.testing/trunk/src/zope/testing/testrunner-ex/sampletests/test_one.py
===================================================================
--- zope.testing/trunk/src/zope/testing/testrunner-ex/sampletests/test_one.py	2005-05-24 20:28:14 UTC (rev 30491)
+++ zope.testing/trunk/src/zope/testing/testrunner-ex/sampletests/test_one.py	2005-05-24 20:28:53 UTC (rev 30492)
@@ -0,0 +1,88 @@
+##############################################################################
+#
+# Copyright (c) 2003 Zope Corporation and Contributors.
+# All Rights Reserved.
+#
+# This software is subject to the provisions of the Zope Public License,
+# Version 2.0 (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.
+#
+##############################################################################
+
+import unittest
+from zope.testing import doctest
+
+x=0
+y=0
+z=0
+
+class TestA(unittest.TestCase):
+    def setUp(self):
+        global x
+        x = 1
+    def tearDown(self):
+        global x
+        x = 0
+    def test_x1(self):
+        self.assertEqual(x, 1)
+    def test_y0(self):
+        self.assertEqual(y, 0)
+    def test_z0(self):
+        self.assertEqual(z, 0)
+
+class TestB(unittest.TestCase):
+    def setUp(self):
+        global y
+        y = 1
+    def tearDown(self):
+        global y
+        y = 0
+    def test_y1(self):
+        self.assertEqual(y, 1)
+    def test_x0(self):
+        self.assertEqual(x, 0)
+    def test_z0(self):
+        self.assertEqual(z, 0)
+
+
+class TestNotMuch(unittest.TestCase):
+    def test_1(self):
+        pass
+    def test_2(self):
+        pass
+    def test_3(self):
+        pass
+
+def setUp(test):
+    test.globs['z'] = 1
+
+def test_y0(self):
+    """
+    >>> y
+    0
+    """
+
+def test_x0(self):
+    """
+    >>> x
+    0
+    """
+
+def test_z1(self):
+    """
+    >>> z
+    1
+    """
+
+def test_suite():
+    suite = unittest.TestSuite()
+    suite.addTest(unittest.makeSuite(TestA))
+    suite.addTest(unittest.makeSuite(TestB))
+    suite.addTest(unittest.makeSuite(TestNotMuch))
+    suite.addTest(doctest.DocTestSuite(setUp=setUp))
+    suite.addTest(doctest.DocFileSuite('../sampletests.txt',
+                                       setUp=setUp))
+    return suite

Added: zope.testing/trunk/src/zope/testing/testrunner-ex/sampletests.txt
===================================================================
--- zope.testing/trunk/src/zope/testing/testrunner-ex/sampletests.txt	2005-05-24 20:28:14 UTC (rev 30491)
+++ zope.testing/trunk/src/zope/testing/testrunner-ex/sampletests.txt	2005-05-24 20:28:53 UTC (rev 30492)
@@ -0,0 +1,20 @@
+This is a sample doctest
+
+    >>> x=1
+    >>> x
+    1
+
+Blah blah blah
+
+    >>> x
+    1
+
+Blah blah blah
+
+    >>> x
+    1
+
+Blah blah blah
+
+    >>> x
+    1

Added: zope.testing/trunk/src/zope/testing/testrunner-ex/sampletestsf.py
===================================================================
--- zope.testing/trunk/src/zope/testing/testrunner-ex/sampletestsf.py	2005-05-24 20:28:14 UTC (rev 30491)
+++ zope.testing/trunk/src/zope/testing/testrunner-ex/sampletestsf.py	2005-05-24 20:28:53 UTC (rev 30492)
@@ -0,0 +1,172 @@
+##############################################################################
+#
+# Copyright (c) 2003 Zope Corporation and Contributors.
+# All Rights Reserved.
+#
+# This software is subject to the provisions of the Zope Public License,
+# Version 2.0 (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.
+#
+##############################################################################
+
+import unittest
+from zope.testing import doctest
+
+x=0
+y=0
+z=0
+
+class TestA(unittest.TestCase):
+    def setUp(self):
+        global x
+        x = 1
+    def tearDown(self):
+        global x
+        x = 0
+    def test_x1(self):
+        self.assertEqual(x, 1)
+    def test_y0(self):
+        self.assertEqual(y, 0)
+    def test_z0(self):
+        self.assertEqual(z, 0)
+
+class TestA2(unittest.TestCase):
+    level = 2
+    
+    def setUp(self):
+        global x
+        x = 1
+    def tearDown(self):
+        global x
+        x = 0
+    def test_x1(self):
+        self.assertEqual(x, 1)
+    def test_y0(self):
+        self.assertEqual(y, 0)
+    def test_z0(self):
+        self.assertEqual(z, 0)
+
+class TestB(unittest.TestCase):
+    def setUp(self):
+        global y
+        y = 1
+    def tearDown(self):
+        global y
+        y = 0
+    def test_y1(self):
+        self.assertEqual(y, 1)
+    def test_x0(self):
+        self.assertEqual(x, 0)
+    def test_z0(self):
+        self.assertEqual(z, 0)
+
+
+class TestNotMuch(unittest.TestCase):
+    def test_1(self):
+        pass
+    def test_2(self):
+        pass
+    def test_3(self):
+        pass
+
+
+def setUp(test):
+    test.globs['z'] = 1
+
+
+def test_y0(self):
+    """
+    >>> y
+    0
+    """
+
+def test_x0(self):
+    """
+    >>> x
+    0
+    """
+
+def test_z1(self):
+    """
+    >>> z
+    1
+    """
+
+import samplelayers
+
+class Layered:
+
+    layer = 'samplelayers.Layer1'
+    layerv = '1'
+    layerx = '0'
+
+class TestA1(unittest.TestCase, Layered):
+    
+    def setUp(self):
+        global x
+        x = 1
+    def tearDown(self):
+        global x
+        x = 0
+    def test_x1(self):
+        self.assertEqual(x, 1)
+        self.assertEqual(samplelayers.layer, self.layerv)
+        self.assertEqual(samplelayers.layerx, self.layerx)
+    def test_y0(self):
+        self.assertEqual(y, 0)
+        self.assertEqual(samplelayers.layer, self.layerv)
+        self.assertEqual(samplelayers.layerx, self.layerx)
+    def test_z0(self):
+        self.assertEqual(z, 0)
+        self.assertEqual(samplelayers.layer, self.layerv)
+        self.assertEqual(samplelayers.layerx, self.layerx)
+
+class TestB1(unittest.TestCase, Layered):
+    def setUp(self):
+        global y
+        y = 1
+    def tearDown(self):
+        global y
+        y = 0
+    def test_y1(self):
+        self.assertEqual(y, 1)
+        self.assertEqual(samplelayers.layer, self.layerv)
+        self.assertEqual(samplelayers.layerx, self.layerx)
+    def test_x0(self):
+        self.assertEqual(x, 0)
+        self.assertEqual(samplelayers.layer, self.layerv)
+        self.assertEqual(samplelayers.layerx, self.layerx)
+    def test_z0(self):
+        self.assertEqual(z, 0)
+        self.assertEqual(samplelayers.layer, self.layerv)
+        self.assertEqual(samplelayers.layerx, self.layerx)
+
+
+class TestNotMuch1(unittest.TestCase, Layered):
+    def test_1(self):
+        self.assertEqual(samplelayers.layer, self.layerv)
+        self.assertEqual(samplelayers.layerx, self.layerx)
+    def test_2(self):
+        self.assertEqual(samplelayers.layer, self.layerv)
+        self.assertEqual(samplelayers.layerx, self.layerx)
+    def test_3(self):
+        self.assertEqual(samplelayers.layer, self.layerv)
+        self.assertEqual(samplelayers.layerx, self.layerx)
+
+
+
+def test_suite():
+    suite = unittest.TestSuite()
+    suite.addTest(unittest.makeSuite(TestA))
+    suite.addTest(unittest.makeSuite(TestA2))
+    suite.addTest(unittest.makeSuite(TestB))
+    suite.addTest(unittest.makeSuite(TestNotMuch))
+    suite.addTest(doctest.DocTestSuite(setUp=setUp))
+    suite.addTest(doctest.DocFileSuite('sampletests.txt', setUp=setUp))
+    suite.addTest(unittest.makeSuite(TestA1))
+    suite.addTest(unittest.makeSuite(TestB1))
+    suite.addTest(unittest.makeSuite(TestNotMuch1))
+    return suite

Added: zope.testing/trunk/src/zope/testing/testrunner-ex/sampletestsl.txt
===================================================================
--- zope.testing/trunk/src/zope/testing/testrunner-ex/sampletestsl.txt	2005-05-24 20:28:14 UTC (rev 30491)
+++ zope.testing/trunk/src/zope/testing/testrunner-ex/sampletestsl.txt	2005-05-24 20:28:53 UTC (rev 30492)
@@ -0,0 +1,28 @@
+This is a sample doctest
+
+    >>> x=1
+    >>> x
+    1
+
+Blah blah blah
+
+    >>> x
+    1
+
+Blah blah blah
+
+    >>> x
+    1
+
+Blah blah blah
+
+    >>> x
+    1
+
+are we in the right laters?
+
+    >>> import samplelayers
+    >>> layer == samplelayers.layer
+    True
+    >>> layerx == samplelayers.layerx
+    True

Added: zope.testing/trunk/src/zope/testing/testrunner.py
===================================================================
--- zope.testing/trunk/src/zope/testing/testrunner.py	2005-05-24 20:28:14 UTC (rev 30491)
+++ zope.testing/trunk/src/zope/testing/testrunner.py	2005-05-24 20:28:53 UTC (rev 30492)
@@ -0,0 +1,971 @@
+##############################################################################
+#
+# Copyright (c) 2004 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.
+#
+##############################################################################
+"""Test runner
+
+$Id$
+"""
+
+# Too bad: For now, we depend on zope.testing.  This is because
+# we want to use the latest, greatest doctest, which zope.testing
+# provides.  Then again, zope.testing is generally useful.
+from zope.testing import doctest
+import gc
+import logging
+import optparse
+import os
+import pdb
+import re
+import sys
+import time
+import traceback
+import threading
+import unittest
+
+
+def run(defaults=None, args=None):
+    options = get_options(args, defaults)
+    run_with_options(options)
+
+def run_with_options(options):
+
+    if options.verbose:
+        if options.all:
+            print "Running tests at all levels"
+        else:
+            print "Running tests at level %d" % options.at_level
+
+    
+    # XXX add tracing later
+
+    # Add directories to the path
+    for path in options.path:
+        if path not in sys.path:
+            sys.path.append(path)
+
+    remove_stale_bytecode(options)
+
+    configure_logging()
+
+    tests_by_layer_name = find_tests(options)
+
+
+    ran = 0
+    failures = []
+    errors = []
+    nlayers = 0
+    if 'unit' in tests_by_layer_name:
+        tests = tests_by_layer_name.pop('unit')
+        if not options.non_unit:
+            if options.layer:
+                should_run = False
+                for pat in options.layer:
+                    if pat('unit'):
+                        should_run = True
+                        break
+            else:
+                should_run = True
+                
+            if should_run:
+                print "Running unit tests:"
+                nlayers += 1
+                ran += run_tests(options, tests, 'unit', failures, errors)
+        
+    setup_layers = {}
+    for layer_name, layer, tests in ordered_layers(tests_by_layer_name):
+        if options.layer:
+            should_run = False
+            for pat in options.layer:
+                if pat(layer_name):
+                    should_run = True
+                    break
+        else:
+            should_run = True
+
+        if should_run:
+            nlayers += 1
+            ran += run_layer(options, layer_name, layer, tests, setup_layers,
+                             failures, errors)
+
+    if setup_layers:
+        print "Tearing down left over layers:"
+        tear_down_unneeded((), setup_layers)
+
+    if options.verbose > 1:
+        if errors:
+            print
+            print "Tests with errors:"
+            for test, exc_info in errors:
+                print "  ", test
+
+        if failures:
+            print
+            print "Tests with failures:"
+            for test, exc_info in failures:
+                print "  ", test
+
+    if nlayers != 1:
+        print "Total: %s tests, %s failures, %s errors" % (
+            ran, len(failures), len(errors))
+    
+
+def run_tests(options, tests, name, failures, errors):
+    repeat = options.repeat or 1
+    ran = 0
+    for i in range(repeat):
+        if repeat > 1:
+            print "Iteration", i+1
+
+        if options.verbose > 0 or options.progress:
+            print '  Running:'
+        if options.verbose == 1 and not options.progress:
+            print '    ',
+        result = TestResult(options, tests)
+        t = time.time()
+        tests(result)
+        t = time.time() - t
+        if options.verbose == 1 or options.progress:
+            print
+        failures.extend(result.failures)
+        errors.extend(result.errors)
+        print (
+            "  Ran %s tests with %s failures and %s errors in %.3f seconds." %
+            (result.testsRun, len(result.failures), len(result.errors), t)
+            )
+        ran += result.testsRun
+
+    return ran
+    
+
+def run_layer(options, layer_name, layer, tests, setup_layers,
+              failures, errors):
+    print "Running %s tests:" % layer_name
+
+    gathered = []
+    gather_layers(layer, gathered)
+    needed = dict([(l, 1) for l in gathered])
+    tear_down_unneeded(needed, setup_layers)
+
+    setup_layer(layer, setup_layers)
+    return run_tests(options, tests, layer_name, failures, errors)
+
+def tear_down_unneeded(needed, setup_layers):
+    # Tear down any layers not needed for these tests. The unneeded
+    # layers might interfere.
+    unneeded = [l for l in setup_layers if l not in needed]
+    unneeded = order_by_bases(unneeded)
+    unneeded.reverse()
+    for l in unneeded:
+        print "  Tear down %s" % name_from_layer(l),
+        t = time.time()
+        l.tearDown()
+        del setup_layers[l]
+        print "in %.3f seconds." % (time.time() - t)
+    
+
+def setup_layer(layer, setup_layers):
+    if layer not in setup_layers:
+        for base in layer.__bases__:
+            setup_layer(base, setup_layers)
+        print "  Set up %s.%s" % (layer.__module__, layer.__name__),
+        t = time.time()
+        layer.setUp()
+        print "in %.3f seconds." % (time.time() - t)
+        setup_layers[layer] = 1
+
+def dependencies(bases, result):
+    for base in bases:
+        result[base] = 1
+        dependencies(base.__bases__, result)
+    
+    
+
+class TestResult(unittest.TestResult):
+
+    def __init__(self, options, tests):
+        unittest.TestResult.__init__(self)
+        self.options = options
+        if options.progress:
+            count = 0
+            for test in tests:
+                count += test.countTestCases()
+            self.count = count
+        self.last_width = 0
+
+    def startTest(self, test):
+        unittest.TestResult.startTest(self, test)
+        testsRun = self.testsRun - 1
+        count = test.countTestCases()
+        self.testsRun = testsRun + count
+        options = self.options
+        self.test_width = 0
+
+        if options.progress:
+            s = "    %d/%d (%.1f%%)" % (
+                self.testsRun, self.count,
+                (self.testsRun) * 100.0 / self.count
+                )
+            sys.stdout.write(s)
+            self.test_width += len(s)
+            
+        elif options.verbose == 1:
+            for i in range(count):
+                sys.stdout.write('.')
+                testsRun += 1
+                if (testsRun % 50) == 0:
+                    print
+                    print '    ',
+        elif options.verbose > 1:
+            print '   ',
+            
+        if options.verbose > 1:
+            s = str(test)
+            sys.stdout.write(' ')
+            sys.stdout.write(s)
+            self.test_width += len(s) + 1
+
+        sys.stdout.flush()
+
+        self._threads = threading.enumerate()
+        self._start_time = time.time()
+
+    def addSuccess(self, test):
+        if self.options.verbose > 2:
+            t = max(time.time() - self._start_time, 0.0)
+            s = " (%.3f ms)" % t
+            sys.stdout.write(s)
+            self.test_width += len(s) + 1
+
+    def addError(self, test, exc_info):
+        if self.options.verbose > 2:
+            print " (%.3f ms)" % (time.time() - self._start_time)
+
+        unittest.TestResult.addError(self, test, exc_info)
+        print
+        self._print_traceback("Error in test %s" % test, exc_info)
+
+        if self.options.post_mortem:
+            post_mortem(exc_info)
+
+        self.test_width = self.last_width = 0
+
+    def addFailure(self, test, exc_info):
+        
+        if self.options.verbose > 2:
+            print " (%.3f ms)" % (time.time() - self._start_time)
+
+        unittest.TestResult.addFailure(self, test, exc_info)
+        print
+        self._print_traceback("Failure in test %s" % test, exc_info)
+
+        if self.options.post_mortem:
+            post_mortem(exc_info)
+
+        self.test_width = self.last_width = 0
+
+
+    def _print_traceback(self, msg, exc_info):
+        print
+        print msg
+
+        v = exc_info[1]
+        if isinstance(v, doctest.DocTestFailureException):
+            tb = v.args[0]
+        else:
+            tb = "".join(traceback.format_exception(*exc_info))
+
+        print tb
+
+    def stopTest(self, test):
+        if self.options.progress:
+            sys.stdout.write(' ' * (self.last_width - self.test_width) + "\r")
+            self.last_width = self.test_width
+        elif self.options.verbose > 1:
+            print
+
+        if gc.garbage:
+            print "The following test left garbage:"
+            print test
+            print gc.garbage
+            # TODO: Perhaps eat the garbage here, so that the garbage isn't
+            #       printed for every subsequent test.
+
+        # Did the test leave any new threads behind?
+        new_threads = [t for t in threading.enumerate()
+                         if (t.isAlive()
+                             and
+                             t not in self._threads)]
+        if new_threads:
+            print "The following test left new threads behind:"
+            print test
+            print "New thread(s):", new_threads
+
+        sys.stdout.flush()
+
+def post_mortem(exc_info):
+    err = exc_info[1]
+    if isinstance(err, (doctest.UnexpectedException, doctest.DocTestFailure)):
+
+        if isinstance(err, doctest.UnexpectedException):
+            exc_info = err.exc_info
+
+            # Print out location info if the error was in a doctest
+            if exc_info[2].tb_frame.f_code.co_filename == '<string>':
+                print_doctest_location(err)
+            
+        else:
+            print_doctest_location(err)
+            # Hm, we have a DocTestFailure exception.  We need to
+            # generate our own traceback
+            try:
+                exec ('raise ValueError'
+                      '("Expected and actual output are different")'
+                      ) in err.test.globs
+            except:
+                exc_info = sys.exc_info()
+        
+    print "%s:" % (exc_info[0], )
+    print exc_info[1]
+    pdb.post_mortem(exc_info[2])
+    sys.exit()
+
+def print_doctest_location(err):
+    # This mimicks pdb's output, which gives way cool results in emacs :)
+    filename = err.test.filename
+    if filename.endswith('.pyc'):
+        filename = filename[:-1]
+    print "> %s(%s)_()" % (filename, err.test.lineno+err.example.lineno+1)
+
+def ordered_layers(tests_by_layer_name):
+    layer_names = dict([(layer_from_name(layer_name), layer_name)
+                        for layer_name in tests_by_layer_name])
+    for layer in order_by_bases(layer_names):
+        layer_name = layer_names[layer]
+        yield layer_name, layer, tests_by_layer_name[layer_name]
+
+def gather_layers(layer, result):
+    result.append(layer)
+    for b in layer.__bases__:
+        gather_layers(b, result)
+
+def layer_from_name(layer_name):
+    layer_names = layer_name.split('.')
+    layer_module, module_layer_name = layer_names[:-1], layer_names[-1]
+    return getattr(import_name('.'.join(layer_module)), module_layer_name)
+
+
+def order_by_bases(layers):
+    """Order the layers from least to most specific (bottom to top)
+    """
+    named_layers = [(name_from_layer(layer), layer) for layer in layers]
+    named_layers.sort()
+    gathered = []
+    for name, layer in named_layers:
+        gather_layers(layer, gathered)
+    gathered.reverse()
+    seen = {}
+    result = []
+    for layer in gathered:
+        if layer not in seen:
+            seen[layer] = 1
+            if layer in layers:
+                result.append(layer)
+    return result
+
+def name_from_layer(layer):
+    return layer.__module__ + '.' + layer.__name__
+
+def find_tests(options):
+    suites = {}
+    for suite in find_suites(options):
+        for test, layer_name in tests_from_suite(suite, options):
+            suite = suites.get(layer_name)
+            if not suite:
+                suite = suites[layer_name] = unittest.TestSuite()
+            suite.addTest(test)
+    return suites
+
+def tests_from_suite(suite, options, dlevel=1, dlayer='unit'):
+    level = getattr(suite, 'level', dlevel)
+    layer = getattr(suite, 'layer', dlayer)
+    if not isinstance(layer, basestring):
+        layer = layer.__module__ + '.' + layer.__name__
+        
+    if isinstance(suite, unittest.TestSuite):
+        for possible_suite in suite:
+            for r in tests_from_suite(possible_suite, options, level, layer):
+                yield r
+    else:
+        if level <= options.at_level:
+            for pat in options.test:
+                if pat(str(suite)):
+                    yield (suite, layer)
+                    break
+
+def find_suites(options):
+    for fpath in find_test_files(options):
+        for prefix in options.prefix:
+            if fpath.startswith(prefix):
+                # strip prefix, strip .py suffix and convert separator to dots
+                module_name = fpath[len(prefix):-3].replace(os.path.sep, '.')
+                try:
+                    module = import_name(module_name)
+                    suite = getattr(module, options.suite_name)()
+                except:
+                    suite = StartUpFailure(
+                        options,
+                        "Couldn't get suite for %s" % module_name,
+                        sys.exc_info()
+                        )
+                
+                yield suite
+                break
+
+class StartUpFailure(unittest.TestCase):
+
+    def __init__(self, options, message, exc_info):
+        if options.post_mortem:
+            post_mortem(exc_info)
+        unittest.TestCase.__init__(self)
+        self.message = message
+        self.exc_info = exc_info
+
+    def __str__(self):
+        return "Startup failure: %s" % self.message
+    
+    def runTest(self):
+        raise self.exc_info[0], self.exc_info[1], self.exc_info[2]
+
+
+def find_test_files(options):
+    found = {}
+    for f in find_test_files_(options):
+        for filter in options.module:
+            if filter(f):
+                if f not in found:
+                    found[f] = 1
+                    yield f
+                    break
+
+def find_test_files_(options):
+    tests_pattern = options.tests_pattern
+    test_file_pattern = options.test_file_pattern
+    for p in test_dirs(options, {}):
+        for dirname, dirs, files in walk_with_symlinks(options, p):
+            d = os.path.split(dirname)[1]
+            if tests_pattern(d) and ('__init__.py' in files):
+                # tests directory
+                for file in files:
+                    if file.endswith('.py') and test_file_pattern(file[:-3]):
+                        f = os.path.join(dirname, file)
+                        yield f
+
+            for file in files:
+                if file.endswith('.py') and tests_pattern(file[:-3]):
+                    f = os.path.join(dirname, file)
+                    yield f
+
+
+def walk_with_symlinks(options, dir):
+    for dirpath, dirs, files in os.walk(dir):
+        dirs[:] = [d for d in dirs if d not in options.ignore_dir]
+        yield (dirpath, dirs, files)
+        for d in dirs:
+            p = os.path.join(dirpath, d)
+            if os.path.islink(p):
+                for dirpath, dirs, files in walk_with_symlinks(options, p):
+                    yield (dirpath, dirs, files)
+
+compiled_sufixes = '.pyc', '.pyo'
+def remove_stale_bytecode(options):
+    if options.keepbytecode:
+        return
+    for p in options.path:
+        for dirname, dirs, files in walk_with_symlinks(options, p):
+            for file in files:
+                if file[-4:] in compiled_sufixes and file[:-1] not in files:
+                    fullname = os.path.join(dirname, file)
+                    print "Removing stale bytecode file", fullname
+                    os.unlink(fullname)
+
+
+def test_dirs(options, seen):
+    if options.package:
+        for p in options.package:
+            p = import_name(p)
+            for p in p.__path__:
+                p = os.path.abspath(p)
+                if p in seen:
+                    continue
+                for prefix in options.prefix:
+                    if p.startswith(prefix):
+                        seen[p] = 1
+                        yield p
+                        break
+    else:
+        for dpath in options.path:
+            yield dpath
+
+
+def import_name(name):
+    __import__(name)
+    return sys.modules[name]
+
+def configure_logging():
+    """Initialize the logging module."""
+    import logging.config
+
+    # Get the log.ini file from the current directory instead of
+    # possibly buried in the build directory.  TODO: This isn't
+    # perfect because if log.ini specifies a log file, it'll be
+    # relative to the build directory.  Hmm...  logini =
+    # os.path.abspath("log.ini")
+
+    logini = os.path.abspath("log.ini")
+    if os.path.exists(logini):
+        logging.config.fileConfig(logini)
+    else:
+        # If there's no log.ini, cause the logging package to be
+        # silent during testing.
+        root = logging.getLogger()
+        root.addHandler(NullHandler())
+        logging.basicConfig()
+
+    if os.environ.has_key("LOGGING"):
+        level = int(os.environ["LOGGING"])
+        logging.getLogger().setLevel(level)
+
+class NullHandler(logging.Handler):
+    """Logging handler that drops everything on the floor.
+
+    We require silence in the test environment.  Hush.
+    """
+
+    def emit(self, record):
+        pass
+
+
+
+###############################################################################
+# Command-line UI
+
+parser = optparse.OptionParser("Usage: %prog [options] [MODULE] [TEST]")
+
+######################################################################
+# Searching and filtering
+
+searching = optparse.OptionGroup(parser, "Searching and filtering", """\
+Options in this group are used to define which tests to run.
+""")
+
+searching.add_option(
+    '--package', '--dir', '-s', action="append", dest='package',
+    help="""\
+Search the given package's directories for tests.  This can be
+specified more than once to run tests in multiple parts of the source
+tree.  For example, if refactoring interfaces, you don't want to see
+the way you have broken setups for tests in other packages. You *just*
+want to run the interface tests.
+
+Packages are supplied as dotted names.  For compatibility with the old
+test runner, forward and backward slashed in package names are
+converted to dots.
+
+(In the special case of packages spread over multiple directories,
+only directories within the test search path are searched. See the
+--path option.)
+
+""")
+
+searching.add_option(
+    '--module', '-m', action="append", dest='module',
+    help="""\
+Specify a test-module filter as a regular expression.  This is a
+case-sensitive regular expression, used in search (not match) mode, to
+limit which test modules are searched for tests.  In an extension of
+Python regexp notation, a leading "!" is stripped and causes the sense
+of the remaining regexp to be negated (so "!bc" matches any string
+that does not match "bc", and vice versa).  The option can be
+specified multiple test-module filters.  Test modules matching any of
+the test filters are searched.  If no test-module filter is specified,
+then all test moduless are used.
+""")
+
+searching.add_option(
+    '--test', '-t', action="append", dest='test',
+    help="""\
+Specify a test filter as a regular expression.  This is a
+case-sensitive regular expression, used in search (not match) mode, to
+limit which tests are run.  In an extension of Python regexp notation,
+a leading "!" is stripped and causes the sense of the remaining regexp
+to be negated (so "!bc" matches any string that does not match "bc",
+and vice versa).  The option can be specified multiple test filters.
+Tests matching any of the test filters are included.  If no test
+filter is specified, then all tests are run.
+""")
+
+searching.add_option(
+    '--unit', '-u', action="store_true", dest='unit',
+    help="""\
+Run only unit tests, ignoring any layer options.
+""")
+
+searching.add_option(
+    '--non-unit', '-f', action="store_true", dest='non_unit',
+    help="""\
+Run tests other than unit tests.
+""")
+
+searching.add_option(
+    '--layer', action="append", dest='layer',
+    help="""\
+Specify a test layer to run.  The option can be given multiple times
+to specify more than one layer.  If not specified, all layers are run.
+It is common for the running script to provide default values for this
+option.  Layers are specified regular expressions, used in search
+mode, for dotted names of objects that define a layer.  In an
+extension of Python regexp notation, a leading "!" is stripped and
+causes the sense of the remaining regexp to be negated (so "!bc"
+matches any string that does not match "bc", and vice versa).  The
+layer named 'unit' is reserved for unit tests, however, take note of
+the --unit and non-unit options.
+""")
+
+searching.add_option(
+    '-a', '--at-level', type='int', dest='at_level',
+    help="""\
+Run the tests at the given level.  Any test at a level at or below
+this is run, any test at a level above this is not run.  Level 0
+runs all tests.
+""")
+
+searching.add_option(
+    '--all', action="store_true", dest='all',
+    help="Run tests at all levels.")
+
+parser.add_option_group(searching)
+
+######################################################################
+# Reporting
+
+reporting = optparse.OptionGroup(parser, "Reporting", """\
+Reporting options control basic aspects of test-runner output
+""")
+
+reporting.add_option(
+    '--verbose', '-v', action="count", dest='verbose',
+    help="""\
+Increment the verbosity level.
+""")
+
+reporting.add_option(
+    '--progress', '-p', action="store_true", dest='progress',
+    help="""\
+Output progress status
+""")
+
+def report_only_first_failure(*args):
+    old = doctest.set_unittest_reportflags(0)
+    doctest.set_unittest_reportflags(old | doctest.REPORT_ONLY_FIRST_FAILURE)
+    
+reporting.add_option(
+    '-1', action="callback", callback=report_only_first_failure,
+    help="""\
+Report only the first failure in a doctest. (Examples after the
+failure are still executed, in case they do any cleanup.)
+""")
+
+parser.add_option_group(reporting)
+
+######################################################################
+# Analysis
+
+analysis = optparse.OptionGroup(parser, "Analysis", """\
+Analysis options provide tools for analysing test output.
+""")
+
+
+analysis.add_option(
+    '--post-mortem', '-D', action="store_true", dest='post_mortem',
+    help="Enable post-mortem debugging of test failures"
+    )
+
+
+def gc_callback(option, opt, GC_THRESHOLD, *args):
+    import gc
+    if GC_THRESHOLD == 0:
+        gc.disable()
+        print "gc disabled"
+    else:
+        gc.set_threshold(GC_THRESHOLD)
+        print "gc threshold:", gc.get_threshold()
+    
+analysis.add_option(
+    '--gc', action="callback", callback=gc_callback, dest='gc', type="int",
+    help="""\
+Set the garbage collector generation0 threshold.  This can be used
+to stress memory and gc correctness.  Some crashes are only
+reproducible when the threshold is set to 1 (agressive garbage
+collection).  Do "--gc 0" to disable garbage collection altogether.
+""")
+
+analysis.add_option(
+    '--repeat', action="store", type="int", dest='repeat',
+    help="""\
+Repeat the testst the given number of times.  This option is used to
+make sure that tests leave thier environment in the state they found
+it and, with the --refcount option to look for memory leaks.
+""")
+
+def refcount_available(*args):
+    if not hasattr(sys, "gettotalrefcount"):
+        raise optparse.OptionValueError("""\
+The Python you are running was not configured with --with-pydebug.
+This is required to use the --refount option.
+""")
+    
+analysis.add_option(
+    '--refcount',
+    action="callback", callback=refcount_available,
+    dest='refcount',
+    help="""\
+After each run of the tests, output a report summarizing changes in
+refcounts by object type.  This option that requires that Python was
+built with the --with-pydebug option to configure.
+""")
+
+analysis.add_option(
+    '--coverage', action="store", dest='coverage',
+    help="""\
+Perform code-coverage analysis, saving trace data to the directory
+with the given anme.  A code coverage summary is printed to standard
+out.
+""")
+
+def do_pychecker(*args):
+    if not os.environ.get("PYCHECKER"):
+        os.environ["PYCHECKER"] = "-q"
+    import pychecker.checker
+    
+analysis.add_option(
+    '--pychecker', action="callback", callback=do_pychecker,
+    help="""\
+Run the tests under pychecker
+""")
+
+parser.add_option_group(analysis)
+
+######################################################################
+# Setup
+
+setup = optparse.OptionGroup(parser, "Setup", """\
+Setup options are normally supplied by the testrunner script, although
+they can be overridden by users.
+""")
+
+setup.add_option(
+    '--path', action="append", dest='path',
+    help="""\
+Specify a path to be added to Python's search path.  This option can
+be used multiple times to specify multiple search paths.  The path is
+usually specified by the test-runner script itself, rather than by
+users of the script, although it can be overridden by users.  Only
+tests found in the path will be run.
+""")
+
+setup.add_option(
+    '--tests-pattern', action="store", dest='tests_pattern',
+    help="""\
+Specify the pattern for identifying tests modules. Tests modules are
+packages containing test modules or modules containing tests.  When
+searching for tests, the test runner looks for modules or packages
+with this name.
+""")
+
+setup.add_option(
+    '--suite-name', action="store", dest='suite_name',
+    help="""\
+Specify the name of the object in each test_module that contains the
+module's test suite.
+""")
+
+setup.add_option(
+    '--test-file-pattern', action="store", dest='test_file_pattern',
+    help="""\
+Specify the name of tests modules. Tests modules are packages
+containing test files or modules containing tests.  When searching for
+tests, the test runner looks for modules or packages with this name.
+""")
+
+setup.add_option(
+    '--ignore_dir', action="append", dest='ignore_dir',
+    help="""\
+Specifies the name of a directory to ignore when looking for tests.
+""")
+
+parser.add_option_group(setup)
+
+######################################################################
+# Other
+
+other = optparse.OptionGroup(parser, "Other", "Other options")
+
+other.add_option(
+    '--keepbytecode', '-k', action="store_true", dest='keepbytecode',
+    help="""\
+Normally, the test runner scans the test paths and the test
+directories looking for and deleting pyc or pyo files without
+corresponding py files.  This is to prevent spurious test failures due
+to finding compiled moudules where source modules have been deleted.
+This scan can be time consuming.  Using this option disables this
+scan.  If you know you haven't removed any modules since last running
+the tests, can make the test run go much faster.
+""")
+
+parser.add_option_group(other)
+
+######################################################################
+# Command-line processing
+
+def compile_filter(pattern):
+    if pattern.startswith('!'):
+        pattern = re.compile(pattern[1:]).search
+        return (lambda s: not pattern(s))
+    return re.compile(pattern).search
+
+def merge_options(options, defaults):
+    odict = options.__dict__
+    for name, value in defaults.__dict__.items():
+        if (value is not None) and (odict[name] is None):
+            odict[name] = value
+
+default_setup_args = [
+    '--tests-pattern', '^tests$',
+    '--at-level', 1,
+    '--ignore', '.svn',
+    '--ignore', 'CVS',
+    '--ignore', '{arch}',
+    '--ignore', '.arch-ids',
+    '--ignore', '_darcs',
+    '--test-file-pattern', '^test',
+    '--suite-name', 'test_suite',
+    ]
+
+def get_options(args=None, defaults=None):
+
+    default_setup, _ = parser.parse_args(default_setup_args)
+    assert not _
+    if defaults:
+        defaults, _ = parser.parse_args(defaults)
+        assert not _
+        merge_options(defaults, default_setup)
+    else:
+        defaults = default_setup
+    
+    if args is None:
+        args = sys.argv[1:]
+    options, positional = parser.parse_args(args)
+    merge_options(options, defaults)
+
+    if positional:
+        module_filter = positional.pop()
+        if module_filter != '.':
+            if options.module:
+                options.module.append(module_filter)
+            else:
+                options.module = [module_filter]
+            
+        if positional:
+            test_filter = [positional]
+            if options.test:
+                options.test.append(test_filter)
+            else:
+                options.test = [test_filter]
+
+    options.ignore_dir = dict([(d,1) for d in options.ignore_dir])
+    options.test_file_pattern = re.compile(options.test_file_pattern).search
+    options.tests_pattern = re.compile(options.tests_pattern).search
+    options.test = map(compile_filter, options.test or ('.'))
+    options.module = map(compile_filter, options.module or ('.'))
+        
+    if options.package:
+        options.package = [p.replace('/', '.').replace('\\', '.')
+                           for p in options.package]
+    options.path = map(os.path.abspath, options.path)
+    options.prefix = [p + os.path.sep for p in options.path]
+    if options.all:
+        options.at_level = sys.maxint
+    
+    if options.unit:
+        options.layer = ['unit']
+    if options.layer:
+        options.layer = map(compile_filter, options.layer)
+
+    options.layer = options.layer and dict([(l, 1) for l in options.layer])
+    
+    return options
+
+# Command-line UI
+###############################################################################
+
+###############################################################################
+# Install 2.4 TestSuite __iter__ into earlier versions
+
+if sys.version_info < (2, 4):
+    def __iter__(suite):
+        return iter(suite._tests)
+    unittest.TestSuite.__iter__ = __iter__
+    del __iter__
+
+# Install 2.4 TestSuite __iter__ into earlier versions
+###############################################################################
+
+###############################################################################
+# Test the testrunner
+
+def test_suite():
+
+    import renormalizing
+    checker = renormalizing.RENormalizing([
+        (re.compile('\\\\'), '/'),   # hopefully, we'll make windows happy
+        (re.compile('/r'), '\\\\r'), # undo damage from previous 
+        (re.compile(r'\r'), '\\\\r\n'),
+        (re.compile(r'0[.]\d\d\d seconds'), '0.NNN seconds'),
+        (re.compile(r'\d+[.]\d\d\d ms'), 'N.NNN ms'),
+        (re.compile('( |")[^\n]+testrunner-ex'), r'\1testrunner-ex'),
+        (re.compile('"[^\n]+(doc|unit)test.py'), r'".../\1test.py'),
+        ])
+
+    def setUp(test):
+        test.globs['saved-sys-info'] = sys.path, sys.argv
+        test.globs['this_directory'] = os.path.split(__file__)[0]
+
+    def tearDown(test):
+        sys.path, sys.argv = test.globs['saved-sys-info']
+
+    return doctest.DocFileSuite('testrunner.txt',
+                                setUp=setUp, tearDown=tearDown,
+                                checker=checker)
+
+def main():
+    default = [
+        '--path', os.path.split(sys.argv[0])[0],
+        '--tests-pattern', '^testrunner$',
+        ]
+    run(default)
+
+if __name__ == '__main__':
+    main()
+
+# Test the testrunner
+###############################################################################

Added: zope.testing/trunk/src/zope/testing/testrunner.txt
===================================================================
--- zope.testing/trunk/src/zope/testing/testrunner.txt	2005-05-24 20:28:14 UTC (rev 30491)
+++ zope.testing/trunk/src/zope/testing/testrunner.txt	2005-05-24 20:28:53 UTC (rev 30492)
@@ -0,0 +1,1332 @@
+Test Runner
+===========
+
+The testrunner module is used to run automated tests defined using the
+unittest framework.  It's primary feature is that it *finds* tests by
+searching directory trees.  It doesn't require the manual
+concatination of specific test suites.  It is highly customizable and
+should be usable with any project.  In addition to finding and running
+tests, it provides the folloawing additional features:
+
+- Test filtering using specifications of:
+
+  o test packages within a larger tree
+
+  o regular expression patters for test modules
+
+  o regular expression patters for individual tests
+
+- Organization of tests into lavels and layers
+
+  Sometimes, tests take so long to run that you don't want to run them
+  on every run of the test runner.  Tests can be defined at different
+  levels. The test runner can be configured to only run tests at a
+  specific level or below by default.  Command-line options can be
+  used to specify a minimum level to use for a specific run, or to run
+  all tests.  Individual tests or test suites can specify their level
+  via a 'level' attribute. where levels are integers increasing from 1.
+
+  Most tests are unit tests. They don;t depend on other facilities or
+  set up whatever dependencies they have.  For larger applications,
+  it's useful to specify common facilities that a large number of
+  tests share.  Making each test set up and and tear down these
+  facilities is both ineffecient and inconvenient. For this reason,
+  we've introduced the concept of layers, based on the idea of layered
+  application architectures.  Software build for a layer should be
+  able to depend on the facilities of lower layers already beeing set
+  up.  For example, Zope defines a component architecture.  Much Zope
+  software depends on that architecture.  We should be able to treat
+  the compent architecture as a layer that we set up once and reuse.
+  Similarly, zope application software should be able to depend on the
+  Zope application server without having to set it up in each test.
+  
+  The test runner introduces test layers, which are objects that can
+  set up environments for tests within the layers to use.  A layer is
+  set up before running the tests in it.  Individual tests or test
+  suites can define a layer by defining a `layer` attribute, which is
+  a test layer.
+
+- Reporting
+
+  - Progress meter
+
+  - summaries of tests run
+
+- Analysis of test execution
+
+  - Post-mortem debugging of test failures 
+
+  - memory leaks
+
+  - code coverage
+
+  - source analysis using pychecker
+
+  - memory errors
+
+  - execution times
+
+  - profiling
+
+Simple Usage
+------------
+
+The test runner consists of an importable module.  The test runner is
+used by providing scripts that import and invoke the `run` method from
+the module.  The `testrunner` module is controlled via command-line
+options.  Test scripts supply base and default options by supplying a
+list of default command-line options that are processed before the
+user-supplied command-line options are provided.
+
+Typically, a test script does 2 things:
+
+- Adds the directory containing the zope package to the Python
+  path:
+
+    >>> import os, sys
+    >>> directory_with_tests = os.path.join(this_directory, 'testrunner-ex')
+    >>> sys.path.append(directory_with_tests)
+
+- Calls the test runner with default arguments and arguments supplied
+  to the script.
+
+  Normally, it just passes default/setup arguments. The test runner
+  uses `sys.argv` to get the user's input.
+
+This directory contains a number of sample packages with tests.
+Let's run the tests found here. First though, we'll set up our default
+options:
+
+    >>> defaults = [
+    ...     '--path', directory_with_tests,
+    ...     '--tests-pattern', '^sampletestsf?$',
+    ...     ]
+
+The default options are used by a script to customize the test runner
+for a particular application.  In this case, we use two options:
+
+path
+  Set the path where the test runner should look for tests.  This path
+  is also added to the Python path.
+
+tests-pattern
+  Tell the test runner how to recognize modules or packages containing
+  tests.
+
+Now, if we run the tests, without any other options:
+
+    >>> from zope.testing import testrunner
+    >>> sys.argv = ['test']
+    >>> testrunner.run(defaults)
+    Running unit tests:
+      Ran 192 tests with 0 failures and 0 errors in 0.034 seconds.
+    Running samplelayers.Layer1 tests:
+      Set up samplelayers.Layer1 in 0.000 seconds.
+      Ran 9 tests with 0 failures and 0 errors in 0.000 seconds.
+    Running samplelayers.Layer12 tests:
+      Set up samplelayers.Layer12 in 0.000 seconds.
+      Ran 34 tests with 0 failures and 0 errors in 0.006 seconds.
+    Running samplelayers.Layer122 tests:
+      Set up samplelayers.Layer122 in 0.000 seconds.
+      Ran 34 tests with 0 failures and 0 errors in 0.006 seconds.
+    Running samplelayers.Layer121 tests:
+      Tear down samplelayers.Layer122 in 0.000 seconds.
+      Set up samplelayers.Layer121 in 0.000 seconds.
+      Ran 34 tests with 0 failures and 0 errors in 0.007 seconds.
+    Running samplelayers.Layer11 tests:
+      Tear down samplelayers.Layer121 in 0.000 seconds.
+      Tear down samplelayers.Layer12 in 0.000 seconds.
+      Set up samplelayers.Layer11 in 0.000 seconds.
+      Ran 34 tests with 0 failures and 0 errors in 0.007 seconds.
+    Running samplelayers.Layer112 tests:
+      Set up samplelayers.Layerx in 0.000 seconds.
+      Set up samplelayers.Layer112 in 0.000 seconds.
+      Ran 34 tests with 0 failures and 0 errors in 0.007 seconds.
+    Running samplelayers.Layer111 tests:
+      Tear down samplelayers.Layer112 in 0.000 seconds.
+      Set up samplelayers.Layer111 in 0.000 seconds.
+      Ran 34 tests with 0 failures and 0 errors in 0.007 seconds.
+    Tearing down left over layers:
+      Tear down samplelayers.Layer111 in 0.000 seconds.
+      Tear down samplelayers.Layer11 in 0.000 seconds.
+      Tear down samplelayers.Layer1 in 0.000 seconds.
+      Tear down samplelayers.Layerx in 0.000 seconds.
+    Total: 405 tests, 0 failures, 0 errors
+
+we see the normal testrunner output, which summarizes the tests runfor
+each layer.  For each layer, we see what layers had to be torn down or
+set up to run the layer and we see the number of tests run, with
+results.
+
+(Of course, the times shown in these examples are just examples.
+Times will vary depending on system speed.)
+
+Layer Selection
+---------------
+
+We can select which layers to run using the --layer option:
+
+    >>> sys.argv = 'test --layer 112 --layer unit'.split()
+    >>> testrunner.run(defaults)
+    Running unit tests:
+      Ran 192 tests with 0 failures and 0 errors in 0.032 seconds.
+    Running samplelayers.Layer112 tests:
+      Set up samplelayers.Layerx in 0.000 seconds.
+      Set up samplelayers.Layer1 in 0.000 seconds.
+      Set up samplelayers.Layer11 in 0.000 seconds.
+      Set up samplelayers.Layer112 in 0.000 seconds.
+      Ran 34 tests with 0 failures and 0 errors in 0.007 seconds.
+    Tearing down left over layers:
+      Tear down samplelayers.Layer112 in 0.000 seconds.
+      Tear down samplelayers.Layer11 in 0.000 seconds.
+      Tear down samplelayers.Layer1 in 0.000 seconds.
+      Tear down samplelayers.Layerx in 0.000 seconds.
+    Total: 226 tests, 0 failures, 0 errors
+
+We can also specify that we want to run only the unit tests:
+
+    >>> sys.argv = 'test -u'.split()
+    >>> testrunner.run(defaults)
+    Running unit tests:
+      Ran 192 tests with 0 failures and 0 errors in 0.033 seconds.
+
+Or that we want to run all of the tests except for the unit tests:
+
+    >>> sys.argv = 'test -f'.split()
+    >>> testrunner.run(defaults)
+    Running samplelayers.Layer1 tests:
+      Set up samplelayers.Layer1 in 0.000 seconds.
+      Ran 9 tests with 0 failures and 0 errors in 0.000 seconds.
+    Running samplelayers.Layer12 tests:
+      Set up samplelayers.Layer12 in 0.000 seconds.
+      Ran 34 tests with 0 failures and 0 errors in 0.007 seconds.
+    Running samplelayers.Layer122 tests:
+      Set up samplelayers.Layer122 in 0.000 seconds.
+      Ran 34 tests with 0 failures and 0 errors in 0.007 seconds.
+    Running samplelayers.Layer121 tests:
+      Tear down samplelayers.Layer122 in 0.000 seconds.
+      Set up samplelayers.Layer121 in 0.000 seconds.
+      Ran 34 tests with 0 failures and 0 errors in 0.007 seconds.
+    Running samplelayers.Layer11 tests:
+      Tear down samplelayers.Layer121 in 0.000 seconds.
+      Tear down samplelayers.Layer12 in 0.000 seconds.
+      Set up samplelayers.Layer11 in 0.000 seconds.
+      Ran 34 tests with 0 failures and 0 errors in 0.007 seconds.
+    Running samplelayers.Layer112 tests:
+      Set up samplelayers.Layerx in 0.000 seconds.
+      Set up samplelayers.Layer112 in 0.000 seconds.
+      Ran 34 tests with 0 failures and 0 errors in 0.008 seconds.
+    Running samplelayers.Layer111 tests:
+      Tear down samplelayers.Layer112 in 0.000 seconds.
+      Set up samplelayers.Layer111 in 0.000 seconds.
+      Ran 34 tests with 0 failures and 0 errors in 0.007 seconds.
+    Tearing down left over layers:
+      Tear down samplelayers.Layer111 in 0.000 seconds.
+      Tear down samplelayers.Layer11 in 0.000 seconds.
+      Tear down samplelayers.Layer1 in 0.000 seconds.
+      Tear down samplelayers.Layerx in 0.000 seconds.
+    Total: 213 tests, 0 failures, 0 errors
+
+Verbose Output
+--------------
+
+Normally, we just get a summary.  We can use the -v option to get
+increasingly more information.
+
+If we use a single --verbose (-v) option, we get a dot printed for each
+test:
+
+    >>> sys.argv = 'test --layer 122 -v'.split()
+    >>> testrunner.run(defaults)
+    Running tests at level 1
+    Running samplelayers.Layer122 tests:
+      Set up samplelayers.Layer1 in 0.000 seconds.
+      Set up samplelayers.Layer12 in 0.000 seconds.
+      Set up samplelayers.Layer122 in 0.000 seconds.
+      Running:
+        ..................................
+      Ran 34 tests with 0 failures and 0 errors in 0.007 seconds.
+    Tearing down left over layers:
+      Tear down samplelayers.Layer122 in 0.000 seconds.
+      Tear down samplelayers.Layer12 in 0.000 seconds.
+      Tear down samplelayers.Layer1 in 0.000 seconds.
+
+If there are more than 50 tests, the dots are printed in groups of 
+50:
+
+    >>> sys.argv = 'test -uv'.split()
+    >>> testrunner.run(defaults)
+    Running tests at level 1
+    Running unit tests:
+      Running:
+        ..................................................
+        ..................................................
+        ..................................................
+        ..........................................
+      Ran 192 tests with 0 failures and 0 errors in 0.035 seconds.
+
+If the --verbose (-v) option is used twice, then the name and location of
+each test is printed as it is run:
+
+    >>> sys.argv = 'test --layer 122 -vv'.split()
+    >>> testrunner.run(defaults)
+    Running tests at level 1
+    Running samplelayers.Layer122 tests:
+      Set up samplelayers.Layer1 in 0.000 seconds.
+      Set up samplelayers.Layer12 in 0.000 seconds.
+      Set up samplelayers.Layer122 in 0.000 seconds.
+      Running:
+        test_x1 (sample1.sampletests.test122.TestA)
+        test_y0 (sample1.sampletests.test122.TestA)
+        test_z0 (sample1.sampletests.test122.TestA)
+        test_x0 (sample1.sampletests.test122.TestB)
+        test_y1 (sample1.sampletests.test122.TestB)
+        test_z0 (sample1.sampletests.test122.TestB)
+        test_1 (sample1.sampletests.test122.TestNotMuch)
+        test_2 (sample1.sampletests.test122.TestNotMuch)
+        test_3 (sample1.sampletests.test122.TestNotMuch)
+        test_x0 (sample1.sampletests.test122)
+        test_y0 (sample1.sampletests.test122)
+        test_z1 (sample1.sampletests.test122)
+        testrunner-ex/sample1/sampletests/../../sampletestsl.txt
+        test_x1 (sampletests.test122.TestA)
+        test_y0 (sampletests.test122.TestA)
+        test_z0 (sampletests.test122.TestA)
+        test_x0 (sampletests.test122.TestB)
+        test_y1 (sampletests.test122.TestB)
+        test_z0 (sampletests.test122.TestB)
+        test_1 (sampletests.test122.TestNotMuch)
+        test_2 (sampletests.test122.TestNotMuch)
+        test_3 (sampletests.test122.TestNotMuch)
+        test_x0 (sampletests.test122)
+        test_y0 (sampletests.test122)
+        test_z1 (sampletests.test122)
+        testrunner-ex/sampletests/../sampletestsl.txt
+      Ran 34 tests with 0 failures and 0 errors in 0.009 seconds.
+    Tearing down left over layers:
+      Tear down samplelayers.Layer122 in 0.000 seconds.
+      Tear down samplelayers.Layer12 in 0.000 seconds.
+      Tear down samplelayers.Layer1 in 0.000 seconds.
+
+if the --verbose (-v) option is used three times, then individual
+test-execution times are printed:
+
+    >>> sys.argv = 'test --layer 122 -vvv'.split()
+    >>> testrunner.run(defaults)
+    Running tests at level 1
+    Running samplelayers.Layer122 tests:
+      Set up samplelayers.Layer1 in 0.000 seconds.
+      Set up samplelayers.Layer12 in 0.000 seconds.
+      Set up samplelayers.Layer122 in 0.000 seconds.
+      Running:
+        test_x1 (sample1.sampletests.test122.TestA) (0.000 ms)
+        test_y0 (sample1.sampletests.test122.TestA) (0.000 ms)
+        test_z0 (sample1.sampletests.test122.TestA) (0.000 ms)
+        test_x0 (sample1.sampletests.test122.TestB) (0.000 ms)
+        test_y1 (sample1.sampletests.test122.TestB) (0.000 ms)
+        test_z0 (sample1.sampletests.test122.TestB) (0.000 ms)
+        test_1 (sample1.sampletests.test122.TestNotMuch) (0.000 ms)
+        test_2 (sample1.sampletests.test122.TestNotMuch) (0.000 ms)
+        test_3 (sample1.sampletests.test122.TestNotMuch) (0.000 ms)
+        test_x0 (sample1.sampletests.test122) (0.001 ms)
+        test_y0 (sample1.sampletests.test122) (0.001 ms)
+        test_z1 (sample1.sampletests.test122) (0.001 ms)
+        testrunner-ex/sample1/sampletests/../../sampletestsl.txt (0.001 ms)
+        test_x1 (sampletests.test122.TestA) (0.000 ms)
+        test_y0 (sampletests.test122.TestA) (0.000 ms)
+        test_z0 (sampletests.test122.TestA) (0.000 ms)
+        test_x0 (sampletests.test122.TestB) (0.000 ms)
+        test_y1 (sampletests.test122.TestB) (0.000 ms)
+        test_z0 (sampletests.test122.TestB) (0.000 ms)
+        test_1 (sampletests.test122.TestNotMuch) (0.000 ms)
+        test_2 (sampletests.test122.TestNotMuch) (0.000 ms)
+        test_3 (sampletests.test122.TestNotMuch) (0.000 ms)
+        test_x0 (sampletests.test122) (0.001 ms)
+        test_y0 (sampletests.test122) (0.001 ms)
+        test_z1 (sampletests.test122) (0.001 ms)
+        testrunner-ex/sampletests/../sampletestsl.txt (0.001 ms)
+      Ran 34 tests with 0 failures and 0 errors in 0.009 seconds.
+    Tearing down left over layers:
+      Tear down samplelayers.Layer122 in 0.000 seconds.
+      Tear down samplelayers.Layer12 in 0.000 seconds.
+      Tear down samplelayers.Layer1 in 0.000 seconds.
+
+Test Selection
+--------------
+
+We've already seen that we can select tests by layer.  There are three
+other ways we can select tests.  We can select tests by package:
+
+    >>> sys.argv = 'test --layer 122 -ssample1 -vv'.split()
+    >>> testrunner.run(defaults)
+    Running tests at level 1
+    Running samplelayers.Layer122 tests:
+      Set up samplelayers.Layer1 in 0.000 seconds.
+      Set up samplelayers.Layer12 in 0.000 seconds.
+      Set up samplelayers.Layer122 in 0.000 seconds.
+      Running:
+        test_x1 (sample1.sampletests.test122.TestA)
+        test_y0 (sample1.sampletests.test122.TestA)
+        test_z0 (sample1.sampletests.test122.TestA)
+        test_x0 (sample1.sampletests.test122.TestB)
+        test_y1 (sample1.sampletests.test122.TestB)
+        test_z0 (sample1.sampletests.test122.TestB)
+        test_1 (sample1.sampletests.test122.TestNotMuch)
+        test_2 (sample1.sampletests.test122.TestNotMuch)
+        test_3 (sample1.sampletests.test122.TestNotMuch)
+        test_x0 (sample1.sampletests.test122)
+        test_y0 (sample1.sampletests.test122)
+        test_z1 (sample1.sampletests.test122)
+        testrunner-ex/sample1/sampletests/../../sampletestsl.txt
+      Ran 17 tests with 0 failures and 0 errors in 0.005 seconds.
+    Tearing down left over layers:
+      Tear down samplelayers.Layer122 in 0.000 seconds.
+      Tear down samplelayers.Layer12 in 0.000 seconds.
+      Tear down samplelayers.Layer1 in 0.000 seconds.
+
+You can specify multiple packages:
+
+    >>> sys.argv = 'test -u  -vv -ssample1 -ssample2'.split()
+    >>> testrunner.run(defaults)
+    Running tests at level 1
+    Running unit tests:
+      Running:
+        test_x1 (sample1.sampletestsf.TestA)
+        test_y0 (sample1.sampletestsf.TestA)
+        test_z0 (sample1.sampletestsf.TestA)
+        test_x0 (sample1.sampletestsf.TestB)
+        test_y1 (sample1.sampletestsf.TestB)
+        test_z0 (sample1.sampletestsf.TestB)
+        test_1 (sample1.sampletestsf.TestNotMuch)
+        test_2 (sample1.sampletestsf.TestNotMuch)
+        test_3 (sample1.sampletestsf.TestNotMuch)
+        test_x0 (sample1.sampletestsf)
+        test_y0 (sample1.sampletestsf)
+        test_z1 (sample1.sampletestsf)
+        testrunner-ex/sample1/../sampletests.txt
+        test_x1 (sample1.sample11.sampletests.TestA)
+        test_y0 (sample1.sample11.sampletests.TestA)
+        test_z0 (sample1.sample11.sampletests.TestA)
+        test_x0 (sample1.sample11.sampletests.TestB)
+        test_y1 (sample1.sample11.sampletests.TestB)
+        test_z0 (sample1.sample11.sampletests.TestB)
+        test_1 (sample1.sample11.sampletests.TestNotMuch)
+        test_2 (sample1.sample11.sampletests.TestNotMuch)
+        test_3 (sample1.sample11.sampletests.TestNotMuch)
+        test_x0 (sample1.sample11.sampletests)
+        test_y0 (sample1.sample11.sampletests)
+        test_z1 (sample1.sample11.sampletests)
+        testrunner-ex/sample1/sample11/../../sampletests.txt
+        test_x1 (sample1.sampletests.test1.TestA)
+        test_y0 (sample1.sampletests.test1.TestA)
+        test_z0 (sample1.sampletests.test1.TestA)
+        test_x0 (sample1.sampletests.test1.TestB)
+        test_y1 (sample1.sampletests.test1.TestB)
+        test_z0 (sample1.sampletests.test1.TestB)
+        test_1 (sample1.sampletests.test1.TestNotMuch)
+        test_2 (sample1.sampletests.test1.TestNotMuch)
+        test_3 (sample1.sampletests.test1.TestNotMuch)
+        test_x0 (sample1.sampletests.test1)
+        test_y0 (sample1.sampletests.test1)
+        test_z1 (sample1.sampletests.test1)
+        testrunner-ex/sample1/sampletests/../../sampletests.txt
+        test_x1 (sample1.sampletests.test_one.TestA)
+        test_y0 (sample1.sampletests.test_one.TestA)
+        test_z0 (sample1.sampletests.test_one.TestA)
+        test_x0 (sample1.sampletests.test_one.TestB)
+        test_y1 (sample1.sampletests.test_one.TestB)
+        test_z0 (sample1.sampletests.test_one.TestB)
+        test_1 (sample1.sampletests.test_one.TestNotMuch)
+        test_2 (sample1.sampletests.test_one.TestNotMuch)
+        test_3 (sample1.sampletests.test_one.TestNotMuch)
+        test_x0 (sample1.sampletests.test_one)
+        test_y0 (sample1.sampletests.test_one)
+        test_z1 (sample1.sampletests.test_one)
+        testrunner-ex/sample1/sampletests/../../sampletests.txt
+        test_x1 (sample1.sample13.sampletests.TestA)
+        test_y0 (sample1.sample13.sampletests.TestA)
+        test_z0 (sample1.sample13.sampletests.TestA)
+        test_x0 (sample1.sample13.sampletests.TestB)
+        test_y1 (sample1.sample13.sampletests.TestB)
+        test_z0 (sample1.sample13.sampletests.TestB)
+        test_1 (sample1.sample13.sampletests.TestNotMuch)
+        test_2 (sample1.sample13.sampletests.TestNotMuch)
+        test_3 (sample1.sample13.sampletests.TestNotMuch)
+        test_x0 (sample1.sample13.sampletests)
+        test_y0 (sample1.sample13.sampletests)
+        test_z1 (sample1.sample13.sampletests)
+        testrunner-ex/sample1/sample13/../../sampletests.txt
+        test_x1 (sample2.sampletests.test_1.TestA)
+        test_y0 (sample2.sampletests.test_1.TestA)
+        test_z0 (sample2.sampletests.test_1.TestA)
+        test_x0 (sample2.sampletests.test_1.TestB)
+        test_y1 (sample2.sampletests.test_1.TestB)
+        test_z0 (sample2.sampletests.test_1.TestB)
+        test_1 (sample2.sampletests.test_1.TestNotMuch)
+        test_2 (sample2.sampletests.test_1.TestNotMuch)
+        test_3 (sample2.sampletests.test_1.TestNotMuch)
+        test_x0 (sample2.sampletests.test_1)
+        test_y0 (sample2.sampletests.test_1)
+        test_z1 (sample2.sampletests.test_1)
+        testrunner-ex/sample2/sampletests/../../sampletests.txt
+        test_x1 (sample2.sampletests.testone.TestA)
+        test_y0 (sample2.sampletests.testone.TestA)
+        test_z0 (sample2.sampletests.testone.TestA)
+        test_x0 (sample2.sampletests.testone.TestB)
+        test_y1 (sample2.sampletests.testone.TestB)
+        test_z0 (sample2.sampletests.testone.TestB)
+        test_1 (sample2.sampletests.testone.TestNotMuch)
+        test_2 (sample2.sampletests.testone.TestNotMuch)
+        test_3 (sample2.sampletests.testone.TestNotMuch)
+        test_x0 (sample2.sampletests.testone)
+        test_y0 (sample2.sampletests.testone)
+        test_z1 (sample2.sampletests.testone)
+        testrunner-ex/sample2/sampletests/../../sampletests.txt
+        test_x1 (sample2.sample21.sampletests.TestA)
+        test_y0 (sample2.sample21.sampletests.TestA)
+        test_z0 (sample2.sample21.sampletests.TestA)
+        test_x0 (sample2.sample21.sampletests.TestB)
+        test_y1 (sample2.sample21.sampletests.TestB)
+        test_z0 (sample2.sample21.sampletests.TestB)
+        test_1 (sample2.sample21.sampletests.TestNotMuch)
+        test_2 (sample2.sample21.sampletests.TestNotMuch)
+        test_3 (sample2.sample21.sampletests.TestNotMuch)
+        test_x0 (sample2.sample21.sampletests)
+        test_y0 (sample2.sample21.sampletests)
+        test_z1 (sample2.sample21.sampletests)
+        testrunner-ex/sample2/sample21/../../sampletests.txt
+      Ran 128 tests with 0 failures and 0 errors in 0.026 seconds.
+
+We can select by test module name:
+
+    >>> sys.argv = 'test -u  -vv -ssample1 -m_one -mtest1'.split()
+    >>> testrunner.run(defaults)
+    Running tests at level 1
+    Running unit tests:
+      Running:
+        test_x1 (sample1.sampletests.test1.TestA)
+        test_y0 (sample1.sampletests.test1.TestA)
+        test_z0 (sample1.sampletests.test1.TestA)
+        test_x0 (sample1.sampletests.test1.TestB)
+        test_y1 (sample1.sampletests.test1.TestB)
+        test_z0 (sample1.sampletests.test1.TestB)
+        test_1 (sample1.sampletests.test1.TestNotMuch)
+        test_2 (sample1.sampletests.test1.TestNotMuch)
+        test_3 (sample1.sampletests.test1.TestNotMuch)
+        test_x0 (sample1.sampletests.test1)
+        test_y0 (sample1.sampletests.test1)
+        test_z1 (sample1.sampletests.test1)
+        testrunner-ex/sample1/sampletests/../../sampletests.txt
+        test_x1 (sample1.sampletests.test_one.TestA)
+        test_y0 (sample1.sampletests.test_one.TestA)
+        test_z0 (sample1.sampletests.test_one.TestA)
+        test_x0 (sample1.sampletests.test_one.TestB)
+        test_y1 (sample1.sampletests.test_one.TestB)
+        test_z0 (sample1.sampletests.test_one.TestB)
+        test_1 (sample1.sampletests.test_one.TestNotMuch)
+        test_2 (sample1.sampletests.test_one.TestNotMuch)
+        test_3 (sample1.sampletests.test_one.TestNotMuch)
+        test_x0 (sample1.sampletests.test_one)
+        test_y0 (sample1.sampletests.test_one)
+        test_z1 (sample1.sampletests.test_one)
+        testrunner-ex/sample1/sampletests/../../sampletests.txt
+      Ran 32 tests with 0 failures and 0 errors in 0.008 seconds.
+    
+and by test within the module:
+
+    >>> sys.argv = 'test -u  -vv -ssample1 -m_one -mtest1 -tx0 -ty0'.split()
+    >>> testrunner.run(defaults)
+    Running tests at level 1
+    Running unit tests:
+      Running:
+        test_y0 (sample1.sampletests.test1.TestA)
+        test_x0 (sample1.sampletests.test1.TestB)
+        test_x0 (sample1.sampletests.test1)
+        test_y0 (sample1.sampletests.test1)
+        test_y0 (sample1.sampletests.test_one.TestA)
+        test_x0 (sample1.sampletests.test_one.TestB)
+        test_x0 (sample1.sampletests.test_one)
+        test_y0 (sample1.sampletests.test_one)
+      Ran 8 tests with 0 failures and 0 errors in 0.003 seconds.
+
+
+    >>> sys.argv = 'test -u  -vv -ssample1 -ttxt'.split()
+    >>> testrunner.run(defaults)
+    Running tests at level 1
+    Running unit tests:
+      Running:
+        testrunner-ex/sample1/../sampletests.txt
+        testrunner-ex/sample1/sample11/../../sampletests.txt
+        testrunner-ex/sample1/sampletests/../../sampletests.txt
+        testrunner-ex/sample1/sampletests/../../sampletests.txt
+        testrunner-ex/sample1/sample13/../../sampletests.txt
+      Ran 20 tests with 0 failures and 0 errors in 0.004 seconds.
+
+Sometimes, there are tests that you don't want to run by default.
+For example, you might have tests that take a long time.  Tests can
+have a level attribute.  If no level is specified, a level of 1 is
+assumed and, by default, only tests at level one are run.  to run
+tests at a higher level, use the --at-level (-a) option to specify a higher
+level.  For example, with the following options:
+
+
+    >>> sys.argv = 'test -u  -vv -t test_y1 -t test_y0'.split()
+    >>> testrunner.run(defaults)
+    Running tests at level 1
+    Running unit tests:
+      Running:
+        test_y0 (sampletestsf.TestA)
+        test_y1 (sampletestsf.TestB)
+        test_y0 (sampletestsf)
+        test_y0 (sample1.sampletestsf.TestA)
+        test_y1 (sample1.sampletestsf.TestB)
+        test_y0 (sample1.sampletestsf)
+        test_y0 (sample1.sample11.sampletests.TestA)
+        test_y1 (sample1.sample11.sampletests.TestB)
+        test_y0 (sample1.sample11.sampletests)
+        test_y0 (sample1.sampletests.test1.TestA)
+        test_y1 (sample1.sampletests.test1.TestB)
+        test_y0 (sample1.sampletests.test1)
+        test_y0 (sample1.sampletests.test_one.TestA)
+        test_y1 (sample1.sampletests.test_one.TestB)
+        test_y0 (sample1.sampletests.test_one)
+        test_y0 (sample1.sample13.sampletests.TestA)
+        test_y1 (sample1.sample13.sampletests.TestB)
+        test_y0 (sample1.sample13.sampletests)
+        test_y0 (sampletests.test1.TestA)
+        test_y1 (sampletests.test1.TestB)
+        test_y0 (sampletests.test1)
+        test_y0 (sampletests.test_one.TestA)
+        test_y1 (sampletests.test_one.TestB)
+        test_y0 (sampletests.test_one)
+        test_y0 (sample3.sampletests.TestA)
+        test_y1 (sample3.sampletests.TestB)
+        test_y0 (sample3.sampletests)
+        test_y0 (sample2.sampletests.test_1.TestA)
+        test_y1 (sample2.sampletests.test_1.TestB)
+        test_y0 (sample2.sampletests.test_1)
+        test_y0 (sample2.sampletests.testone.TestA)
+        test_y1 (sample2.sampletests.testone.TestB)
+        test_y0 (sample2.sampletests.testone)
+        test_y0 (sample2.sample21.sampletests.TestA)
+        test_y1 (sample2.sample21.sampletests.TestB)
+        test_y0 (sample2.sample21.sampletests)
+      Ran 36 tests with 0 failures and 0 errors in 0.009 seconds.
+
+
+We get run 36 tests.  If we specify a level of 2, we get some
+additional tests:
+
+    >>> sys.argv = 'test -u  -vv -a 2 -t test_y1 -t test_y0'.split()
+    >>> testrunner.run(defaults)
+    Running tests at level 2
+    Running unit tests:
+      Running:
+        test_y0 (sampletestsf.TestA)
+        test_y0 (sampletestsf.TestA2)
+        test_y1 (sampletestsf.TestB)
+        test_y0 (sampletestsf)
+        test_y0 (sample1.sampletestsf.TestA)
+        test_y1 (sample1.sampletestsf.TestB)
+        test_y0 (sample1.sampletestsf)
+        test_y0 (sample1.sample11.sampletests.TestA)
+        test_y1 (sample1.sample11.sampletests.TestB)
+        test_y1 (sample1.sample11.sampletests.TestB2)
+        test_y0 (sample1.sample11.sampletests)
+        test_y0 (sample1.sampletests.test1.TestA)
+        test_y1 (sample1.sampletests.test1.TestB)
+        test_y0 (sample1.sampletests.test1)
+        test_y0 (sample1.sampletests.test_one.TestA)
+        test_y1 (sample1.sampletests.test_one.TestB)
+        test_y0 (sample1.sampletests.test_one)
+        test_y0 (sample1.sample13.sampletests.TestA)
+        test_y1 (sample1.sample13.sampletests.TestB)
+        test_y0 (sample1.sample13.sampletests)
+        test_y0 (sampletests.test1.TestA)
+        test_y1 (sampletests.test1.TestB)
+        test_y0 (sampletests.test1)
+        test_y0 (sampletests.test_one.TestA)
+        test_y1 (sampletests.test_one.TestB)
+        test_y0 (sampletests.test_one)
+        test_y0 (sample3.sampletests.TestA)
+        test_y1 (sample3.sampletests.TestB)
+        test_y0 (sample3.sampletests)
+        test_y0 (sample2.sampletests.test_1.TestA)
+        test_y1 (sample2.sampletests.test_1.TestB)
+        test_y0 (sample2.sampletests.test_1)
+        test_y0 (sample2.sampletests.testone.TestA)
+        test_y1 (sample2.sampletests.testone.TestB)
+        test_y0 (sample2.sampletests.testone)
+        test_y0 (sample2.sample21.sampletests.TestA)
+        test_y1 (sample2.sample21.sampletests.TestB)
+        test_y0 (sample2.sample21.sampletests)
+      Ran 38 tests with 0 failures and 0 errors in 0.009 seconds.
+
+We can use the --all option to run tests at all levels:
+
+    >>> sys.argv = 'test -u  -vv --all -t test_y1 -t test_y0'.split()
+    >>> testrunner.run(defaults)
+    Running tests at all levels
+    Running unit tests:
+      Running:
+        test_y0 (sampletestsf.TestA)
+        test_y0 (sampletestsf.TestA2)
+        test_y1 (sampletestsf.TestB)
+        test_y0 (sampletestsf)
+        test_y0 (sample1.sampletestsf.TestA)
+        test_y1 (sample1.sampletestsf.TestB)
+        test_y0 (sample1.sampletestsf)
+        test_y0 (sample1.sample11.sampletests.TestA)
+        test_y0 (sample1.sample11.sampletests.TestA3)
+        test_y1 (sample1.sample11.sampletests.TestB)
+        test_y1 (sample1.sample11.sampletests.TestB2)
+        test_y0 (sample1.sample11.sampletests)
+        test_y0 (sample1.sampletests.test1.TestA)
+        test_y1 (sample1.sampletests.test1.TestB)
+        test_y0 (sample1.sampletests.test1)
+        test_y0 (sample1.sampletests.test_one.TestA)
+        test_y1 (sample1.sampletests.test_one.TestB)
+        test_y0 (sample1.sampletests.test_one)
+        test_y0 (sample1.sample13.sampletests.TestA)
+        test_y1 (sample1.sample13.sampletests.TestB)
+        test_y0 (sample1.sample13.sampletests)
+        test_y0 (sampletests.test1.TestA)
+        test_y1 (sampletests.test1.TestB)
+        test_y0 (sampletests.test1)
+        test_y0 (sampletests.test_one.TestA)
+        test_y1 (sampletests.test_one.TestB)
+        test_y0 (sampletests.test_one)
+        test_y0 (sample3.sampletests.TestA)
+        test_y1 (sample3.sampletests.TestB)
+        test_y0 (sample3.sampletests)
+        test_y0 (sample2.sampletests.test_1.TestA)
+        test_y1 (sample2.sampletests.test_1.TestB)
+        test_y0 (sample2.sampletests.test_1)
+        test_y0 (sample2.sampletests.testone.TestA)
+        test_y1 (sample2.sampletests.testone.TestB)
+        test_y0 (sample2.sampletests.testone)
+        test_y0 (sample2.sample21.sampletests.TestA)
+        test_y1 (sample2.sample21.sampletests.TestB)
+        test_y0 (sample2.sample21.sampletests)
+      Ran 39 tests with 0 failures and 0 errors in 0.009 seconds.
+
+Test Progress
+-------------
+
+If the --progress (-p) option is used, progress information is printed and
+a carriage return, rather than a new-line is printed between 
+detail lines. Let's look at the effect of --progress (-p) at different
+levels of verbosity.
+
+    >>> sys.argv = 'test --layer 122 -p'.split()
+    >>> testrunner.run(defaults)
+    Running samplelayers.Layer122 tests:
+      Set up samplelayers.Layer1 in 0.000 seconds.
+      Set up samplelayers.Layer12 in 0.000 seconds.
+      Set up samplelayers.Layer122 in 0.000 seconds.
+      Running:
+        1/34 (2.9%)\r
+        2/34 (5.9%)\r
+        3/34 (8.8%)\r
+        4/34 (11.8%)\r
+        5/34 (14.7%)\r
+        6/34 (17.6%)\r
+        7/34 (20.6%)\r
+        8/34 (23.5%)\r
+        9/34 (26.5%)\r
+        10/34 (29.4%)\r
+        11/34 (32.4%)\r
+        12/34 (35.3%)\r
+        17/34 (50.0%)\r
+        18/34 (52.9%)\r
+        19/34 (55.9%)\r
+        20/34 (58.8%)\r
+        21/34 (61.8%)\r
+        22/34 (64.7%)\r
+        23/34 (67.6%)\r
+        24/34 (70.6%)\r
+        25/34 (73.5%)\r
+        26/34 (76.5%)\r
+        27/34 (79.4%)\r
+        28/34 (82.4%)\r
+        29/34 (85.3%)\r
+        34/34 (100.0%)\r
+    <BLANKLINE>
+      Ran 34 tests with 0 failures and 0 errors in 0.010 seconds.
+    Tearing down left over layers:
+      Tear down samplelayers.Layer122 in 0.000 seconds.
+      Tear down samplelayers.Layer12 in 0.000 seconds.
+      Tear down samplelayers.Layer1 in 0.000 seconds.
+
+(Note that, in the examples above and below, we show "\r" followed by
+new lines where carriage returns would appear in actual output.)
+
+Using a single level of verbosity has only a small effect:
+
+    >>> sys.argv = 'test --layer 122 -pv'.split()
+    >>> testrunner.run(defaults)
+    Running tests at level 1
+    Running samplelayers.Layer122 tests:
+      Set up samplelayers.Layer1 in 0.000 seconds.
+      Set up samplelayers.Layer12 in 0.000 seconds.
+      Set up samplelayers.Layer122 in 0.000 seconds.
+      Running:
+        1/34 (2.9%)\r
+        2/34 (5.9%)\r
+        3/34 (8.8%)\r
+        4/34 (11.8%)\r
+        5/34 (14.7%)\r
+        6/34 (17.6%)\r
+        7/34 (20.6%)\r
+        8/34 (23.5%)\r
+        9/34 (26.5%)\r
+        10/34 (29.4%)\r
+        11/34 (32.4%)\r
+        12/34 (35.3%)\r
+        17/34 (50.0%)\r
+        18/34 (52.9%)\r
+        19/34 (55.9%)\r
+        20/34 (58.8%)\r
+        21/34 (61.8%)\r
+        22/34 (64.7%)\r
+        23/34 (67.6%)\r
+        24/34 (70.6%)\r
+        25/34 (73.5%)\r
+        26/34 (76.5%)\r
+        27/34 (79.4%)\r
+        28/34 (82.4%)\r
+        29/34 (85.3%)\r
+        34/34 (100.0%)\r
+    <BLANKLINE>
+      Ran 34 tests with 0 failures and 0 errors in 0.009 seconds.
+    Tearing down left over layers:
+      Tear down samplelayers.Layer122 in 0.000 seconds.
+      Tear down samplelayers.Layer12 in 0.000 seconds.
+      Tear down samplelayers.Layer1 in 0.000 seconds.
+
+
+If a second or third level of verbosity are added, we get additional
+information.
+
+    >>> sys.argv = 'test --layer 122 -pvv -t !txt'.split()
+    >>> testrunner.run(defaults)
+    Running tests at level 1
+    Running samplelayers.Layer122 tests:
+      Set up samplelayers.Layer1 in 0.000 seconds.
+      Set up samplelayers.Layer12 in 0.000 seconds.
+      Set up samplelayers.Layer122 in 0.000 seconds.
+      Running:
+        1/24 (4.2%) test_x1 (sample1.sampletests.test122.TestA)\r
+        2/24 (8.3%) test_y0 (sample1.sampletests.test122.TestA)\r
+        3/24 (12.5%) test_z0 (sample1.sampletests.test122.TestA)\r
+        4/24 (16.7%) test_x0 (sample1.sampletests.test122.TestB)\r
+        5/24 (20.8%) test_y1 (sample1.sampletests.test122.TestB)\r
+        6/24 (25.0%) test_z0 (sample1.sampletests.test122.TestB)\r
+        7/24 (29.2%) test_1 (sample1.sampletests.test122.TestNotMuch)\r
+        8/24 (33.3%) test_2 (sample1.sampletests.test122.TestNotMuch)\r
+        9/24 (37.5%) test_3 (sample1.sampletests.test122.TestNotMuch)\r
+        10/24 (41.7%) test_x0 (sample1.sampletests.test122)          \r
+        11/24 (45.8%) test_y0 (sample1.sampletests.test122)\r
+        12/24 (50.0%) test_z1 (sample1.sampletests.test122)\r
+        13/24 (54.2%) test_x1 (sampletests.test122.TestA)  \r
+        14/24 (58.3%) test_y0 (sampletests.test122.TestA)\r
+        15/24 (62.5%) test_z0 (sampletests.test122.TestA)\r
+        16/24 (66.7%) test_x0 (sampletests.test122.TestB)\r
+        17/24 (70.8%) test_y1 (sampletests.test122.TestB)\r
+        18/24 (75.0%) test_z0 (sampletests.test122.TestB)\r
+        19/24 (79.2%) test_1 (sampletests.test122.TestNotMuch)\r
+        20/24 (83.3%) test_2 (sampletests.test122.TestNotMuch)\r
+        21/24 (87.5%) test_3 (sampletests.test122.TestNotMuch)\r
+        22/24 (91.7%) test_x0 (sampletests.test122)           \r
+        23/24 (95.8%) test_y0 (sampletests.test122)\r
+        24/24 (100.0%) test_z1 (sampletests.test122)\r
+    <BLANKLINE>
+      Ran 24 tests with 0 failures and 0 errors in 0.006 seconds.
+    Tearing down left over layers:
+      Tear down samplelayers.Layer122 in 0.000 seconds.
+      Tear down samplelayers.Layer12 in 0.000 seconds.
+      Tear down samplelayers.Layer1 in 0.000 seconds.
+
+Note that, in this example, we used a test-selection pattern starting
+with '!' to exclude tests containing the string "txt".
+
+    >>> sys.argv = 'test --layer 122 -pvvv -t!(txt|NotMuch)'.split()
+    >>> testrunner.run(defaults)
+    Running tests at level 1
+    Running samplelayers.Layer122 tests:
+      Set up samplelayers.Layer1 in 0.000 seconds.
+      Set up samplelayers.Layer12 in 0.000 seconds.
+      Set up samplelayers.Layer122 in 0.000 seconds.
+      Running:
+        1/18 (5.6%) test_x1 (sample1.sampletests.test122.TestA) (0.000 ms)\r
+        2/18 (11.1%) test_y0 (sample1.sampletests.test122.TestA) (0.000 ms)\r
+        3/18 (16.7%) test_z0 (sample1.sampletests.test122.TestA) (0.000 ms)\r
+        4/18 (22.2%) test_x0 (sample1.sampletests.test122.TestB) (0.000 ms)\r
+        5/18 (27.8%) test_y1 (sample1.sampletests.test122.TestB) (0.000 ms)\r
+        6/18 (33.3%) test_z0 (sample1.sampletests.test122.TestB) (0.000 ms)\r
+        7/18 (38.9%) test_x0 (sample1.sampletests.test122) (0.001 ms)      \r
+        8/18 (44.4%) test_y0 (sample1.sampletests.test122) (0.001 ms)\r
+        9/18 (50.0%) test_z1 (sample1.sampletests.test122) (0.001 ms)\r
+        10/18 (55.6%) test_x1 (sampletests.test122.TestA) (0.000 ms) \r
+        11/18 (61.1%) test_y0 (sampletests.test122.TestA) (0.000 ms)\r
+        12/18 (66.7%) test_z0 (sampletests.test122.TestA) (0.000 ms)\r
+        13/18 (72.2%) test_x0 (sampletests.test122.TestB) (0.000 ms)\r
+        14/18 (77.8%) test_y1 (sampletests.test122.TestB) (0.000 ms)\r
+        15/18 (83.3%) test_z0 (sampletests.test122.TestB) (0.000 ms)\r
+        16/18 (88.9%) test_x0 (sampletests.test122) (0.001 ms)      \r
+        17/18 (94.4%) test_y0 (sampletests.test122) (0.001 ms)\r
+        18/18 (100.0%) test_z1 (sampletests.test122) (0.001 ms)\r
+    <BLANKLINE>
+      Ran 18 tests with 0 failures and 0 errors in 0.006 seconds.
+    Tearing down left over layers:
+      Tear down samplelayers.Layer122 in 0.000 seconds.
+      Tear down samplelayers.Layer12 in 0.000 seconds.
+      Tear down samplelayers.Layer1 in 0.000 seconds.
+
+In this example, we also excluded tests with "NotMuch" in their names.
+
+Errors and Failures
+-------------------
+
+Let's look at tests that have errors and failures:
+
+    >>> sys.argv = 'test --tests-pattern ^sampletests(f|_e|_f)?$ '.split()
+    >>> testrunner.run(defaults)
+    ... # doctest: +NORMALIZE_WHITESPACE +REPORT_NDIFF
+    Running unit tests:
+    <BLANKLINE>
+    <BLANKLINE>
+    Failure in test eek (sample2.sampletests_e)
+    Failed doctest test for sample2.sampletests_e.eek
+      File "testrunner-ex/sample2/sampletests_e.py", line 28, in eek
+    <BLANKLINE>
+    ----------------------------------------------------------------------
+    File "testrunner-ex/sample2/sampletests_e.py", line 30, 
+                              in sample2.sampletests_e.eek
+    Failed example:
+        f()
+    Exception raised:
+        Traceback (most recent call last):
+          File ".../doctest.py", line 1256, in __run
+            compileflags, 1) in test.globs
+          File "<doctest sample2.sampletests_e.eek[0]>", line 1, in ?
+            f()
+          File "testrunner-ex/sample2/sampletests_e.py", line 19, in f
+            g()
+          File "testrunner-ex/sample2/sampletests_e.py", line 24, in g
+            x = y + 1
+        NameError: global name 'y' is not defined
+    <BLANKLINE>
+    <BLANKLINE>
+    <BLANKLINE>
+    Error in test test3 (sample2.sampletests_e.Test)
+    Traceback (most recent call last):
+      File "testrunner-ex/sample2/sampletests_e.py", line 43, in test3
+        f()
+      File "testrunner-ex/sample2/sampletests_e.py", line 19, in f
+        g()
+      File "testrunner-ex/sample2/sampletests_e.py", line 24, in g
+        x = y + 1
+    NameError: global name 'y' is not defined
+    <BLANKLINE>
+    <BLANKLINE>
+    <BLANKLINE>
+    Failure in test testrunner-ex/sample2/e.txt
+    Failed doctest test for e.txt
+      File "testrunner-ex/sample2/e.txt", line 0
+    <BLANKLINE>
+    ----------------------------------------------------------------------
+    File "testrunner-ex/sample2/e.txt", line 4, in e.txt
+    Failed example:
+        f()
+    Exception raised:
+        Traceback (most recent call last):
+          File ".../doctest.py", line 1256, in __run
+            compileflags, 1) in test.globs
+          File "<doctest e.txt[1]>", line 1, in ?
+            f()
+          File "<doctest e.txt[0]>", line 2, in f
+            return x
+        NameError: global name 'x' is not defined
+    <BLANKLINE>
+    <BLANKLINE>
+    <BLANKLINE>
+    Failure in test test (sample2.sampletests_f.Test)
+    Traceback (most recent call last):
+      File "testrunner-ex/sample2/sampletests_f.py", line 21, in test
+        self.assertEqual(1,0)
+      File ".../unittest.py", line 302, in failUnlessEqual
+        raise self.failureException, \
+    AssertionError: 1 != 0
+    <BLANKLINE>
+      Ran 200 tests with 3 failures and 1 errors in 0.153 seconds.
+    Running samplelayers.Layer1 tests:
+      Set up samplelayers.Layer1 in 0.000 seconds.
+      Ran 9 tests with 0 failures and 0 errors in 0.002 seconds.
+    Running samplelayers.Layer12 tests:
+      Set up samplelayers.Layer12 in 0.000 seconds.
+      Ran 34 tests with 0 failures and 0 errors in 0.028 seconds.
+    Running samplelayers.Layer122 tests:
+      Set up samplelayers.Layer122 in 0.000 seconds.
+      Ran 34 tests with 0 failures and 0 errors in 0.028 seconds.
+    Running samplelayers.Layer121 tests:
+      Tear down samplelayers.Layer122 in 0.000 seconds.
+      Set up samplelayers.Layer121 in 0.000 seconds.
+      Ran 34 tests with 0 failures and 0 errors in 0.028 seconds.
+    Running samplelayers.Layer11 tests:
+      Tear down samplelayers.Layer121 in 0.000 seconds.
+      Tear down samplelayers.Layer12 in 0.000 seconds.
+      Set up samplelayers.Layer11 in 0.000 seconds.
+      Ran 34 tests with 0 failures and 0 errors in 0.028 seconds.
+    Running samplelayers.Layer112 tests:
+      Set up samplelayers.Layerx in 0.000 seconds.
+      Set up samplelayers.Layer112 in 0.000 seconds.
+      Ran 34 tests with 0 failures and 0 errors in 0.029 seconds.
+    Running samplelayers.Layer111 tests:
+      Tear down samplelayers.Layer112 in 0.000 seconds.
+      Set up samplelayers.Layer111 in 0.000 seconds.
+      Ran 34 tests with 0 failures and 0 errors in 0.028 seconds.
+    Tearing down left over layers:
+      Tear down samplelayers.Layer111 in 0.000 seconds.
+      Tear down samplelayers.Layer11 in 0.000 seconds.
+      Tear down samplelayers.Layer1 in 0.000 seconds.
+      Tear down samplelayers.Layerx in 0.000 seconds.
+    Total: 413 tests, 3 failures, 1 errors
+
+We see that we get an error report and a traceback for the failing
+test.
+
+If we ask for single verbosity, the dotted output will be interrupted:
+
+    >>> sys.argv = 'test --tests-pattern ^sampletests(f|_e|_f)?$ -uv'.split()
+    >>> testrunner.run(defaults)
+    ... # doctest: +NORMALIZE_WHITESPACE +REPORT_NDIFF
+    Running tests at level 1
+    Running unit tests:
+      Running:
+        ..................................................
+        ..................................................
+        .............................................
+    <BLANKLINE>
+    Failure in test eek (sample2.sampletests_e)
+    Failed doctest test for sample2.sampletests_e.eek
+      File "testrunner-ex/sample2/sampletests_e.py", line 28, in eek
+    <BLANKLINE>
+    ----------------------------------------------------------------------
+    File "testrunner-ex/sample2/sampletests_e.py", line 30, in 
+              sample2.sampletests_e.eek
+    Failed example:
+        f()
+    Exception raised:
+        Traceback (most recent call last):
+          File ".../doctest.py", line 1256, in __run
+            compileflags, 1) in test.globs
+          File "<doctest sample2.sampletests_e.eek[0]>", line 1, in ?
+            f()
+          File "testrunner-ex/sample2/sampletests_e.py", line 19, in f
+            g()
+          File "testrunner-ex/sample2/sampletests_e.py", line 24, in g
+            x = y + 1
+        NameError: global name 'y' is not defined
+    <BLANKLINE>
+    ...
+    <BLANKLINE>
+    Error in test test3 (sample2.sampletests_e.Test)
+    Traceback (most recent call last):
+      File "testrunner-ex/sample2/sampletests_e.py", line 43, in test3
+        f()
+      File "testrunner-ex/sample2/sampletests_e.py", line 19, in f
+        g()
+      File "testrunner-ex/sample2/sampletests_e.py", line 24, in g
+        x = y + 1
+    NameError: global name 'y' is not defined
+    <BLANKLINE>
+    ..
+        .
+    <BLANKLINE>
+    Failure in test testrunner-ex/sample2/e.txt
+    Failed doctest test for e.txt
+      File "testrunner-ex/sample2/e.txt", line 0
+    <BLANKLINE>
+    ----------------------------------------------------------------------
+    File "testrunner-ex/sample2/e.txt", line 4, in e.txt
+    Failed example:
+        f()
+    Exception raised:
+        Traceback (most recent call last):
+          File ".../doctest.py", line 1256, in __run
+            compileflags, 1) in test.globs
+          File "<doctest e.txt[1]>", line 1, in ?
+            f()
+          File "<doctest e.txt[0]>", line 2, in f
+            return x
+        NameError: global name 'x' is not defined
+    <BLANKLINE>
+    .
+    <BLANKLINE>
+    Failure in test test (sample2.sampletests_f.Test)
+    Traceback (most recent call last):
+      File "testrunner-ex/sample2/sampletests_f.py", line 21, in test
+        self.assertEqual(1,0)
+      File ".../unittest.py", line 302, in failUnlessEqual
+        raise self.failureException, \
+    AssertionError: 1 != 0
+    <BLANKLINE>
+    ................................................
+    <BLANKLINE>
+      Ran 200 tests with 3 failures and 1 errors in 0.159 seconds.
+
+Similarly for progress output:
+
+    >>> sys.argv = ('test --tests-pattern ^sampletests(f|_e|_f)?$ -u -ssample2'
+    ...             ' -p').split()
+    >>> testrunner.run(defaults)
+    ... # doctest: +NORMALIZE_WHITESPACE +REPORT_NDIFF
+    Running unit tests:
+      Running:
+        1/56 (1.8%)
+    <BLANKLINE>
+    Failure in test eek (sample2.sampletests_e)
+    Failed doctest test for sample2.sampletests_e.eek
+      File "testrunner-ex/sample2/sampletests_e.py", line 28, in eek
+    <BLANKLINE>
+    ----------------------------------------------------------------------
+    File "testrunner-ex/sample2/sampletests_e.py", line 30, 
+           in sample2.sampletests_e.eek
+    Failed example:
+        f()
+    Exception raised:
+        Traceback (most recent call last):
+          File ".../doctest.py", line 1256, in __run
+            compileflags, 1) in test.globs
+          File "<doctest sample2.sampletests_e.eek[0]>", line 1, in ?
+            f()
+          File "testrunner-ex/sample2/sampletests_e.py", line 19, in f
+            g()
+          File "testrunner-ex/sample2/sampletests_e.py", line 24, in g
+            x = y + 1
+        NameError: global name 'y' is not defined
+    <BLANKLINE>
+    \r
+        2/56 (3.6%)\r
+        3/56 (5.4%)\r
+        4/56 (7.1%)
+    <BLANKLINE>
+    Error in test test3 (sample2.sampletests_e.Test)
+    Traceback (most recent call last):
+      File "testrunner-ex/sample2/sampletests_e.py", line 43, in test3
+        f()
+      File "testrunner-ex/sample2/sampletests_e.py", line 19, in f
+        g()
+      File "testrunner-ex/sample2/sampletests_e.py", line 24, in g
+        x = y + 1
+    NameError: global name 'y' is not defined
+    <BLANKLINE>
+    \r
+        5/56 (8.9%)\r
+        6/56 (10.7%)\r
+        7/56 (12.5%)
+    <BLANKLINE>
+    Failure in test testrunner-ex/sample2/e.txt
+    Failed doctest test for e.txt
+      File "testrunner-ex/sample2/e.txt", line 0
+    <BLANKLINE>
+    ----------------------------------------------------------------------
+    File "testrunner-ex/sample2/e.txt", line 4, in e.txt
+    Failed example:
+        f()
+    Exception raised:
+        Traceback (most recent call last):
+          File ".../doctest.py", line 1256, in __run
+            compileflags, 1) in test.globs
+          File "<doctest e.txt[1]>", line 1, in ?
+            f()
+          File "<doctest e.txt[0]>", line 2, in f
+            return x
+        NameError: global name 'x' is not defined
+    <BLANKLINE>
+    \r
+        8/56 (14.3%)
+    <BLANKLINE>
+    Failure in test test (sample2.sampletests_f.Test)
+    Traceback (most recent call last):
+      File "testrunner-ex/sample2/sampletests_f.py", line 21, in test
+        self.assertEqual(1,0)
+      File ".../unittest.py", line 302, in failUnlessEqual
+        raise self.failureException, \
+    AssertionError: 1 != 0
+    <BLANKLINE>
+    \r
+        9/56 (16.1%)\r
+        10/56 (17.9%)\r
+        11/56 (19.6%)\r
+        12/56 (21.4%)\r
+        13/56 (23.2%)\r
+        14/56 (25.0%)\r
+        15/56 (26.8%)\r
+        16/56 (28.6%)\r
+        17/56 (30.4%)\r
+        18/56 (32.1%)\r
+        19/56 (33.9%)\r
+        20/56 (35.7%)\r
+        24/56 (42.9%)\r
+        25/56 (44.6%)\r
+        26/56 (46.4%)\r
+        27/56 (48.2%)\r
+        28/56 (50.0%)\r
+        29/56 (51.8%)\r
+        30/56 (53.6%)\r
+        31/56 (55.4%)\r
+        32/56 (57.1%)\r
+        33/56 (58.9%)\r
+        34/56 (60.7%)\r
+        35/56 (62.5%)\r
+        36/56 (64.3%)\r
+        40/56 (71.4%)\r
+        41/56 (73.2%)\r
+        42/56 (75.0%)\r
+        43/56 (76.8%)\r
+        44/56 (78.6%)\r
+        45/56 (80.4%)\r
+        46/56 (82.1%)\r
+        47/56 (83.9%)\r
+        48/56 (85.7%)\r
+        49/56 (87.5%)\r
+        50/56 (89.3%)\r
+        51/56 (91.1%)\r
+        52/56 (92.9%)\r
+        56/56 (100.0%)\r
+    <BLANKLINE>
+      Ran 56 tests with 3 failures and 1 errors in 0.054 seconds.
+
+For greater levels of verbosity, we summarize the errors at the end of
+the test
+
+    >>> sys.argv = ('test --tests-pattern ^sampletests(f|_e|_f)?$ -u -ssample2'
+    ...             ' -vv').split()
+    >>> testrunner.run(defaults)
+    ... # doctest: +NORMALIZE_WHITESPACE +REPORT_NDIFF
+    Running tests at level 1
+    Running unit tests:
+      Running:
+        eek (sample2.sampletests_e)
+    <BLANKLINE>
+    Failure in test eek (sample2.sampletests_e)
+    Failed doctest test for sample2.sampletests_e.eek
+      File "testrunner-ex/sample2/sampletests_e.py", line 28, in eek
+    <BLANKLINE>
+    ----------------------------------------------------------------------
+    File "testrunner-ex/sample2/sampletests_e.py", line 30, 
+           in sample2.sampletests_e.eek
+    Failed example:
+        f()
+    Exception raised:
+        Traceback (most recent call last):
+          File ".../doctest.py", line 1256, in __run
+            compileflags, 1) in test.globs
+          File "<doctest sample2.sampletests_e.eek[0]>", line 1, in ?
+            f()
+          File "testrunner-ex/sample2/sampletests_e.py", line 19, in f
+            g()
+          File "testrunner-ex/sample2/sampletests_e.py", line 24, in g
+            x = y + 1
+        NameError: global name 'y' is not defined
+    <BLANKLINE>
+    <BLANKLINE>
+        test1 (sample2.sampletests_e.Test)
+        test2 (sample2.sampletests_e.Test)
+        test3 (sample2.sampletests_e.Test)
+    <BLANKLINE>
+    Error in test test3 (sample2.sampletests_e.Test)
+    Traceback (most recent call last):
+      File "testrunner-ex/sample2/sampletests_e.py", line 43, in test3
+        f()
+      File "testrunner-ex/sample2/sampletests_e.py", line 19, in f
+        g()
+      File "testrunner-ex/sample2/sampletests_e.py", line 24, in g
+        x = y + 1
+    NameError: global name 'y' is not defined
+    <BLANKLINE>
+    <BLANKLINE>
+        test4 (sample2.sampletests_e.Test)
+        test5 (sample2.sampletests_e.Test)
+        testrunner-ex/sample2/e.txt
+    <BLANKLINE>
+    Failure in test testrunner-ex/sample2/e.txt
+    Failed doctest test for e.txt
+      File "testrunner-ex/sample2/e.txt", line 0
+    <BLANKLINE>
+    ----------------------------------------------------------------------
+    File "testrunner-ex/sample2/e.txt", line 4, in e.txt
+    Failed example:
+        f()
+    Exception raised:
+        Traceback (most recent call last):
+          File ".../doctest.py", line 1256, in __run
+            compileflags, 1) in test.globs
+          File "<doctest e.txt[1]>", line 1, in ?
+            f()
+          File "<doctest e.txt[0]>", line 2, in f
+            return x
+        NameError: global name 'x' is not defined
+    <BLANKLINE>
+    <BLANKLINE>
+        test (sample2.sampletests_f.Test)
+    <BLANKLINE>
+    Failure in test test (sample2.sampletests_f.Test)
+    Traceback (most recent call last):
+      File "testrunner-ex/sample2/sampletests_f.py", line 21, in test
+        self.assertEqual(1,0)
+      File ".../unittest.py", line 302, in failUnlessEqual
+        raise self.failureException, \
+    AssertionError: 1 != 0
+    <BLANKLINE>
+    <BLANKLINE>
+        test_x1 (sample2.sampletests.test_1.TestA)
+        test_y0 (sample2.sampletests.test_1.TestA)
+        test_z0 (sample2.sampletests.test_1.TestA)
+        test_x0 (sample2.sampletests.test_1.TestB)
+        test_y1 (sample2.sampletests.test_1.TestB)
+        test_z0 (sample2.sampletests.test_1.TestB)
+        test_1 (sample2.sampletests.test_1.TestNotMuch)
+        test_2 (sample2.sampletests.test_1.TestNotMuch)
+        test_3 (sample2.sampletests.test_1.TestNotMuch)
+        test_x0 (sample2.sampletests.test_1)
+        test_y0 (sample2.sampletests.test_1)
+        test_z1 (sample2.sampletests.test_1)
+        testrunner-ex/sample2/sampletests/../../sampletests.txt
+        test_x1 (sample2.sampletests.testone.TestA)
+        test_y0 (sample2.sampletests.testone.TestA)
+        test_z0 (sample2.sampletests.testone.TestA)
+        test_x0 (sample2.sampletests.testone.TestB)
+        test_y1 (sample2.sampletests.testone.TestB)
+        test_z0 (sample2.sampletests.testone.TestB)
+        test_1 (sample2.sampletests.testone.TestNotMuch)
+        test_2 (sample2.sampletests.testone.TestNotMuch)
+        test_3 (sample2.sampletests.testone.TestNotMuch)
+        test_x0 (sample2.sampletests.testone)
+        test_y0 (sample2.sampletests.testone)
+        test_z1 (sample2.sampletests.testone)
+        testrunner-ex/sample2/sampletests/../../sampletests.txt
+        test_x1 (sample2.sample21.sampletests.TestA)
+        test_y0 (sample2.sample21.sampletests.TestA)
+        test_z0 (sample2.sample21.sampletests.TestA)
+        test_x0 (sample2.sample21.sampletests.TestB)
+        test_y1 (sample2.sample21.sampletests.TestB)
+        test_z0 (sample2.sample21.sampletests.TestB)
+        test_1 (sample2.sample21.sampletests.TestNotMuch)
+        test_2 (sample2.sample21.sampletests.TestNotMuch)
+        test_3 (sample2.sample21.sampletests.TestNotMuch)
+        test_x0 (sample2.sample21.sampletests)
+        test_y0 (sample2.sample21.sampletests)
+        test_z1 (sample2.sample21.sampletests)
+        testrunner-ex/sample2/sample21/../../sampletests.txt
+      Ran 56 tests with 3 failures and 1 errors in 0.060 seconds.
+    <BLANKLINE>
+    Tests with errors:
+       test3 (sample2.sampletests_e.Test)
+    <BLANKLINE>
+    Tests with failures:
+       eek (sample2.sampletests_e)
+       testrunner-ex/sample2/e.txt
+       test (sample2.sampletests_f.Test)

Modified: zope.testing/trunk/src/zope/testing/tests.py
===================================================================
--- zope.testing/trunk/src/zope/testing/tests.py	2005-05-24 20:28:14 UTC (rev 30491)
+++ zope.testing/trunk/src/zope/testing/tests.py	2005-05-24 20:28:53 UTC (rev 30492)
@@ -15,16 +15,18 @@
 
 $Id$
 """
+import os
+import sys
 import unittest
-from zope.testing.doctestunit import DocTestSuite, DocFileSuite
+from zope.testing import doctest, testrunner
 
-
 def test_suite():
     return unittest.TestSuite((
-        DocFileSuite('formparser.txt'),
-        DocTestSuite('zope.testing.loggingsupport'),
+        doctest.DocTestSuite('zope.testing.renormalizing'),
+        doctest.DocFileSuite('formparser.txt'),
+        doctest.DocTestSuite('zope.testing.loggingsupport'),
+        testrunner.test_suite(),
         ))
 
 if __name__ == '__main__':
     unittest.main(defaultTest='test_suite')
-

Added: zope.testing/trunk/test.py
===================================================================
--- zope.testing/trunk/test.py	2005-05-24 20:28:14 UTC (rev 30491)
+++ zope.testing/trunk/test.py	2005-05-24 20:28:53 UTC (rev 30492)
@@ -0,0 +1,33 @@
+##############################################################################
+#
+# Copyright (c) 2004 Zope Corporation and Contributors.
+# All Rights Reserved.
+#
+# This software is subject to the provisions of the Zope Public License,
+# Version 2.0 (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.
+#
+##############################################################################
+"""Sample test script using zope.testing.testrunner
+
+see zope.testing testrunner.txt
+
+$Id$
+"""
+
+import os, sys
+
+src = os.path.join(os.path.split(sys.argv[0])[0], 'src')
+sys.path.append(src)
+
+from zope.testing import testrunner
+
+defaults = [
+    '--path', src,
+    '--tests-pattern', '^tests$',
+    ]
+
+testrunner.run(defaults)



More information about the Zope3-Checkins mailing list