[Checkins] SVN: zope.etree/trunk/src/zope/etree/ Upgrade the ways in which this package can be used for testing XML content.

Michael Kerrin michael.kerrin at openapp.biz
Wed Apr 4 14:20:41 EDT 2007


Log message for revision 74010:
  Upgrade the ways in which this package can be used for testing XML content.
  
  * When running tests - guess which elementtree engine to use instead of
    requiring others to edit some ZCML file. This is also over-ridable with
    an environmental variable.
  * Integrate the assertXMLEqual method with doctests which has helped in
    writing much more readable tests in zope.webdav.
  

Changed:
  A   zope.etree/trunk/src/zope/etree/doctests.py
  A   zope.etree/trunk/src/zope/etree/doctests.txt
  A   zope.etree/trunk/src/zope/etree/doctestssuccess.txt
  A   zope.etree/trunk/src/zope/etree/doctesttests.txt
  U   zope.etree/trunk/src/zope/etree/testing.py
  U   zope.etree/trunk/src/zope/etree/tests.py

-=-
Added: zope.etree/trunk/src/zope/etree/doctests.py
===================================================================
--- zope.etree/trunk/src/zope/etree/doctests.py	2007-04-04 18:13:17 UTC (rev 74009)
+++ zope.etree/trunk/src/zope/etree/doctests.py	2007-04-04 18:20:41 UTC (rev 74010)
@@ -0,0 +1,16 @@
+import unittest
+from zope.testing import doctest
+import zope.etree.testing
+
+
+def test_suite():
+    suite = unittest.TestSuite()
+
+    suite.addTest(doctest.DocFileSuite(
+        "doctests.txt",
+        checker = zope.etree.testing.xmlOutputChecker,
+        setUp = zope.etree.testing.etreeSetup,
+        tearDown = zope.etree.testing.etreeTearDown,
+        optionflags = zope.etree.testing.XMLDATA))
+
+    return suite


Property changes on: zope.etree/trunk/src/zope/etree/doctests.py
___________________________________________________________________
Name: svn:eol-style
   + native

Added: zope.etree/trunk/src/zope/etree/doctests.txt
===================================================================
--- zope.etree/trunk/src/zope/etree/doctests.txt	2007-04-04 18:13:17 UTC (rev 74009)
+++ zope.etree/trunk/src/zope/etree/doctests.txt	2007-04-04 18:20:41 UTC (rev 74010)
@@ -0,0 +1,55 @@
+Test subelement with different name
+-----------------------------------
+
+  >>> '<test><subtest a="b"/></test>'
+  '<test><subtest1>Content</subtest1></test>'
+
+Test different number of elements on a sub element
+--------------------------------------------------
+  
+  >>> '<test><subtest>Content</subtest></test>'
+  '<test><subtest><subtest-2/></subtest></test>'
+
+Different element content
+-------------------------
+
+  >>> '<test><subtest>XXX</subtest></test>'
+  '<test><subtest>YYY</subtest></test>'
+
+Different number of attributes
+------------------------------
+
+  >>> '<test><subtest a="b" c="d">XXX</subtest></test>'
+  '<test><subtest a="b">XXX</subtest></test>'
+
+Different attribute content on subelement
+-----------------------------------------
+
+  >>> '<test><subtest a="d">XXX</subtest></test>'
+  '<test><subtest a="b">XXX</subtest></test>'
+
+Missing attribute
+-----------------
+
+  >>> '<test><subtest attr="d">XXX</subtest></test>'
+  '<test><subtest a="b">XXX</subtest></test>'
+
+Recursion ok
+------------
+
+  >>> '<test><subtest attr="d">XXX</subtest></test>'
+  '<test><subtest attr="d">XXX</subtest></test>'
+
+ElementTree objects
+===================
+
+Got to see what happens when 'got' argument is an ElementTree object.
+
+  >>> el = etree.Element('test')
+  >>> el.append(etree.Element('subtest'))
+
+  >>> print etree.tostring(el)
+  <test>
+    <subtest>
+    </subtest>
+  </test>

