testxhtml.py 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256
  1. #!/usr/bin/env python
  2. # -*- coding: utf-8 -*-
  3. # Copyright (C) 2007 Søren Roug, European Environment Agency
  4. #
  5. # This is free software. You may redistribute it under the terms
  6. # of the Apache license and the GNU General Public License Version
  7. # 2 or at your option any later version.
  8. #
  9. # This program is distributed in the hope that it will be useful,
  10. # but WITHOUT ANY WARRANTY; without even the implied warranty of
  11. # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  12. # GNU General Public License for more details.
  13. #
  14. # You should have received a copy of the GNU General Public
  15. # License along with this program; if not, write to the Free Software
  16. # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
  17. #
  18. # Contributor(s):
  19. #
  20. import unittest
  21. import sys, os, os.path, re
  22. import io
  23. from odf.odf2xhtml import ODF2XHTML
  24. from odf.opendocument import OpenDocumentText
  25. from odf import style
  26. from odf.text import H, P, Span
  27. def has_rules(html, selector, rules):
  28. """ Returns false if the selector or rule is not found in html
  29. """
  30. selstart = html.find(selector)
  31. if selstart == -1:
  32. return False
  33. selend = html[selstart:].find('}')
  34. if selend == -1:
  35. return False
  36. rulelist = rules.split(";")
  37. for rule in rulelist:
  38. if html[selstart:selstart+selend].find(rule.strip()) == -1:
  39. return False
  40. return True
  41. def divWithClass_has_styles(s,classname, styleString):
  42. """
  43. Checks whether a div with some class attribute bears a set of other
  44. attributes.
  45. @param s string to be searched
  46. @param classname the value of the class attribute
  47. @param styleString a sequence of style stances separated by semicolons
  48. @return True when the div opening tag bears all the requested
  49. styles, independently of their order
  50. """
  51. pattern=re.compile(r'<div [^>]*class="'+classname+r'"[^>]*>', re.MULTILINE)
  52. found=pattern.findall(s)
  53. if not found:
  54. return False
  55. found=found[0]
  56. foundStyle=re.match(r'''.*style ?= ?["']([^"']*)["'].*''', found)
  57. if not foundStyle:
  58. return False
  59. foundStyle=foundStyle.group(1)
  60. foundStyle = map(lambda x: x.replace(' ',''), foundStyle.split(';'))
  61. styleString = map(lambda x: x.replace(' ',''), styleString.split(';'))
  62. return set(foundStyle)==set(styleString)
  63. htmlout = """<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
  64. <html xmlns="http://www.w3.org/1999/xhtml">
  65. <head>
  66. <meta content="text/html;charset=UTF-8" http-equiv="Content-Type"/>
  67. <meta name="generator" content="ODFPY/0.7"/>
  68. <style type="text/css">
  69. /*<![CDATA[*/
  70. img { width: 100%; height: 100%; }
  71. * { padding: 0; margin: 0; }
  72. body { margin: 0 1em; }
  73. ol, ul { padding-left: 2em; }
  74. h1 {
  75. font-size: 24pt;
  76. font-weight: bold;
  77. }
  78. .S-Bold {
  79. font-weight: bold;
  80. }
  81. /*]]>*/
  82. </style>
  83. </head>
  84. <body>
  85. <h1>Simple test document<a id="anchor001"></a></h1>
  86. <p>The earth's climate has not changed many times in the course of its long history. <span class="S-Bold">This part is bold. </span>This is after bold.</p>
  87. </body>
  88. </html>
  89. """
  90. class TestXHTML(unittest.TestCase):
  91. def setUp(self):
  92. d = OpenDocumentText()
  93. # Styles
  94. h1style = style.Style(name=u"Heading 1",family=u"paragraph")
  95. h1style.addElement(style.TextProperties(attributes={'fontsize':u"24pt", 'fontweight':u"bold"}))
  96. d.styles.addElement(h1style)
  97. boldstyle = style.Style(name=u"Bold",family=u"text")
  98. boldstyle.addElement(style.TextProperties(attributes={'fontweight':u"bold"}))
  99. d.automaticstyles.addElement(boldstyle)
  100. # Text
  101. h = H(outlinelevel=1, stylename=h1style, text=u"Simple test document")
  102. d.text.addElement(h)
  103. p = P(text=u"The earth's climate has not changed many times in the course of its long history. ")
  104. d.text.addElement(p)
  105. boldpart = Span(stylename=boldstyle, text=u"This part is bold. ")
  106. p.addElement(boldpart)
  107. p.addText(u"This is after bold.")
  108. d.save(u"TEST.odt")
  109. def tearDown(self):
  110. os.unlink(u"TEST.odt")
  111. def testParsing(self):
  112. """ Parse the test file """
  113. odhandler = ODF2XHTML()
  114. outf = io.BytesIO()
  115. result = odhandler.odf2xhtml(u"TEST.odt")
  116. outf.write(result.encode('utf-8'))
  117. strresult = outf.getvalue().decode('utf-8')
  118. #self.assertEqual(strresult, htmlout)
  119. self.assertNotEqual(-1, strresult.find(u"""<p>The earth's climate has \
  120. not changed many times in the course of its long history. \
  121. <span class="S-Bold">This part is bold. </span>This is after bold.</p>"""))
  122. self.assertNotEqual(-1, strresult.find(u"""<h1>Simple test document<a id="anchor001"></a></h1>"""))
  123. self.assertNotEqual(-1, strresult.find(u""".S-Bold {"""))
  124. self.assertEqual(-1, strresult.find(u"<ol "))
  125. class TestExampleDocs(unittest.TestCase):
  126. def test_twolevellist(self):
  127. """ Check CSS has list styles for two level lists"""
  128. twolevellist_odt = os.path.join(
  129. os.path.dirname(__file__), u"examples", u"twolevellist.odt")
  130. odhandler = ODF2XHTML()
  131. result = odhandler.odf2xhtml(twolevellist_odt)
  132. assert has_rules(result,u".L1_2",u"list-style-type: circle; font-family: StarSymbol, sans-serif;")
  133. def test_simplestyles(self):
  134. """ Check CSS has text and paragraph styles """
  135. simplestyles_odt = os.path.join(
  136. os.path.dirname(__file__), u"examples", u"simplestyles.odt")
  137. odhandler = ODF2XHTML()
  138. result = odhandler.odf2xhtml(simplestyles_odt)
  139. assert has_rules(result,u".S-T1",u"font-weight: normal;")
  140. assert has_rules(result,u".P-P2",u"font-weight: bold; font-style: italic;")
  141. assert has_rules(result,u".S-T11",u"text-decoration: underline;")
  142. self.assertNotEqual(-1, result.find(u"""<p class="P-P2"><span class="S-T1">Italic</span></p>\n"""))
  143. self.assertNotEqual(-1, result.find(u"""\n\ttext-decoration: underline;\n"""))
  144. self.assertNotEqual(-1, result.find(u"""<p class="P-P3"><span class="S-T1">Underline italic</span></p>\n"""))
  145. def test_simplelist(self):
  146. """ Check CSS has list styles """
  147. simplelist_odt = os.path.join(
  148. os.path.dirname(__file__), u"examples", u"simplelist.odt")
  149. odhandler = ODF2XHTML()
  150. result = odhandler.odf2xhtml(simplelist_odt)
  151. assert has_rules(result,u".L1_1",u"list-style-type: disc;")
  152. assert has_rules(result,u".L1_2",u"list-style-type: circle;")
  153. assert has_rules(result,u".L1_3",u"list-style-type: square;")
  154. self.assertNotEqual(-1, result.find(u"""<p class="P-Standard">Line 1</p>\n<ul class="L1_1"><li><p class="P-P1">Item A</p>"""))
  155. def test_mixedlist(self):
  156. """ Check CSS has list styles """
  157. simplelist_odt = os.path.join(
  158. os.path.dirname(__file__), u"examples", u"ol.odp")
  159. odhandler = ODF2XHTML()
  160. result = odhandler.odf2xhtml(simplelist_odt)
  161. assert has_rules(result,u".L2_1",u"list-style-type: decimal;")
  162. assert has_rules(result,u".L2_2",u"list-style-type: circle;")
  163. assert has_rules(result,u".L2_3",u"list-style-type: square;")
  164. assert has_rules(result,u".L3_1",u"list-style-type: disc;")
  165. assert has_rules(result,u".L3_2",u"list-style-type: decimal;")
  166. assert has_rules(result,u".L3_3",u"list-style-type: square;")
  167. assert has_rules(result,u".MP-Default",u"height: 19.05cm; width: 25.4cm; position: relative;")
  168. self.assertNotEqual(-1, result.find(u"""<ol class="L2_1">"""))
  169. self.assertNotEqual(-1, result.find(u"""<ol class="L3_2">"""))
  170. self.assertNotEqual(-1, result.find(u"""position:absolute;width:22.86cm;height:3.176cm;left:1.27cm;top:0.762cm;"""))
  171. def test_simpletable(self):
  172. """ Check CSS has table styles """
  173. simpletable_odt = os.path.join(
  174. os.path.dirname(__file__), u"examples", u"simpletable.odt")
  175. odhandler = ODF2XHTML()
  176. result = odhandler.odf2xhtml(simpletable_odt)
  177. assert result.find(u"""<td class="TD-Tabel1_A1"><p class="P-Table_20_Contents">Cell 1</p>""") != -1
  178. assert result.find(u"""<tr><td class="TD-Tabel1_A2"><p class="P-P1">Cell 3 (bold)</p>""") != -1
  179. assert result.find(u"""<td class="TD-Tabel1_B2"><p class="P-P2">Cell 4 (italic)</p>""") != -1
  180. def test_images(self):
  181. """ Check CSS has frame styles for images """
  182. odt = os.path.join(os.path.dirname(__file__), u"examples", u"images.odt")
  183. odhandler = ODF2XHTML()
  184. result = odhandler.odf2xhtml(odt)
  185. assert has_rules(result,u".G-fr1",u"margin-left: 0cm; margin-right: auto;")
  186. assert has_rules(result,u".G-fr2",u"margin-left: auto; margin-right: 0cm;")
  187. assert has_rules(result,u".G-fr3",u"float: left")
  188. assert has_rules(result,u".G-fr4",u"margin-right: auto;margin-left: auto;")
  189. assert has_rules(result,u".G-fr5",u"float: right")
  190. def test_imageslabels(self):
  191. """ Check CSS has frame styles for images with captions"""
  192. odt = os.path.join(os.path.dirname(__file__), u"examples", u"imageslabels.odt")
  193. odhandler = ODF2XHTML()
  194. result = odhandler.odf2xhtml(odt)
  195. assert has_rules(result,u".G-fr1",u"margin-left: 0cm; margin-right: auto;")
  196. assert has_rules(result,u".G-fr2",u"margin-left: auto; margin-right: 0cm;")
  197. assert has_rules(result,u".G-fr3",u"float: left")
  198. assert has_rules(result,u".G-fr4",u"float: right")
  199. assert has_rules(result,u".G-fr5",u"margin-right: auto;margin-left: auto;")
  200. assert has_rules(result,u".G-fr7",u"margin-right: auto;margin-left: auto;")
  201. assert has_rules(result,u".P-Illustration",u"font-size: 10pt;")
  202. def test_css(self):
  203. """ Test css() method """
  204. odt = os.path.join(os.path.dirname(__file__), u"examples", u"imageslabels.odt")
  205. odhandler = ODF2XHTML()
  206. odhandler.load(odt)
  207. result = odhandler.css()
  208. assert has_rules(result,u".G-fr1",u"margin-left: 0cm;margin-right: auto")
  209. assert has_rules(result,u".G-fr2",u"margin-left: auto;margin-right: 0cm")
  210. assert has_rules(result,u".G-fr3",u"float: left")
  211. assert has_rules(result,u".G-fr4",u"float: right")
  212. assert has_rules(result,u".G-fr5",u"margin-right: auto;margin-left: auto")
  213. assert has_rules(result,u".G-fr7",u"margin-right: auto;margin-left: auto")
  214. assert has_rules(result,u".P-Illustration",u"font-size: 10pt;")
  215. def test_positioned_shapes(self):
  216. """ Test positioned custom-shapes """
  217. odt = os.path.join(os.path.dirname(__file__), u"examples", u"cols.odp")
  218. odhandler = ODF2XHTML()
  219. result = odhandler.odf2xhtml(odt)
  220. # Python3 can ouput style stances in a non-predictable order when
  221. # parsing an XML document; so the following test may fail
  222. # unexpectedly with Python3. It is replaced by a more robust test.
  223. ## self.assertNotEqual(-1, result.find(u'''<div style="position: absolute;width:5.503cm;height:1.905cm;left:2.117cm;top:3.175cm;" class="G-gr1">'''))
  224. assert(divWithClass_has_styles(result, u"G-gr1", u"position: absolute;width:5.503cm;height:1.905cm;left:2.117cm;top:3.175cm;"))
  225. assert has_rules(result,u".MP-Default",u"height: 19.05cm; width: 25.4cm; position: relative;")
  226. if __name__ == '__main__':
  227. unittest.main()