PageRenderTime 65ms CodeModel.GetById 26ms RepoModel.GetById 0ms app.codeStats 0ms

/trac/mimeview/tests/api.py

https://bitbucket.org/bluezoo/trac
Python | 364 lines | 344 code | 8 blank | 12 comment | 0 complexity | f206fb4adc7120282c8f3b353604a51b MD5 | raw file
  1. # -*- coding: utf-8 -*-
  2. #
  3. # Copyright (C) 2006-2013 Edgewall Software
  4. # All rights reserved.
  5. #
  6. # This software is licensed as described in the file COPYING, which
  7. # you should have received as part of this distribution. The terms
  8. # are also available at http://trac.edgewall.org/wiki/TracLicense.
  9. #
  10. # This software consists of voluntary contributions made by many
  11. # individuals. For the exact contribution history, see the revision
  12. # history and logs, available at http://trac.edgewall.org/log/.
  13. import doctest
  14. import io
  15. import unittest
  16. from genshi import Stream, Namespace
  17. from genshi.core import Attrs, TEXT, START, END
  18. from genshi.input import HTMLParser
  19. from trac.core import Component, implements
  20. from trac.test import EnvironmentStub, MockRequest
  21. from trac.mimeview import api
  22. from trac.mimeview.api import IContentConverter, Mimeview, RenderingContext, \
  23. get_mimetype, _group_lines
  24. from trac.resource import Resource
  25. from trac.web.api import RequestDone
  26. class GetMimeTypeTestCase(unittest.TestCase):
  27. def test_from_suffix_using_MIME_MAP(self):
  28. self.assertEqual('text/plain', get_mimetype('README', None))
  29. self.assertEqual('text/plain', get_mimetype('README.txt', None))
  30. def test_from_suffix_using_mimetypes(self):
  31. accepted = ('image/png', 'image/x-png')
  32. self.assertTrue(get_mimetype('doc/trac_logo.png', None) in accepted)
  33. def test_from_content_using_CONTENT_RE(self):
  34. self.assertEqual('text/x-python',
  35. get_mimetype('xxx', """
  36. #!/usr/bin/python
  37. # This is a python script
  38. """))
  39. self.assertEqual('text/x-python',
  40. get_mimetype('xxx', """
  41. #!/usr/bin/env python
  42. # This is a python script
  43. """))
  44. self.assertEqual('text/x-ksh',
  45. get_mimetype('xxx', """
  46. #!/bin/ksh
  47. # This is a shell script
  48. """))
  49. self.assertEqual('text/x-python',
  50. get_mimetype('xxx', """
  51. # -*- Python -*-
  52. # This is a python script
  53. """))
  54. self.assertEqual('text/x-ruby',
  55. get_mimetype('xxx', """
  56. # -*- mode: ruby -*-
  57. # This is a ruby script
  58. """))
  59. self.assertEqual('text/x-python',
  60. get_mimetype('xxx', ' ' * 2000 + '# vim: ft=python'))
  61. def test_from_content_using_is_binary(self):
  62. self.assertEqual('application/octet-stream',
  63. get_mimetype('xxx', "abc\0xyz"))
  64. class MimeviewTestCase(unittest.TestCase):
  65. def setUp(self):
  66. self.env = EnvironmentStub(default_data=False,
  67. enable=['%s.%s' % (self.__module__, c)
  68. for c in ['Converter0', 'Converter1', 'Converter2']])
  69. def tearDown(self):
  70. pass
  71. def test_get_supported_conversions(self):
  72. class Converter0(Component):
  73. implements(IContentConverter)
  74. def get_supported_conversions(self):
  75. yield 'key0', 'Format 0', 'c0', 'text/x-sample', 'text/html', 8
  76. class Converter2(Component):
  77. implements(IContentConverter)
  78. def get_supported_conversions(self):
  79. yield 'key2', 'Format 2', 'c2', 'text/x-sample', 'text/html', 2
  80. class Converter1(Component):
  81. implements(IContentConverter)
  82. def get_supported_conversions(self):
  83. yield 'key1', 'Format 1', 'c1', 'text/x-sample', 'text/html', 4
  84. mimeview = Mimeview(self.env)
  85. conversions = mimeview.get_supported_conversions('text/x-sample')
  86. self.assertEqual(Converter0(self.env), conversions[0].converter)
  87. self.assertEqual(Converter1(self.env), conversions[1].converter)
  88. self.assertEqual(Converter2(self.env), conversions[2].converter)
  89. class GroupLinesTestCase(unittest.TestCase):
  90. def test_empty_stream(self):
  91. # FIXME: this currently fails
  92. lines = list(_group_lines([]))
  93. self.assertEqual(len(lines), 0)
  94. def test_text_only_stream(self):
  95. input = [(TEXT, "test", (None, -1, -1))]
  96. lines = list(_group_lines(input))
  97. self.assertEqual(len(lines), 1)
  98. self.assertIsInstance(lines[0], Stream)
  99. self.assertEqual(lines[0].events, input)
  100. def test_text_only_stream2(self):
  101. input = [(TEXT, "test\n", (None, -1, -1))]
  102. lines = list(_group_lines(input))
  103. self.assertEqual(len(lines), 1)
  104. self.assertIsInstance(lines[0], Stream)
  105. self.assertEqual(lines[0].events, [(TEXT, "test", (None, -1, -1))])
  106. def test_simplespan(self):
  107. input = HTMLParser(io.StringIO(u"<span>test</span>"), encoding=None)
  108. lines = list(_group_lines(input))
  109. self.assertEqual(len(lines), 1)
  110. self.assertIsInstance(lines[0], Stream)
  111. for (a, b) in zip(lines[0], input):
  112. self.assertEqual(a, b)
  113. def test_empty_text_stream(self):
  114. """
  115. http://trac.edgewall.org/ticket/4336
  116. """
  117. input = [(TEXT, "", (None, -1, -1))]
  118. lines = list(_group_lines(input))
  119. self.assertEqual(len(lines), 0)
  120. def test_newline_stream(self):
  121. input = [(TEXT, "\n", (None, -1, -1))]
  122. lines = list(_group_lines(input))
  123. self.assertEqual(len(lines), 1)
  124. def test_newline_stream2(self):
  125. input = [(TEXT, "\n\n\n", (None, -1, -1))]
  126. lines = list(_group_lines(input))
  127. self.assertEqual(len(lines), 3)
  128. def test_empty_text_in_span(self):
  129. """
  130. http://trac.edgewall.org/ticket/4336
  131. """
  132. ns = Namespace('http://www.w3.org/1999/xhtml')
  133. input = [(START, (ns.span, Attrs([])), (None, -1, -1)),
  134. (TEXT, "", (None, -1, -1)),
  135. (END, ns.span, (None, -1, -1)),
  136. ]
  137. lines = list(_group_lines(input))
  138. self.assertEqual(len(lines), 0)
  139. def test_newline(self):
  140. """
  141. If the text element does not end with a newline, it's not properly
  142. closed.
  143. """
  144. input = HTMLParser(io.StringIO(u'<span class="c">a\nb</span>'),
  145. encoding=None)
  146. expected = ['<span class="c">a</span>',
  147. '<span class="c">b</span>',
  148. ]
  149. lines = list(_group_lines(input))
  150. self.assertEqual(len(lines), len(expected))
  151. for a, b in zip(lines, expected):
  152. self.assertEqual(a.render('html'), b)
  153. def test_newline2(self):
  154. """
  155. Same as test_newline above, but make sure it behaves properly wrt
  156. the trailing \\n, especially given it's inside an element.
  157. """
  158. input = HTMLParser(io.StringIO(u'<span class="c">a\nb\n</span>'),
  159. encoding=None)
  160. expected = ['<span class="c">a</span>',
  161. '<span class="c">b</span>',
  162. ]
  163. lines = list(_group_lines(input))
  164. self.assertEqual(len(lines), len(expected))
  165. for a, b in zip(lines, expected):
  166. self.assertEqual(a.render('html'), b)
  167. def test_multinewline(self):
  168. """
  169. ditto.
  170. """
  171. input = HTMLParser(io.StringIO(u'<span class="c">\n\n\na</span>'),
  172. encoding=None)
  173. expected = ['<span class="c"></span>',
  174. '<span class="c"></span>',
  175. '<span class="c"></span>',
  176. '<span class="c">a</span>',
  177. ]
  178. lines = list(_group_lines(input))
  179. self.assertEqual(len(lines), len(expected))
  180. for a, b in zip(lines, expected):
  181. self.assertEqual(a.render('html'), b)
  182. class TestMimeviewConverter(Component):
  183. implements(IContentConverter)
  184. in_mimetype = __module__ + '.' + __name__
  185. def get_supported_conversions(self):
  186. yield ('text', self.__module__, 'txt', self.in_mimetype, 'text/plain',
  187. 8)
  188. def convert_content(self, req, mimetype, content, key):
  189. if content == 'iterable-bytes':
  190. def fn_bytes():
  191. for idx in xrange(256):
  192. yield 'b' * 256
  193. return fn_bytes(), 'text/plain'
  194. if content == 'iterable-unicode':
  195. def fn_unicode():
  196. for idx in xrange(0x10000):
  197. yield u'ü'
  198. return fn_unicode(), 'text/plain'
  199. if content == 'bytes':
  200. return 'a' * 0x10000, 'text/plain'
  201. if content == 'unicode':
  202. return u'Ü' * 0x10000, 'text/plain'
  203. class MimeviewConverterTestCase(unittest.TestCase):
  204. in_mimetype = TestMimeviewConverter.in_mimetype
  205. def setUp(self):
  206. self.env = EnvironmentStub(enable=['trac.*', TestMimeviewConverter])
  207. def tearDown(self):
  208. pass
  209. def _test_convert_content(self, expected, content, iterable):
  210. mimeview = Mimeview(self.env)
  211. output = mimeview.convert_content(MockRequest(self.env),
  212. self.in_mimetype,
  213. content, 'text', iterable=iterable)
  214. if iterable:
  215. self.assertNotIn(type(output[0]), (str, unicode))
  216. self.assertEqual(expected, ''.join(output[0]))
  217. else:
  218. self.assertEqual(type(expected), type(output[0]))
  219. self.assertEqual(expected, output[0])
  220. self.assertEqual('text/plain', output[1])
  221. self.assertEqual('txt', output[2])
  222. def test_convert_content_iterable_bytes(self):
  223. self._test_convert_content('b' * 0x10000, 'iterable-bytes', False)
  224. def test_convert_content_iterable_unicode(self):
  225. self._test_convert_content(u'ü' * 0x10000, 'iterable-unicode', False)
  226. def test_convert_content_bytes(self):
  227. self._test_convert_content('a' * 0x10000, 'bytes', False)
  228. def test_convert_content_unicode(self):
  229. self._test_convert_content(u'Ü' * 0x10000, 'unicode', False)
  230. def test_convert_content_iterable_bytes_iterable(self):
  231. self._test_convert_content('b' * 0x10000, 'iterable-bytes', True)
  232. def test_convert_content_iterable_unicode_iterable(self):
  233. self._test_convert_content(u'ü' * 0x10000, 'iterable-unicode', True)
  234. def test_convert_content_bytes_iterable(self):
  235. self._test_convert_content('a' * 0x10000, 'bytes', True)
  236. def test_convert_content_unicode_iterable(self):
  237. self._test_convert_content(u'Ü' * 0x10000, 'unicode', True)
  238. def _test_send_converted(self, expected, content, use_chunked_encoding):
  239. self.env.config.set('trac', 'use_chunked_encoding',
  240. 'true' if use_chunked_encoding else 'false')
  241. mimeview = Mimeview(self.env)
  242. req = MockRequest(self.env)
  243. self.assertRaises(RequestDone, mimeview.send_converted, req,
  244. self.in_mimetype, content, 'text')
  245. result = req.response_sent.getvalue()
  246. if use_chunked_encoding:
  247. self.assertNotIn('Content-Length', req.headers_sent)
  248. else:
  249. self.assertIn('Content-Length', req.headers_sent)
  250. self.assertEqual(str(len(expected)),
  251. req.headers_sent['Content-Length'])
  252. self.assertEqual('text/plain', req.headers_sent['Content-Type'])
  253. self.assertEqual(set(expected), set(result))
  254. self.assertEqual(expected, result)
  255. def test_send_converted_iterable_bytes(self):
  256. self._test_send_converted('b' * 0x10000, 'iterable-bytes', False)
  257. def test_send_converted_iterable_unicode(self):
  258. self._test_send_converted('ü' * 0x10000, 'iterable-unicode', False)
  259. def test_send_converted_bytes(self):
  260. self._test_send_converted('a' * 0x10000, 'bytes', False)
  261. def test_send_converted_unicode(self):
  262. self._test_send_converted('Ü' * 0x10000, 'unicode', False)
  263. def test_send_converted_iterable_bytes_chunked(self):
  264. self._test_send_converted('b' * 0x10000, 'iterable-bytes', True)
  265. def test_send_converted_iterable_unicode_chunked(self):
  266. self._test_send_converted('ü' * 0x10000, 'iterable-unicode', True)
  267. def test_send_converted_bytes_chunked(self):
  268. self._test_send_converted('a' * 0x10000, 'bytes', True)
  269. def test_send_converted_unicode_chunked(self):
  270. self._test_send_converted('Ü' * 0x10000, 'unicode', True)
  271. class MimeviewRenderTestCase(unittest.TestCase):
  272. def setUp(self):
  273. self.env = EnvironmentStub()
  274. def test_plain_text_content(self):
  275. """Render simple plain text content."""
  276. mimeview = Mimeview(self.env)
  277. req = MockRequest(self.env)
  278. context = RenderingContext(Resource('wiki', 'readme.txt'))
  279. context.req = req
  280. content = io.BytesIO("""\
  281. Some text.
  282. """)
  283. rendered = mimeview.render(context, 'text/plain', content)
  284. self.assertEqual('<div class="code"><pre>Some text.\n</pre></div>',
  285. str(rendered))
  286. def test_suite():
  287. suite = unittest.TestSuite()
  288. suite.addTest(doctest.DocTestSuite(api))
  289. suite.addTest(unittest.makeSuite(GetMimeTypeTestCase))
  290. suite.addTest(unittest.makeSuite(MimeviewTestCase))
  291. suite.addTest(unittest.makeSuite(GroupLinesTestCase))
  292. suite.addTest(unittest.makeSuite(MimeviewConverterTestCase))
  293. suite.addTest(unittest.makeSuite(MimeviewRenderTestCase))
  294. return suite
  295. if __name__ == '__main__':
  296. unittest.main(defaultTest='test_suite')