Added: zope.etree/trunk/src/zope/etree/doctestssuccess.txt
===================================================================
--- zope.etree/trunk/src/zope/etree/doctestssuccess.txt	2007-04-04 18:13:17 UTC (rev 74009)
+++ zope.etree/trunk/src/zope/etree/doctestssuccess.txt	2007-04-04 18:20:41 UTC (rev 74010)
@@ -0,0 +1,11 @@
+Whitespace doesn't matter
+-------------------------
+
+  >>> '<test ><b><c /></b></test>' #doctest:+XMLDATA
+  '<test><b><c/></b></test>'
+
+String comparison still works
+-----------------------------
+
+  >>> 'Hello, world!'
+  'Hello, world!'


Property changes on: zope.etree/trunk/src/zope/etree/doctestssuccess.txt
___________________________________________________________________
Name: svn:eol-style
   + native

Added: zope.etree/trunk/src/zope/etree/doctesttests.txt
===================================================================
--- zope.etree/trunk/src/zope/etree/doctesttests.txt	2007-04-04 18:13:17 UTC (rev 74009)
+++ zope.etree/trunk/src/zope/etree/doctesttests.txt	2007-04-04 18:20:41 UTC (rev 74010)
@@ -0,0 +1,86 @@
+===================
+XML doctest support 
+===================
+
+  >>> import sys
+  >>> from zope.testing import testrunner
+  >>> defaults = [
+  ...    '--path', this_directory,
+  ...    '--tests-pattern', '^doctests$',
+  ...    ]
+
+Some simple basic tests.
+
+  >>> sys.argv = 'test --tests-pattern ^doctests$ '.split()
+  >>> testrunner.run(defaults)
+  ... # doctest: +NORMALIZE_WHITESPACE
+  Running unit tests:
+  <BLANKLINE>
+  <BLANKLINE>
+  Failure doctests.txt
+  Failed doctests.txt
+   doctests.txt", line 0
+  <BLANKLINE>
+  ----------------------------------------------------------------------
+  File doctests.txt
+  Failed example:
+      '<test><subtest a="b"/></test>'
+  Expected:
+      '<test><subtest1>Content</subtest1></test>'
+  Got:
+      '<test><subtest a="b"/></test>'
+  XML differences:
+      'subtest1' != 'subtest' different tag name.
+  ----------------------------------------------------------------------
+  File doctests.txt
+  Failed example:
+      '<test><subtest>Content</subtest></test>'
+  Expected:
+      '<test><subtest><subtest-2/></subtest></test>'
+  Got:
+      '<test><subtest>Content</subtest></test>'
+  XML differences:
+      1 != 0 different number of subchildren on 'subtest'.
+  ----------------------------------------------------------------------
+  File doctests.txt
+  Failed example:
+      '<test><subtest>XXX</subtest></test>'
+  Expected:
+      '<test><subtest>YYY</subtest></test>'
+  Got:
+      '<test><subtest>XXX</subtest></test>'
+  XML differences:
+      ''YYY' != 'XXX'' have different element content.
+  ----------------------------------------------------------------------
+  File doctests.txt
+  Failed example:
+      '<test><subtest a="b" c="d">XXX</subtest></test>'
+  Expected:
+      '<test><subtest a="b">XXX</subtest></test>'
+  Got:
+      '<test><subtest a="b" c="d">XXX</subtest></test>'
+  XML differences:
+      1 != 2 different number of attributes on 'subtest'.
+  ----------------------------------------------------------------------
+  File doctests.txt
+  Failed example:
+      '<test><subtest a="d">XXX</subtest></test>'
+  Expected:
+      '<test><subtest a="b">XXX</subtest></test>'
+  Got:
+      '<test><subtest a="d">XXX</subtest></test>'
+  XML differences:
+      'a' attribute has different value for the 'subtest' tag.
+  ----------------------------------------------------------------------
+  File doctests.txt
+  Failed example:
+      '<test><subtest attr="d">XXX</subtest></test>'
+  Expected:
+      '<test><subtest a="b">XXX</subtest></test>'
+  Got:
+      '<test><subtest attr="d">XXX</subtest></test>'
+  XML differences:
+      'subtest' expected to find the 'a' attribute.
+  <BLANKLINE>
+    Ran N tests with N failures and N errors in N.NNN seconds.
+  True

