test_verify.py 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656
  1. ##############################################################################
  2. #
  3. # Copyright (c) 2001, 2002 Zope Foundation and Contributors.
  4. # All Rights Reserved.
  5. #
  6. # This software is subject to the provisions of the Zope Public License,
  7. # Version 2.1 (ZPL). A copy of the ZPL should accompany this distribution.
  8. # THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
  9. # WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
  10. # WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
  11. # FOR A PARTICULAR PURPOSE.
  12. #
  13. ##############################################################################
  14. """ zope.interface.verify unit tests
  15. """
  16. import unittest
  17. # pylint:disable=inherit-non-class,no-method-argument,no-self-argument
  18. class Test_verifyClass(unittest.TestCase):
  19. verifier = None
  20. def setUp(self):
  21. self.verifier = self._get_FUT()
  22. @classmethod
  23. def _get_FUT(cls):
  24. from zope.interface.verify import verifyClass
  25. return verifyClass
  26. _adjust_object_before_verify = lambda self, x: x
  27. def _callFUT(self, iface, klass, **kwargs):
  28. return self.verifier(iface,
  29. self._adjust_object_before_verify(klass),
  30. **kwargs)
  31. def test_class_doesnt_implement(self):
  32. from zope.interface import Interface
  33. from zope.interface.exceptions import DoesNotImplement
  34. class ICurrent(Interface):
  35. pass
  36. class Current(object):
  37. pass
  38. self.assertRaises(DoesNotImplement, self._callFUT, ICurrent, Current)
  39. def test_class_doesnt_implement_but_classImplements_later(self):
  40. from zope.interface import Interface
  41. from zope.interface import classImplements
  42. class ICurrent(Interface):
  43. pass
  44. class Current(object):
  45. pass
  46. classImplements(Current, ICurrent)
  47. self._callFUT(ICurrent, Current)
  48. def test_class_doesnt_have_required_method_simple(self):
  49. from zope.interface import Interface
  50. from zope.interface import implementer
  51. from zope.interface.exceptions import BrokenImplementation
  52. class ICurrent(Interface):
  53. def method():
  54. """docstring"""
  55. @implementer(ICurrent)
  56. class Current(object):
  57. pass
  58. self.assertRaises(BrokenImplementation,
  59. self._callFUT, ICurrent, Current)
  60. def test_class_has_required_method_simple(self):
  61. from zope.interface import Interface
  62. from zope.interface import implementer
  63. class ICurrent(Interface):
  64. def method():
  65. """docstring"""
  66. @implementer(ICurrent)
  67. class Current(object):
  68. def method(self):
  69. raise NotImplementedError()
  70. self._callFUT(ICurrent, Current)
  71. def test_class_doesnt_have_required_method_derived(self):
  72. from zope.interface import Interface
  73. from zope.interface import implementer
  74. from zope.interface.exceptions import BrokenImplementation
  75. class IBase(Interface):
  76. def method():
  77. """docstring"""
  78. class IDerived(IBase):
  79. pass
  80. @implementer(IDerived)
  81. class Current(object):
  82. pass
  83. self.assertRaises(BrokenImplementation,
  84. self._callFUT, IDerived, Current)
  85. def test_class_has_required_method_derived(self):
  86. from zope.interface import Interface
  87. from zope.interface import implementer
  88. class IBase(Interface):
  89. def method():
  90. """docstring"""
  91. class IDerived(IBase):
  92. pass
  93. @implementer(IDerived)
  94. class Current(object):
  95. def method(self):
  96. raise NotImplementedError()
  97. self._callFUT(IDerived, Current)
  98. def test_method_takes_wrong_arg_names_but_OK(self):
  99. # We no longer require names to match.
  100. from zope.interface import Interface
  101. from zope.interface import implementer
  102. class ICurrent(Interface):
  103. def method(a):
  104. """docstring"""
  105. @implementer(ICurrent)
  106. class Current(object):
  107. def method(self, b):
  108. raise NotImplementedError()
  109. self._callFUT(ICurrent, Current)
  110. def test_method_takes_not_enough_args(self):
  111. from zope.interface import Interface
  112. from zope.interface import implementer
  113. from zope.interface.exceptions import BrokenMethodImplementation
  114. class ICurrent(Interface):
  115. def method(a):
  116. """docstring"""
  117. @implementer(ICurrent)
  118. class Current(object):
  119. def method(self):
  120. raise NotImplementedError()
  121. self.assertRaises(BrokenMethodImplementation,
  122. self._callFUT, ICurrent, Current)
  123. def test_method_doesnt_take_required_starargs(self):
  124. from zope.interface import Interface
  125. from zope.interface import implementer
  126. from zope.interface.exceptions import BrokenMethodImplementation
  127. class ICurrent(Interface):
  128. def method(*args):
  129. """docstring"""
  130. @implementer(ICurrent)
  131. class Current(object):
  132. def method(self):
  133. raise NotImplementedError()
  134. self.assertRaises(BrokenMethodImplementation,
  135. self._callFUT, ICurrent, Current)
  136. def test_method_doesnt_take_required_only_kwargs(self):
  137. from zope.interface import Interface
  138. from zope.interface import implementer
  139. from zope.interface.exceptions import BrokenMethodImplementation
  140. class ICurrent(Interface):
  141. def method(**kw):
  142. """docstring"""
  143. @implementer(ICurrent)
  144. class Current(object):
  145. def method(self):
  146. raise NotImplementedError()
  147. self.assertRaises(BrokenMethodImplementation,
  148. self._callFUT, ICurrent, Current)
  149. def test_method_takes_extra_arg(self):
  150. from zope.interface import Interface
  151. from zope.interface import implementer
  152. from zope.interface.exceptions import BrokenMethodImplementation
  153. class ICurrent(Interface):
  154. def method(a):
  155. """docstring"""
  156. @implementer(ICurrent)
  157. class Current(object):
  158. def method(self, a, b):
  159. raise NotImplementedError()
  160. self.assertRaises(BrokenMethodImplementation,
  161. self._callFUT, ICurrent, Current)
  162. def test_method_takes_extra_arg_with_default(self):
  163. from zope.interface import Interface
  164. from zope.interface import implementer
  165. class ICurrent(Interface):
  166. def method(a):
  167. """docstring"""
  168. @implementer(ICurrent)
  169. class Current(object):
  170. def method(self, a, b=None):
  171. raise NotImplementedError()
  172. self._callFUT(ICurrent, Current)
  173. def test_method_takes_only_positional_args(self):
  174. from zope.interface import Interface
  175. from zope.interface import implementer
  176. class ICurrent(Interface):
  177. def method(a):
  178. """docstring"""
  179. @implementer(ICurrent)
  180. class Current(object):
  181. def method(self, *args):
  182. raise NotImplementedError()
  183. self._callFUT(ICurrent, Current)
  184. def test_method_takes_only_kwargs(self):
  185. from zope.interface import Interface
  186. from zope.interface import implementer
  187. from zope.interface.exceptions import BrokenMethodImplementation
  188. class ICurrent(Interface):
  189. def method(a):
  190. """docstring"""
  191. @implementer(ICurrent)
  192. class Current(object):
  193. def method(self, **kw):
  194. raise NotImplementedError()
  195. self.assertRaises(BrokenMethodImplementation,
  196. self._callFUT, ICurrent, Current)
  197. def test_method_takes_extra_starargs(self):
  198. from zope.interface import Interface
  199. from zope.interface import implementer
  200. class ICurrent(Interface):
  201. def method(a):
  202. """docstring"""
  203. @implementer(ICurrent)
  204. class Current(object):
  205. def method(self, a, *args):
  206. raise NotImplementedError()
  207. self._callFUT(ICurrent, Current)
  208. def test_method_takes_extra_starargs_and_kwargs(self):
  209. from zope.interface import Interface
  210. from zope.interface import implementer
  211. class ICurrent(Interface):
  212. def method(a):
  213. """docstring"""
  214. @implementer(ICurrent)
  215. class Current(object):
  216. def method(self, a, *args, **kw):
  217. raise NotImplementedError()
  218. self._callFUT(ICurrent, Current)
  219. def test_method_doesnt_take_required_positional_and_starargs(self):
  220. from zope.interface import Interface
  221. from zope.interface import implementer
  222. from zope.interface.exceptions import BrokenMethodImplementation
  223. class ICurrent(Interface):
  224. def method(a, *args):
  225. """docstring"""
  226. @implementer(ICurrent)
  227. class Current(object):
  228. def method(self, a):
  229. raise NotImplementedError()
  230. self.assertRaises(BrokenMethodImplementation,
  231. self._callFUT, ICurrent, Current)
  232. def test_method_takes_required_positional_and_starargs(self):
  233. from zope.interface import Interface
  234. from zope.interface import implementer
  235. class ICurrent(Interface):
  236. def method(a, *args):
  237. """docstring"""
  238. @implementer(ICurrent)
  239. class Current(object):
  240. def method(self, a, *args):
  241. raise NotImplementedError()
  242. self._callFUT(ICurrent, Current)
  243. def test_method_takes_only_starargs(self):
  244. from zope.interface import Interface
  245. from zope.interface import implementer
  246. class ICurrent(Interface):
  247. def method(a, *args):
  248. """docstring"""
  249. @implementer(ICurrent)
  250. class Current(object):
  251. def method(self, *args):
  252. raise NotImplementedError()
  253. self._callFUT(ICurrent, Current)
  254. def test_method_takes_required_kwargs(self):
  255. from zope.interface import Interface
  256. from zope.interface import implementer
  257. class ICurrent(Interface):
  258. def method(**kwargs):
  259. """docstring"""
  260. @implementer(ICurrent)
  261. class Current(object):
  262. def method(self, **kw):
  263. raise NotImplementedError()
  264. self._callFUT(ICurrent, Current)
  265. def test_method_takes_positional_plus_required_starargs(self):
  266. from zope.interface import Interface
  267. from zope.interface import implementer
  268. from zope.interface.exceptions import BrokenMethodImplementation
  269. class ICurrent(Interface):
  270. def method(*args):
  271. """docstring"""
  272. @implementer(ICurrent)
  273. class Current(object):
  274. def method(self, a, *args):
  275. raise NotImplementedError()
  276. self.assertRaises(BrokenMethodImplementation,
  277. self._callFUT, ICurrent, Current)
  278. def test_method_doesnt_take_required_kwargs(self):
  279. from zope.interface import Interface
  280. from zope.interface import implementer
  281. from zope.interface.exceptions import BrokenMethodImplementation
  282. class ICurrent(Interface):
  283. def method(**kwargs):
  284. """docstring"""
  285. @implementer(ICurrent)
  286. class Current(object):
  287. def method(self, a):
  288. raise NotImplementedError()
  289. self.assertRaises(BrokenMethodImplementation,
  290. self._callFUT, ICurrent, Current)
  291. def test_class_has_method_for_iface_attr(self):
  292. from zope.interface import Attribute
  293. from zope.interface import Interface
  294. from zope.interface import implementer
  295. class ICurrent(Interface):
  296. attr = Attribute("The foo Attribute")
  297. @implementer(ICurrent)
  298. class Current:
  299. def attr(self):
  300. raise NotImplementedError()
  301. self._callFUT(ICurrent, Current)
  302. def test_class_has_nonmethod_for_method(self):
  303. from zope.interface import Interface
  304. from zope.interface import implementer
  305. from zope.interface.exceptions import BrokenMethodImplementation
  306. class ICurrent(Interface):
  307. def method():
  308. """docstring"""
  309. @implementer(ICurrent)
  310. class Current:
  311. method = 1
  312. self.assertRaises(BrokenMethodImplementation,
  313. self._callFUT, ICurrent, Current)
  314. def test_class_has_attribute_for_attribute(self):
  315. from zope.interface import Attribute
  316. from zope.interface import Interface
  317. from zope.interface import implementer
  318. class ICurrent(Interface):
  319. attr = Attribute("The foo Attribute")
  320. @implementer(ICurrent)
  321. class Current:
  322. attr = 1
  323. self._callFUT(ICurrent, Current)
  324. def test_class_misses_attribute_for_attribute(self):
  325. # This check *passes* for verifyClass
  326. from zope.interface import Attribute
  327. from zope.interface import Interface
  328. from zope.interface import implementer
  329. class ICurrent(Interface):
  330. attr = Attribute("The foo Attribute")
  331. @implementer(ICurrent)
  332. class Current:
  333. pass
  334. self._callFUT(ICurrent, Current)
  335. def test_w_callable_non_func_method(self):
  336. from zope.interface.interface import Method
  337. from zope.interface import Interface
  338. from zope.interface import implementer
  339. class QuasiMethod(Method):
  340. def __call__(self, *args, **kw):
  341. raise NotImplementedError()
  342. class QuasiCallable(object):
  343. def __call__(self, *args, **kw):
  344. raise NotImplementedError()
  345. class ICurrent(Interface):
  346. attr = QuasiMethod('This is callable')
  347. @implementer(ICurrent)
  348. class Current:
  349. attr = QuasiCallable()
  350. self._callFUT(ICurrent, Current)
  351. def test_w_decorated_method(self):
  352. from zope.interface import Interface
  353. from zope.interface import implementer
  354. def decorator(func):
  355. # this is, in fact, zope.proxy.non_overridable
  356. return property(lambda self: func.__get__(self))
  357. class ICurrent(Interface):
  358. def method(a):
  359. """docstring"""
  360. @implementer(ICurrent)
  361. class Current(object):
  362. @decorator
  363. def method(self, a):
  364. raise NotImplementedError()
  365. self._callFUT(ICurrent, Current)
  366. def test_dict_IFullMapping(self):
  367. # A dict should be an IFullMapping, but this exposes two
  368. # issues. First, on CPython, methods of builtin types are
  369. # "method_descriptor" objects, and are harder to introspect.
  370. # Second, on PyPy, the signatures can be just plain wrong,
  371. # specifying as required arguments that are actually optional.
  372. # See https://github.com/zopefoundation/zope.interface/issues/118
  373. from zope.interface.common.mapping import IFullMapping
  374. self._callFUT(IFullMapping, dict, tentative=True)
  375. def test_list_ISequence(self):
  376. # As for test_dict_IFullMapping
  377. from zope.interface.common.sequence import ISequence
  378. self._callFUT(ISequence, list, tentative=True)
  379. def test_tuple_IReadSequence(self):
  380. # As for test_dict_IFullMapping
  381. from zope.interface.common.sequence import IReadSequence
  382. self._callFUT(IReadSequence, tuple, tentative=True)
  383. def test_multiple_invalid(self):
  384. from zope.interface.exceptions import MultipleInvalid
  385. from zope.interface.exceptions import DoesNotImplement
  386. from zope.interface.exceptions import BrokenImplementation
  387. from zope.interface import Interface
  388. from zope.interface import classImplements
  389. class ISeveralMethods(Interface):
  390. def meth1(arg1):
  391. "Method 1"
  392. def meth2(arg1):
  393. "Method 2"
  394. class SeveralMethods(object):
  395. pass
  396. with self.assertRaises(MultipleInvalid) as exc:
  397. self._callFUT(ISeveralMethods, SeveralMethods)
  398. ex = exc.exception
  399. self.assertEqual(3, len(ex.exceptions))
  400. self.assertIsInstance(ex.exceptions[0], DoesNotImplement)
  401. self.assertIsInstance(ex.exceptions[1], BrokenImplementation)
  402. self.assertIsInstance(ex.exceptions[2], BrokenImplementation)
  403. # If everything else is correct, only the single error is raised without
  404. # the wrapper.
  405. classImplements(SeveralMethods, ISeveralMethods)
  406. SeveralMethods.meth1 = lambda self, arg1: "Hi"
  407. with self.assertRaises(BrokenImplementation):
  408. self._callFUT(ISeveralMethods, SeveralMethods)
  409. class Test_verifyObject(Test_verifyClass):
  410. @classmethod
  411. def _get_FUT(cls):
  412. from zope.interface.verify import verifyObject
  413. return verifyObject
  414. def _adjust_object_before_verify(self, target):
  415. if isinstance(target, (type, type(OldSkool))):
  416. target = target()
  417. return target
  418. def test_class_misses_attribute_for_attribute(self):
  419. # This check *fails* for verifyObject
  420. from zope.interface import Attribute
  421. from zope.interface import Interface
  422. from zope.interface import implementer
  423. from zope.interface.exceptions import BrokenImplementation
  424. class ICurrent(Interface):
  425. attr = Attribute("The foo Attribute")
  426. @implementer(ICurrent)
  427. class Current:
  428. pass
  429. self.assertRaises(BrokenImplementation,
  430. self._callFUT, ICurrent, Current)
  431. def test_module_hit(self):
  432. from .idummy import IDummyModule
  433. from . import dummy
  434. self._callFUT(IDummyModule, dummy)
  435. def test_module_miss(self):
  436. from zope.interface import Interface
  437. from . import dummy
  438. from zope.interface.exceptions import DoesNotImplement
  439. # same name, different object
  440. class IDummyModule(Interface):
  441. pass
  442. self.assertRaises(DoesNotImplement,
  443. self._callFUT, IDummyModule, dummy)
  444. def test_staticmethod_hit_on_class(self):
  445. from zope.interface import Interface
  446. from zope.interface import provider
  447. from zope.interface.verify import verifyObject
  448. class IFoo(Interface):
  449. def bar(a, b):
  450. "The bar method"
  451. @provider(IFoo)
  452. class Foo(object):
  453. @staticmethod
  454. def bar(a, b):
  455. raise AssertionError("We're never actually called")
  456. # Don't use self._callFUT, we don't want to instantiate the
  457. # class.
  458. verifyObject(IFoo, Foo)
  459. class OldSkool:
  460. pass