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