Modified: zope.etree/trunk/src/zope/etree/testing.py
===================================================================
--- zope.etree/trunk/src/zope/etree/testing.py	2007-04-04 18:13:17 UTC (rev 74009)
+++ zope.etree/trunk/src/zope/etree/testing.py	2007-04-04 18:20:41 UTC (rev 74010)
@@ -17,126 +17,357 @@
 """
 __docformat__ = 'restructuredtext'
 
+import os
 import zope.component
-import zope.app.component
-from zope.configuration import xmlconfig
-from zope.app.testing import setup
+from zope.testing import doctest
 
-from interfaces import IEtree
 import zope.etree
+import zope.etree.etree
 
 #
 # Setup for Zope etree. 
 #
 
+engine_env_key = "ELEMENTTREE_ENGINE"
+
+known_engines = {
+    "cElementTree": ("cElementTree", zope.etree.etree.CEtree),
+    "elementtree": ("elementtree.ElemenTree", zope.etree.etree.EtreeEtree),
+    "lxml": ("lxml.etree", zope.etree.etree.LxmlEtree),
+    "py25": ("xml.etree", zope.etree.etree.EtreePy25),
+    }
+
 def etreeSetup(test = None):
-    setup.placelessSetUp()
-    context = xmlconfig.file("meta.zcml", package = zope.app.component)
-    xmlconfig.file("zope.etree-configure.zcml", package = zope.etree,
-                   context = context)
+    engine = None
 
-    etreeEtree = zope.component.getUtility(IEtree)
+    if engine_env_key in os.environ:
+        engine = known_engines[os.environ[engine_env_key]][1]()
+    else:
+        for key, info in known_engines.items():
+            modname, factory = info
+            try:
+                __import__(modname)
+            except ImportError:
+                pass
+            else:
+                engine = factory()
+                break
 
+    if engine is None:
+        raise ValueError("Failed to import a known element tree implementation")
+
+    zope.component.getGlobalSiteManager().registerUtility(engine)
+
     if test is not None:
-        test.globs["etree"] = etreeEtree
+        test.globs["etree"] = engine
         test.globs["assertXMLEqual"] = assertXMLEqual
-    return etreeEtree
 
+    return engine
+
+
 def etreeTearDown(test = None):
     if test is not None:
         del test.globs["etree"]
         del test.globs["assertXMLEqual"]
-    etreeEtree = zope.component.getUtility(IEtree)
+    etreeEtree = zope.etree.getEngine()
     zope.component.getGlobalSiteManager().unregisterUtility(etreeEtree)
+    zope.etree._utility = None # clear the cache
 
-    setup.placelessTearDown()
-
 #
 # Handy methods for testing if two xml fragmenets are equal.
 #
 
-def _assertTextEqual(got, expected):
+def _assertTextEqual(want, got, optionflags):
     """
-      >>> _assertTextEqual(None, "\\n")
-      True
 
-      >>> _assertTextEqual("\\n", "\\n")
-      True
+    Equal values.
 
-      >>> _assertTextEqual("test", "test")
-      True
+      >>> _assertTextEqual(None, "\\n", XMLDATA)
+      (True, None)
 
