[IMP] use model._fields instead of model._all_columns to cover all fields
[odoo/odoo.git] / openerp / addons / test_converter / tests / test_html.py
1 # -*- encoding: utf-8 -*-
2 import json
3 import os
4 import datetime
5
6 from lxml import etree
7
8 from openerp.tests import common
9 from openerp.tools import html_escape as e
10 from openerp.addons.base.ir import ir_qweb
11
12 directory = os.path.dirname(__file__)
13
14 class TestExport(common.TransactionCase):
15     _model = None
16
17     def setUp(self):
18         super(TestExport, self).setUp()
19         self.Model = self.registry(self._model)
20
21     def get_field(self, name):
22         return self.Model._fields[name]
23
24     def get_converter(self, name, type=None):
25         field = self.get_field(name)
26
27         for postfix in type, field.type, '':
28             fs = ['ir', 'qweb', 'field']
29             if postfix is None: continue
30             if postfix: fs.append(postfix)
31
32             try:
33                 model = self.registry('.'.join(fs))
34                 break
35             except KeyError: pass
36
37         return lambda value, options=None, context=None: e(model.value_to_html(
38             self.cr, self.uid, value, field, options=options, context=context))
39
40 class TestBasicExport(TestExport):
41     _model = 'test_converter.test_model'
42
43 class TestCharExport(TestBasicExport):
44     def test_char(self):
45         converter = self.get_converter('char')
46
47         value = converter('foo')
48         self.assertEqual(value, 'foo')
49
50         value = converter("foo<bar>")
51         self.assertEqual(value, "foo&lt;bar&gt;")
52
53 class TestIntegerExport(TestBasicExport):
54     def test_integer(self):
55         converter = self.get_converter('integer')
56
57         value = converter(42)
58         self.assertEqual(value, "42")
59
60 class TestFloatExport(TestBasicExport):
61     def setUp(self):
62         super(TestFloatExport, self).setUp()
63         self.registry('res.lang').write(self.cr, self.uid, [1], {
64             'grouping': '[3,0]'
65         })
66
67     def test_float(self):
68         converter = self.get_converter('float')
69
70         value = converter(42.0)
71         self.assertEqual(value, "42.0")
72
73         value = converter(42.0100)
74         self.assertEqual(value, "42.01")
75
76         value = converter(42.01234)
77         self.assertEqual(value, "42.01234")
78
79         value = converter(1234567.89)
80         self.assertEqual(value, '1,234,567.89')
81
82     def test_numeric(self):
83         converter = self.get_converter('numeric')
84
85         value = converter(42.0)
86         self.assertEqual(value, '42.00')
87
88         value = converter(42.01234)
89         self.assertEqual(value, '42.01')
90
91 class TestCurrencyExport(TestExport):
92     _model = 'test_converter.monetary'
93
94     def setUp(self):
95         super(TestCurrencyExport, self).setUp()
96         self.Currency = self.registry('res.currency')
97         self.base = self.create(self.Currency, name="Source", symbol=u'source')
98
99     def create(self, model, context=None, **values):
100         return model.browse(
101             self.cr, self.uid,
102             model.create(self.cr, self.uid, values, context=context),
103             context=context)
104
105     def convert(self, obj, dest):
106         converter = self.registry('ir.qweb.field.monetary')
107         options = {
108             'widget': 'monetary',
109             'display_currency': 'c2'
110         }
111         context = dict(inherit_branding=True)
112         converted = converter.to_html(
113             self.cr, self.uid, 'value', obj, options,
114             etree.Element('span'),
115             {'field': 'obj.value', 'field-options': json.dumps(options)},
116             '', ir_qweb.QWebContext(self.cr, self.uid, {'obj': obj, 'c2': dest, }),
117             context=context,
118         )
119         return converted
120
121     def test_currency_post(self):
122         currency = self.create(self.Currency, name="Test", symbol=u"test")
123         obj = self.create(self.Model, value=0.12)
124
125         converted = self.convert(obj, dest=currency)
126
127         self.assertEqual(
128             converted,
129             '<span data-oe-model="{obj._model._name}" data-oe-id="{obj.id}" '
130                   'data-oe-field="value" data-oe-type="monetary" '
131                   'data-oe-expression="obj.value">'
132                       '<span class="oe_currency_value">0.12</span>'
133                       ' {symbol}</span>'.format(
134                 obj=obj,
135                 symbol=currency.symbol.encode('utf-8')
136             ),)
137
138     def test_currency_pre(self):
139         currency = self.create(
140             self.Currency, name="Test", symbol=u"test", position='before')
141         obj = self.create(self.Model, value=0.12)
142
143         converted = self.convert(obj, dest=currency)
144
145         self.assertEqual(
146             converted,
147             '<span data-oe-model="{obj._model._name}" data-oe-id="{obj.id}" '
148                   'data-oe-field="value" data-oe-type="monetary" '
149                   'data-oe-expression="obj.value">'
150                       '{symbol} '
151                       '<span class="oe_currency_value">0.12</span>'
152                       '</span>'.format(
153                 obj=obj,
154                 symbol=currency.symbol.encode('utf-8')
155             ),)
156
157     def test_currency_precision(self):
158         """ Precision should be the currency's, not the float field's
159         """
160         currency = self.create(self.Currency, name="Test", symbol=u"test",)
161         obj = self.create(self.Model, value=0.1234567)
162
163         converted = self.convert(obj, dest=currency)
164
165         self.assertEqual(
166             converted,
167             '<span data-oe-model="{obj._model._name}" data-oe-id="{obj.id}" '
168                   'data-oe-field="value" data-oe-type="monetary" '
169                   'data-oe-expression="obj.value">'
170                       '<span class="oe_currency_value">0.12</span>'
171                       ' {symbol}</span>'.format(
172                 obj=obj,
173                 symbol=currency.symbol.encode('utf-8')
174             ),)
175
176 class TestTextExport(TestBasicExport):
177     def test_text(self):
178         converter = self.get_converter('text')
179
180         value = converter("This is my text-kai")
181         self.assertEqual(value, "This is my text-kai")
182
183         value = converter("""
184             .  The current line (address) in the buffer.
185             $  The last line in the buffer.
186             n  The nth, line in the buffer where n is a number in the range [0,$].
187             $  The last line in the buffer.
188             -  The previous line. This is equivalent to -1 and may be repeated with cumulative effect.
189             -n The nth previous line, where n is a non-negative number.
190             +  The next line. This is equivalent to +1 and may be repeated with cumulative effect.
191         """)
192         self.assertEqual(value, """<br>
193             .  The current line (address) in the buffer.<br>
194             $  The last line in the buffer.<br>
195             n  The nth, line in the buffer where n is a number in the range [0,$].<br>
196             $  The last line in the buffer.<br>
197             -  The previous line. This is equivalent to -1 and may be repeated with cumulative effect.<br>
198             -n The nth previous line, where n is a non-negative number.<br>
199             +  The next line. This is equivalent to +1 and may be repeated with cumulative effect.<br>
200         """)
201
202         value = converter("""
203         fgdkls;hjas;lj <b>fdslkj</b> d;lasjfa lkdja <a href=http://spam.com>lfks</a>
204         fldkjsfhs <i style="color: red"><a href="http://spamspam.com">fldskjh</a></i>
205         """)
206         self.assertEqual(value, """<br>
207         fgdkls;hjas;lj &lt;b&gt;fdslkj&lt;/b&gt; d;lasjfa lkdja &lt;a href=http://spam.com&gt;lfks&lt;/a&gt;<br>
208         fldkjsfhs &lt;i style=&quot;color: red&quot;&gt;&lt;a href=&quot;http://spamspam.com&quot;&gt;fldskjh&lt;/a&gt;&lt;/i&gt;<br>
209         """)
210
211 class TestMany2OneExport(TestBasicExport):
212     def test_many2one(self):
213         Sub = self.registry('test_converter.test_model.sub')
214
215
216         id0 = self.Model.create(self.cr, self.uid, {
217             'many2one': Sub.create(self.cr, self.uid, {'name': "Foo"})
218         })
219         id1 = self.Model.create(self.cr, self.uid, {
220             'many2one': Sub.create(self.cr, self.uid, {'name': "Fo<b>o</b>"})
221         })
222
223         def converter(record):
224             model = self.registry('ir.qweb.field.many2one')
225             return e(model.record_to_html(self.cr, self.uid, 'many2one', record))
226
227         value = converter(self.Model.browse(self.cr, self.uid, id0))
228         self.assertEqual(value, "Foo")
229
230         value = converter(self.Model.browse(self.cr, self.uid, id1))
231         self.assertEqual(value, "Fo&lt;b&gt;o&lt;/b&gt;")
232
233 class TestBinaryExport(TestBasicExport):
234     def test_image(self):
235         field = self.get_field('binary')
236         converter = self.registry('ir.qweb.field.image')
237
238         with open(os.path.join(directory, 'test_vectors', 'image'), 'rb') as f:
239             content = f.read()
240
241         encoded_content = content.encode('base64')
242         value = e(converter.value_to_html(
243             self.cr, self.uid, encoded_content, field))
244         self.assertEqual(
245             value, '<img src="data:image/jpeg;base64,%s">' % (
246                 encoded_content
247             ))
248
249         with open(os.path.join(directory, 'test_vectors', 'pdf'), 'rb') as f:
250             content = f.read()
251
252         with self.assertRaises(ValueError):
253             e(converter.value_to_html(
254                 self.cr, self.uid, 'binary', content.encode('base64'), field))
255
256         with open(os.path.join(directory, 'test_vectors', 'pptx'), 'rb') as f:
257             content = f.read()
258
259         with self.assertRaises(ValueError):
260             e(converter.value_to_html(
261                 self.cr, self.uid, 'binary', content.encode('base64'), field))
262
263 class TestSelectionExport(TestBasicExport):
264     def test_selection(self):
265         [record] = self.Model.browse(self.cr, self.uid, [self.Model.create(self.cr, self.uid, {
266             'selection': 2,
267             'selection_str': 'C',
268         })])
269
270         converter = self.registry('ir.qweb.field.selection')
271
272         field_name = 'selection'
273         value = converter.record_to_html(self.cr, self.uid, field_name, record)
274         self.assertEqual(value, "rĂ©ponse B")
275
276         field_name = 'selection_str'
277         value = converter.record_to_html(self.cr, self.uid, field_name, record)
278         self.assertEqual(value, "Qu'est-ce qu'il fout ce maudit pancake, tabernacle ?")
279
280 class TestHTMLExport(TestBasicExport):
281     def test_html(self):
282         converter = self.get_converter('html')
283
284         input = '<span>span</span>'
285         value = converter(input)
286         self.assertEqual(value, input)
287
288 class TestDatetimeExport(TestBasicExport):
289     def setUp(self):
290         super(TestDatetimeExport, self).setUp()
291         # set user tz to known value
292         Users = self.registry('res.users')
293         Users.write(self.cr, self.uid, self.uid, {
294             'tz': 'Pacific/Niue'
295         }, context=None)
296
297     def test_date(self):
298         converter = self.get_converter('date')
299
300         value = converter('2011-05-03')
301
302         # default lang/format is US
303         self.assertEqual(value, '05/03/2011')
304
305     def test_datetime(self):
306         converter = self.get_converter('datetime')
307
308         value = converter('2011-05-03 11:12:13')
309
310         # default lang/format is US
311         self.assertEqual(value, '05/03/2011 00:12:13')
312
313     def test_custom_format(self):
314         converter = self.get_converter('datetime')
315         converter2 = self.get_converter('date')
316         opts = {'format': 'MMMM d'}
317
318         value = converter('2011-03-02 11:12:13', options=opts)
319         value2 = converter2('2001-03-02', options=opts)
320         self.assertEqual(
321             value,
322             'March 2'
323         )
324         self.assertEqual(
325             value2,
326             'March 2'
327         )
328
329 class TestDurationExport(TestBasicExport):
330     def setUp(self):
331         super(TestDurationExport, self).setUp()
332         # needs to have lang installed otherwise falls back on en_US
333         self.registry('res.lang').load_lang(self.cr, self.uid, 'fr_FR')
334
335     def test_negative(self):
336         converter = self.get_converter('float', 'duration')
337
338         with self.assertRaises(ValueError):
339             converter(-4)
340
341     def test_missing_unit(self):
342         converter = self.get_converter('float', 'duration')
343
344         with self.assertRaises(ValueError):
345             converter(4)
346
347     def test_basic(self):
348         converter = self.get_converter('float', 'duration')
349
350         result = converter(4, {'unit': 'hour'}, {'lang': 'fr_FR'})
351         self.assertEqual(result, u'4 heures')
352
353         result = converter(50, {'unit': 'second'}, {'lang': 'fr_FR'})
354         self.assertEqual(result, u'50 secondes')
355
356     def test_multiple(self):
357         converter = self.get_converter('float', 'duration')
358
359         result = converter(1.5, {'unit': 'hour'}, {'lang': 'fr_FR'})
360         self.assertEqual(result, u"1 heure 30 minutes")
361
362         result = converter(72, {'unit': 'second'}, {'lang': 'fr_FR'})
363         self.assertEqual(result, u"1 minute 12 secondes")
364
365 class TestRelativeDatetime(TestBasicExport):
366     # not sure how a test based on "current time" should be tested. Even less
367     # so as it would mostly be a test of babel...
368
369     def setUp(self):
370         super(TestRelativeDatetime, self).setUp()
371         # needs to have lang installed otherwise falls back on en_US
372         self.registry('res.lang').load_lang(self.cr, self.uid, 'fr_FR')
373
374     def test_basic(self):
375         converter = self.get_converter('datetime', 'relative')
376         t = datetime.datetime.utcnow() - datetime.timedelta(hours=1)
377
378         result = converter(t, context={'lang': 'fr_FR'})
379         self.assertEqual(result, u"il y a 1 heure")