root/relatorio/tests/test_odt.py @ 126:386be867715c

Revision 126:386be867715c, 13.3 kB (checked in by Ga?tan de Menten <ged@…>, 4 years ago)

- simplified test_directives test
- added column looping test
- added text_outside_p test (closes #10)

Line 
1# -*- encoding: utf-8 -*-
2###############################################################################
3#
4# Copyright (c) 2007, 2008 OpenHex SPRL. (http://openhex.com) All Rights
5# Reserved.
6#
7# This program is free software; you can redistribute it and/or modify it under
8# the terms of the GNU General Public License as published by the Free Software
9# Foundation; either version 2 of the License, or (at your option) any later
10# version.
11#
12# This program is distributed in the hope that it will be useful, but WITHOUT
13# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
14# FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
15# details.
16#
17# You should have received a copy of the GNU General Public License along with
18# this program.  If not, see <http://www.gnu.org/licenses/>.
19#
20###############################################################################
21
22
23import os
24import re
25from cStringIO import StringIO
26
27import lxml.etree
28from nose.tools import *
29import genshi
30from genshi.filters import Translator
31from genshi.core import PI
32from genshi.template.eval import UndefinedError
33
34from templates.opendocument import Template, GENSHI_EXPR, GENSHI_URI, \
35                                   RELATORIO_URI
36
37OO_TABLE_NS = "urn:oasis:names:tc:opendocument:xmlns:table:1.0"
38
39def pseudo_gettext(string):
40    catalog = {'Mes collègues sont:': 'My colleagues are:',
41               'Bonjour,': 'Hello,',
42               'Je suis un test de templating en odt.':
43                'I am an odt templating test',
44               'Felix da housecat': unicode('Félix le chat de la maison',
45                                            'utf8'),
46               'We sell stuff': u'On vend des choses',
47              }
48    return catalog.get(string, string)
49
50
51class TestOOTemplating(object):
52
53    def setup(self):
54        thisdir = os.path.dirname(__file__)
55        filepath = os.path.join(thisdir, 'test.odt')
56        self.oot = Template(file(filepath), filepath)
57        self.data = {'first_name': u'Trente',
58                     'last_name': unicode('Møller', 'utf8'),
59                     'ville': unicode('Liège', 'utf8'),
60                     'friends': [{'first_name': u'Camille',
61                                  'last_name': u'Salauhpe'},
62                                 {'first_name': u'Mathias',
63                                  'last_name': u'Lechat'}],
64                     'hobbies': [u'Music', u'Dancing', u'DJing'],
65                     'animals': [u'Felix da housecat', u'Dog eat Dog'],
66                     'images': [(file(os.path.join(thisdir, 'one.jpg')),
67                                 'image/jpeg'),
68                                (file(os.path.join(thisdir, 'two.png')),
69                                 'image/png')],
70                     'oeuf': file(os.path.join(thisdir, 'egg.jpg')),
71                     'footer': u'We sell stuff'}
72
73    def test_init(self):
74        "Testing the correct handling of the styles.xml and content.xml files"
75        ok_(isinstance(self.oot.stream, list))
76        eq_(self.oot.stream[0], (PI, ('relatorio', 'content.xml'), None))
77        ok_((PI, ('relatorio', 'content.xml'), None) in self.oot.stream)
78
79    def test_directives(self):
80        "Testing the directives interpolation"
81        xml = '''<xml xmlns:text="urn:text" xmlns:xlink="urn:xlink">
82                    <text:a xlink:href="relatorio://foo">foo</text:a>
83                 </xml>'''
84        interpolated = self.oot.insert_directives(xml)
85        root_interpolated = lxml.etree.parse(interpolated).getroot()
86        child = root_interpolated[0]
87        eq_(child.get('{http://genshi.edgewall.org/}replace'), 'foo')
88
89    def test_column_looping(self):
90        xml = '''
91<table:table
92    xmlns:table="urn:oasis:names:tc:opendocument:xmlns:table:1.0"
93    xmlns:office="urn:oasis:names:tc:opendocument:xmlns:office:1.0"
94    xmlns:text="urn:oasis:names:tc:opendocument:xmlns:text:1.0"
95    xmlns:xlink="http://www.w3.org/1999/xlink"
96    table:name="Tableau1"
97    table:style-name="Tableau1">
98    <table:table-column table:style-name="Tableau1.A"
99                        table:number-columns-repeated="2"/>
100    <table:table-column table:style-name="Tableau1.C"/>
101    <table:table-column table:style-name="Tableau1.A"/>
102    <table:table-column table:style-name="Tableau1.E"/>
103    <table:table-header-rows>
104        <table:table-row table:style-name="Tableau1.1">
105            <table:table-cell table:style-name="Tableau1.A1"
106                              office:value-type="string">
107                <text:p text:style-name="Table_20_Heading">Brol</text:p>
108            </table:table-cell>
109            <table:table-cell table:style-name="Tableau1.A1"
110                              office:value-type="string">
111                <text:p text:style-name="Table_20_Heading">
112                    <text:a xlink:type="simple"
113                            xlink:href="relatorio://for each=&quot;title in titles&quot;">for each=&quot;title in titles&quot;</text:a>
114                </text:p>
115            </table:table-cell>
116            <table:table-cell table:style-name="Tableau1.A1"
117                              office:value-type="string">
118                <text:p text:style-name="Table_20_Heading">${title}</text:p>
119                <text:p text:style-name="Table_20_Heading"/>
120            </table:table-cell>
121            <table:table-cell table:style-name="Tableau1.A1"
122                              office:value-type="string">
123                <text:p text:style-name="Table_20_Heading">
124                    <text:a xlink:type="simple"
125                            xlink:href="relatorio:///for">/for</text:a>
126                </text:p>
127            </table:table-cell>
128            <table:table-cell table:style-name="Tableau1.E1"
129                              office:value-type="string">
130                <text:p text:style-name="Table_20_Heading">Truc</text:p>
131            </table:table-cell>
132        </table:table-row>
133    </table:table-header-rows>
134    <table:table-row>
135        <table:table-cell table:style-name="Tableau1.A2"
136                          table:number-columns-spanned="5"
137                          office:value-type="string">
138            <text:p text:style-name="Table_20_Contents">
139                <text:a xlink:type="simple"
140                        xlink:href="relatorio://for%20each=%22items%20in%20lst%22">for each=&quot;items in lst&quot;</text:a>
141            </text:p>
142        </table:table-cell>
143        <table:covered-table-cell/>
144        <table:covered-table-cell/>
145        <table:covered-table-cell/>
146        <table:covered-table-cell/>
147    </table:table-row>
148    <table:table-row>
149        <table:table-cell table:style-name="Tableau1.A3"
150                          office:value-type="string">
151            <text:p text:style-name="Table_20_Contents">Brol</text:p>
152        </table:table-cell>
153        <table:table-cell table:style-name="Tableau1.A3"
154                          office:value-type="string">
155            <text:p text:style-name="Table_20_Contents">
156                <text:a xlink:type="simple"
157                        xlink:href="relatorio://for%20each=%22item%20in%20items%22">for each=&quot;item in items&quot;</text:a>
158            </text:p>
159        </table:table-cell>
160        <table:table-cell table:style-name="Tableau1.A3"
161                          office:value-type="string">
162            <text:p text:style-name="Table_20_Contents">${item}</text:p>
163            <text:p text:style-name="Table_20_Contents"/>
164        </table:table-cell>
165        <table:table-cell table:style-name="Tableau1.A3"
166                          office:value-type="string">
167            <text:p text:style-name="Table_20_Contents">
168                <text:a xlink:type="simple"
169                        xlink:href="relatorio:///for">/for</text:a>
170            </text:p>
171        </table:table-cell>
172        <table:table-cell table:style-name="Tableau1.A2"
173                          office:value-type="string">
174            <text:p text:style-name="Table_20_Contents">Truc</text:p>
175        </table:table-cell>
176    </table:table-row>
177    <table:table-row>
178        <table:table-cell table:style-name="Tableau1.A2"
179                          table:number-columns-spanned="5"
180                          office:value-type="string">
181            <text:p text:style-name="Table_20_Contents">
182                <text:a xlink:type="simple"
183                        xlink:href="relatorio:///for">/for</text:a>
184            </text:p>
185        </table:table-cell>
186        <table:covered-table-cell/>
187        <table:covered-table-cell/>
188        <table:covered-table-cell/>
189        <table:covered-table-cell/>
190    </table:table-row>
191</table:table>'''
192        interpolated = self.oot.insert_directives(xml)
193        root = lxml.etree.parse(interpolated).getroot()
194        child2 = root[1]
195        eq_(child2.tag, "{%s}repeat" % RELATORIO_URI)
196        eq_(child2.get("closing"), "3")
197        eq_(child2.get("opening"), "1")
198        eq_(len(child2), 1)
199        child4 = root[3]
200        eq_(child4.tag, "{%s}table-header-rows" % OO_TABLE_NS)
201        row1 = child4[0]
202        ok_(row1.get("{%s}attrs" % GENSHI_URI)
203                .startswith('__relatorio_reset_col_count'))
204        eq_(len(row1), 4)
205        loop = row1[1]
206        eq_(loop.tag, "{%s}for" % GENSHI_URI)
207        cell = loop[0]
208        ok_(cell.get("{%s}attrs" % GENSHI_URI)
209                .startswith('__relatorio_inc_col_count'))
210        last_row_node = row1[3]
211        eq_(last_row_node.tag, "{%s}replace" % GENSHI_URI)
212        ok_(last_row_node.get("value")
213                         .startswith('__relatorio_store_col_count'))
214
215    def test_text_outside_p(self):
216        "Testing that the tail text of a directive node is handled properly"
217        xml = '''<xml xmlns:text="urn:text" xmlns:xlink="urn:xlink">
218                    <text:a xlink:href="relatorio://if%20test=%22True%22">if test=&quot;True&quot;</text:a>
219                    xxx
220                    <text:p text:style-name="other">yyy</text:p>
221                    zzz
222                    <text:a xlink:href="relatorio:///if">/if</text:a>
223                 </xml>'''
224        interpolated = self.oot.insert_directives(xml)
225        root_interpolated = lxml.etree.parse(interpolated).getroot()
226        child = root_interpolated[0]
227        eq_(child.tag, '{http://genshi.edgewall.org/}if')
228        eq_(child.text.strip(), 'xxx')
229
230    def test_styles(self):
231        "Testing that styles get rendered"
232        stream = self.oot.generate(**self.data)
233        rendered = stream.events.render()
234        ok_('We sell stuff' in rendered)
235
236        dico = self.data.copy()
237        del dico['footer']
238        stream = self.oot.generate(**dico)
239        assert_raises(UndefinedError, lambda: stream.events.render())
240
241    def test_generate(self):
242        "Testing that content get rendered"
243        stream = self.oot.generate(**self.data)
244        rendered = stream.events.render()
245        ok_('Bonjour,' in rendered)
246        ok_('Trente' in rendered)
247        ok_('Møller' in rendered)
248        ok_('Dog eat Dog' in rendered)
249        ok_('Felix da housecat' in rendered)
250
251    def test_filters(self):
252        "Testing the filters with the Translator filter"
253        stream = self.oot.generate(**self.data)
254        translated = stream.filter(Translator(pseudo_gettext))
255        translated_xml = translated.events.render()
256        ok_("Hello," in translated_xml)
257        ok_("I am an odt templating test" in translated_xml)
258        ok_('Felix da housecat' not in translated_xml)
259        ok_('Félix le chat de la maison' in translated_xml)
260        ok_('We sell stuff' not in translated_xml)
261        ok_('On vend des choses' in translated_xml)
262
263    def test_images(self):
264        "Testing the image replacement directive"
265        stream = self.oot.generate(**self.data)
266        rendered = stream.events.render()
267        styles_idx = rendered.find('<?relatorio styles.xml?>')
268        tree = lxml.etree.parse(StringIO(rendered[25:styles_idx]))
269        root = tree.getroot()
270        images = root.xpath('//draw:frame', namespaces=self.oot.namespaces)
271        eq_(len(images), 3)
272        eq_(images[0].get('{%s}name' % self.oot.namespaces['draw']),
273            "image: (oeuf, 'image/png')")
274        eq_(images[1].get('{%s}name' % self.oot.namespaces['draw']),
275            'image: img')
276        eq_(images[1].get('{%s}width' % self.oot.namespaces['svg']),
277            '1.732cm')
278        eq_(images[1].get('{%s}height' % self.oot.namespaces['svg']),
279            '1.513cm')
280        eq_(images[2].get('{%s}width' % self.oot.namespaces['svg']),
281            '1.732cm')
282        eq_(images[2].get('{%s}height' % self.oot.namespaces['svg']),
283            '1.513cm')
284
285    def test_regexp(self):
286        "Testing the regexp used to find relatorio tags"
287        # a valid expression
288        group = GENSHI_EXPR.match('for each="foo in bar"').groups()
289        eq_(group, (None, 'for', 'each', 'foo in bar'))
290
291        # invalid expr
292        group = GENSHI_EXPR.match('foreach="foo in bar"').groups()
293        eq_(group, (None, None, None, None))
294
295        # valid closing tags
296        group = GENSHI_EXPR.match('/for').groups()
297        eq_(group, ('/', 'for', None, None))
298        group = GENSHI_EXPR.match('/for ').groups()
299        eq_(group, ('/', 'for', None, None))
300
301        # another non matching expr
302        group = GENSHI_EXPR.match('formatLang("en")').groups()
303        eq_(group, (None, None, None, None))
304
305    def test_str(self):
306        "Testing that a RelatorioStream str returns a bitstream"
307        stream = str(self.oot.generate(**self.data))
308        ok_(isinstance(stream, str))
Note: See TracBrowser for help on using the browser.