+      >>> _assertTextEqual(None, "\\n", XMLDATA)
+      (True, None)
+
+      >>> _assertTextEqual("\\n", None, XMLDATA)
+      (True, None)
+
+      >>> _assertTextEqual("\\n", "\\n", XMLDATA)
+      (True, None)
+
+      >>> _assertTextEqual("test", "test", XMLDATA)
+      (True, None)
+
+    Unequal values.
+
+      >>> _assertTextEqual("test", None, XMLDATA)
+      (False, "''test' != None' have different element content.")
+
+      >>> _assertTextEqual(None, "test", XMLDATA)
+      (False, "'None != 'test'' have different element content.")
+
+      >>> _assertTextEqual("test", "nottest", XMLDATA)
+      (False, "''test' != 'nottest'' have different element content.")
+
+      >>> etree = zope.etree.getEngine()
+      >>> _assertTextEqual("test", etree.Element("test"), XMLDATA)
+      Traceback (most recent call last):
+      ...
+      ValueError: _assertTextEqual can only tests text content
+
     """
-    tgot = got and got.strip()
-    texpected = expected and expected.strip()
+    twant = isinstance(want, (str, unicode)) and want.strip()
+    tgot = isinstance(got, (str, unicode)) and got.strip()
 
-    error_msg = "'%r != %r' have different element content." %(
-        got, expected)
+    if want is None:
+        twant = ""
 
-    if not tgot:
-        assert not texpected, error_msg
-        return True
+    if got is None:
+        tgot = ""
 
-    if not texpected:
-        assert not tgot, error_msg
-        return True
+    if not isinstance(twant, (str, unicode)) or \
+           not isinstance(tgot, (str, unicode)):
+        raise ValueError("_assertTextEqual can only tests text content")
 
-    assert isinstance(tgot, (str, unicode)), error_msg
-    assert isinstance(texpected, (str, unicode)), error_msg
+    if twant == tgot:
+        return True, None
+    return False, "'%r != %r' have different element content." %(want, got)
 
-    assert tgot == texpected, error_msg
 
-    return True
+def _assertXMLElementEqual(want, got, optionflags):
+    # See assertXMLEqual for tests - it is easier to the tests with strings that
+    # get converted to element tree objects in assertXMLEqual.
+    etree = zope.etree.getEngine()
 
-def _assertXMLElementEqual(got, expected):
-    etree = zope.component.getUtility(IEtree)
+    if want.tag != got.tag:
+        return False, "%r != %r different tag name." %(want.tag, got.tag)
+    if len(want) != len(got):
+        return False, "%d != %d different number of subchildren on %r." %(
+            len(want), len(got), want.tag)
 
-    assert got.tag == expected.tag, \
-           "'%r != %r' different tag name." %(got.tag, expected.tag)
-    assert len(got) == len(expected), \
-           "'%d != %d' different number of subchildren on %r." %(
-               len(got), len(expected), got.tag)
-    _assertTextEqual(got.text, expected.text)
+    result, msg =_assertTextEqual(want.text, got.text, optionflags)
+    if not result:
+        return result, msg
 
-    for index in range(0, len(got)):
-        _assertXMLElementEqual(got[index], expected[index])
+    if len(want.attrib) != len(got.attrib):
+        return False, "%d != %d different number of attributes on %r." %(
+            len(want.attrib), len(got.attrib), want.tag)
+    for attrib, attrib_value in want.attrib.items():
+        if attrib not in got.attrib:
+            return False, "%r expected to find the %r attribute." %(
+                want.tag, attrib)
+        if got.attrib[attrib] != attrib_value:
+            return \
+               False, "%r attribute has different value for the %r tag." %(
+                   attrib, want.tag)
 
+    for index in range(0, len(want)):
+        result, msg = _assertXMLElementEqual(
+            want[index], got[index], optionflags)
+        if not result:
+            return result, msg
 
-def assertXMLEqual(got, expected):
+    return True, None
+
+
+def assertXMLEqual(want, got):
     """
+
       >>> assertXMLEqual('<test>xml</test>', '<test>xml</test>')
 
+    Different element names. Element names are tested before attributes and
+    number of children, and content.
+
+      >>> assertXMLEqual('<test>XXX</test>', '<testx b="c">YYY</testx>')
+      Traceback (most recent call last):
+      ...
+      AssertionError: 'test' != 'testx' different tag name.
+
+    Different number of children. Number of children is tested before
+    content.
+
+      >>> assertXMLEqual('<test><subtest>Test</subtest></test>',
+      ...                '<test>Sub-Test</test>')
+      Traceback (most recent call last):
+      ...
+      AssertionError: 1 != 0 different number of subchildren on 'test'.
+
+    Different element content.
+
       >>> assertXMLEqual('<test>xml</test>', '<test>xml1</test>')
       Traceback (most recent call last):
       ...
       AssertionError: ''xml' != 'xml1'' have different element content.
 
