[Zope3-checkins] SVN: zope.testing/branches/gotcha-test-layers/src/zope/testing/testrunner/ savepoint
Godefroid Chapelle
gotcha at bubblenet.be
Tue Mar 1 04:54:39 EST 2011
Log message for revision 120629:
savepoint
Changed:
A zope.testing/branches/gotcha-test-layers/src/zope/testing/testrunner/layerutils.py
U zope.testing/branches/gotcha-test-layers/src/zope/testing/testrunner/runner.py
U zope.testing/branches/gotcha-test-layers/src/zope/testing/testrunner/tests.py
-=-
Added: zope.testing/branches/gotcha-test-layers/src/zope/testing/testrunner/layerutils.py
===================================================================
--- zope.testing/branches/gotcha-test-layers/src/zope/testing/testrunner/layerutils.py (rev 0)
+++ zope.testing/branches/gotcha-test-layers/src/zope/testing/testrunner/layerutils.py 2011-03-01 09:54:38 UTC (rev 120629)
@@ -0,0 +1,157 @@
+##############################################################################
+#
+# Copyright (c) 2004-2008 Zope Foundation 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.
+#
+##############################################################################
+"""Layer helpers
+"""
+from zope.testing.testrunner.find import name_from_layer
+
+
+def order_by_bases(layers):
+ """Order the layers from least to most specific (bottom to top)
+
+ >>> class Base(object):
+ ... __bases__ = ()
+ ... @property
+ ... def __name__(self):
+ ... return self.__class__.__name__
+ ... def __repr__(self):
+ ... return self.__name__
+
+ A layer without any base:
+
+ >>> class Zero(Base):
+ ... pass
+ >>> zero = Zero()
+
+ A layer with a single base:
+
+ >>> class One(Base):
+ ... __bases__ = (zero, )
+ >>> one = One()
+
+ Less specific comes first:
+
+ >>> order_by_bases([one, zero])
+ [Zero, One]
+
+
+ Another layer with a single base:
+
+ >>> class OneBis(Base):
+ ... __bases__ = (one, )
+ >>> one_bis = OneBis()
+
+ Less specific comes first:
+
+ >>> order_by_bases([one, zero, one_bis])
+ [Zero, One, OneBis]
+
+ Order of layers of identical specificity does not depend
+ on their order in the input:
+
+ >>> order_by_bases([one_bis, zero, one])
+ [Zero, One, OneBis]
+ >>> order_by_bases([one_bis, one, zero])
+ [Zero, One, OneBis]
+ >>> order_by_bases([zero, one_bis, one])
+ [Zero, One, OneBis]
+
+ Another layer with a single base:
+
+ >>> class OneTer(Base):
+ ... __bases__ = (zero, )
+ >>> one_ter = OneTer()
+
+ Less specific still comes first:
+
+ >>> order_by_bases([one_bis, one_ter, one, zero])
+ [Zero, OneTer, One, OneBis]
+
+ Order of layers of identical specificity does still not depend
+ on their order in the input:
+
+ >>> order_by_bases([one_ter, one_bis, one, zero])
+ [Zero, OneTer, One, OneBis]
+ >>> order_by_bases([zero, one_ter, one_bis, one])
+ [Zero, OneTer, One, OneBis]
+
+ A layer with two bases of different specificity:
+
+ >>> class Two(Base):
+ ... __bases__ = (zero, one)
+ >>> two = Two()
+
+ Ordered by inverse specificity:
+
+ >>> order_by_bases([two, one, zero])
+ [Zero, One, Two]
+ >>> order_by_bases([zero, two, one])
+ [Zero, One, Two]
+ >>> order_by_bases([two, zero, one])
+ [Zero, One, Two]
+
+ Another layer with two bases of different specificity:
+
+ >>> class TwoBis(Base):
+ ... __bases__ = (zero, one_bis)
+ >>> two_bis = TwoBis()
+
+ >>> order_by_bases([two, two_bis, one, zero])
+ [Zero, One, Two, TwoBis]
+ >>> order_by_bases([two_bis, two, one, zero])
+ [Zero, One, Two, TwoBis]
+
+ >>> order_by_bases([one_bis, two_bis, two, one, zero])
+ [Zero, One, OneBis, Two, TwoBis]
+
+ >>> class Three(Base):
+ ... __bases__ = (two, one_bis)
+ >>> three = Three()
+
+ >>> order_by_bases([one_bis, two_bis, three, two, one, zero])
+ [Zero, One, OneBis, Two, TwoBis, Three]
+ """
+ named_layers = [(name_from_layer(layer), layer) for layer in layers]
+ named_layers.sort()
+ named_layers.reverse()
+ # Store layers along with their specificity measured by numbers of
+ # sublayers.
+ all_layers = {}
+ for name, layer in named_layers:
+ gathered = []
+ gather_layers(layer, gathered)
+ index = len(gathered)
+ some_layers = all_layers.setdefault(index, [])
+ some_layers.append(gathered)
+ keys = all_layers.keys()
+ keys.sort()
+ # Gather them all starting by the least specific.
+ gathered = []
+ for key in keys:
+ for some_layers in all_layers[key]:
+ gathered.extend(some_layers)
+ seen = {}
+ result = []
+ for layer in gathered:
+ if layer not in seen:
+ seen[layer] = 1
+ if layer in layers:
+ result.append(layer)
+ return result
+
+
+def gather_layers(layer, result):
+ if layer is not object:
+ result.append(layer)
+ for b in layer.__bases__:
+ gather_layers(b, result)
Modified: zope.testing/branches/gotcha-test-layers/src/zope/testing/testrunner/runner.py
===================================================================
--- zope.testing/branches/gotcha-test-layers/src/zope/testing/testrunner/runner.py 2011-03-01 09:45:09 UTC (rev 120628)
+++ zope.testing/branches/gotcha-test-layers/src/zope/testing/testrunner/runner.py 2011-03-01 09:54:38 UTC (rev 120629)
@@ -29,6 +29,7 @@
import traceback
import unittest
+from zope.testing.testrunner.layerutils import order_by_bases, gather_layers
from zope.testing.testrunner.find import import_name
from zope.testing.testrunner.find import name_from_layer, _layer_name_cache
from zope.testing.testrunner.refcount import TrackRefs
@@ -206,7 +207,7 @@
Returns True if there where failures or False if all tests passed.
"""
- setup_layers = {}
+ setup_layers = []
layers_to_run = list(self.ordered_layers())
should_resume = False
@@ -592,27 +593,32 @@
def tear_down_unneeded(options, needed, setup_layers, optional=False):
# 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()
- output = options.output
- for l in unneeded:
- output.start_tear_down(name_from_layer(l))
- t = time.time()
+ unneeded = set([l for l in setup_layers if l not in needed])
+ while unneeded:
+ l = setup_layers[-1]
+ if l not in unneeded:
+ raise ValueError('Unexpected layer teardown order.')
try:
- try:
- if hasattr(l, 'tearDown'):
- l.tearDown()
- except NotImplementedError:
- output.tear_down_not_supported()
- if not optional:
- raise CanNotTearDown(l)
- else:
- output.stop_tear_down(time.time() - t)
+ tear_down_layer(options, l, optional)
finally:
- del setup_layers[l]
+ setup_layers.pop()
+ unneeded.remove(l)
+def tear_down_layer(options, l, optional):
+ output = options.output
+ output.start_tear_down(name_from_layer(l))
+ t = time.time()
+ try:
+ if hasattr(l, 'tearDown'):
+ l.tearDown()
+ except NotImplementedError:
+ output.tear_down_not_supported()
+ if not optional:
+ raise CanNotTearDown(l)
+ else:
+ output.stop_tear_down(time.time() - t)
+
cant_pm_in_subprocess_message = """
Can't post-mortem debug when running a layer as a subprocess!
Try running layer %r by itself.
@@ -645,15 +651,11 @@
raise
output.stop_set_up(time.time() - t)
- setup_layers[layer] = 1
+ setup_layers.append(layer)
class TestResult(unittest.TestResult):
- # Handle unexpected success as failure:
- # https://bugs.launchpad.net/zope.testrunner/+bug/719369
- addUnexpectedSuccess = None
-
def __init__(self, options, tests, layer_name=None):
unittest.TestResult.__init__(self)
self.options = options
@@ -777,33 +779,6 @@
% (module_name, 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()
- named_layers.reverse()
- 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 gather_layers(layer, result):
- if layer is not object:
- result.append(layer)
- for b in layer.__bases__:
- gather_layers(b, result)
-
-
class FakeInputContinueGenerator:
def readline(self):
Modified: zope.testing/branches/gotcha-test-layers/src/zope/testing/testrunner/tests.py
===================================================================
--- zope.testing/branches/gotcha-test-layers/src/zope/testing/testrunner/tests.py 2011-03-01 09:45:09 UTC (rev 120628)
+++ zope.testing/branches/gotcha-test-layers/src/zope/testing/testrunner/tests.py 2011-03-01 09:54:38 UTC (rev 120629)
@@ -194,6 +194,7 @@
optionflags=doctest.ELLIPSIS+doctest.NORMALIZE_WHITESPACE),
doctest.DocTestSuite('zope.testing.testrunner.options'),
doctest.DocTestSuite('zope.testing.testrunner.find'),
+ doctest.DocTestSuite('zope.testing.testrunner.layerutils'),
]
if sys.platform == 'win32':
More information about the Zope3-Checkins
mailing list