diff options
Diffstat (limited to 'src/zope/traversing')
-rw-r--r-- | src/zope/traversing/adapters.py | 5 | ||||
-rw-r--r-- | src/zope/traversing/api.py | 7 | ||||
-rw-r--r-- | src/zope/traversing/browser/absoluteurl.py | 52 | ||||
-rw-r--r-- | src/zope/traversing/browser/tests.py | 96 | ||||
-rw-r--r-- | src/zope/traversing/interfaces.py | 7 | ||||
-rw-r--r-- | src/zope/traversing/namespace.py | 54 | ||||
-rw-r--r-- | src/zope/traversing/publicationtraverse.py | 4 | ||||
-rw-r--r-- | src/zope/traversing/testing.py | 4 | ||||
-rw-r--r-- | src/zope/traversing/tests/test_conveniencefunctions.py | 143 | ||||
-rw-r--r-- | src/zope/traversing/tests/test_lang.py | 7 | ||||
-rw-r--r-- | src/zope/traversing/tests/test_namespacetrversal.py | 112 | ||||
-rw-r--r-- | src/zope/traversing/tests/test_presentation.py | 11 | ||||
-rw-r--r-- | src/zope/traversing/tests/test_publicationtraverse.py | 106 | ||||
-rw-r--r-- | src/zope/traversing/tests/test_skin.py | 10 | ||||
-rw-r--r-- | src/zope/traversing/tests/test_traverser.py | 75 | ||||
-rw-r--r-- | src/zope/traversing/tests/test_vhosting.py | 65 |
16 files changed, 503 insertions, 255 deletions
diff --git a/src/zope/traversing/adapters.py b/src/zope/traversing/adapters.py index a4985a2..45d6e92 100644 --- a/src/zope/traversing/adapters.py +++ b/src/zope/traversing/adapters.py @@ -151,7 +151,4 @@ def traversePathElement(obj, name, further_path, default=_marker, except LocationError: if default is not _marker: return default - else: - raise - - return obj + raise diff --git a/src/zope/traversing/api.py b/src/zope/traversing/api.py index 63b65d7..7a938b2 100644 --- a/src/zope/traversing/api.py +++ b/src/zope/traversing/api.py @@ -88,8 +88,7 @@ def traverse(object, path, default=_marker, request=None): traverser = ITraverser(object) if default is _marker: return traverser.traverse(path, request=request) - else: - return traverser.traverse(path, default=default, request=request) + return traverser.traverse(path, default=default, request=request) def traverseName(obj, name, default=_marker, traversable=None, request=None): @@ -118,8 +117,8 @@ def traverseName(obj, name, default=_marker, traversable=None, request=None): traversable=traversable, request=request) if further_path: raise NotImplementedError('further_path returned from traverse') - else: - return obj + + return obj def getName(obj): diff --git a/src/zope/traversing/browser/absoluteurl.py b/src/zope/traversing/browser/absoluteurl.py index a07f389..9b89d46 100644 --- a/src/zope/traversing/browser/absoluteurl.py +++ b/src/zope/traversing/browser/absoluteurl.py @@ -14,10 +14,15 @@ """Absolute URL View components """ try: - from urllib import quote as quote, unquote -except ImportError: from urllib.parse import quote_from_bytes as quote +except ImportError: + from urllib import quote + +try: from urllib.parse import unquote_to_bytes as unquote +except ImportError: + from urllib import unquote + import zope.component from zope.interface import implementer @@ -29,8 +34,8 @@ from zope.i18nmessageid import MessageFactory _ = MessageFactory('zope') _insufficientContext = _("There isn't enough context to get URL information. " - "This is probably due to a bug in setting up location " - "information.") + "This is probably due to a bug in setting up location " + "information.") _safe = '@+' # Characters that we don't want to have quoted @@ -38,13 +43,16 @@ _safe = '@+' # Characters that we don't want to have quoted def absoluteURL(ob, request): return zope.component.getMultiAdapter((ob, request), IAbsoluteURL)() - -@implementer(IAbsoluteURL) -class AbsoluteURL(BrowserView): +class _EncodedUnicode(object): def __unicode__(self): return unquote(self.__str__()).decode('utf-8') + +@implementer(IAbsoluteURL) +class AbsoluteURL(_EncodedUnicode, + BrowserView): + def __str__(self): context = self.context request = self.request @@ -102,26 +110,27 @@ class AbsoluteURL(BrowserView): return ({'name': '', 'url': self.request.getApplicationURL()}, ) base = tuple(zope.component.getMultiAdapter( - (container, request), IAbsoluteURL).breadcrumbs()) + (container, request), IAbsoluteURL).breadcrumbs()) name = getattr(context, '__name__', None) if name is None: raise TypeError(_insufficientContext) if name: - base += ({'name': name, - 'url': ("%s/%s" % (base[-1]['url'], - quote(name.encode('utf-8'), _safe))) - }, ) + base += ( + { + 'name': name, + 'url': ("%s/%s" % (base[-1]['url'], + quote(name.encode('utf-8'), _safe))) + }, + ) return base @implementer(IAbsoluteURL) -class SiteAbsoluteURL(BrowserView): - - def __unicode__(self): - return unquote(self.__str__()).decode('utf-8') +class SiteAbsoluteURL(_EncodedUnicode, + BrowserView): def __str__(self): context = self.context @@ -151,9 +160,12 @@ class SiteAbsoluteURL(BrowserView): name = getattr(context, '__name__', None) if name: - base += ({'name': name, - 'url': ("%s/%s" % (base[-1]['url'], - quote(name.encode('utf-8'), _safe))) - }, ) + base += ( + { + 'name': name, + 'url': ("%s/%s" % (base[-1]['url'], + quote(name.encode('utf-8'), _safe))) + }, + ) return base diff --git a/src/zope/traversing/browser/tests.py b/src/zope/traversing/browser/tests.py index 6eab7b1..861cb9c 100644 --- a/src/zope/traversing/browser/tests.py +++ b/src/zope/traversing/browser/tests.py @@ -13,12 +13,13 @@ ############################################################################## """Test the AbsoluteURL view """ -from unittest import TestCase, main, makeSuite +import unittest import zope.component from zope.component import getMultiAdapter, adapter from zope.component.testing import PlacelessSetup from zope.traversing.browser.absoluteurl import absoluteURL +from zope.traversing.browser.absoluteurl import AbsoluteURL from zope.traversing.browser.interfaces import IAbsoluteURL from zope.traversing.testing import browserView from zope.i18n.interfaces import IUserPreferredCharsets @@ -70,7 +71,7 @@ class FooLocation(object): return contained(TrivialContent(), Root(), name='bar') -class TestAbsoluteURL(PlacelessSetup, TestCase): +class TestAbsoluteURL(PlacelessSetup, unittest.TestCase): def setUp(self): PlacelessSetup.setUp(self) @@ -127,7 +128,7 @@ class TestAbsoluteURL(PlacelessSetup, TestCase): {'name': 'a', 'url': 'http://127.0.0.1/a'}, {'name': 'b', 'url': 'http://127.0.0.1/a/b'}, {'name': 'c', 'url': 'http://127.0.0.1/a/b/c'}, - )) + )) def testParentButNoLocation(self): request = TestRequest() @@ -163,7 +164,7 @@ class TestAbsoluteURL(PlacelessSetup, TestCase): ({'name': '', 'url': 'http://127.0.0.1'}, {'name': 'bar', 'url': 'http://127.0.0.1/bar'}, {'name': 'foo', 'url': 'http://127.0.0.1/bar/foo'}, - )) + )) def testParentTrumpsAdapter(self): # if we have a location adapter for a content object but @@ -210,7 +211,7 @@ class TestAbsoluteURL(PlacelessSetup, TestCase): {'name': u'\u0441', 'url': 'http://127.0.0.1/%D0%B9/%D1%82/%D0%B5/%D1%81'}, - )) + )) def testRetainSkin(self): request = TestRequest() @@ -230,7 +231,7 @@ class TestAbsoluteURL(PlacelessSetup, TestCase): {'name': 'a', 'url': base + '/a'}, {'name': 'b', 'url': base + '/a/b'}, {'name': 'c', 'url': base + '/a/b/c'}, - )) + )) def testVirtualHosting(self): request = TestRequest() @@ -245,10 +246,10 @@ class TestAbsoluteURL(PlacelessSetup, TestCase): breadcrumbs = view.breadcrumbs() self.assertEqual(breadcrumbs, - ({'name': '', 'url': 'http://127.0.0.1'}, - {'name': 'b', 'url': 'http://127.0.0.1/b'}, - {'name': 'c', 'url': 'http://127.0.0.1/b/c'}, - )) + ({'name': '', 'url': 'http://127.0.0.1'}, + {'name': 'b', 'url': 'http://127.0.0.1/b'}, + {'name': 'c', 'url': 'http://127.0.0.1/b/c'}, + )) def testVirtualHostingWithVHElements(self): request = TestRequest() @@ -263,10 +264,10 @@ class TestAbsoluteURL(PlacelessSetup, TestCase): breadcrumbs = view.breadcrumbs() self.assertEqual(breadcrumbs, - ({'name': '', 'url': 'http://127.0.0.1'}, - {'name': 'b', 'url': 'http://127.0.0.1/b'}, - {'name': 'c', 'url': 'http://127.0.0.1/b/c'}, - )) + ({'name': '', 'url': 'http://127.0.0.1'}, + {'name': 'b', 'url': 'http://127.0.0.1/b'}, + {'name': 'c', 'url': 'http://127.0.0.1/b/c'}, + )) def testVirtualHostingInFront(self): request = TestRequest() @@ -282,11 +283,11 @@ class TestAbsoluteURL(PlacelessSetup, TestCase): breadcrumbs = view.breadcrumbs() self.assertEqual(breadcrumbs, - ({'name': '', 'url': 'http://127.0.0.1'}, - {'name': 'a', 'url': 'http://127.0.0.1/a'}, - {'name': 'b', 'url': 'http://127.0.0.1/a/b'}, - {'name': 'c', 'url': 'http://127.0.0.1/a/b/c'}, - )) + ({'name': '', 'url': 'http://127.0.0.1'}, + {'name': 'a', 'url': 'http://127.0.0.1/a'}, + {'name': 'b', 'url': 'http://127.0.0.1/a/b'}, + {'name': 'c', 'url': 'http://127.0.0.1/a/b/c'}, + )) def testNoContextInformation(self): request = TestRequest() @@ -302,8 +303,57 @@ class TestAbsoluteURL(PlacelessSetup, TestCase): self.assertEqual(absoluteURL(None, request), 'http://127.0.0.1') -def test_suite(): - return makeSuite(TestAbsoluteURL) + def test_breadcrumbs_no_parent(self): + + view = AbsoluteURL(self, None) + with self.assertRaisesRegexp(TypeError, + "There isn't enough context"): + view.breadcrumbs() + + def test_nameless_context(self): -if __name__ == '__main__': - main(defaultTest='test_suite') + @implementer(ILocation) + class Context(object): + __parent__ = self + __name__ = None + + class DummyAbsoluteURL(object): + # Our implementation of IAbsoluteURL + # for our parent + + def __init__(self, *args): + pass + + called = False + + def __str__(self): + DummyAbsoluteURL.called = True + return '' + + def breadcrumbs(self): + DummyAbsoluteURL.called = True + return () + + browserView(type(self), '', DummyAbsoluteURL, IAbsoluteURL) + + request = TestRequest() + self.assertIsInstance(zope.component.getMultiAdapter((self, request), IAbsoluteURL), + DummyAbsoluteURL) + context = Context() + + # First the view + view = AbsoluteURL(context, request) + with self.assertRaisesRegexp(TypeError, + "There isn't enough context"): + str(view) + + self.assertTrue(DummyAbsoluteURL.called) + DummyAbsoluteURL.called = False + + # Now the breadcrumbs + view = AbsoluteURL(context, request) + with self.assertRaisesRegexp(TypeError, + "There isn't enough context"): + view.breadcrumbs() + + self.assertTrue(DummyAbsoluteURL.called) diff --git a/src/zope/traversing/interfaces.py b/src/zope/traversing/interfaces.py index 151a4ce..cd515ed 100644 --- a/src/zope/traversing/interfaces.py +++ b/src/zope/traversing/interfaces.py @@ -17,7 +17,8 @@ from zope.interface import Attribute from zope.interface import Interface from zope.interface import implementer -from zope.component.interfaces import IObjectEvent +from zope.interface.interfaces import IObjectEvent +from zope.interface.interfaces import ObjectEvent # BBB: Re-import symbols to their old location. from zope.location.interfaces import LocationError as TraversalError @@ -180,10 +181,10 @@ class IBeforeTraverseEvent(IObjectEvent): @implementer(IBeforeTraverseEvent) -class BeforeTraverseEvent(object): +class BeforeTraverseEvent(ObjectEvent): """An event which gets sent on publication traverse""" def __init__(self, ob, request): - self.object = ob + ObjectEvent.__init__(self, ob) self.request = request diff --git a/src/zope/traversing/namespace.py b/src/zope/traversing/namespace.py index 68b17cf..7ef07a4 100644 --- a/src/zope/traversing/namespace.py +++ b/src/zope/traversing/namespace.py @@ -376,9 +376,6 @@ class vh(view): request = self.request - traversal_stack = request.getTraversalStack() - app_names = [] - if not six.PY3: # `name` comes in as unicode, we need to make it a string # so absolute URLs don't all become unicode. @@ -393,6 +390,9 @@ class vh(view): request.setApplicationServer(host, proto, port) + traversal_stack = request.getTraversalStack() + app_names = [] + if '++' in traversal_stack: segment = traversal_stack.pop() while segment != '++': @@ -455,6 +455,8 @@ class adapter(SimpleHandler): class debug(view): + enable_debug = __debug__ + def traverse(self, name, ignored): """Debug traversal adapter @@ -516,27 +518,37 @@ class debug(view): ... print('unknown debugging flag') unknown debugging flag + Of course, if Python was started with the ``-O`` flag to + disable debugging, none of this is allowed (we simulate this + with a private setting on the instance): + + >>> adapter.enable_debug = False + >>> adapter.traverse('source', ()) + Traceback (most recent call last): + ... + ValueError: Debug flags only allowed in debug mode + """ - if __debug__: - request = self.request - for flag in name.split(','): - if flag == 'source': - request.debug.sourceAnnotations = True - elif flag == 'tal': - request.debug.showTAL = True - elif flag == 'errors': - # TODO: I am not sure this is the best solution. What - # if we want to enable tracebacks when also trying to - # debug a different skin? - skin = zope.component.getUtility(IBrowserSkinType, 'Debug') - directlyProvides(request, providedBy(request) + skin) - else: - raise ValueError("Unknown debug flag: %s" % flag) - return self.context - else: + if not self.enable_debug or not __debug__: raise ValueError("Debug flags only allowed in debug mode") - if not __debug__: + request = self.request + for flag in name.split(','): + if flag == 'source': + request.debug.sourceAnnotations = True + elif flag == 'tal': + request.debug.showTAL = True + elif flag == 'errors': + # TODO: I am not sure this is the best solution. What + # if we want to enable tracebacks when also trying to + # debug a different skin? + skin = zope.component.getUtility(IBrowserSkinType, 'Debug') + directlyProvides(request, providedBy(request) + skin) + else: + raise ValueError("Unknown debug flag: %s" % flag) + return self.context + + if not __debug__: # pragma: no cover # If not in debug mode, we should get an error: traverse.__doc__ = """Disabled debug traversal adapter diff --git a/src/zope/traversing/publicationtraverse.py b/src/zope/traversing/publicationtraverse.py index a030776..6a16401 100644 --- a/src/zope/traversing/publicationtraverse.py +++ b/src/zope/traversing/publicationtraverse.py @@ -90,10 +90,10 @@ class PublicationTraverser(object): path.reverse() - # Remove double dots + # Remove double dots if possible while '..' in path: l = path.index('..') - if l < 0 or l + 2 > len(path): + if l + 2 > len(path): break del path[l:l + 2] diff --git a/src/zope/traversing/testing.py b/src/zope/traversing/testing.py index e10ea6b..177b76d 100644 --- a/src/zope/traversing/testing.py +++ b/src/zope/traversing/testing.py @@ -49,7 +49,7 @@ class ContainedProxy(object): if name in ['__parent__', '__name__', '__obj__']: self.__dict__[name] = value return - setattr(self.__obj__, name, value) + setattr(self.__obj__, name, value) # pragma: no cover def __eq__(self, value): return self.__obj__ == value @@ -63,7 +63,7 @@ def contained(obj, root, name=None): return obj # BBB: Kept for backward-compatibility, in case some package depends on it. -def setUp(): #pragma: nocover +def setUp(): # pragma: no cover zope.component.provideAdapter(Traverser, (None,), ITraverser) zope.component.provideAdapter(DefaultTraversable, (None,), ITraversable) zope.component.provideAdapter(LocationPhysicallyLocatable, diff --git a/src/zope/traversing/tests/test_conveniencefunctions.py b/src/zope/traversing/tests/test_conveniencefunctions.py index b69d165..be50c6a 100644 --- a/src/zope/traversing/tests/test_conveniencefunctions.py +++ b/src/zope/traversing/tests/test_conveniencefunctions.py @@ -13,20 +13,18 @@ ############################################################################## """Test traversal convenience functions. """ -from unittest import TestCase, main, makeSuite +import unittest +from zope import interface import zope.component from zope.component.testing import PlacelessSetup -from zope.interface import directlyProvides from zope.location.traversing \ import LocationPhysicallyLocatable, RootPhysicallyLocatable from zope.location.interfaces import ILocationInfo, IRoot, LocationError -from zope.security.proxy import Proxy -from zope.security.checker import selectChecker from zope.traversing.adapters import Traverser, DefaultTraversable from zope.traversing.interfaces import ITraversable, ITraverser -from zope.traversing.testing import contained, Contained +from zope.traversing.testing import contained class C(object): __parent__ = None @@ -34,29 +32,28 @@ class C(object): def __init__(self, name): self.name = name -def _proxied(*args): - return Proxy(args, selectChecker(args)) -class Test(PlacelessSetup, TestCase): +class TestFunctional(PlacelessSetup, unittest.TestCase): def setUp(self): PlacelessSetup.setUp(self) # Build up a wrapper chain root = C('root') - directlyProvides(root, IRoot) + interface.directlyProvides(root, IRoot) folder = C('folder') item = C('item') self.root = root # root is not usually wrapped - self.folder = contained(folder, self.root, name='folder') - self.item = contained(item, self.folder, name='item') + self.folder = contained(folder, self.root, name='folder') + self.item = contained(item, self.folder, name='item') self.unwrapped_item = item self.broken_chain_folder = contained(folder, None) - self.broken_chain_item = contained(item, - self.broken_chain_folder, - name='item' - ) + self.broken_chain_item = contained( + item, + self.broken_chain_folder, + name='item' + ) root.folder = folder folder.item = item @@ -75,6 +72,13 @@ class Test(PlacelessSetup, TestCase): self.tr.traverse('/folder/item') ) + def test_traverse_with_default(self): + from zope.traversing.api import traverse + self.assertIs( + traverse(self.item, '/no/path', self), + self + ) + def testTraverseFromUnwrapped(self): from zope.traversing.api import traverse self.assertRaises( @@ -88,15 +92,23 @@ class Test(PlacelessSetup, TestCase): self.assertEqual( traverseName(self.folder, 'item'), self.tr.traverse('/folder/item') - ) + ) self.assertEqual( traverseName(self.item, '.'), self.tr.traverse('/folder/item') - ) + ) self.assertEqual( traverseName(self.item, '..'), self.tr.traverse('/folder') - ) + ) + self.assertEqual( + traverseName(self.folder, 'item', default=self), + self.tr.traverse('/folder/item') + ) + self.assertIs( + traverseName(self.folder, 'nothing', default=self), + self, + ) # TODO test that ++names++ and @@names work too @@ -127,7 +139,7 @@ class Test(PlacelessSetup, TestCase): def traverse(self, name, furtherPath): getattr(self, u'\u2019', None) # The above actually works on Python 3 - raise LocationError() + raise unittest.SkipTest("Unicode attrs legal on Py3") self.assertRaises( LocationError, @@ -241,19 +253,20 @@ class Test(PlacelessSetup, TestCase): _good_locations = ( # location returned as string - ( u'/xx/yy/zz', - # arguments to try in addition to the above - '/xx/yy/zz', - '/xx/./yy/ww/../zz', + (u'/xx/yy/zz', + # arguments to try in addition to the above + '/xx/yy/zz', + '/xx/./yy/ww/../zz', ), - ( u'/xx/yy/zz', - '/xx/yy/zz', + (u'/xx/yy/zz', + '/xx/yy/zz', ), - ( u'/xx', - '/xx', + (u'/xx', + '/xx', ), - ( u'/', - '/', + (u'/', + '/', + self.root, ), ) @@ -285,26 +298,26 @@ class Test(PlacelessSetup, TestCase): _good_locations = ( # location returned as string - ( '/xx/yy/zz', - # arguments to try in addition to the above - '/xx/yy/zz', - '/xx/./yy/ww/../zz', - '/xx/./yy/ww/./../zz', + ('/xx/yy/zz', + # arguments to try in addition to the above + '/xx/yy/zz', + '/xx/./yy/ww/../zz', + '/xx/./yy/ww/./../zz', ), - ( 'xx/yy/zz', - # arguments to try in addition to the above - 'xx/yy/zz', - 'xx/./yy/ww/../zz', - 'xx/./yy/ww/./../zz', + ('xx/yy/zz', + # arguments to try in addition to the above + 'xx/yy/zz', + 'xx/./yy/ww/../zz', + 'xx/./yy/ww/./../zz', ), - ( '/xx/yy/zz', - '/xx/yy/zz', + ('/xx/yy/zz', + '/xx/yy/zz', ), - ( '/xx', - '/xx', + ('/xx', + '/xx', ), - ( '/', - '/', + ('/', + '/', ), ) @@ -361,9 +374,41 @@ class Test(PlacelessSetup, TestCase): args = ('foo', 'bar', '.', 'baz', 'bone') self.assertEqual(joinPath(path, *args), u'/foo/bar/baz/bone') + def test_joinPath_empty_args(self): + from zope.traversing.api import joinPath + path = 'abc' + self.assertEqual(joinPath(path), u'abc') + -def test_suite(): - return makeSuite(Test) +class TestStandalone(unittest.TestCase): + # Unlike TestFunctional, we don't register gobs of + # adapters, making these tests more self-contained -if __name__=='__main__': - main(defaultTest='test_suite') + def test_getParent_no_location_info(self): + from zope.traversing.api import getParent + test = self + class Context(object): + called = False + def __conform__(self, iface): + self.called = True + test.assertEqual(iface, ILocationInfo) + raise TypeError() + + context = Context() + with self.assertRaisesRegexp(TypeError, + "Not enough context"): + getParent(context) + + self.assertTrue(context.called) + context.called = False + + # Now give it a parent + context.__parent__ = self + self.assertIs(self, getParent(context)) + + self.assertTrue(context.called) + context.called = False + + # Now if it's a root, it has no parent + interface.alsoProvides(context, IRoot) + self.assertIsNone(getParent(context)) diff --git a/src/zope/traversing/tests/test_lang.py b/src/zope/traversing/tests/test_lang.py index 888091b..d6f9ff8 100644 --- a/src/zope/traversing/tests/test_lang.py +++ b/src/zope/traversing/tests/test_lang.py @@ -55,10 +55,3 @@ class Test(CleanUp, unittest.TestCase): self.assertTrue(ob is ob2) self.assertTrue(request.shifted) self.assertEqual(["ru"], browser_languages.getPreferredLanguages()) - - -def test_suite(): - return unittest.makeSuite(Test) - -if __name__=='__main__': - unittest.main(defaultTest='test_suite') diff --git a/src/zope/traversing/tests/test_namespacetrversal.py b/src/zope/traversing/tests/test_namespacetrversal.py index bde36c3..0fdd4db 100644 --- a/src/zope/traversing/tests/test_namespacetrversal.py +++ b/src/zope/traversing/tests/test_namespacetrversal.py @@ -14,12 +14,110 @@ """Traversal Namespace Tests """ import re -from unittest import main +import unittest from doctest import DocTestSuite + +from zope import interface +from zope import component +from zope.location.interfaces import LocationError +from zope.traversing import namespace + +from zope.component.testing import PlacelessSetup from zope.component.testing import setUp, tearDown from zope.testing.renormalizing import RENormalizing +class TestFunctions(unittest.TestCase): + + def test_getResource_not_found(self): + with self.assertRaises(LocationError): + namespace.getResource(None, '', None) + + +class TestAcquire(unittest.TestCase): + + def test_excessive_depth_on_path_extension(self): + from zope.traversing.interfaces import ITraversable + from zope.traversing.namespace import ExcessiveDepth + + @interface.implementer(ITraversable) + class Context(object): + + max_call_count = 200 + + def traverse(self, name, path): + if self.max_call_count: + path.append("I added something") + self.max_call_count -= 1 + + acq = namespace.acquire(Context(), None) + with self.assertRaises(ExcessiveDepth): + acq.traverse(None, None) + + +class TestEtc(PlacelessSetup, unittest.TestCase): + + def test_traverse_non_site_name(self): + with self.assertRaises(LocationError) as ctx: + namespace.etc(None, None).traverse('foobar', ()) + + ex = ctx.exception + self.assertEqual((None, 'foobar'), ex.args) + + def test_traverse_site_no_manager(self): + test = self + class Context(object): + def __getattribute__(self, name): + test.assertEqual(name, 'getSiteManager') + return None + + context = Context() + with self.assertRaises(LocationError) as ctx: + namespace.etc(context, None).traverse('site', ()) + + ex = ctx.exception + self.assertEqual((context, 'site'), ex.args) + + def test_traverse_site_lookup_error(self): + class Context(object): + called = False + def getSiteManager(self): + self.called = True + from zope.component import ComponentLookupError + raise ComponentLookupError() + + context = Context() + with self.assertRaises(LocationError) as ctx: + namespace.etc(context, None).traverse('site', ()) + + ex = ctx.exception + self.assertEqual((context, 'site'), ex.args) + self.assertTrue(context.called) + + def test_traverse_utility(self): + from zope.traversing.interfaces import IEtcNamespace + component.provideUtility(self, provides=IEtcNamespace, name='my etc name') + + result = namespace.etc(None, None).traverse('my etc name', ()) + self.assertIs(result, self) + + +class TestView(unittest.TestCase): + + def test_not_found(self): + with self.assertRaises(LocationError) as ctx: + namespace.view(None, None).traverse('name', ()) + + ex = ctx.exception + self.assertEqual((None, 'name'), ex.args) + + +class TestVh(unittest.TestCase): + + def test_invalid_vh(self): + with self.assertRaisesRegexp(ValueError, + 'Vhost directive should have the form'): + namespace.vh(None, None).traverse(u'invalid name', ()) def test_suite(): checker = RENormalizing([ @@ -28,9 +126,9 @@ def test_suite(): "LocationError"), ]) - return DocTestSuite('zope.traversing.namespace', - setUp=setUp, tearDown=tearDown, - checker=checker) - -if __name__ == '__main__': - main(defaultTest='test_suite') + suite = unittest.defaultTestLoader.loadTestsFromName(__name__) + suite.addTest(DocTestSuite( + 'zope.traversing.namespace', + setUp=setUp, tearDown=tearDown, + checker=checker)) + return suite diff --git a/src/zope/traversing/tests/test_presentation.py b/src/zope/traversing/tests/test_presentation.py index c658ca2..6299ddc 100644 --- a/src/zope/traversing/tests/test_presentation.py +++ b/src/zope/traversing/tests/test_presentation.py @@ -13,7 +13,7 @@ ############################################################################## """Presentation Traverser Tests """ -from unittest import TestCase, main, makeSuite +import unittest from zope.testing.cleanup import CleanUp from zope.interface import Interface, implementer from zope.publisher.browser import TestRequest @@ -38,7 +38,7 @@ class View(object): self.content = content -class Test(CleanUp, TestCase): +class Test(CleanUp, unittest.TestCase): def testView(self): browserView(IContent, 'foo', View) @@ -53,10 +53,3 @@ class Test(CleanUp, TestCase): ob = Content() r = resource(ob, TestRequest()).traverse('foo', ()) self.assertEqual(r.__class__, Resource) - - -def test_suite(): - return makeSuite(Test) - -if __name__=='__main__': - main(defaultTest='test_suite') diff --git a/src/zope/traversing/tests/test_publicationtraverse.py b/src/zope/traversing/tests/test_publicationtraverse.py index da0adf6..7f9e156 100644 --- a/src/zope/traversing/tests/test_publicationtraverse.py +++ b/src/zope/traversing/tests/test_publicationtraverse.py @@ -13,7 +13,8 @@ ############################################################################## """Tests of PublicationTraverser """ -from unittest import TestCase, main, makeSuite +import unittest + from zope.testing.cleanup import CleanUp from zope.component import provideAdapter from zope.interface import Interface, implementer @@ -23,21 +24,20 @@ from zope.publisher.interfaces import NotFound from zope.publisher.interfaces.browser import IBrowserPublisher from zope.security.proxy import removeSecurityProxy from zope.traversing.interfaces import ITraversable +from zope.traversing.publicationtraverse import PublicationTraverser -class TestPublicationTraverser(CleanUp, TestCase): +class TestPublicationTraverser(CleanUp, unittest.TestCase): def testViewNotFound(self): ob = Content() - from zope.traversing.publicationtraverse import PublicationTraverser t = PublicationTraverser() request = TestRequest() self.assertRaises(NotFound, t.traverseName, request, ob, '@@foo') def testViewFound(self): provideAdapter(DummyViewTraverser, (Interface, Interface), - ITraversable, name='view') + ITraversable, name='view') ob = Content() - from zope.traversing.publicationtraverse import PublicationTraverser t = PublicationTraverser() request = TestRequest() proxy = t.traverseName(request, ob, '@@foo') @@ -48,23 +48,20 @@ class TestPublicationTraverser(CleanUp, TestCase): def testDot(self): ob = Content() - from zope.traversing.publicationtraverse import PublicationTraverser t = PublicationTraverser() request = TestRequest() self.assertEqual(ob, t.traverseName(request, ob, '.')) def testNameNotFound(self): ob = Content() - from zope.traversing.publicationtraverse import PublicationTraverser t = PublicationTraverser() request = TestRequest() self.assertRaises(NotFound, t.traverseName, request, ob, 'foo') def testNameFound(self): provideAdapter(DummyPublishTraverse, (Interface, Interface), - IPublishTraverse) + IPublishTraverse) ob = Content() - from zope.traversing.publicationtraverse import PublicationTraverser t = PublicationTraverser() request = TestRequest() proxy = t.traverseName(request, ob, 'foo') @@ -76,7 +73,6 @@ class TestPublicationTraverser(CleanUp, TestCase): def testDirectTraversal(self): request = TestRequest() ob = DummyPublishTraverse(Content(), request) - from zope.traversing.publicationtraverse import PublicationTraverser t = PublicationTraverser() proxy = t.traverseName(request, ob, 'foo') view = removeSecurityProxy(proxy) @@ -86,16 +82,14 @@ class TestPublicationTraverser(CleanUp, TestCase): def testPathNotFound(self): ob = Content() - from zope.traversing.publicationtraverse import PublicationTraverser t = PublicationTraverser() request = TestRequest() self.assertRaises(NotFound, t.traversePath, request, ob, 'foo/bar') def testPathFound(self): provideAdapter(DummyPublishTraverse, (Interface, Interface), - IPublishTraverse) + IPublishTraverse) ob = Content() - from zope.traversing.publicationtraverse import PublicationTraverser t = PublicationTraverser() request = TestRequest() proxy = t.traversePath(request, ob, 'foo/bar') @@ -106,9 +100,8 @@ class TestPublicationTraverser(CleanUp, TestCase): def testComplexPath(self): provideAdapter(DummyPublishTraverse, (Interface, Interface), - IPublishTraverse) + IPublishTraverse) ob = Content() - from zope.traversing.publicationtraverse import PublicationTraverser t = PublicationTraverser() request = TestRequest() proxy = t.traversePath(request, ob, 'foo/../alpha//beta/./bar') @@ -119,11 +112,11 @@ class TestPublicationTraverser(CleanUp, TestCase): def testTraverseRelativeURL(self): provideAdapter(DummyPublishTraverse, (Interface, Interface), - IPublishTraverse) + IPublishTraverse) provideAdapter(DummyBrowserPublisher, (Interface,), - IBrowserPublisher) + IBrowserPublisher) ob = Content() - from zope.traversing.publicationtraverse import PublicationTraverser + t = PublicationTraverser() request = TestRequest() proxy = t.traverseRelativeURL(request, ob, 'foo/bar') @@ -134,13 +127,78 @@ class TestPublicationTraverser(CleanUp, TestCase): def testMissingSkin(self): ob = Content() - from zope.traversing.publicationtraverse import PublicationTraverser t = PublicationTraverser() request = TestRequest() self.assertRaises( NotFound, t.traversePath, request, ob, '/++skin++missingskin') + def test_traversePath_trailing_slash(self): + class Traverser(PublicationTraverser): + def __init__(self): + self.names = [] + + def traverseName(self, request, ob, name): + self.names.append(name) + + + t = Traverser() + t.traversePath(None, None, 'abc/def/') + self.assertEqual(t.names, ['abc', 'def']) + + t = Traverser() + t.traversePath(None, None, 'abc/def///') + + # Note that only *one* trailing slash is removed + self.assertEqual(t.names, ['abc', 'def', '', '']) + + + def test_traversePath_double_dots_cannot_remove(self): + class Traverser(PublicationTraverser): + def __init__(self): + self.names = [] + + def traverseName(self, request, ob, name): + self.names.append(name) + + + t = Traverser() + t.traversePath(None, None, '..') + self.assertEqual(t.names, ['..']) + + def test_traverseRelativeURL_to_no_browser_publisher(self): + test = self + class Traverser(PublicationTraverser): + def traversePath(self, request, ob, path): + return ob + + + class Context(object): + called = False + def __conform__(self, iface): + self.called = True + test.assertEqual(iface, IBrowserPublisher) + return None + + t = Traverser() + context = Context() + ob = t.traverseRelativeURL(None, context, None) + self.assertIs(ob, context) + + self.assertTrue(context.called) + +class TestBeforeTraverseEvent(unittest.TestCase): + + def test_interfaces(self): + from zope.traversing.interfaces import IBeforeTraverseEvent + from zope.traversing.interfaces import BeforeTraverseEvent + from zope.interface.verify import verifyObject + + ob = BeforeTraverseEvent(self, self) + self.assertIs(self, ob.request) + self.assertIs(self, ob.object) + verifyObject(IBeforeTraverseEvent, ob) + class IContent(Interface): pass @@ -179,12 +237,4 @@ class DummyBrowserPublisher(object): def browserDefault(self, request): if self.context.name != 'more': return self.context, ['more'] - else: - return self.context, () - - -def test_suite(): - return makeSuite(TestPublicationTraverser) - -if __name__ == '__main__': - main() + return self.context, () diff --git a/src/zope/traversing/tests/test_skin.py b/src/zope/traversing/tests/test_skin.py index 405bb23..0a12825 100644 --- a/src/zope/traversing/tests/test_skin.py +++ b/src/zope/traversing/tests/test_skin.py @@ -13,7 +13,7 @@ ############################################################################## """Test skin traversal. """ -from unittest import TestCase, main, makeSuite +import unittest import zope.component from zope.testing.cleanup import CleanUp @@ -29,7 +29,7 @@ class IFoo(Interface): directlyProvides(IFoo, IBrowserSkinType) -class Test(CleanUp, TestCase): +class Test(CleanUp, unittest.TestCase): def setUp(self): super(Test, self).setUp() @@ -52,9 +52,3 @@ class Test(CleanUp, TestCase): ob = object() traverser = skin(ob, request) self.assertRaises(LocationError, traverser.traverse, 'bar', ()) - -def test_suite(): - return makeSuite(Test) - -if __name__=='__main__': - main(defaultTest='test_suite') diff --git a/src/zope/traversing/tests/test_traverser.py b/src/zope/traversing/tests/test_traverser.py index 2c81ac3..9eeb211 100644 --- a/src/zope/traversing/tests/test_traverser.py +++ b/src/zope/traversing/tests/test_traverser.py @@ -11,7 +11,7 @@ # FOR A PARTICULAR PURPOSE. # ############################################################################## -"""Traverser Adapter tests. +"""Traverser Adapter tests (adapter.py) """ import unittest @@ -29,6 +29,7 @@ from zope.security.checker \ from zope.security.management import newInteraction, endInteraction from zope.traversing.adapters import Traverser, DefaultTraversable +from zope.traversing import adapters from zope.traversing.interfaces import ITraversable, ITraverser from zope.traversing.testing import contained, Contained @@ -47,9 +48,9 @@ class TraverserTests(PlacelessSetup, unittest.TestCase): def setUp(self): PlacelessSetup.setUp(self) # Build up a wrapper chain - self.root = C('root') - self.folder = contained(C('folder'), self.root, name='folder') - self.item = contained(C('item'), self.folder, name='item') + self.root = C('root') + self.folder = contained(C('folder'), self.root, name='folder') + self.item = contained(C('item'), self.folder, name='item') self.tr = Traverser(self.item) def testImplementsITraverser(self): @@ -59,6 +60,9 @@ class TraverserTests(PlacelessSetup, unittest.TestCase): for interface in implementedBy(Traverser): verifyClass(interface, Traverser) + def test_traverse_empty_path_is_context(self): + self.assertIs(self.item, self.tr.traverse('')) + class UnrestrictedNoTraverseTests(unittest.TestCase): def setUp(self): self.root = root = C('root') @@ -193,9 +197,11 @@ class RestrictedTraverseTests(PlacelessSetup, unittest.TestCase): self.tr = Traverser(ProxyFactory(root)) def testAllAllowed(self): - defineChecker(C, Checker({'folder': CheckerPublic, - 'item': CheckerPublic, - })) + defineChecker(C, + Checker({ + 'folder': CheckerPublic, + 'item': CheckerPublic, + })) tr = Traverser(ProxyFactory(self.root)) item = self.item @@ -210,12 +216,12 @@ class RestrictedTraverseTests(PlacelessSetup, unittest.TestCase): folder = self.folder self.assertRaises(Unauthorized, tr.traverse, - ('', 'folder', 'item')) + ('', 'folder', 'item')) self.assertRaises(Unauthorized, tr.traverse, - ('folder', 'item')) + ('folder', 'item')) self.assertEqual(tr.traverse(('', 'folder')), folder) self.assertEqual(tr.traverse(('folder', '..', 'folder')), - folder) + folder) self.assertEqual(tr.traverse(('folder',)), folder) def testException(self): @@ -230,10 +236,10 @@ class RestrictedTraverseTests(PlacelessSetup, unittest.TestCase): # AttributeError becomes LocationError if there's no __getitem__ # on the object self.assertRaises(LocationError, tr.traverse, - ('foobar', 'attributeerror')) + ('foobar', 'attributeerror')) # Other exceptions raised as usual self.assertRaises(ValueError, tr.traverse, - ('foobar', 'valueerror')) + ('foobar', 'valueerror')) class DefaultTraversableTests(unittest.TestCase): @@ -275,14 +281,37 @@ class DefaultTraversableTests(unittest.TestCase): df = DefaultTraversable(object()) self.assertRaises(LocationError, df.traverse, u'\u2019', ()) -def test_suite(): - loader = unittest.TestLoader() - suite = loader.loadTestsFromTestCase(TraverserTests) - suite.addTest(loader.loadTestsFromTestCase(DefaultTraversableTests)) - suite.addTest(loader.loadTestsFromTestCase(UnrestrictedNoTraverseTests)) - suite.addTest(loader.loadTestsFromTestCase(UnrestrictedTraverseTests)) - suite.addTest(loader.loadTestsFromTestCase(RestrictedTraverseTests)) - return suite - -if __name__=='__main__': - unittest.TextTestRunner().run(test_suite()) + +class TestFunctions(unittest.TestCase): + + def test_traversePathElement_UnicodeEncodeError_with_default(self): + test = self + class Traversable(object): + called = False + fail = test.fail + def traverse(self, nm, further_path): + self.called = True + u'\xff'.encode("ascii") + self.fail("Should not be reached") + + t = Traversable() + self.assertIs(self, + adapters.traversePathElement(None, None, (), + default=self, + traversable=t)) + self.assertTrue(t.called) + + + def test_traversePathElement_LocationError_with_default(self): + class Traversable(object): + called = False + def traverse(self, nm, further_path): + self.called = True + raise LocationError() + + t = Traversable() + self.assertIs(self, + adapters.traversePathElement(None, None, (), + default=self, + traversable=t)) + self.assertTrue(t.called) diff --git a/src/zope/traversing/tests/test_vhosting.py b/src/zope/traversing/tests/test_vhosting.py index 38864e2..ed393e6 100644 --- a/src/zope/traversing/tests/test_vhosting.py +++ b/src/zope/traversing/tests/test_vhosting.py @@ -14,17 +14,10 @@ """Functional tests for virtual hosting. """ import os -import transaction import unittest -try: - from StringIO import StringIO -except ImportError: - from io import StringIO +from io import StringIO -try: - from UserDict import UserDict -except ImportError: - from collections import UserDict +import transaction import zope.component import zope.interface @@ -44,7 +37,7 @@ from zope.testing.cleanup import cleanUp from zope.traversing.adapters import traversePathElement from zope.traversing.api import traverse -from zope.traversing.testing import browserResource, Contained, contained +from zope.traversing.testing import browserResource, Contained class MyObj(Contained): @@ -55,19 +48,19 @@ class IFolder(zope.interface.Interface): pass @zope.interface.implementer(IFolder, IBrowserPublisher) -class Folder(Contained, UserDict): +class Folder(Contained, dict): def __init__(self): - UserDict.__init__(self, {}) + dict.__init__(self, {}) def __setitem__(self, name, value): value.__parent__ = self value.__name__ = name - UserDict.__setitem__(self, name, value) + dict.__setitem__(self, name, value) def publishTraverse(self, request, name): subob = self.get(name, None) if subob is None: - raise NotFound(self.context, name, request) + raise NotFound(self.context, name, request) # pragma: no cover return subob @@ -86,11 +79,9 @@ class ZopeTraverser(object): while path_items: name = path_items.pop() - if getattr(object, '__class__', None) == dict: - object = object[name] - else: - object = traversePathElement(object, name, path_items, - request=request) + assert getattr(object, '__class__', None) != dict + object = traversePathElement(object, name, path_items, + request=request) return object zopeTraverser = ZopeTraverser() @@ -169,7 +160,7 @@ class TestVirtualHosting(unittest.TestCase): if len(p) == 1: env['PATH_INFO'] = p[0] - request = BrowserRequest(StringIO(''), env) + request = BrowserRequest(StringIO(u''), env) request.setPublication(DummyPublication(self.app)) setDefaultSkin(request) return request @@ -279,7 +270,7 @@ class TestVirtualHosting(unittest.TestCase): self.assertEqual(result.getHeader('Location'), location) -class DummyPublication: +class DummyPublication(object): def __init__(self, app): self.app = app @@ -307,18 +298,13 @@ class DummyPublication: Name must be an ASCII string or Unicode object.""" if name == 'index.html': - from zope.component import queryMultiAdapter - view = queryMultiAdapter((ob, request), name=name) - if view is None: - from zope.publisher.interfaces import NotFound - import pdb; pdb.set_trace() - raise NotFound(ob, name) + from zope.component import getMultiAdapter + view = getMultiAdapter((ob, request), name=name) return view - else: - from zope.traversing.publicationtraverse \ - import PublicationTraverserWithoutProxy - t = PublicationTraverserWithoutProxy() - return t.traverseName(request, ob, name) + + from zope.traversing.publicationtraverse import PublicationTraverserWithoutProxy + t = PublicationTraverserWithoutProxy() + return t.traverseName(request, ob, name) def afterTraversal(self, request, ob): """Post-traversal hook. @@ -340,7 +326,7 @@ class DummyPublication: """Post-callObject hook (if it was successful). """ - def handleException(self, ob, request, exc_info, retry_allowed=1): + def handleException(self, ob, request, exc_info, retry_allowed=1): # pragma: no cover """Handle an exception Either: @@ -358,15 +344,4 @@ class DummyPublication: def getDefaultTraversal(self, request, ob): if hasattr(ob, 'index'): return ob, () - else: - return ob, ('index.html',) - - -def test_suite(): - suite = unittest.TestSuite() - suite.addTest(unittest.makeSuite(TestVirtualHosting)) - return suite - - -if __name__ == '__main__': - unittest.main() + return ob, ('index.html',) |