-      >>> assertXMLEqual('<test><subtest>Test</subtest></test>',
-      ...                '<test>Test</test>')
+    Different number of attributes on a tag.
+
+      >>> assertXMLEqual('<test b="c"/>', '<test/>')
       Traceback (most recent call last):
       ...
-      AssertionError: '1 != 0' different number of subchildren on 'test'.
+      AssertionError: 1 != 0 different number of attributes on 'test'.
 
-      >>> assertXMLEqual('<test1/>', '<test2/>')
+    Different attribute content.
+
+      >>> assertXMLEqual('<test b="c"/>', '<test b="d"/>')
       Traceback (most recent call last):
       ...
-      AssertionError: ''test1' != 'test2'' different tag name.
+      AssertionError: 'b' attribute has different value for the 'test' tag.
 
-      >>> assertXMLEqual('<a><b><c /></b></a>', '<a><b><c/></b></a>')
+    Different attributes.
 
+      >>> assertXMLEqual('<test b="c"/>', '<test bb="d"/>')
+      Traceback (most recent call last):
+      ...
+      AssertionError: 'test' expected to find the 'b' attribute.
+
+    Attributes ok.
+
+      >>> assertXMLEqual('<test b="c"/>', '<test b="c"/>')
+
+    Subelement is wrong. Tests _assertXMLElementEqual recursion. First test
+    subelement with different name.
+
+      >>> assertXMLEqual('<test><subtest a="b"/></test>',
+      ...    '<test><subtest1>Content</subtest1></test>')
+      Traceback (most recent call last):
+      ...
+      AssertionError: 'subtest' != 'subtest1' different tag name.
+
+    Test different number of elements on a sub element.
+      
+      >>> assertXMLEqual('<test><subtest>Content</subtest></test>',
+      ...    '<test><subtest><subtest-2/></subtest></test>')
+      Traceback (most recent call last):
+      ...
+      AssertionError: 0 != 1 different number of subchildren on 'subtest'.
+
+    Different element content.
+
+      >>> assertXMLEqual('<test><subtest>XXX</subtest></test>',
+      ...    '<test><subtest>YYY</subtest></test>')
+      Traceback (most recent call last):
+      ...
+      AssertionError: ''XXX' != 'YYY'' have different element content.
+
+    Different number of attributes.
+
+      >>> assertXMLEqual('<test><subtest a="b" c="d">XXX</subtest></test>',
+      ...    '<test><subtest a="b">XXX</subtest></test>')
+      Traceback (most recent call last):
+      ...
+      AssertionError: 2 != 1 different number of attributes on 'subtest'.
+
+    Different attribute content on subelement.
+
+      >>> assertXMLEqual('<test><subtest a="d">XXX</subtest></test>',
+      ...    '<test><subtest a="b">XXX</subtest></test>')
+      Traceback (most recent call last):
+      ...
+      AssertionError: 'a' attribute has different value for the 'subtest' tag.
+
+    Missing attribute.
+
+      >>> assertXMLEqual('<test><subtest attr="d">XXX</subtest></test>',
+      ...    '<test><subtest a="b">XXX</subtest></test>')
+      Traceback (most recent call last):
+      ...
+      AssertionError: 'subtest' expected to find the 'attr' attribute.
+
+    Recursion ok.
+
+      >>> assertXMLEqual('<test><subtest attr="d">XXX</subtest></test>',
+      ...    '<test><subtest attr="d">XXX</subtest></test>')
+
+    Whitespace doesn't matter.
+
+      >>> assertXMLEqual('<test ><b><c /></b></test>',
+      ...    '<test><b><c/></b></test>')
+
+    Test passing elementtree objects through the first arguement.
+
+      >>> etree = zope.etree.getEngine()
+      >>> elroot = etree.Element('test')
+      >>> eltree = etree.ElementTree(elroot)
+
+      >>> assertXMLEqual(eltree, '<test />')
+
+      >>> assertXMLEqual(eltree, etree.ElementTree(etree.Element('test')))
+
+      >>> assertXMLEqual(eltree, etree.Element('test'))
+
+      >>> assertXMLEqual(elroot, '<test />')
+
     """
-    etree = zope.component.getUtility(IEtree)
+    etree = zope.etree.getEngine()
 
+    if isinstance(want, (str, unicode)):
+        want = etree.fromstring(want)
     if isinstance(got, (str, unicode)):
         got = etree.fromstring(got)
-    if isinstance(expected, (str, unicode)):
-        expected = etree.fromstring(expected)
 
+    if getattr(want, "getroot", None) is not None:
+        # Most then likely a ElementTree object.
+        want = want.getroot()
+
     if getattr(got, "getroot", None) is not None:
-        # XXX - is this all neccessary.
+        # Most then likely a ElementTree object.
         got = got.getroot()
+        
+    result, msg = _assertXMLElementEqual(want, got, XMLDATA)
+    assert result, msg
 
-        assert getattr(expected, "getroot", None) is not None
-        expected = expected.getroot()
+#
+# Integrate the above methods with doctest.
+#
 
-    _assertXMLElementEqual(got, expected)
+def _assertXMLElement(want, got, optionflags):
+    etree = zope.etree.getEngine()
+
+    def clean_string(s):
+        if not isinstance(s, (str, unicode)):
+            return s # not tested
+        s = s.strip()
+        if s[0] in ("'", '"') and s[-1] in ("'", '"'):
+            s = s[1:-1]
+        return s
+
+    want = etree.fromstring(clean_string(want))
+    got = etree.fromstring(clean_string(got))
+
+    return _assertXMLElementEqual(want, got, optionflags)
+
+
+XMLDATA = doctest.register_optionflag("XMLDATA")
+
+class XMLOutputChecker(doctest.OutputChecker):
+
+    def check_output(self, want, got, optionflags):
+        if optionflags & XMLDATA:
+            if want and got: # it only makes sense to compare actual data.
+                result, msg = _assertXMLElement(want, got, optionflags)
+                return result
+        return doctest.OutputChecker.check_output(
+            self, want, got, optionflags)
+
+    def output_difference(self, example, got, optionflags):
+        if optionflags & XMLDATA:
+            want = example.want
+            if want and got: # it only makes sense to compare actual data
+                error = 'Expected:\n%sGot:\n%s' %(doctest._indent(want),
+                                                  doctest._indent(got))
+                result, errmsg = _assertXMLElement(want, got, optionflags)
+                assert not result, "assertXMLEqual didn't fail."
+
+                if errmsg:
+                    error += "XML differences:\n" + \
+                                 doctest._indent(errmsg) + "\n"
+                else: # XXX - not tested
+                    error += "No known XML difference."
+
+                return error
+        return doctest.OutputChecker.output_difference(
+            self, example, got, optionflags)
+
+xmlOutputChecker = XMLOutputChecker()
+
+__all__ = ("etreeSetup", "etreeTearDown", "assertXMLEqual",
+           "xmlOutputChecker", "XMLDATA")

Modified: zope.etree/trunk/src/zope/etree/tests.py
===================================================================
--- zope.etree/trunk/src/zope/etree/tests.py	2007-04-04 18:13:17 UTC (rev 74009)
+++ zope.etree/trunk/src/zope/etree/tests.py	2007-04-04 18:20:41 UTC (rev 74010)
@@ -21,13 +21,21 @@
 $Id$
 """
 
