##############################################################################
#
# Copyright (c) 2003 Zope Foundation 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 the new API for making and checking interface declarations
"""
import unittest
from zope.interface._compat import _skip_under_py3k
from zope.interface._compat import PYTHON3
from zope.interface.tests import OptimizationTestMixin
from zope.interface.tests import MissingSomeAttrs
from zope.interface.tests.test_interface import NameAndModuleComparisonTestsMixin
# pylint:disable=inherit-non-class,too-many-lines,protected-access
# pylint:disable=blacklisted-name,attribute-defined-outside-init
class _Py3ClassAdvice(object):
def _run_generated_code(self, code, globs, locs,
fails_under_py3k=True,
):
# pylint:disable=exec-used,no-member
import warnings
with warnings.catch_warnings(record=True) as log:
warnings.resetwarnings()
if not PYTHON3:
exec(code, globs, locs)
self.assertEqual(len(log), 0) # no longer warn
return True
try:
exec(code, globs, locs)
except TypeError:
return False
else:
if fails_under_py3k:
self.fail("Didn't raise TypeError")
return None
class NamedTests(unittest.TestCase):
def test_class(self):
from zope.interface.declarations import named
@named(u'foo')
class Foo(object):
pass
self.assertEqual(Foo.__component_name__, u'foo') # pylint:disable=no-member
def test_function(self):
from zope.interface.declarations import named
@named(u'foo')
def doFoo(o):
raise NotImplementedError()
self.assertEqual(doFoo.__component_name__, u'foo')
def test_instance(self):
from zope.interface.declarations import named
class Foo(object):
pass
foo = Foo()
named(u'foo')(foo)
self.assertEqual(foo.__component_name__, u'foo') # pylint:disable=no-member
class EmptyDeclarationTests(unittest.TestCase):
# Tests that should pass for all objects that are empty
# declarations. This includes a Declaration explicitly created
# that way, and the empty ImmutableDeclaration.
def _getEmpty(self):
from zope.interface.declarations import Declaration
return Declaration()
def test___iter___empty(self):
decl = self._getEmpty()
self.assertEqual(list(decl), [])
def test_flattened_empty(self):
from zope.interface.interface import Interface
decl = self._getEmpty()
self.assertEqual(list(decl.flattened()), [Interface])
def test___contains___empty(self):
from zope.interface.interface import Interface
decl = self._getEmpty()
self.assertNotIn(Interface, decl)
def test_extends_empty(self):
from zope.interface.interface import Interface
decl = self._getEmpty()
self.assertTrue(decl.extends(Interface))
self.assertTrue(decl.extends(Interface, strict=True))
def test_interfaces_empty(self):
decl = self._getEmpty()
l = list(decl.interfaces())
self.assertEqual(l, [])
def test___sro___(self):
from zope.interface.interface import Interface
decl = self._getEmpty()
self.assertEqual(decl.__sro__, (decl, Interface,))
def test___iro___(self):
from zope.interface.interface import Interface
decl = self._getEmpty()
self.assertEqual(decl.__iro__, (Interface,))
def test_get(self):
decl = self._getEmpty()
self.assertIsNone(decl.get('attr'))
self.assertEqual(decl.get('abc', 'def'), 'def')
# It's a positive cache only (when it even exists)
# so this added nothing.
self.assertFalse(decl._v_attrs)
def test_changed_w_existing__v_attrs(self):
decl = self._getEmpty()
decl._v_attrs = object()
decl.changed(decl)
self.assertFalse(decl._v_attrs)
class DeclarationTests(EmptyDeclarationTests):
def _getTargetClass(self):
from zope.interface.declarations import Declaration
return Declaration
def _makeOne(self, *args, **kw):
return self._getTargetClass()(*args, **kw)
def test_ctor_no_bases(self):
decl = self._makeOne()
self.assertEqual(list(decl.__bases__), [])
def test_ctor_w_interface_in_bases(self):
from zope.interface.interface import InterfaceClass
IFoo = InterfaceClass('IFoo')
decl = self._makeOne(IFoo)
self.assertEqual(list(decl.__bases__), [IFoo])
def test_ctor_w_implements_in_bases(self):
from zope.interface.declarations import Implements
impl = Implements()
decl = self._makeOne(impl)
self.assertEqual(list(decl.__bases__), [impl])
def test_changed_wo_existing__v_attrs(self):
decl = self._makeOne()
decl.changed(decl) # doesn't raise
self.assertIsNone(decl._v_attrs)
def test___contains__w_self(self):
decl = self._makeOne()
self.assertNotIn(decl, decl)
def test___contains__w_unrelated_iface(self):
from zope.interface.interface import InterfaceClass
IFoo = InterfaceClass('IFoo')
decl = self._makeOne()
self.assertNotIn(IFoo, decl)
def test___contains__w_base_interface(self):
from zope.interface.interface import InterfaceClass
IFoo = InterfaceClass('IFoo')
decl = self._makeOne(IFoo)
self.assertIn(IFoo, decl)
def test___iter___single_base(self):
from zope.interface.interface import InterfaceClass
IFoo = InterfaceClass('IFoo')
decl = self._makeOne(IFoo)
self.assertEqual(list(decl), [IFoo])
def test___iter___multiple_bases(self):
from zope.interface.interface import InterfaceClass
IFoo = InterfaceClass('IFoo')
IBar = InterfaceClass('IBar')
decl = self._makeOne(IFoo, IBar)
self.assertEqual(list(decl), [IFoo, IBar])
def test___iter___inheritance(self):
from zope.interface.interface import InterfaceClass
IFoo = InterfaceClass('IFoo')
IBar = InterfaceClass('IBar', (IFoo,))
decl = self._makeOne(IBar)
self.assertEqual(list(decl), [IBar]) #IBar.interfaces() omits bases
def test___iter___w_nested_sequence_overlap(self):
from zope.interface.interface import InterfaceClass
IFoo = InterfaceClass('IFoo')
IBar = InterfaceClass('IBar')
decl = self._makeOne(IBar, (IFoo, IBar))
self.assertEqual(list(decl), [IBar, IFoo])
def test_flattened_single_base(self):
from zope.interface.interface import Interface
from zope.interface.interface import InterfaceClass
IFoo = InterfaceClass('IFoo')
decl = self._makeOne(IFoo)
self.assertEqual(list(decl.flattened()), [IFoo, Interface])
def test_flattened_multiple_bases(self):
from zope.interface.interface import Interface
from zope.interface.interface import InterfaceClass
IFoo = InterfaceClass('IFoo')
IBar = InterfaceClass('IBar')
decl = self._makeOne(IFoo, IBar)
self.assertEqual(list(decl.flattened()), [IFoo, IBar, Interface])
def test_flattened_inheritance(self):
from zope.interface.interface import Interface
from zope.interface.interface import InterfaceClass
IFoo = InterfaceClass('IFoo')
IBar = InterfaceClass('IBar', (IFoo,))
decl = self._makeOne(IBar)
self.assertEqual(list(decl.flattened()), [IBar, IFoo, Interface])
def test_flattened_w_nested_sequence_overlap(self):
from zope.interface.interface import Interface
from zope.interface.interface import InterfaceClass
IFoo = InterfaceClass('IFoo')
IBar = InterfaceClass('IBar')
# This is the same as calling ``Declaration(IBar, IFoo, IBar)``
# which doesn't make much sense, but here it is. In older
# versions of zope.interface, the __iro__ would have been
# IFoo, IBar, Interface, which especially makes no sense.
decl = self._makeOne(IBar, (IFoo, IBar))
# Note that decl.__iro__ has IFoo first.
self.assertEqual(list(decl.flattened()), [IBar, IFoo, Interface])
def test___sub___unrelated_interface(self):
from zope.interface.interface import InterfaceClass
IFoo = InterfaceClass('IFoo')
IBar = InterfaceClass('IBar')
before = self._makeOne(IFoo)
after = before - IBar
self.assertIsInstance(after, self._getTargetClass())
self.assertEqual(list(after), [IFoo])
def test___sub___related_interface(self):
from zope.interface.interface import InterfaceClass
IFoo = InterfaceClass('IFoo')
before = self._makeOne(IFoo)
after = before - IFoo
self.assertEqual(list(after), [])
def test___sub___related_interface_by_inheritance(self):
from zope.interface.interface import InterfaceClass
IFoo = InterfaceClass('IFoo')
IBar = InterfaceClass('IBar', (IFoo,))
before = self._makeOne(IBar)
after = before - IBar
self.assertEqual(list(after), [])
def test___add___unrelated_interface(self):
from zope.interface.interface import InterfaceClass
IFoo = InterfaceClass('IFoo')
IBar = InterfaceClass('IBar')
before = self._makeOne(IFoo)
after = before + IBar
self.assertIsInstance(after, self._getTargetClass())
self.assertEqual(list(after), [IFoo, IBar])
def test___add___related_interface(self):
from zope.interface.interface import InterfaceClass
IFoo = InterfaceClass('IFoo')
IBar = InterfaceClass('IBar')
IBaz = InterfaceClass('IBaz')
before = self._makeOne(IFoo, IBar)
other = self._makeOne(IBar, IBaz)
after = before + other
self.assertEqual(list(after), [IFoo, IBar, IBaz])
class TestImmutableDeclaration(EmptyDeclarationTests):
def _getTargetClass(self):
from zope.interface.declarations import _ImmutableDeclaration
return _ImmutableDeclaration
def _getEmpty(self):
from zope.interface.declarations import _empty
return _empty
def test_pickle(self):
import pickle
copied = pickle.loads(pickle.dumps(self._getEmpty()))
self.assertIs(copied, self._getEmpty())
def test_singleton(self):
self.assertIs(
self._getTargetClass()(),
self._getEmpty()
)
def test__bases__(self):
self.assertEqual(self._getEmpty().__bases__, ())
def test_change__bases__(self):
empty = self._getEmpty()
empty.__bases__ = ()
self.assertEqual(self._getEmpty().__bases__, ())
with self.assertRaises(TypeError):
empty.__bases__ = (1,)
def test_dependents(self):
empty = self._getEmpty()
deps = empty.dependents
self.assertEqual({}, deps)
# Doesn't change the return.
deps[1] = 2
self.assertEqual({}, empty.dependents)
def test_changed(self):
# Does nothing, has no visible side-effects
self._getEmpty().changed(None)
def test_extends_always_false(self):
self.assertFalse(self._getEmpty().extends(self))
self.assertFalse(self._getEmpty().extends(self, strict=True))
self.assertFalse(self._getEmpty().extends(self, strict=False))
def test_get_always_default(self):
self.assertIsNone(self._getEmpty().get('name'))
self.assertEqual(self._getEmpty().get('name', 42), 42)
Loading ...