############################################################################## # # Copyright (c) 2001, 2002 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. # ############################################################################## """Component Directives Tests $Id: test_directives.py 67630 2006-04-27 00:54:03Z jim $ """ import re import unittest import pprint import warnings from cStringIO import StringIO from zope.interface import Interface, implements from zope.testing.doctestunit import DocTestSuite from zope.component import createObject from zope.component.interfaces import IDefaultViewName from zope.component.registry import SubscriptionRegistration from zope.component.interfaces import ComponentLookupError from zope.component.interface import queryInterface from zope.configuration.xmlconfig import xmlconfig, XMLConfig from zope.configuration.exceptions import ConfigurationError from zope.configuration.xmlconfig import ZopeXMLConfigurationError from zope.security.proxy import removeSecurityProxy, getTestProxyItems from zope.security.checker import ProxyFactory, selectChecker import zope.app.component from zope.app import zapi from zope.app.testing.placelesssetup import PlacelessSetup from zope.app.component.tests.adapter import A1, A2, A3, Handler from zope.app.component.tests.adapter import I1, I2, I3, IS from zope.app.component.tests.components import IContent, Content, Comp, comp from zope.app.component.tests.components import IApp from zope.app.component.tests.views import Request, IV, IC, V1, R1, IR from zope.app.content.interfaces import IContentType from zope.app.component.tests import module, exampleclass # TODO: tests for other directives needed atre = re.compile(' at [0-9a-fA-Fx]+') class Context(object): actions = () def action(self, discriminator, callable, args): self.actions += ((discriminator, callable, args), ) def __repr__(self): stream = StringIO() pprinter = pprint.PrettyPrinter(stream=stream, width=60) pprinter.pprint(self.actions) r = stream.getvalue() return (''.join(atre.split(r))).strip() template = """ %s """ class Ob(object): implements(IC) def definePermissions(): XMLConfig('meta.zcml', zope.app.component)() class Test(PlacelessSetup, unittest.TestCase): def setUp(self): super(Test, self).setUp() XMLConfig('meta.zcml', zope.app.component)() XMLConfig('meta.zcml', zope.app.security)() def testView(self): ob = Ob() request = Request(IV) self.assertEqual( zapi.queryMultiAdapter((ob, request), name=u'test'), None) xmlconfig(StringIO(template % ''' ''' )) self.assertEqual( zapi.queryMultiAdapter((ob, request), name=u'test').__class__, V1) def testMultiView(self): xmlconfig(StringIO(template % ''' ''' )) ob = Ob() a1 = A1() a2 = A2() request = Request(IV) view = zapi.queryMultiAdapter((ob, a1, a2, request), name=u'test') self.assertEqual(view.__class__, A3) self.assertEqual(view.context, (ob, a1, a2, request)) def testMultiView_fails_w_multiple_factories(self): self.assertRaises( ConfigurationError, xmlconfig, StringIO(template % ''' ''' ) ) def testView_w_multiple_factories(self): xmlconfig(StringIO(template % ''' ''' )) ob = Ob() # The view should be a V1 around an A3, around an A2, around # an A1, anround ob: view = zapi.queryMultiAdapter((ob, Request(IV)), name=u'test') self.assertEqual(view.__class__, V1) a3 = view.context self.assertEqual(a3.__class__, A3) a2 = a3.context[0] self.assertEqual(a2.__class__, A2) a1 = a2.context[0] self.assertEqual(a1.__class__, A1) self.assertEqual(a1.context[0], ob) def testView_fails_w_no_factories(self): self.assertRaises(ConfigurationError, xmlconfig, StringIO(template % ''' ''' ), ) def testViewThatProvidesAnInterface(self): ob = Ob() self.assertEqual( zapi.queryMultiAdapter((ob, Request(IR)), IV, u'test'), None) xmlconfig(StringIO(template % ''' ''' )) self.assertEqual( zapi.queryMultiAdapter((ob, Request(IR)), IV, u'test'), None) xmlconfig(StringIO(template % ''' ''' )) v = zapi.queryMultiAdapter((ob, Request(IR)), IV, u'test') self.assertEqual(v.__class__, V1) def testUnnamedViewThatProvidesAnInterface(self): ob = Ob() self.assertEqual( zapi.queryMultiAdapter((ob, Request(IR)), IV), None) xmlconfig(StringIO(template % ''' ''' )) v = zapi.queryMultiAdapter((ob, Request(IR)), IV) self.assertEqual(v, None) xmlconfig(StringIO(template % ''' ''' )) v = zapi.queryMultiAdapter((ob, Request(IR)), IV) self.assertEqual(v.__class__, V1) def testViewHavingARequiredClass(self): xmlconfig(StringIO(template % ( ''' ''' ))) content = Content() a1 = zapi.getMultiAdapter((content, Request(IR))) self.assert_(isinstance(a1, A1)) class MyContent: implements(IContent) self.assertRaises(ComponentLookupError, zapi.getMultiAdapter, (MyContent(), Request(IR))) def testInterfaceProtectedView(self): xmlconfig(StringIO(template % ''' ''' )) v = ProxyFactory(zapi.getMultiAdapter((Ob(), Request(IV)), name='test')) self.assertEqual(v.index(), 'V1 here') self.assertRaises(Exception, getattr, v, 'action') def testAttributeProtectedView(self): xmlconfig(StringIO(template % ''' ''' )) v = ProxyFactory(zapi.getMultiAdapter((Ob(), Request(IV)), name='test')) self.assertEqual(v.action(), 'done') self.assertRaises(Exception, getattr, v, 'index') def testInterfaceAndAttributeProtectedView(self): xmlconfig(StringIO(template % ''' ''' )) v = zapi.getMultiAdapter((Ob(), Request(IV)), name='test') self.assertEqual(v.index(), 'V1 here') self.assertEqual(v.action(), 'done') def testDuplicatedInterfaceAndAttributeProtectedView(self): xmlconfig(StringIO(template % ''' ''' )) v = zapi.getMultiAdapter((Ob(), Request(IV)), name='test') self.assertEqual(v.index(), 'V1 here') self.assertEqual(v.action(), 'done') def testIncompleteProtectedViewNoPermission(self): self.assertRaises( ConfigurationError, xmlconfig, StringIO(template % ''' ''' )) def testViewUndefinedPermission(self): config = StringIO(template % ( ''' ''' )) self.assertRaises(ValueError, xmlconfig, config, testing=1) def testDefaultView(self): ob = Ob() self.assertEqual( zapi.queryMultiAdapter((Ob(), Request(IV)), name='test'), None) xmlconfig(StringIO(template % ( ''' ''' ))) self.assertEqual( zapi.queryMultiAdapter((Ob(), Request(IV)), name='test'), None) self.assertEqual( zapi.getGlobalSiteManager().adapters.lookup((IC, IV), IDefaultViewName), 'test') def testResource(self): ob = Ob() self.assertEqual( zapi.queryAdapter(Request(IV), name=u'test'), None) xmlconfig(StringIO(template % ( ''' ''' ))) self.assertEqual( zapi.queryAdapter(Request(IV), name=u'test').__class__, R1) def testResourceThatProvidesAnInterface(self): ob = Ob() self.assertEqual(zapi.queryAdapter(Request(IR), IV, u'test'), None) xmlconfig(StringIO(template % ''' ''' )) v = zapi.queryAdapter(Request(IR), IV, name=u'test') self.assertEqual(v, None) xmlconfig(StringIO(template % ''' ''' )) v = zapi.queryAdapter(Request(IR), IV, name=u'test') self.assertEqual(v.__class__, R1) def testUnnamedResourceThatProvidesAnInterface(self): ob = Ob() self.assertEqual(zapi.queryAdapter(Request(IR), IV), None) xmlconfig(StringIO(template % ''' ''' )) v = zapi.queryAdapter(Request(IR), IV) self.assertEqual(v, None) xmlconfig(StringIO(template % ''' ''' )) v = zapi.queryAdapter(Request(IR), IV) self.assertEqual(v.__class__, R1) def testResourceUndefinedPermission(self): config = StringIO(template % ( ''' ''' )) self.assertRaises(ValueError, xmlconfig, config, testing=1) # BBB 2006/02/24, to be removed after 12 months def testFactory(self): showwarning = warnings.showwarning warnings.showwarning = lambda *a, **k: None self.assertRaises(ComponentLookupError, zapi.createObject, 'foo') xmlconfig(StringIO(template % ( ''' ''' ))) from factory import X self.assertEqual(zapi.createObject('foo.bar').__class__, X) warnings.showwarning = showwarning class ParticipationStub(object): def __init__(self, principal): self.principal = principal self.interaction = None def configfile(s): return StringIO(""" %s """ % s) class TestFactoryDirective(PlacelessSetup, unittest.TestCase): def setUp(self): super(TestFactoryDirective, self).setUp() XMLConfig('meta.zcml', zope.app.component)() XMLConfig('meta.zcml', zope.app.security)() def testFactory(self): f = configfile(''' ''') xmlconfig(f) obj = createObject('test.Example') self.failUnless(zapi.isinstance(obj, exampleclass.ExampleClass)) PREFIX = module.__name__ + '.' def defineDirectives(): XMLConfig('meta.zcml', zope.app.component)() XMLConfig('meta.zcml', zope.app.security)() xmlconfig(StringIO(""" """)) NOTSET = [] P1 = "zope.Extravagant" P2 = "zope.Paltry" class TestRequireDirective(PlacelessSetup, unittest.TestCase): def setUp(self): super(TestRequireDirective, self).setUp() defineDirectives() class B(object): def m1(self): return "m1" def m2(self): return "m2" class C(B): implements(module.I) def m3(self): return "m3" def m4(self): return "m4" module.test_base = B module.test_class = C module.test_instance = C() self.assertState() def tearDown(self): PlacelessSetup.tearDown(self) module.test_class = None def assertState(self, m1P=NOTSET, m2P=NOTSET, m3P=NOTSET): "Verify that class, instance, and methods have expected permissions." from zope.security.checker import selectChecker checker = selectChecker(module.test_instance) self.assertEqual(checker.permission_id('m1'), (m1P or None)) self.assertEqual(checker.permission_id('m2'), (m2P or None)) self.assertEqual(checker.permission_id('m3'), (m3P or None)) def assertDeclaration(self, declaration, **state): apply_declaration(module.template_bracket % declaration) self.assertState(**state) # "testSimple*" exercises tags that do NOT have children. This mode # inherently sets the instances as well as the class attributes. def testSimpleMethodsPlural(self): declaration = (''' ''' % (PREFIX+"test_class", P1)) self.assertDeclaration(declaration, m1P=P1, m3P=P1) def assertSetattrState(self, m1P=NOTSET, m2P=NOTSET, m3P=NOTSET): "Verify that class, instance, and methods have expected permissions." from zope.security.checker import selectChecker checker = selectChecker(module.test_instance) self.assertEqual(checker.setattr_permission_id('m1'), (m1P or None)) self.assertEqual(checker.setattr_permission_id('m2'), (m2P or None)) self.assertEqual(checker.setattr_permission_id('m3'), (m3P or None)) def assertSetattrDeclaration(self, declaration, **state): self.assertSetattrState(**state) def test_set_attributes(self): declaration = (''' ''' % (PREFIX+"test_class", P1)) apply_declaration(module.template_bracket % declaration) checker = selectChecker(module.test_instance) self.assertEqual(checker.setattr_permission_id('m1'), P1) self.assertEqual(checker.setattr_permission_id('m2'), None) self.assertEqual(checker.setattr_permission_id('m3'), P1) def test_set_schema(self): self.assertEqual(queryInterface(PREFIX+"S"), None) declaration = (''' ''' % (PREFIX+"test_class", P1, PREFIX+"S")) apply_declaration(module.template_bracket % declaration) self.assertEqual(queryInterface(PREFIX+"S"), module.S) checker = selectChecker(module.test_instance) self.assertEqual(checker.setattr_permission_id('m1'), None) self.assertEqual(checker.setattr_permission_id('m2'), None) self.assertEqual(checker.setattr_permission_id('m3'), None) self.assertEqual(checker.setattr_permission_id('foo'), P1) self.assertEqual(checker.setattr_permission_id('bar'), P1) self.assertEqual(checker.setattr_permission_id('baro'), None) def test_multiple_set_schema(self): self.assertEqual(queryInterface(PREFIX+"S"), None) self.assertEqual(queryInterface(PREFIX+"S2"), None) declaration = (''' ''' % (PREFIX+"test_class", P1, PREFIX+"S", PREFIX+"S2")) apply_declaration(module.template_bracket % declaration) self.assertEqual(queryInterface(PREFIX+"S"), module.S) self.assertEqual(queryInterface(PREFIX+"S2"), module.S2) checker = selectChecker(module.test_instance) self.assertEqual(checker.setattr_permission_id('m1'), None) self.assertEqual(checker.setattr_permission_id('m2'), None) self.assertEqual(checker.setattr_permission_id('m3'), None) self.assertEqual(checker.setattr_permission_id('foo'), P1) self.assertEqual(checker.setattr_permission_id('bar'), P1) self.assertEqual(checker.setattr_permission_id('foo2'), P1) self.assertEqual(checker.setattr_permission_id('bar2'), P1) self.assertEqual(checker.setattr_permission_id('baro'), None) def testSimpleInterface(self): self.assertEqual(queryInterface(PREFIX+"I"), None) declaration = (''' ''' % (PREFIX+"test_class", P1, PREFIX+"I")) # m1 and m2 are in the interface, so should be set, and m3 should not: self.assertDeclaration(declaration, m1P=P1, m2P=P1) # Make sure we know about the interfaces self.assertEqual(queryInterface(PREFIX+"I"), module.I) def testMultipleInterface(self): self.assertEqual(queryInterface(PREFIX+"I3"), None) self.assertEqual(queryInterface(PREFIX+"I4"), None) declaration = (''' ''' % (PREFIX+"test_class", P1, PREFIX+"I3", PREFIX+"I4")) self.assertDeclaration(declaration, m3P=P1, m2P=P1) # Make sure we know about the interfaces self.assertEqual(queryInterface(PREFIX+"I3"), module.I3) self.assertEqual(queryInterface(PREFIX+"I4"), module.I4) # "testComposite*" exercises tags that DO have children. # "testComposite*TopPerm" exercises tags with permission in containing tag. # "testComposite*ElementPerm" exercises tags w/permission in children. def testCompositeNoPerm(self): # Establish rejection of declarations lacking a permission spec. declaration = (''' ''' % (PREFIX+"test_class")) self.assertRaises(ZopeXMLConfigurationError, self.assertDeclaration, declaration) def testCompositeMethodsPluralElementPerm(self): declaration = (''' ''' % (PREFIX+"test_class", P1)) self.assertDeclaration(declaration, m1P=P1, m3P=P1) def testCompositeInterfaceTopPerm(self): declaration = (''' ''' % (PREFIX+"test_class", P1, PREFIX+"I")) self.assertDeclaration(declaration, m1P=P1, m2P=P1) def testSubInterfaces(self): declaration = (''' ''' % (PREFIX+"test_class", P1, PREFIX+"I2")) # m1 and m2 are in the interface, so should be set, and m3 should not: self.assertDeclaration(declaration, m1P=P1, m2P=P1) def testMimicOnly(self): declaration = (''' ''' % (PREFIX+"test_base", P1, PREFIX+"test_class", PREFIX+"test_base")) # m1 and m2 are in the interface, so should be set, and m3 should not: self.assertDeclaration(declaration, m1P=P1, m2P=P1) def testMimicAsDefault(self): declaration = (''' ''' % (PREFIX+"test_base", P1, PREFIX+"test_class", PREFIX+"test_base", P2)) # m1 and m2 are in the interface, so should be set, and m3 should not: self.assertDeclaration(declaration, m1P=P1, m2P=P2, m3P=P2) def apply_declaration(declaration): '''Apply the xmlconfig machinery.''' return xmlconfig(StringIO(declaration)) def test_suite(): return unittest.TestSuite(( unittest.makeSuite(Test), unittest.makeSuite(TestFactoryDirective), unittest.makeSuite(TestRequireDirective), DocTestSuite(), )) if __name__ == "__main__": unittest.TextTestRunner().run(test_suite())