+import os
+import os.path
+import sys
+import gc
+import re
 import unittest
-import doctest
 from cStringIO import StringIO
 
+from zope import component
+from zope.testing import doctest
+from zope.testing import renormalizing
+from zope.testing import testrunner
 from zope.interface.verify import verifyObject
-from zope import component
-from zope.etree import etree
+
+import zope.etree.etree
 from interfaces import IEtree
 from testing import etreeSetup, etreeTearDown
 
@@ -155,7 +163,7 @@
         """)
 
 
-class doctestSetup(object):
+class setUp(object):
 
     def __init__(self, etree):
         self.etree = etree
@@ -165,11 +173,78 @@
         test.globs["etree"] = self.etree
 
 
-def doctestTeardown(test):
+def tearDown(test):
     component.getGlobalSiteManager().unregisterUtility(test.globs["etree"])
     del test.globs["etree"]
 
 
+checker = renormalizing.RENormalizing([
+    # 2.5 changed the way pdb reports exceptions
+        (re.compile(r"<class 'exceptions.(\w+)Error'>:"),
+                    r'exceptions.\1Error:'),
+
+        (re.compile('^> [^\n]+->None$', re.M), '> ...->None'),
+        (re.compile("'[A-Z]:\\\\"), "'"), # hopefully, we'll make Windows happy
+        (re.compile(r'\\\\'), '/'), # more Windows happiness
+        (re.compile(r'\\'), '/'), # even more Windows happiness
+       (re.compile('/r'), '\\\\r'), # undo damage from previous
+       (re.compile(r'\r'), '\\\\r\n'),
+       (re.compile(r'\d+[.]\d\d\d seconds'), 'N.NNN seconds'),
+       (re.compile(r'\d+[.]\d\d\d ms'), 'N.NNN ms'),
+        (re.compile('( |")[^\n]+doctest'), r'\1doctest'),
+        (re.compile('( |")[^\n]+testrunner.py'), r'\1testrunner.py'),
+        (re.compile(r'> [^\n]*(doc|unit)test[.]py\(\d+\)'),
+                    r'\1doctest.py(NNN)'),
+        (re.compile(r'[.]py\(\d+\)'), r'.py(NNN)'),
+        (re.compile(r'[.]py:\d+'), r'.py:NNN'),
+        (re.compile(r' line \d+,', re.IGNORECASE), r' Line NNN,'),
+
+        # omit traceback entries for unittest.py or doctest.py from
+        # output:
+        (re.compile(r'^ +File "[^\n]+(doc|unit)test.py", [^\n]+\n[^\n]+\n',
+                    re.MULTILINE),
+         r''),
+        (re.compile('^> [^\n]+->None$', re.M), '> ...->None'),
+        (re.compile('import pdb; pdb'), 'Pdb()'), # Py 2.3
+
+        # Omit the number of tests ran
+        (re.compile(r'Ran \d tests with \d failures and \d errors'),
+                    r'Ran N tests with N failures and N errors'),
+        ])
+
+
+class doctestsSetup(object):
+
+    def __init__(self, engine_key):
+        self.engine_key = engine_key
+
+    def __call__(self, test):
+        test.globs['saved-sys-info'] = (
+            sys.path[:],
+            sys.argv[:],
+            sys.modules.copy(),
+            gc.get_threshold(),
+            )
+        test.globs['this_directory'] = os.path.split(__file__)[0]
+        test.globs['testrunner_script'] = __file__
+        test.globs['old_configure_logging'] = testrunner.configure_logging
+        testrunner.configure_logging = lambda : None
+        test.globs['old_engine'] = os.environ.get(
+            zope.etree.testing.engine_env_key)
+        os.environ[zope.etree.testing.engine_env_key] = self.engine_key
+
+
+def doctestsTearDown(test):
+    sys.path[:], sys.argv[:] = test.globs['saved-sys-info'][:2]
+    gc.set_threshold(*test.globs['saved-sys-info'][3])
+    sys.modules.clear()
+    sys.modules.update(test.globs['saved-sys-info'][2])
+    testrunner.configure_logging = test.globs['old_configure_logging']
+    del test.globs['old_configure_logging']
+    del os.environ[zope.etree.testing.engine_env_key]
+    del test.globs['old_engine']
+
+
 def test_suite():
     suite = unittest.TestSuite()
 
@@ -181,8 +256,20 @@
         suite.addTest(doctest.DocTestSuite(
             "zope.etree.testing",
             optionflags = doctest.ELLIPSIS + doctest.NORMALIZE_WHITESPACE,
-            setUp = doctestSetup(etree.EtreeEtree()),
-            tearDown = doctestTeardown))
+            setUp = setUp(zope.etree.etree.EtreeEtree()),
+            tearDown = tearDown))
+        suite.addTest(doctest.DocFileSuite(
+            "doctesttests.txt", package = zope.etree,
+            checker = checker,
+            optionflags = doctest.ELLIPSIS + doctest.NORMALIZE_WHITESPACE,
+            setUp = doctestsSetup("elementtree"),
+            tearDown = doctestsTearDown))
+        suite.addTest(doctest.DocFileSuite(
+            "doctestssuccess.txt", package = zope.etree,
+            checker = zope.etree.testing.xmlOutputChecker,
+            optionflags = doctest.ELLIPSIS + doctest.NORMALIZE_WHITESPACE,
+            setUp = setUp(zope.etree.etree.EtreeEtree()),
+            tearDown = tearDown))
         foundetree = True
     except ImportError:
         pass
@@ -193,8 +280,20 @@
         suite.addTest(doctest.DocTestSuite(
             "zope.etree.testing",
             optionflags = doctest.ELLIPSIS + doctest.NORMALIZE_WHITESPACE,
-            setUp = doctestSetup(etree.CEtree()),
-            tearDown = doctestTeardown))
+            setUp = setUp(zope.etree.etree.CEtree()),
+            tearDown = tearDown))
+        suite.addTest(doctest.DocFileSuite(
+            "doctesttests.txt", package = zope.etree,
+            checker = checker,
+            optionflags = doctest.ELLIPSIS + doctest.NORMALIZE_WHITESPACE,
+            setUp = doctestsSetup("cElementTree"),
+            tearDown = doctestsTearDown))
+        suite.addTest(doctest.DocFileSuite(
+            "doctestssuccess.txt", package = zope.etree,
+            checker = zope.etree.testing.xmlOutputChecker,
+            optionflags = doctest.ELLIPSIS + doctest.NORMALIZE_WHITESPACE,
+            setUp = setUp(zope.etree.etree.CEtree()),
+            tearDown = tearDown))
         foundetree = True
     except ImportError:
         pass
@@ -205,8 +304,20 @@
         suite.addTest(doctest.DocTestSuite(
             "zope.etree.testing",
             optionflags = doctest.ELLIPSIS + doctest.NORMALIZE_WHITESPACE,
-            setUp = doctestSetup(etree.LxmlEtree()),
-            tearDown = doctestTeardown))
+            setUp = setUp(zope.etree.etree.LxmlEtree()),
+            tearDown = tearDown))
+        suite.addTest(doctest.DocFileSuite(
+            "doctesttests.txt", package = zope.etree,
+            checker = checker,
+            optionflags = doctest.ELLIPSIS + doctest.NORMALIZE_WHITESPACE,
+            setUp = doctestsSetup("lxml"),
+            tearDown = doctestsTearDown))
+        suite.addTest(doctest.DocFileSuite(
+            "doctestssuccess.txt", package = zope.etree,
+            checker = zope.etree.testing.xmlOutputChecker,
+            optionflags = doctest.ELLIPSIS + doctest.NORMALIZE_WHITESPACE,
+            setUp = setUp(zope.etree.etree.LxmlEtree()),
+            tearDown = tearDown))
         foundetree = True
     except ImportError:
         pass
@@ -217,8 +328,20 @@
         suite.addTest(doctest.DocTestSuite(
             "zope.etree.testing",
             optionflags = doctest.ELLIPSIS + doctest.NORMALIZE_WHITESPACE,
-            setUp = doctestSetup(etree.EtreePy25()),
-            tearDown = doctestTeardown))
+            setUp = setUp(zope.etree.etree.EtreePy25()),
+            tearDown = tearDown))
+        suite.addTest(doctest.DocFileSuite(
+            "doctesttests.txt", package = zope.etree,
+            checker = checker,
+            optionflags = doctest.ELLIPSIS + doctest.NORMALIZE_WHITESPACE,
+            setUp = doctestsSetup("py25"),
+            tearDown = doctestsTearDown))
+        suite.addTest(doctest.DocFileSuite(
+            "doctestssuccess.txt", package = zope.etree,
+            checker = zope.etree.testing.xmlOutputChecker,
+            optionflags = doctest.ELLIPSIS + doctest.NORMALIZE_WHITESPACE,
+            setUp = setUp(zope.etree.etree.EtreePy25()),
+            tearDown = tearDown))
         foundetree = True
     except ImportError:
         pass



More information about the Checkins mailing list