test_document.py 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547
  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. """Documentation tests.
  15. """
  16. import sys
  17. import unittest
  18. class Test_asStructuredText(unittest.TestCase):
  19. def _callFUT(self, iface):
  20. from zope.interface.document import asStructuredText
  21. return asStructuredText(iface)
  22. def test_asStructuredText_no_docstring(self):
  23. from zope.interface import Interface
  24. EXPECTED = '\n\n'.join([
  25. "INoDocstring",
  26. " Attributes:",
  27. " Methods:",
  28. ""
  29. ])
  30. class INoDocstring(Interface):
  31. pass
  32. self.assertEqual(self._callFUT(INoDocstring), EXPECTED)
  33. def test_asStructuredText_empty_with_docstring(self):
  34. from zope.interface import Interface
  35. EXPECTED = '\n\n'.join([
  36. "IEmpty",
  37. " This is an empty interface.",
  38. " Attributes:",
  39. " Methods:",
  40. ""
  41. ])
  42. class IEmpty(Interface):
  43. """ This is an empty interface.
  44. """
  45. self.assertEqual(self._callFUT(IEmpty), EXPECTED)
  46. def test_asStructuredText_empty_with_multiline_docstring(self):
  47. from zope.interface import Interface
  48. # In Python 3.13+, compiler strips indents from docstrings
  49. indent = " " * 12 if sys.version_info < (3, 13) else ""
  50. EXPECTED = '\n'.join([
  51. "IEmpty",
  52. "",
  53. " This is an empty interface.",
  54. " ",
  55. (f"{indent} It can be used to annotate any class or object, "
  56. "because it promises"), # noqa E127
  57. f"{indent} nothing.",
  58. "",
  59. " Attributes:",
  60. "",
  61. " Methods:",
  62. "",
  63. ""
  64. ])
  65. class IEmpty(Interface):
  66. """ This is an empty interface.
  67. It can be used to annotate any class or object, because it promises
  68. nothing.
  69. """
  70. self.assertEqual(self._callFUT(IEmpty), EXPECTED)
  71. def test_asStructuredText_with_attribute_no_docstring(self):
  72. from zope.interface import Attribute
  73. from zope.interface import Interface
  74. EXPECTED = '\n\n'.join([
  75. "IHasAttribute",
  76. " This interface has an attribute.",
  77. " Attributes:",
  78. " an_attribute -- no documentation",
  79. " Methods:",
  80. ""
  81. ])
  82. class IHasAttribute(Interface):
  83. """ This interface has an attribute.
  84. """
  85. an_attribute = Attribute('an_attribute')
  86. self.assertEqual(self._callFUT(IHasAttribute), EXPECTED)
  87. def test_asStructuredText_with_attribute_with_docstring(self):
  88. from zope.interface import Attribute
  89. from zope.interface import Interface
  90. EXPECTED = '\n\n'.join([
  91. "IHasAttribute",
  92. " This interface has an attribute.",
  93. " Attributes:",
  94. " an_attribute -- This attribute is documented.",
  95. " Methods:",
  96. ""
  97. ])
  98. class IHasAttribute(Interface):
  99. """ This interface has an attribute.
  100. """
  101. an_attribute = Attribute('an_attribute',
  102. 'This attribute is documented.')
  103. self.assertEqual(self._callFUT(IHasAttribute), EXPECTED)
  104. def test_asStructuredText_with_method_no_args_no_docstring(self):
  105. from zope.interface import Interface
  106. EXPECTED = '\n\n'.join([
  107. "IHasMethod",
  108. " This interface has a method.",
  109. " Attributes:",
  110. " Methods:",
  111. " aMethod() -- no documentation",
  112. ""
  113. ])
  114. class IHasMethod(Interface):
  115. """ This interface has a method.
  116. """
  117. def aMethod():
  118. pass # pragma: no cover
  119. self.assertEqual(self._callFUT(IHasMethod), EXPECTED)
  120. def test_asStructuredText_with_method_positional_args_no_docstring(self):
  121. from zope.interface import Interface
  122. EXPECTED = '\n\n'.join([
  123. "IHasMethod",
  124. " This interface has a method.",
  125. " Attributes:",
  126. " Methods:",
  127. " aMethod(first, second) -- no documentation",
  128. ""
  129. ])
  130. class IHasMethod(Interface):
  131. """ This interface has a method.
  132. """
  133. def aMethod(first, second):
  134. pass # pragma: no cover
  135. self.assertEqual(self._callFUT(IHasMethod), EXPECTED)
  136. def test_asStructuredText_with_method_starargs_no_docstring(self):
  137. from zope.interface import Interface
  138. EXPECTED = '\n\n'.join([
  139. "IHasMethod",
  140. " This interface has a method.",
  141. " Attributes:",
  142. " Methods:",
  143. " aMethod(first, second, *rest) -- no documentation",
  144. ""
  145. ])
  146. class IHasMethod(Interface):
  147. """ This interface has a method.
  148. """
  149. def aMethod(first, second, *rest):
  150. pass # pragma: no cover
  151. self.assertEqual(self._callFUT(IHasMethod), EXPECTED)
  152. def test_asStructuredText_with_method_kwargs_no_docstring(self):
  153. from zope.interface import Interface
  154. EXPECTED = '\n\n'.join([
  155. "IHasMethod",
  156. " This interface has a method.",
  157. " Attributes:",
  158. " Methods:",
  159. " aMethod(first, second, **kw) -- no documentation",
  160. ""
  161. ])
  162. class IHasMethod(Interface):
  163. """ This interface has a method.
  164. """
  165. def aMethod(first, second, **kw):
  166. pass # pragma: no cover
  167. self.assertEqual(self._callFUT(IHasMethod), EXPECTED)
  168. def test_asStructuredText_with_method_with_docstring(self):
  169. from zope.interface import Interface
  170. EXPECTED = '\n\n'.join([
  171. "IHasMethod",
  172. " This interface has a method.",
  173. " Attributes:",
  174. " Methods:",
  175. " aMethod() -- This method is documented.",
  176. ""
  177. ])
  178. class IHasMethod(Interface):
  179. """ This interface has a method.
  180. """
  181. def aMethod():
  182. """This method is documented.
  183. """
  184. self.assertEqual(self._callFUT(IHasMethod), EXPECTED)
  185. def test_asStructuredText_derived_ignores_base(self):
  186. from zope.interface import Attribute
  187. from zope.interface import Interface
  188. EXPECTED = '\n\n'.join([
  189. "IDerived",
  190. " IDerived doc",
  191. " This interface extends:",
  192. " o IBase",
  193. " Attributes:",
  194. " attr1 -- no documentation",
  195. " attr2 -- attr2 doc",
  196. " Methods:",
  197. " method3() -- method3 doc",
  198. " method4() -- no documentation",
  199. " method5() -- method5 doc",
  200. "",
  201. ])
  202. class IBase(Interface):
  203. def method1():
  204. """docstring"""
  205. def method2():
  206. """docstring"""
  207. class IDerived(IBase):
  208. "IDerived doc"
  209. attr1 = Attribute('attr1')
  210. attr2 = Attribute('attr2', 'attr2 doc')
  211. def method3():
  212. "method3 doc"
  213. def method4():
  214. pass # pragma: no cover
  215. def method5():
  216. "method5 doc"
  217. self.assertEqual(self._callFUT(IDerived), EXPECTED)
  218. class Test_asReStructuredText(unittest.TestCase):
  219. def _callFUT(self, iface):
  220. from zope.interface.document import asReStructuredText
  221. return asReStructuredText(iface)
  222. def test_asReStructuredText_no_docstring(self):
  223. from zope.interface import Interface
  224. EXPECTED = '\n\n'.join([
  225. "``INoDocstring``",
  226. " Attributes:",
  227. " Methods:",
  228. ""
  229. ])
  230. class INoDocstring(Interface):
  231. pass
  232. self.assertEqual(self._callFUT(INoDocstring), EXPECTED)
  233. def test_asReStructuredText_empty_with_docstring(self):
  234. from zope.interface import Interface
  235. EXPECTED = '\n\n'.join([
  236. "``IEmpty``",
  237. " This is an empty interface.",
  238. " Attributes:",
  239. " Methods:",
  240. ""
  241. ])
  242. class IEmpty(Interface):
  243. """ This is an empty interface.
  244. """
  245. self.assertEqual(self._callFUT(IEmpty), EXPECTED)
  246. def test_asReStructuredText_empty_with_multiline_docstring(self):
  247. from zope.interface import Interface
  248. # In Python 3.13+, compiler strips indents from docstrings
  249. indent = " " * 12 if sys.version_info < (3, 13) else ""
  250. EXPECTED = '\n'.join([
  251. "``IEmpty``",
  252. "",
  253. " This is an empty interface.",
  254. " ",
  255. (f"{indent} It can be used to annotate any class or object, "
  256. f"because it"
  257. ), # noqa E124
  258. f"{indent} promises nothing.",
  259. "",
  260. " Attributes:",
  261. "",
  262. " Methods:",
  263. "",
  264. ""
  265. ])
  266. class IEmpty(Interface):
  267. """ This is an empty interface.
  268. It can be used to annotate any class or object, because it
  269. promises nothing.
  270. """
  271. self.assertEqual(self._callFUT(IEmpty), EXPECTED)
  272. def test_asReStructuredText_with_attribute_no_docstring(self):
  273. from zope.interface import Attribute
  274. from zope.interface import Interface
  275. EXPECTED = '\n\n'.join([
  276. "``IHasAttribute``",
  277. " This interface has an attribute.",
  278. " Attributes:",
  279. " ``an_attribute`` -- no documentation",
  280. " Methods:",
  281. ""
  282. ])
  283. class IHasAttribute(Interface):
  284. """ This interface has an attribute.
  285. """
  286. an_attribute = Attribute('an_attribute')
  287. self.assertEqual(self._callFUT(IHasAttribute), EXPECTED)
  288. def test_asReStructuredText_with_attribute_with_docstring(self):
  289. from zope.interface import Attribute
  290. from zope.interface import Interface
  291. EXPECTED = '\n\n'.join([
  292. "``IHasAttribute``",
  293. " This interface has an attribute.",
  294. " Attributes:",
  295. " ``an_attribute`` -- This attribute is documented.",
  296. " Methods:",
  297. ""
  298. ])
  299. class IHasAttribute(Interface):
  300. """ This interface has an attribute.
  301. """
  302. an_attribute = Attribute('an_attribute',
  303. 'This attribute is documented.')
  304. self.assertEqual(self._callFUT(IHasAttribute), EXPECTED)
  305. def test_asReStructuredText_with_method_no_args_no_docstring(self):
  306. from zope.interface import Interface
  307. EXPECTED = '\n\n'.join([
  308. "``IHasMethod``",
  309. " This interface has a method.",
  310. " Attributes:",
  311. " Methods:",
  312. " ``aMethod()`` -- no documentation",
  313. ""
  314. ])
  315. class IHasMethod(Interface):
  316. """ This interface has a method.
  317. """
  318. def aMethod():
  319. pass # pragma: no cover
  320. self.assertEqual(self._callFUT(IHasMethod), EXPECTED)
  321. def test_asReStructuredText_with_method_positional_args_no_docstring(self):
  322. from zope.interface import Interface
  323. EXPECTED = '\n\n'.join([
  324. "``IHasMethod``",
  325. " This interface has a method.",
  326. " Attributes:",
  327. " Methods:",
  328. " ``aMethod(first, second)`` -- no documentation",
  329. ""
  330. ])
  331. class IHasMethod(Interface):
  332. """ This interface has a method.
  333. """
  334. def aMethod(first, second):
  335. pass # pragma: no cover
  336. self.assertEqual(self._callFUT(IHasMethod), EXPECTED)
  337. def test_asReStructuredText_with_method_starargs_no_docstring(self):
  338. from zope.interface import Interface
  339. EXPECTED = '\n\n'.join([
  340. "``IHasMethod``",
  341. " This interface has a method.",
  342. " Attributes:",
  343. " Methods:",
  344. " ``aMethod(first, second, *rest)`` -- no documentation",
  345. ""
  346. ])
  347. class IHasMethod(Interface):
  348. """ This interface has a method.
  349. """
  350. def aMethod(first, second, *rest):
  351. pass # pragma: no cover
  352. self.assertEqual(self._callFUT(IHasMethod), EXPECTED)
  353. def test_asReStructuredText_with_method_kwargs_no_docstring(self):
  354. from zope.interface import Interface
  355. EXPECTED = '\n\n'.join([
  356. "``IHasMethod``",
  357. " This interface has a method.",
  358. " Attributes:",
  359. " Methods:",
  360. " ``aMethod(first, second, **kw)`` -- no documentation",
  361. ""
  362. ])
  363. class IHasMethod(Interface):
  364. """ This interface has a method.
  365. """
  366. def aMethod(first, second, **kw):
  367. pass # pragma: no cover
  368. self.assertEqual(self._callFUT(IHasMethod), EXPECTED)
  369. def test_asReStructuredText_with_method_with_docstring(self):
  370. from zope.interface import Interface
  371. EXPECTED = '\n\n'.join([
  372. "``IHasMethod``",
  373. " This interface has a method.",
  374. " Attributes:",
  375. " Methods:",
  376. " ``aMethod()`` -- This method is documented.",
  377. ""
  378. ])
  379. class IHasMethod(Interface):
  380. """ This interface has a method.
  381. """
  382. def aMethod():
  383. """This method is documented.
  384. """
  385. self.assertEqual(self._callFUT(IHasMethod), EXPECTED)
  386. def test_asReStructuredText_derived_ignores_base(self):
  387. from zope.interface import Attribute
  388. from zope.interface import Interface
  389. EXPECTED = '\n\n'.join([
  390. "``IDerived``",
  391. " IDerived doc",
  392. " This interface extends:",
  393. " o ``IBase``",
  394. " Attributes:",
  395. " ``attr1`` -- no documentation",
  396. " ``attr2`` -- attr2 doc",
  397. " Methods:",
  398. " ``method3()`` -- method3 doc",
  399. " ``method4()`` -- no documentation",
  400. " ``method5()`` -- method5 doc",
  401. "",
  402. ])
  403. class IBase(Interface):
  404. def method1():
  405. pass # pragma: no cover
  406. def method2():
  407. pass # pragma: no cover
  408. class IDerived(IBase):
  409. "IDerived doc"
  410. attr1 = Attribute('attr1')
  411. attr2 = Attribute('attr2', 'attr2 doc')
  412. def method3():
  413. "method3 doc"
  414. def method4():
  415. pass # pragma: no cover
  416. def method5():
  417. "method5 doc"
  418. self.assertEqual(self._callFUT(IDerived), EXPECTED)
  419. class Test__justify_and_indent(unittest.TestCase):
  420. def _callFUT(self, text, level, **kw):
  421. from zope.interface.document import _justify_and_indent
  422. return _justify_and_indent(text, level, **kw)
  423. def test_simple_level_0(self):
  424. LINES = ['Three blind mice', 'See how they run']
  425. text = '\n'.join(LINES)
  426. self.assertEqual(self._callFUT(text, 0), text)
  427. def test_simple_level_1(self):
  428. LINES = ['Three blind mice', 'See how they run']
  429. text = '\n'.join(LINES)
  430. self.assertEqual(self._callFUT(text, 1),
  431. '\n'.join([' ' + line for line in LINES]))
  432. def test_simple_level_2(self):
  433. LINES = ['Three blind mice', 'See how they run']
  434. text = '\n'.join(LINES)
  435. self.assertEqual(self._callFUT(text, 1),
  436. '\n'.join([' ' + line for line in LINES]))
  437. def test_simple_w_CRLF(self):
  438. LINES = ['Three blind mice', 'See how they run']
  439. text = '\r\n'.join(LINES)
  440. self.assertEqual(self._callFUT(text, 1),
  441. '\n'.join([' ' + line for line in LINES]))
  442. def test_with_munge(self):
  443. TEXT = ("This is a piece of text longer than 15 characters, \n"
  444. "and split across multiple lines.")
  445. EXPECTED = (" This is a piece\n"
  446. " of text longer\n"
  447. " than 15 characters,\n"
  448. " and split across\n"
  449. " multiple lines.\n"
  450. " ")
  451. self.assertEqual(self._callFUT(TEXT, 1, munge=1, width=15), EXPECTED)