Back to index

plone3  3.1.7
dummy.py
Go to the documentation of this file.
00001 ##############################################################################
00002 #
00003 # Copyright (c) 2002 Zope Corporation and Contributors. All Rights Reserved.
00004 #
00005 # This software is subject to the provisions of the Zope Public License,
00006 # Version 2.1 (ZPL).  A copy of the ZPL should accompany this distribution.
00007 # THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
00008 # WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
00009 # WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
00010 # FOR A PARTICULAR PURPOSE.
00011 #
00012 ##############################################################################
00013 """ Unit test dummies.
00014 
00015 $Id: dummy.py 76996 2007-06-24 00:18:49Z hannosch $
00016 """
00017 
00018 from Acquisition import Implicit, aq_base, aq_inner, aq_parent
00019 from OFS.event import ObjectWillBeAddedEvent
00020 from OFS.event import ObjectWillBeRemovedEvent
00021 from OFS.interfaces import IObjectManager
00022 from OFS.SimpleItem import Item
00023 from webdav.common import rfc1123_date
00024 from zope.app.container.contained import notifyContainerModified
00025 from zope.app.container.contained import ObjectAddedEvent
00026 from zope.app.container.contained import ObjectRemovedEvent
00027 from zope.component.factory import Factory
00028 from zope.event import notify
00029 from zope.interface import implements
00030 
00031 from Products.CMFCore.interfaces import IContentish
00032 from Products.CMFCore.interfaces import ISiteRoot
00033 from Products.CMFCore.interfaces import ITypeInformation
00034 from Products.CMFCore.ActionProviderBase import ActionProviderBase
00035 from Products.CMFCore.PortalContent import PortalContent
00036 
00037 from security import OmnipotentUser
00038 
00039 
00040 class DummyObject(Implicit):
00041     """
00042     A dummy callable object.
00043     Comes with getIcon and restrictedTraverse
00044     methods.
00045     """
00046     def __init__(self, id='dummy',**kw):
00047         self._id = id
00048         self.__dict__.update( kw )
00049 
00050     def __str__(self):
00051         return self._id
00052 
00053     def __call__(self):
00054         return self._id
00055 
00056     def restrictedTraverse( self, path ):
00057         return path and getattr( self, path ) or self
00058 
00059     def getIcon( self, relative=0 ):
00060         return 'Site: %s' % relative
00061 
00062     def getId(self):
00063         return self._id
00064 
00065 
00066 class DummyType(DummyObject):
00067     """ A Dummy Type object """
00068     implements(ITypeInformation)
00069 
00070     def __init__(self, id='Dummy Content', title='Dummy Content', actions=()):
00071         """ To fake out some actions, pass in a sequence of tuples where the
00072         first element represents the ID or alias of the action and the
00073         second element is the path to the object to be invoked, such as 
00074         a page template.
00075         """
00076 
00077         self.id = self._id = id
00078         self.title = title
00079         self._actions = {}
00080 
00081         self._setActions(actions)
00082 
00083     def _setActions(self, actions=()):
00084         for action_id, action_path in actions:
00085             self._actions[action_id] = action_path
00086 
00087     def Title(self):
00088         return self.title
00089 
00090     def allowType(self, contentType):
00091         return True
00092 
00093     def allowDiscussion(self):
00094         return False
00095 
00096     def queryMethodID(self, alias, default=None, context=None):
00097         return self._actions.get(alias, default)
00098 
00099     def isConstructionAllowed(self, container):
00100         return True
00101 
00102 
00103 class DummyContent( PortalContent, Item ):
00104     """
00105     A Dummy piece of PortalContent
00106     """
00107     implements(IContentish)
00108 
00109     meta_type = 'Dummy'
00110     portal_type = 'Dummy Content'
00111     url = 'foo_url'
00112     after_add_called = before_delete_called = 0
00113 
00114     def __init__( self, id='dummy', *args, **kw ):
00115         self.id = id
00116         self._args = args
00117         self._kw = {}
00118         self._kw.update( kw )
00119 
00120         self.reset()
00121         self.catalog = kw.get('catalog',0)
00122         self.url = kw.get('url',None)
00123         self.view_id = kw.get('view_id',None)
00124 
00125     def manage_afterAdd(self, item, container):
00126         self.after_add_called = 1
00127 
00128     def manage_beforeDelete(self, item, container):
00129         self.before_delete_called = 1
00130 
00131     def absolute_url(self):
00132        return self.url
00133 
00134     def reset( self ):
00135         self.after_add_called = self.before_delete_called = 0
00136 
00137     # Make sure normal Database export/import stuff doesn't trip us up.
00138     def _getCopy(self, container):
00139         return DummyContent( self.id, catalog=self.catalog )
00140 
00141     def _safe_get(self,attr):
00142         if self.catalog:
00143             return getattr(self,attr,'')
00144         else:
00145             return getattr(self,attr)
00146 
00147     def Title( self ):
00148         return self.title
00149 
00150     def listCreators(self):
00151         return self._safe_get('creators')
00152 
00153     def Subject( self ):
00154         return self._safe_get('subject')
00155 
00156     def Description( self ):
00157         return self._safe_get('description')
00158 
00159     def created( self ):
00160         return self._safe_get('created_date')
00161 
00162     def modified( self ):
00163         return self._safe_get('modified_date')
00164 
00165     def Type( self ):
00166         return 'Dummy Content Title'
00167 
00168     def __call__(self):
00169         if self.view_id is None:
00170            return DummyContent.inheritedAttribute('__call__')(self)
00171         else:
00172            # view_id control for testing
00173            template = getattr(self, self.view_id)
00174            if getattr(aq_base(template), 'isDocTemp', 0):
00175                return template(self, self.REQUEST, self.REQUEST['RESPONSE'])
00176            else:
00177                return template()
00178 
00179 DummyFactory = Factory(DummyContent)
00180 
00181 
00182 class DummyFactoryDispatcher:
00183 
00184     """
00185     Dummy Product Factory Dispatcher
00186     """
00187     def __init__( self, folder ):
00188         self._folder = folder
00189 
00190     def getId(self):
00191         return 'DummyFactoryDispatcher'
00192 
00193     def addFoo( self, id, *args, **kw ):
00194         if getattr(self._folder, '_prefix', None):
00195             id = '%s_%s' % ( self._folder._prefix, id )
00196         foo = DummyContent(id, *args, **kw)
00197         self._folder._setObject(id, foo)
00198         if getattr(self._folder, '_prefix', None):
00199             return id
00200 
00201     __roles__ = ( 'FooAdder', )
00202     __allow_access_to_unprotected_subobjects__ = { 'addFoo' : 1 }
00203 
00204 
00205 class DummyFolder(DummyObject):
00206 
00207     """Dummy Container for testing.
00208     """
00209     implements(IObjectManager)
00210 
00211     def __init__( self, id='dummy', fake_product=0, prefix='' ):
00212         self._prefix = prefix
00213         self._id = id
00214 
00215         if fake_product:
00216             self.manage_addProduct = {
00217                                    'FooProduct': DummyFactoryDispatcher(self)}
00218 
00219     def _setOb(self, id, object):
00220         setattr(self, id, object)
00221 
00222     def _delOb(self, id):
00223         delattr(self, id)
00224 
00225     def _getOb( self, id ):
00226         return getattr(self, id)
00227 
00228     def _setObject(self, id, object):
00229         notify(ObjectWillBeAddedEvent(object, self, id))
00230         self._setOb(id, object)
00231         object = self._getOb(id)
00232         if hasattr(aq_base(object), 'manage_afterAdd'):
00233             object.manage_afterAdd(object, self)
00234         notify(ObjectAddedEvent(object, self, id))
00235         notifyContainerModified(self)
00236         return object
00237 
00238     def _delObject(self, id):
00239         object = self._getOb(id)
00240         notify(ObjectWillBeRemovedEvent(object, self, id))
00241         if hasattr(aq_base(object), 'manage_beforeDelete'):
00242             object.manage_beforeDelete(object, self)
00243         self._delOb(id)
00244         notify(ObjectRemovedEvent(object, self, id))
00245         notifyContainerModified(self)
00246 
00247     def getPhysicalPath(self):
00248         p = aq_parent(aq_inner(self))
00249         path = (self._id, )
00250         if p is not None:
00251             path = p.getPhysicalPath() + path
00252         return path
00253 
00254     def getId(self):
00255         return self._id
00256 
00257     def reindexObjectSecurity(self):
00258         pass
00259 
00260     def contentIds(self):
00261         return ('user_bar',)
00262 
00263     def all_meta_types(self):
00264         return ({'name': 'Dummy', 'permission': 'addFoo'},)
00265 
00266     def getTypeInfo(self):
00267         return self.portal_types.getTypeInfo(self)  # Can return None.
00268 
00269 class DummySite(DummyFolder):
00270     """ A dummy portal folder.
00271     """
00272 
00273     _domain = 'http://www.foobar.com'
00274     _path = 'bar'
00275     implements(ISiteRoot)
00276 
00277     def absolute_url(self, relative=0):
00278         return '/'.join( (self._domain, self._path, self._id) )
00279 
00280     def getPhysicalPath(self):
00281         return ('', self._path, self._id)
00282 
00283     def getPhysicalRoot(self):
00284         return self
00285 
00286     def unrestrictedTraverse(self, path, default=None, restricted=0):
00287         if path == ['acl_users']:
00288             return self.acl_users
00289         else:
00290             obj = self
00291             for id in path[3:]:
00292                 obj = getattr(obj, id)
00293             return obj
00294 
00295     def userdefined_roles(self):
00296         return ('Member', 'Reviewer')
00297 
00298     def getProperty(self, id, default=None):
00299         return getattr(self, id, default)
00300 
00301 
00302 class DummyUser(Implicit):
00303     """ A dummy User.
00304     """
00305 
00306     def __init__(self, id='dummy'):
00307         self.id = id
00308 
00309     def getId(self):
00310         return self.id
00311 
00312     getUserName = getId
00313 
00314     def allowed(self, object, object_roles=None):
00315         if object_roles is None or 'Anonymous' in object_roles:
00316             return 1
00317         for role in object_roles:
00318             if role in self.getRolesInContext(object):
00319                 return 1
00320         return 0
00321 
00322     def getRolesInContext(self, object):
00323         return ('Authenticated', 'Dummy', 'Member')
00324 
00325     def _check_context(self, object):
00326         return 1
00327 
00328 
00329 class DummyUserFolder(Implicit):
00330     """ A dummy User Folder with 2 dummy Users.
00331     """
00332 
00333     id = 'acl_users'
00334 
00335     def __init__(self):
00336         setattr( self, 'user_foo', DummyUser(id='user_foo') )
00337         setattr( self, 'user_bar', DummyUser(id='user_bar') )
00338         setattr( self, 'all_powerful_Oz', OmnipotentUser() )
00339 
00340     def getUsers(self):
00341         pass
00342 
00343     def getUser(self, name):
00344         return getattr(self, name, None)
00345 
00346     def getUserById(self, id, default=None):
00347         return self.getUser(id)
00348 
00349     def userFolderDelUsers(self, names):
00350         for user_id in names:
00351             delattr(self, user_id)
00352 
00353 
00354 class DummyTool(Implicit,ActionProviderBase):
00355     """
00356     This is a Dummy Tool that behaves as a
00357     a MemberShipTool, a URLTool and an
00358     Action Provider
00359     """
00360 
00361     def __init__(self, anon=1):
00362         self.anon = anon
00363 
00364     def getIcon( self, relative=0 ):
00365         return 'Tool: %s' % relative
00366 
00367     # IMembershipTool
00368     def getAuthenticatedMember(self):
00369         return DummyUser()
00370 
00371     def isAnonymousUser(self):
00372         return self.anon
00373 
00374     def checkPermission(self, permissionName, object, subobjectName=None):
00375         return True
00376 
00377     # ITypesTool
00378     _type_id = 'Dummy Content'
00379     _type_actions = (('', 'dummy_view'),
00380                      ('view', 'dummy_view'),
00381                      ('(Default)', 'dummy_view'))
00382 
00383     def getTypeInfo(self, contentType):
00384         return DummyType(self._type_id, title=self._type_id,
00385                          actions=self._type_actions)
00386 
00387     def listTypeInfo(self, container=None):
00388         return (DummyType(self._type_id, title=self._type_id,
00389                           actions=self._type_actions),)
00390 
00391     def listContentTypes(self, container=None, by_metatype=0):
00392         return (self._type_id,)
00393 
00394     # IURLTool
00395     root = 'DummyTool'
00396 
00397     def __call__(self):
00398         return self.root
00399 
00400     def getPortalObject(self):
00401         return aq_parent(aq_inner(self))
00402 
00403     getPortalPath = __call__
00404 
00405     # IWorkflowTool
00406     test_notified = None
00407 
00408     def notifyCreated(self, ob):
00409         self.test_notified = ob
00410 
00411     def getCatalogVariablesFor(self, obj):
00412         return {}
00413 
00414 
00415 class DummyCachingManager:
00416 
00417     def getHTTPCachingHeaders( self, content, view_name, keywords, time=None ):
00418          return (
00419              ('foo', 'Foo'), ('bar', 'Bar'),
00420              ('test_path', '/'.join(content.getPhysicalPath())),
00421              )
00422 
00423     def getModTimeAndETag(self, content, view_method, keywords, time=None ):
00424          return (None, None, False)
00425 
00426     def getPhysicalPath(self):
00427         return ('baz',)
00428 
00429 
00430 FAKE_ETAG = None # '--FAKE ETAG--'
00431 
00432 class DummyCachingManagerWithPolicy(DummyCachingManager):
00433 
00434     # dummy fixture implementing a single policy:
00435     #  - always set the last-modified date if available
00436     #  - calculate the date using the modified method on content
00437 
00438     def getHTTPCachingHeaders( self, content, view_name, keywords, time=None ):
00439 
00440          # if the object has a modified method, add it as last-modified
00441          if hasattr(content, 'modified'):
00442              headers = ( ('Last-modified', rfc1123_date(content.modified()) ), )
00443          return headers
00444 
00445     def getModTimeAndETag(self, content, view_method, keywords, time=None ):
00446          modified_date = None
00447          if hasattr(content, 'modified'):
00448             modified_date = content.modified()
00449          set_last_modified = (modified_date is not None)
00450          return (modified_date, FAKE_ETAG, set_last_modified)