############################################################################## # # Copyright (c) 2004, 2005 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 Default View functionality $Id: test_defaultview.py 70531 2006-10-04 16:09:30Z tseaver $ """ import os, sys if __name__ == '__main__': execfile(os.path.join(sys.path[0], 'framework.py')) def test_default_view(): """ Test default view functionality Let's register a couple of default views and make our stub classes default viewable: >>> import Products.Five.browser.tests >>> from Products.Five import zcml >>> zcml.load_config("configure.zcml", Products.Five) >>> zcml.load_config('defaultview.zcml', Products.Five.browser.tests) Now let's add a couple of stub objects: >>> from Products.Five.tests.testing.simplecontent import manage_addSimpleContent >>> from Products.Five.tests.testing.simplecontent import manage_addCallableSimpleContent >>> from Products.Five.tests.testing.simplecontent import manage_addIndexSimpleContent >>> manage_addSimpleContent(self.folder, 'testoid', 'Testoid') >>> manage_addCallableSimpleContent(self.folder, 'testcall', 'TestCall') >>> manage_addIndexSimpleContent(self.folder, 'testindex', 'TestIndex') As a last act of preparation, we create a manager login: >>> uf = self.folder.acl_users >>> uf._doAddUser('manager', 'r00t', ['Manager'], []) BBB This is a test of backwards comaptibility with Five 1.3/Zope 2.9. The deprecated directive five:defaultViewable would before make index.html the default view. Test that this is still the case. five:defaultViewable goes away in Zope 2.12, and this test goes then too: >>> import warnings >>> showwarning = warnings.showwarning >>> warnings.showwarning = lambda *a, **k: None >>> zcml.load_string(''' ... ... ... ''') >>> print http(r''' ... GET /test_folder_1_/testoid HTTP/1.1 ... Authorization: Basic manager:r00t ... ''') HTTP/1.1 200 OK ... The eagle has landed >>> warnings.showwarning = showwarning But if we want to, we can specify another default view with browser:defaultView: >>> zcml.load_string(''' ... ... ... ''') >>> print http(r''' ... GET /test_folder_1_/testoid HTTP/1.1 ... Authorization: Basic manager:r00t ... ''') HTTP/1.1 200 OK ... The mouse has been eaten by the eagle In Five 1.5 ``index_html`` you can no longer set default views to anything else than views: >>> print http(r''' ... GET /test_folder_1_/testindex HTTP/1.1 ... ''') HTTP/1.1 404 Not Found ... Disabled __call__ overriding for now. Causes more trouble than it fixes. Thus, no test here: #>>> print http(r''' #... GET /test_folder_1_/testcall HTTP/1.1 #... ''') #HTTP/1.1 200 OK #... #Default __call__ called Clean up: >>> from zope.app.testing.placelesssetup import tearDown >>> tearDown() """ def test_default_method_args_marshalling(): """\ Test the default call method of a view, with respect to possible breakage of argument marshalling from other components This is not directly a bug in Five, just a change that enables components have simpler code to imitate ZPublisher's arguments marshalling strategy on default view methods. The ZPublisher marshalls arguments to called methods from the request based on the method's signature. This however assumes that it finds the real callable method. However in case of the autogenerated __call__ method of a view, the real method is wrapped. Although the publisher correctly handles this by looking at the __browser_default__ and applying the request on the real method, Plone's portal factory does not do this correctly, thus causing these method calls fail with TypeError, since no parameters will be marshalled to the browser default methods if within the portal factory. The applied fix changes the __call__ in such a way that it is not wrapper any more, but yields the original callable instead. This test simply checks that this is so, in other words this is a check that would have failed with the original version. First, we load the configuration file: >>> import Products.Five.tests >>> from Products.Five import zcml >>> zcml.load_config('meta.zcml', Products.Five) >>> zcml.load_config("permissions.zcml", Products.Five) >>> zcml.load_config('directives.zcml', Products.Five.tests) Define a view, with a single attribute and the name of the view is the same as the attribute. Important is that we will use the default browser view. >>> zcml.load_string(''' ... ... ... ... ''') Create a context object and a request. Provide parameters on the request. >>> from Products.Five.browser.tests.classes import One >>> context = One() >>> from zope.publisher.browser import TestRequest >>> request = TestRequest(form={'arg1': 'A', 'arg2': 'B', 'kw1': 'C'}) Create the view. >>> from zope.component import getMultiAdapter >>> from zope.interface import Interface >>> view = getMultiAdapter((context, request), Interface, 'my_method') Check that the __call__ method's signature equals to the real method's signature. They both should yield the four parameters. >>> def args(method): ... f = method.im_func ... c = f.func_code ... defaults = f.func_defaults ... names = c.co_varnames[1:c.co_argcount] ... return names >>> args(view.my_method) ('arg1', 'arg2', 'kw1', 'kw2') >>> args(view.__call__) ('arg1', 'arg2', 'kw1', 'kw2') Finally, call the view's default method. Important is, if this gives a TypeError then the portal factory will fail. This is in effect the same as the previous argument check was. >>> from ZPublisher.mapply import mapply >>> mapply(view.__call__, (), request) CALLED A B C D Clean up adapter registry and others: >>> from zope.testing.cleanup import cleanUp >>> cleanUp() """ def test_suite(): from Testing.ZopeTestCase import FunctionalDocTestSuite return FunctionalDocTestSuite() if __name__ == '__main__': framework()