This repository has been archived on 2023-02-21. You can view files and clone it, but cannot push or open issues or pull requests.
plone.dexterity/plone/dexterity/tests/test_content.py

684 lines
25 KiB
Python

# -*- coding: utf-8 -*-
import unittest
from plone.mocktestcase import MockTestCase
from zope.interface import Interface, alsoProvides
from zope.component import provideAdapter
import zope.schema
from plone.dexterity.interfaces import IDexterityFTI
from plone.dexterity.fti import DexterityFTI
from plone.dexterity.schema import SCHEMA_CACHE
from plone.dexterity.content import Item, Container
from plone.behavior.interfaces import IBehavior
from plone.behavior.registration import BehaviorRegistration
from plone.folder.default import DefaultOrdering
from zope.annotation.attribute import AttributeAnnotations
class TestContent(MockTestCase):
def setUp(self):
SCHEMA_CACHE.clear()
provideAdapter(DefaultOrdering)
provideAdapter(AttributeAnnotations)
def test_provided_by_item(self):
class FauxDataManager(object):
def setstate(self, obj): pass
def oldstate(self, obj, tid): pass
def register(self, obj): pass
# Dummy instance
item = Item(id=u'id')
item.portal_type = 'testtype'
item._p_jar = FauxDataManager()
# Dummy schema
class ISchema(Interface):
foo = zope.schema.TextLine(title=u"foo", default=u"foo_default")
bar = zope.schema.TextLine(title=u"bar")
class IMarker(Interface):
pass
# Schema is not implemented by class or provided by instance
self.assertEquals(False, ISchema.implementedBy(Item))
self.assertEquals(False, ISchema.providedBy(item))
# FTI mock
fti_mock = self.mocker.proxy(DexterityFTI(u"testtype"))
self.expect(fti_mock.lookupSchema()).result(ISchema).count(1)
self.mock_utility(fti_mock, IDexterityFTI, name=u"testtype")
self.replay()
self.assertEquals(False, ISchema.implementedBy(Item))
# Schema as looked up in FTI is now provided by item ...
self.assertEquals(True, ISchema.providedBy(item))
# If the _v_ attribute cache does not work, then we'd expect to have
# to look up the schema more than once (since we invalidated)
# the cache. This is not the case, as evidenced by .count(1) above.
self.assertEquals(True, ISchema.providedBy(item))
# We also need to ensure that the _v_ attribute doesn't hide any
# interface set directly on the instance with alsoProvides() or
# directlyProvides(). This is done by clearing the cache when these
# are invoked.
alsoProvides(item, IMarker)
self.assertEquals(True, IMarker.providedBy(item))
self.assertEquals(True, ISchema.providedBy(item))
def test_provided_by_subclass(self):
# Make sure the __providedBy__ descriptor lives in sub-classes
# Dummy type
class MyItem(Item):
pass
class FauxDataManager(object):
def setstate(self, obj): pass
def oldstate(self, obj, tid): pass
def register(self, obj): pass
# Dummy instance
item = MyItem(id=u'id')
item.portal_type = 'testtype'
item._p_jar = FauxDataManager()
# Dummy schema
class ISchema(Interface):
foo = zope.schema.TextLine(title=u"foo", default=u"foo_default")
bar = zope.schema.TextLine(title=u"bar")
class IMarker(Interface):
pass
# Schema is not implemented by class or provided by instance
self.assertEquals(False, ISchema.implementedBy(MyItem))
self.assertEquals(False, ISchema.providedBy(item))
# FTI mock
fti_mock = self.mocker.proxy(DexterityFTI(u"testtype"))
self.expect(fti_mock.lookupSchema()).result(ISchema).count(1)
self.mock_utility(fti_mock, IDexterityFTI, name=u"testtype")
self.replay()
self.assertEquals(False, ISchema.implementedBy(MyItem))
# Schema as looked up in FTI is now provided by item ...
self.assertEquals(True, ISchema.providedBy(item))
# If the _v_ attribute cache does not work, then we'd expect to have
# to look up the schema more than once (since we invalidated)
# the cache. This is not the case, as evidenced by .count(1) above.
self.assertEquals(True, ISchema.providedBy(item))
# We also need to ensure that the _v_ attribute doesn't hide any
# interface set directly on the instance with alsoProvides() or
# directlyProvides(). This is done by clearing the cache when these
# are invoked.
alsoProvides(item, IMarker)
self.assertEquals(True, IMarker.providedBy(item))
self.assertEquals(True, ISchema.providedBy(item))
def test_provided_by_subclass_nojar(self):
# Dummy type
class MyItem(Item):
pass
# Dummy instance
item = MyItem(id=u'id')
item.portal_type = 'testtype'
# Without a persistence jar, the _p_changed check doesn't work. In
# this case, the cache is a bit slower.
# item._p_jar = FauxDataManager()
# Dummy schema
class ISchema(Interface):
foo = zope.schema.TextLine(title=u"foo", default=u"foo_default")
bar = zope.schema.TextLine(title=u"bar")
class IMarker(Interface):
pass
# Schema is not implemented by class or provided by instance
self.assertEquals(False, ISchema.implementedBy(MyItem))
self.assertEquals(False, ISchema.providedBy(item))
# FTI mock
fti_mock = self.mocker.proxy(DexterityFTI(u"testtype"))
self.expect(fti_mock.lookupSchema()).result(ISchema).count(1)
self.mock_utility(fti_mock, IDexterityFTI, name=u"testtype")
self.replay()
self.assertEquals(False, ISchema.implementedBy(MyItem))
# Schema as looked up in FTI is now provided by item ...
self.assertEquals(True, ISchema.providedBy(item))
# If the _v_ attribute cache does not work, then we'd expect to have
# to look up the schema more than once (since we invalidated)
# the cache. This is not the case, as evidenced by .count(1) above.
self.assertEquals(True, ISchema.providedBy(item))
# We also need to ensure that the _v_ attribute doesn't hide any
# interface set directly on the instance with alsoProvides() or
# directlyProvides(). This is done by clearing the cache when these
# are invoked.
alsoProvides(item, IMarker)
self.assertEquals(True, IMarker.providedBy(item))
self.assertEquals(True, ISchema.providedBy(item))
def test_provided_by_behavior_subtype(self):
# Dummy type
class MyItem(Item):
pass
# Fake data manager
class FauxDataManager(object):
def setstate(self, obj): pass
def oldstate(self, obj, tid): pass
def register(self, obj): pass
# Dummy instance
item = MyItem(id=u'id')
item.portal_type = 'testtype'
# Without a persistence jar, the _p_changed check doesn't work. In
# this case, the cache is a bit slower.
item._p_jar = FauxDataManager()
# Dummy schema
class ISchema(Interface):
foo = zope.schema.TextLine(title=u"foo", default=u"foo_default")
bar = zope.schema.TextLine(title=u"bar")
class IMarker(Interface):
pass
# Schema is not implemented by class or provided by instance
self.assertEquals(False, ISchema.implementedBy(MyItem))
self.assertEquals(False, ISchema.providedBy(item))
# Behaviors - one with a subtype and one without
class IBehavior1(Interface):
pass
class IBehavior2(Interface):
pass
class ISubtype(Interface):
baz = zope.schema.TextLine(title=u"baz", default=u"baz")
behavior1 = BehaviorRegistration(u"Behavior1", "", IBehavior1, None, None)
behavior2 = BehaviorRegistration(u"Behavior2", "", IBehavior2, ISubtype, None)
self.mock_utility(behavior1, IBehavior, name="behavior1")
self.mock_utility(behavior2, IBehavior, name="behavior2")
# FTI mock
fti_mock = self.mocker.proxy(DexterityFTI(u"testtype"))
self.expect(fti_mock.lookupSchema()).result(ISchema).count(1)
self.expect(fti_mock.behaviors).result(['behavior1', 'behavior2']).count(1)
self.mock_utility(fti_mock, IDexterityFTI, name=u"testtype")
self.replay()
self.assertEquals(False, ISchema.implementedBy(MyItem))
# Schema as looked up in FTI is now provided by item ...
self.assertEquals(True, ISubtype.providedBy(item))
self.assertEquals(True, ISchema.providedBy(item))
# If the _v_ attribute cache does not work, then we'd expect to have
# to look up the schema more than once (since we invalidated)
# the cache. This is not the case, as evidenced by .count(1) above.
self.assertEquals(True, ISubtype.providedBy(item))
self.assertEquals(True, ISchema.providedBy(item))
# Subtypes provide field defaults.
self.assertEquals(u"baz", getattr(item, "baz", None))
# We also need to ensure that the _v_ attribute doesn't hide any
# interface set directly on the instance with alsoProvides() or
# directlyProvides(). This is done by clearing the cache when these
# are invoked.
alsoProvides(item, IMarker)
self.assertEquals(True, IMarker.providedBy(item))
self.assertEquals(True, ISubtype.providedBy(item))
self.assertEquals(True, ISchema.providedBy(item))
def test_provided_by_behavior_subtype_invalidation(self):
# Dummy type
class MyItem(Item):
pass
# Fake data manager
class FauxDataManager(object):
def setstate(self, obj): pass
def oldstate(self, obj, tid): pass
def register(self, obj): pass
# Dummy instance
item = MyItem(id=u'id')
item.portal_type = 'testtype'
# Without a persistence jar, the _p_changed check doesn't work. In
# this case, the cache is a bit slower.
item._p_jar = FauxDataManager()
# Dummy schema
class ISchema(Interface):
foo = zope.schema.TextLine(title=u"foo", default=u"foo_default")
bar = zope.schema.TextLine(title=u"bar")
# Schema is not implemented by class or provided by instance
self.assertEquals(False, ISchema.implementedBy(MyItem))
self.assertEquals(False, ISchema.providedBy(item))
# Behaviors - one with a subtype and one without
class IBehavior1(Interface):
pass
class IBehavior2(Interface):
pass
class IBehavior3(Interface):
pass
class ISubtype1(Interface):
pass
class ISubtype2(Interface):
pass
behavior1 = BehaviorRegistration(u"Behavior1", "", IBehavior1, None, None)
behavior2 = BehaviorRegistration(u"Behavior2", "", IBehavior2, ISubtype1, None)
behavior3 = BehaviorRegistration(u"Behavior3", "", IBehavior3, ISubtype2, None)
self.mock_utility(behavior1, IBehavior, name="behavior1")
self.mock_utility(behavior2, IBehavior, name="behavior2")
self.mock_utility(behavior3, IBehavior, name="behavior3")
# FTI mock
fti_mock = self.mocker.proxy(DexterityFTI(u"testtype"))
self.expect(fti_mock.lookupSchema()).result(ISchema).count(2) # twice, since we invalidate
# First time around, we have only these behaviors
self.expect(fti_mock.behaviors).result(['behavior1', 'behavior2']).count(1)
# Second time around, we add another one
self.expect(fti_mock.behaviors).result(['behavior1', 'behavior2', 'behavior3']).count(1)
self.mock_utility(fti_mock, IDexterityFTI, name=u"testtype")
self.replay()
self.assertEquals(False, ISchema.implementedBy(MyItem))
# Schema as looked up in FTI is now provided by item ...
self.assertEquals(True, ISubtype1.providedBy(item))
self.assertEquals(False, ISubtype2.providedBy(item))
self.assertEquals(True, ISchema.providedBy(item))
# If the _v_ attribute cache does not work, then we'd expect to have
# to look up the schema more than once (since we invalidated)
# the cache. This is not the case, as evidenced by .count(1) above.
self.assertEquals(True, ISubtype1.providedBy(item))
self.assertEquals(False, ISubtype2.providedBy(item))
self.assertEquals(True, ISchema.providedBy(item))
# If we now invalidate the schema cache, we should get the second set
# of behaviors
SCHEMA_CACHE.invalidate('testtype')
# Schema as looked up in FTI is now provided by item ...
self.assertEquals(True, ISubtype1.providedBy(item))
self.assertEquals(True, ISubtype2.providedBy(item))
self.assertEquals(True, ISchema.providedBy(item))
# If the _v_ attribute cache does not work, then we'd expect to have
# to look up the schema more than once (since we invalidated)
# the cache. This is not the case, as evidenced by .count(1) above.
self.assertEquals(True, ISubtype1.providedBy(item))
self.assertEquals(True, ISubtype2.providedBy(item))
self.assertEquals(True, ISchema.providedBy(item))
def test_getattr_consults_schema_item(self):
content = Item()
content.id = u"id"
content.portal_type = u"testtype"
class ISchema(Interface):
foo = zope.schema.TextLine(title=u"foo", default=u"foo_default")
bar = zope.schema.TextLine(title=u"bar")
# FTI mock
fti_mock = self.mocker.proxy(DexterityFTI(u"testtype"))
self.expect(fti_mock.lookupSchema()).result(ISchema)
self.mock_utility(fti_mock, IDexterityFTI, name=u"testtype")
self.replay()
self.assertEquals(u"foo_default", content.foo)
self.assertEquals(None, content.bar)
self.assertEquals(u"id", content.id)
self.assertRaises(AttributeError, getattr, content, 'baz')
def test_getattr_consults_schema_container(self):
content = Container()
content.id = u"id"
content.portal_type = u"testtype"
class ISchema(Interface):
foo = zope.schema.TextLine(title=u"foo", default=u"foo_default")
bar = zope.schema.TextLine(title=u"bar")
# FTI mock
fti_mock = self.mocker.proxy(DexterityFTI(u"testtype"))
self.expect(fti_mock.lookupSchema()).result(ISchema)
self.mock_utility(fti_mock, IDexterityFTI, name=u"testtype")
self.replay()
self.assertEquals(u"foo_default", content.foo)
self.assertEquals(None, content.bar)
self.assertEquals(u"id", content.id)
self.assertRaises(AttributeError, getattr, content, 'baz')
def test_getattr_on_container_returns_children(self):
content = Container()
content.id = u"id"
content.portal_type = u"testtype"
content['foo'] = Item('foo')
content['quux'] = Item('quux')
class ISchema(Interface):
foo = zope.schema.TextLine(title=u"foo", default=u"foo_default")
bar = zope.schema.TextLine(title=u"bar")
# FTI mock
fti_mock = self.mocker.proxy(DexterityFTI(u"testtype"))
self.expect(fti_mock.lookupSchema()).result(ISchema)
self.mock_utility(fti_mock, IDexterityFTI, name=u"testtype")
self.replay()
# Schema field masks contained item
self.assertEquals(u"foo_default", content.foo)
# But we can still obtain an item
self.failUnless(isinstance(content['foo'], Item))
self.assertEquals('foo', content['foo'].id)
# And if the item isn't masked by an attribute, we can still getattr it
self.failUnless(isinstance(content['quux'], Item))
self.assertEquals('quux', content['quux'].id)
self.failUnless(isinstance(getattr(content, 'quux'), Item))
self.assertEquals('quux', getattr(content, 'quux').id)
def test_ZMI_manage_options_container(self):
# Make sure we get the expected tabs in the ZMI
containerOptions = [o['label'] for o in Container.manage_options]
for tab in ['Security', 'View', 'Contents', 'Properties', 'Undo', 'Ownership', 'Interfaces']:
self.failUnless(tab in containerOptions, "Tab %s not found" % tab)
def test_ZMI_manage_options_item(self):
# Make sure we get the expected tabs in the ZMI
containerOptions = [o['label'] for o in Item.manage_options]
for tab in ['Security', 'View', 'Undo', 'Ownership', 'Interfaces', 'Dublin Core']:
self.failUnless(tab in containerOptions, "Tab %s not found" % tab)
def test_name_and_id_in_sync(self):
i = Item()
self.assertEquals('', i.id)
self.assertEquals('', i.getId())
self.assertEquals(u'', i.__name__)
i = Item()
i.id = "foo"
self.assertEquals('foo', i.id)
self.assertEquals('foo', i.getId())
self.assertEquals(u'foo', i.__name__)
i = Item()
i.__name__ = u"foo"
self.assertEquals('foo', i.id)
self.assertEquals('foo', i.getId())
self.assertEquals(u'foo', i.__name__)
def test_name_unicode_id_str(self):
i = Item()
try:
i.__name__ = '\xc3\xb8'.decode('utf-8')
except UnicodeEncodeError:
pass
else:
self.fail()
i.__name__ = u"o"
self.assertEquals(u"o", i.__name__)
self.assertEquals("o", i.id)
self.assertEquals("o", i.getId())
self.failUnless(isinstance(i.__name__, unicode))
self.failUnless(isinstance(i.id, str))
self.failUnless(isinstance(i.getId(), str))
def test_item_init_dublincore(self):
from DateTime.DateTime import DateTime
i = Item(title=u"Test title", language="en", effective_date="2010-08-20")
self.assertEqual(i.title, u"Test title")
self.assertEqual(i.language, "en")
self.assertTrue(isinstance(i.effective_date, DateTime))
def test_item_init_nondc_kwargs(self):
i = Item(foo="bar")
self.assertEqual(i.foo, "bar")
def test_container_init_dublincore(self):
from DateTime.DateTime import DateTime
c = Container(title=u"Test title", language="en", effective_date="2010-08-20")
self.assertEqual(c.title, u"Test title")
self.assertEqual(c.language, "en")
self.assertTrue(isinstance(c.effective_date, DateTime))
def test_container_init_nondc_kwargs(self):
c = Container(foo="bar")
self.assertEqual(c.foo, "bar")
def test_setTitle_converts_to_unicode(self):
#fix http://code.google.com/p/dexterity/issues/detail?id=145
i = Item()
i.setTitle("é")
self.assertEqual(i.title, u"é")
i.setTitle(u"é")
self.assertEqual(i.title, u"é")
c = Container()
c.setTitle("é")
self.assertEqual(c.title, u"é")
c.setTitle(u"é")
self.assertEqual(c.title, u"é")
def test_Title_converts_to_utf8(self):
i = Item()
i.title = u"é"
self.assertEqual("é", i.Title())
i.title = "é"
self.assertEqual("é", i.Title())
c = Container()
c.title = u"é"
self.assertEqual("é", c.Title())
c.title = "é"
self.assertEqual("é", c.Title())
def test_Title_handles_None(self):
i = Item(title=None)
self.assertEqual('', i.Title())
c = Container(title=None)
self.assertEqual('', c.Title())
def test_Description_converts_to_utf8(self):
i = Item()
i.description = u"é"
self.assertEqual("é", i.Description())
i.description = "é"
self.assertEqual("é", i.Description())
c = Container()
c.description = u"é"
self.assertEqual("é", c.Description())
c.description = "é"
self.assertEqual("é", c.Description())
def test_setDescription_converts_to_unicode(self):
i = Item()
i.setDescription("é")
self.assertEqual(i.description, u"é")
i.setDescription(u"é")
self.assertEqual(i.description, u"é")
c = Container()
c.setDescription("é")
self.assertEqual(c.description, u"é")
c.setDescription(u"é")
self.assertEqual(c.description, u"é")
def test_Description_handles_None(self):
i = Item(description=None)
self.assertEqual('', i.Description())
c = Container(description=None)
self.assertEqual('', c.Description())
def test_Subject_converts_to_utf8(self):
i = Item()
i.subject = (u"é",)
self.assertEqual(("é",), i.Subject())
i.subject = ("é",)
self.assertEqual(("é",), i.Subject())
c = Container()
c.subject = (u"é",)
self.assertEqual(("é",), c.Subject())
c.subject = ("é",)
self.assertEqual(("é",), c.Subject())
def test_setSubject_converts_to_unicode(self):
i = Item()
i.setSubject(("é",))
self.assertEqual(i.subject, (u"é",))
i.setSubject((u"é",))
self.assertEqual(i.subject, (u"é",))
c = Container()
c.setSubject(("é",))
self.assertEqual(c.subject, (u"é",))
c.setSubject((u"é",))
self.assertEqual(c.subject, (u"é",))
def test_Subject_handles_None(self):
i = Item()
i.subject = None
self.assertEqual((), i.Subject())
c = Container()
c.subject = None
self.assertEqual((), c.Subject())
def test_field_default_independence(self):
# Ensure that fields using the default value aren't being assigned
# shallow copies.
class FauxDataManager(object):
def setstate(self, obj): pass
def oldstate(self, obj, tid): pass
def register(self, obj): pass
# Dummy instances
foo = Item(id=u'foo')
foo.portal_type = 'testtype'
foo._p_jar = FauxDataManager()
bar = Item(id=u'bar')
bar.portal_type = 'testtype'
bar._p_jar = FauxDataManager()
baz = Container(id=u'baz')
baz.portal_type = 'testtype'
baz._p_jar = FauxDataManager()
# Dummy schema
class ISchema(Interface):
listfield = zope.schema.List(title=u"listfield", default=[1,2])
# FTI mock
fti_mock = self.mocker.proxy(DexterityFTI(u"testtype"))
self.expect(fti_mock.lookupSchema()).result(ISchema).count(1)
self.mock_utility(fti_mock, IDexterityFTI, name=u"testtype")
self.replay()
# Ensure that the field of foo is not the same field, also attached to
# bar.
self.assertTrue(foo.listfield is not bar.listfield)
self.assertTrue(foo.listfield is not baz.listfield)
# And just to reinforce why this is awful, we'll ensure that updating
# the field's value on one object does not change the value on the
# other.
foo.listfield.append(3)
self.assertEquals(bar.listfield, [1,2])
self.assertEquals(baz.listfield, [1,2])
def test_container_manage_delObjects(self):
# OFS does not check the delete permission for each object being
# deleted. We want to.
item = Item(id='test')
container = Container(id='container')
container['test'] = item
from zExceptions import Unauthorized
self.assertRaises(Unauthorized, container.manage_delObjects, ['test'])
# Now permit it and try again.
from Products.CMFCore.permissions import DeleteObjects
item.manage_permission(DeleteObjects, ('Anonymous',))
container.manage_delObjects(['test'])
self.assertFalse('test' in container)
def test_suite():
return unittest.defaultTestLoader.loadTestsFromName(__name__)