1 # -*- encoding: utf-8 -*-
7 from werkzeug.utils import escape as e
9 from openerp.tests import common
10 from openerp.addons.base.ir import ir_qweb
12 directory = os.path.dirname(__file__)
14 impl = xml.dom.minidom.getDOMImplementation()
15 doc = impl.createDocument(None, None, None)
17 class TestExport(common.TransactionCase):
21 super(TestExport, self).setUp()
22 self.Model = self.registry(self._model)
23 self.columns = self.Model._all_columns
25 def get_column(self, name):
26 return self.Model._all_columns[name].column
28 def get_converter(self, name, type=None):
29 column = self.get_column(name)
31 for postfix in type, column._type, '':
32 fs = ['ir', 'qweb', 'field']
33 if postfix is None: continue
34 if postfix: fs.append(postfix)
37 model = self.registry('.'.join(fs))
41 return lambda value, options=None, context=None: e(model.value_to_html(
42 self.cr, self.uid, value, column, options=options, context=context))
44 class TestBasicExport(TestExport):
45 _model = 'test_converter.test_model'
47 class TestCharExport(TestBasicExport):
49 converter = self.get_converter('char')
51 value = converter('foo')
52 self.assertEqual(value, 'foo')
54 value = converter("foo<bar>")
55 self.assertEqual(value, "foo<bar>")
57 class TestIntegerExport(TestBasicExport):
58 def test_integer(self):
59 converter = self.get_converter('integer')
62 self.assertEqual(value, "42")
64 class TestFloatExport(TestBasicExport):
66 super(TestFloatExport, self).setUp()
67 self.registry('res.lang').write(self.cr, self.uid, [1], {
72 converter = self.get_converter('float')
74 value = converter(42.0)
75 self.assertEqual(value, "42.0")
77 value = converter(42.0100)
78 self.assertEqual(value, "42.01")
80 value = converter(42.01234)
81 self.assertEqual(value, "42.01234")
83 value = converter(1234567.89)
84 self.assertEqual(value, '1,234,567.89')
86 def test_numeric(self):
87 converter = self.get_converter('numeric')
89 value = converter(42.0)
90 self.assertEqual(value, '42.00')
92 value = converter(42.01234)
93 self.assertEqual(value, '42.01')
95 class TestCurrencyExport(TestExport):
96 _model = 'test_converter.monetary'
99 super(TestCurrencyExport, self).setUp()
100 self.Currency = self.registry('res.currency')
101 self.base = self.create(self.Currency, name="Source", symbol=u'source')
103 def create(self, model, context=None, **values):
106 model.create(self.cr, self.uid, values, context=context),
109 def convert(self, obj, dest):
110 converter = self.registry('ir.qweb.field.monetary')
112 'widget': 'monetary',
113 'display_currency': 'c2'
115 converted = converter.to_html(
116 self.cr, self.uid, 'value', obj, options,
117 doc.createElement('span'),
118 {'field': 'obj.value', 'field-options': json.dumps(options)},
119 '', ir_qweb.QWebContext(self.cr, self.uid, {'obj': obj, 'c2': dest, }))
122 def test_currency_post(self):
123 currency = self.create(self.Currency, name="Test", symbol=u"test")
124 obj = self.create(self.Model, value=0.12)
126 converted = self.convert(obj, dest=currency)
130 '<span data-oe-model="{obj._model._name}" data-oe-id="{obj.id}" '
131 'data-oe-field="value" data-oe-type="monetary" '
132 'data-oe-expression="obj.value">'
133 '<span class="oe_currency_value">0.12</span>'
134 ' {symbol}</span>'.format(
136 symbol=currency.symbol.encode('utf-8')
139 def test_currency_pre(self):
140 currency = self.create(
141 self.Currency, name="Test", symbol=u"test", position='before')
142 obj = self.create(self.Model, value=0.12)
144 converted = self.convert(obj, dest=currency)
148 '<span data-oe-model="{obj._model._name}" data-oe-id="{obj.id}" '
149 'data-oe-field="value" data-oe-type="monetary" '
150 'data-oe-expression="obj.value">'
152 '<span class="oe_currency_value">0.12</span>'
155 symbol=currency.symbol.encode('utf-8')
158 def test_currency_precision(self):
159 """ Precision should be the currency's, not the float field's
161 currency = self.create(self.Currency, name="Test", symbol=u"test",)
162 obj = self.create(self.Model, value=0.1234567)
164 converted = self.convert(obj, dest=currency)
168 '<span data-oe-model="{obj._model._name}" data-oe-id="{obj.id}" '
169 'data-oe-field="value" data-oe-type="monetary" '
170 'data-oe-expression="obj.value">'
171 '<span class="oe_currency_value">0.12</span>'
172 ' {symbol}</span>'.format(
174 symbol=currency.symbol.encode('utf-8')
177 class TestTextExport(TestBasicExport):
179 converter = self.get_converter('text')
181 value = converter("This is my text-kai")
182 self.assertEqual(value, "This is my text-kai")
184 value = converter("""
185 . The current line (address) in the buffer.
186 $ The last line in the buffer.
187 n The nth, line in the buffer where n is a number in the range [0,$].
188 $ The last line in the buffer.
189 - The previous line. This is equivalent to -1 and may be repeated with cumulative effect.
190 -n The nth previous line, where n is a non-negative number.
191 + The next line. This is equivalent to +1 and may be repeated with cumulative effect.
193 self.assertEqual(value, """<br>
194 . The current line (address) in the buffer.<br>
195 $ The last line in the buffer.<br>
196 n The nth, line in the buffer where n is a number in the range [0,$].<br>
197 $ The last line in the buffer.<br>
198 - The previous line. This is equivalent to -1 and may be repeated with cumulative effect.<br>
199 -n The nth previous line, where n is a non-negative number.<br>
200 + The next line. This is equivalent to +1 and may be repeated with cumulative effect.<br>
203 value = converter("""
204 fgdkls;hjas;lj <b>fdslkj</b> d;lasjfa lkdja <a href=http://spam.com>lfks</a>
205 fldkjsfhs <i style="color: red"><a href="http://spamspam.com">fldskjh</a></i>
207 self.assertEqual(value, """<br>
208 fgdkls;hjas;lj <b>fdslkj</b> d;lasjfa lkdja <a href=http://spam.com>lfks</a><br>
209 fldkjsfhs <i style="color: red"><a href="http://spamspam.com">fldskjh</a></i><br>
212 class TestMany2OneExport(TestBasicExport):
213 def test_many2one(self):
214 Sub = self.registry('test_converter.test_model.sub')
217 id0 = self.Model.create(self.cr, self.uid, {
218 'many2one': Sub.create(self.cr, self.uid, {'name': "Foo"})
220 id1 = self.Model.create(self.cr, self.uid, {
221 'many2one': Sub.create(self.cr, self.uid, {'name': "Fo<b>o</b>"})
224 def converter(record):
225 column = self.get_column('many2one')
226 model = self.registry('ir.qweb.field.many2one')
228 return e(model.record_to_html(
229 self.cr, self.uid, 'many2one', record, column))
231 value = converter(self.Model.browse(self.cr, self.uid, id0))
232 self.assertEqual(value, "Foo")
234 value = converter(self.Model.browse(self.cr, self.uid, id1))
235 self.assertEqual(value, "Fo<b>o</b>")
237 class TestBinaryExport(TestBasicExport):
238 def test_image(self):
239 column = self.get_column('binary')
240 converter = self.registry('ir.qweb.field.image')
242 with open(os.path.join(directory, 'test_vectors', 'image'), 'rb') as f:
245 encoded_content = content.encode('base64')
246 value = e(converter.value_to_html(
247 self.cr, self.uid, encoded_content, column))
249 value, '<img src="data:image/jpeg;base64,%s">' % (
253 with open(os.path.join(directory, 'test_vectors', 'pdf'), 'rb') as f:
256 with self.assertRaises(ValueError):
257 e(converter.value_to_html(
258 self.cr, self.uid, 'binary', content.encode('base64'), column))
260 with open(os.path.join(directory, 'test_vectors', 'pptx'), 'rb') as f:
263 with self.assertRaises(ValueError):
264 e(converter.value_to_html(
265 self.cr, self.uid, 'binary', content.encode('base64'), column))
267 class TestSelectionExport(TestBasicExport):
268 def test_selection(self):
269 [record] = self.Model.browse(self.cr, self.uid, [self.Model.create(self.cr, self.uid, {
271 'selection_str': 'C',
274 column_name = 'selection'
275 column = self.get_column(column_name)
276 converter = self.registry('ir.qweb.field.selection')
278 value = converter.record_to_html(
279 self.cr, self.uid, column_name, record, column)
280 self.assertEqual(value, "réponse B")
282 column_name = 'selection_str'
283 column = self.get_column(column_name)
284 value = converter.record_to_html(
285 self.cr, self.uid, column_name, record, column)
286 self.assertEqual(value, "Qu'est-ce qu'il fout ce maudit pancake, tabernacle ?")
288 class TestHTMLExport(TestBasicExport):
290 converter = self.get_converter('html')
292 input = '<span>span</span>'
293 value = converter(input)
294 self.assertEqual(value, input)
296 class TestDatetimeExport(TestBasicExport):
298 super(TestDatetimeExport, self).setUp()
299 # set user tz to known value
300 Users = self.registry('res.users')
301 Users.write(self.cr, self.uid, self.uid, {
306 converter = self.get_converter('date')
308 value = converter('2011-05-03')
310 # default lang/format is US
311 self.assertEqual(value, '05/03/2011')
313 def test_datetime(self):
314 converter = self.get_converter('datetime')
316 value = converter('2011-05-03 11:12:13')
318 # default lang/format is US
319 self.assertEqual(value, '05/03/2011 00:12:13')
321 def test_custom_format(self):
322 converter = self.get_converter('datetime')
323 converter2 = self.get_converter('date')
324 opts = {'format': 'MMMM d'}
326 value = converter('2011-03-02 11:12:13', options=opts)
327 value2 = converter2('2001-03-02', options=opts)
337 class TestDurationExport(TestBasicExport):
339 super(TestDurationExport, self).setUp()
340 # needs to have lang installed otherwise falls back on en_US
341 self.registry('res.lang').load_lang(self.cr, self.uid, 'fr_FR')
343 def test_negative(self):
344 converter = self.get_converter('float', 'duration')
346 with self.assertRaises(ValueError):
349 def test_missing_unit(self):
350 converter = self.get_converter('float', 'duration')
352 with self.assertRaises(ValueError):
355 def test_basic(self):
356 converter = self.get_converter('float', 'duration')
358 result = converter(4, {'unit': 'hour'}, {'lang': 'fr_FR'})
359 self.assertEqual(result, u'4 heures')
361 result = converter(50, {'unit': 'second'}, {'lang': 'fr_FR'})
362 self.assertEqual(result, u'50 secondes')
364 def test_multiple(self):
365 converter = self.get_converter('float', 'duration')
367 result = converter(1.5, {'unit': 'hour'}, {'lang': 'fr_FR'})
368 self.assertEqual(result, u"1 heure 30 minutes")
370 result = converter(72, {'unit': 'second'}, {'lang': 'fr_FR'})
371 self.assertEqual(result, u"1 minute 12 secondes")
373 class TestRelativeDatetime(TestBasicExport):
374 # not sure how a test based on "current time" should be tested. Even less
375 # so as it would mostly be a test of babel...
378 super(TestRelativeDatetime, self).setUp()
379 # needs to have lang installed otherwise falls back on en_US
380 self.registry('res.lang').load_lang(self.cr, self.uid, 'fr_FR')
382 def test_basic(self):
383 converter = self.get_converter('datetime', 'relative')
384 t = datetime.datetime.utcnow() - datetime.timedelta(hours=1)
386 result = converter(t, context={'lang': 'fr_FR'})
387 self.assertEqual(result, u"il y a 1 heure")