[IMP] use model._fields instead of model._all_columns to cover all fields
[odoo/odoo.git] / addons / website / tests / test_converter.py
1 # -*- coding: utf-8 -*-
2 import textwrap
3 import unittest2
4
5 from lxml import etree, html
6 from lxml.builder import E
7
8 from openerp.tests import common
9 from openerp.addons.base.ir import ir_qweb
10 from openerp.addons.website.models.ir_qweb import html_to_text
11 from openerp.addons.website.models.website import slugify, unslug
12
13 class TestUnslug(unittest2.TestCase):
14     def test_unslug(self):
15         tests = {
16             '': (None, None),
17             'foo': (None, None),
18             'foo-': (None, None),
19             '-': (None, None),
20             'foo-1': ('foo', 1),
21             'foo-bar-1': ('foo-bar', 1),
22             'foo--1': ('foo', -1),
23             '1': (None, 1),
24             '1-1': ('1', 1),
25             '--1': (None, None),
26             'foo---1': (None, None),
27             'foo1': (None, None),
28         }
29
30         for slug, expected in tests.iteritems():
31             self.assertEqual(unslug(slug), expected)
32
33
34 class TestHTMLToText(unittest2.TestCase):
35     def test_rawstring(self):
36         self.assertEqual(
37             "foobar",
38             html_to_text(E.div("foobar")))
39
40     def test_br(self):
41         self.assertEqual(
42             "foo\nbar",
43             html_to_text(E.div("foo", E.br(), "bar")))
44
45         self.assertEqual(
46             "foo\n\nbar\nbaz",
47             html_to_text(E.div(
48                 "foo", E.br(), E.br(),
49                 "bar", E.br(),
50                 "baz")))
51
52     def test_p(self):
53         self.assertEqual(
54             "foo\n\nbar\n\nbaz",
55             html_to_text(E.div(
56                 "foo",
57                 E.p("bar"),
58                 "baz")))
59
60         self.assertEqual(
61             "foo",
62             html_to_text(E.div(E.p("foo"))))
63
64         self.assertEqual(
65             "foo\n\nbar",
66             html_to_text(E.div("foo", E.p("bar"))))
67         self.assertEqual(
68             "foo\n\nbar",
69             html_to_text(E.div(E.p("foo"), "bar")))
70
71         self.assertEqual(
72             "foo\n\nbar\n\nbaz",
73             html_to_text(E.div(
74                 E.p("foo"),
75                 E.p("bar"),
76                 E.p("baz"),
77             )))
78
79     def test_div(self):
80         self.assertEqual(
81             "foo\nbar\nbaz",
82             html_to_text(E.div(
83                 "foo",
84                 E.div("bar"),
85                 "baz"
86             )))
87
88         self.assertEqual(
89             "foo",
90             html_to_text(E.div(E.div("foo"))))
91
92         self.assertEqual(
93             "foo\nbar",
94             html_to_text(E.div("foo", E.div("bar"))))
95         self.assertEqual(
96             "foo\nbar",
97             html_to_text(E.div(E.div("foo"), "bar")))
98
99         self.assertEqual(
100             "foo\nbar\nbaz",
101             html_to_text(E.div(
102                 "foo",
103                 E.div("bar"),
104                 E.div("baz")
105             )))
106
107     def test_other_block(self):
108         self.assertEqual(
109             "foo\nbar\nbaz",
110             html_to_text(E.div(
111                 "foo",
112                 E.section("bar"),
113                 "baz"
114             )))
115
116     def test_inline(self):
117         self.assertEqual(
118             "foobarbaz",
119             html_to_text(E.div("foo", E.span("bar"), "baz")))
120
121     def test_whitespace(self):
122         self.assertEqual(
123             "foo bar\nbaz",
124             html_to_text(E.div(
125                 "foo\nbar",
126                 E.br(),
127                 "baz")
128             ))
129
130         self.assertEqual(
131             "foo bar\nbaz",
132             html_to_text(E.div(
133                 E.div(E.span("foo"), " bar"),
134                 "baz")))
135
136 class TestConvertBack(common.TransactionCase):
137     def setUp(self):
138         super(TestConvertBack, self).setUp()
139
140     def field_rountrip_result(self, field, value, expected):
141         model = 'website.converter.test'
142         Model = self.registry(model)
143         id = Model.create(
144             self.cr, self.uid, {
145                 field: value
146             })
147         [record] = Model.browse(self.cr, self.uid, [id])
148
149         e = etree.Element('span')
150         field_value = 'record.%s' % field
151         e.set('t-field', field_value)
152
153         rendered = self.registry('website.qweb').render_tag_field(
154             e, {'field': field_value}, '', ir_qweb.QWebContext(self.cr, self.uid, {
155                 'record': record,
156             }, context={'inherit_branding': True}))
157         element = html.fromstring(
158             rendered, parser=html.HTMLParser(encoding='utf-8'))
159
160         converter = self.registry('website.qweb').get_converter_for(
161             element.get('data-oe-type'))
162
163         value_back = converter.from_html(
164             self.cr, self.uid, model, Model._fields[field], element)
165
166         if isinstance(expected, str):
167             expected = expected.decode('utf-8')
168         self.assertEqual(value_back, expected)
169
170     def field_roundtrip(self, field, value):
171         self.field_rountrip_result(field, value, value)
172
173     def test_integer(self):
174         self.field_roundtrip('integer', 42)
175
176     def test_float(self):
177         self.field_roundtrip('float', 42.567890)
178         self.field_roundtrip('float', 324542.567890)
179
180     def test_numeric(self):
181         self.field_roundtrip('numeric', 42.77)
182
183     def test_char(self):
184         self.field_roundtrip('char', "foo bar")
185
186         self.field_roundtrip('char', "ⒸⓄⓇⒼⒺ")
187
188     def test_selection(self):
189         self.field_roundtrip('selection', 3)
190
191     def test_selection_str(self):
192         self.field_roundtrip('selection_str', 'B')
193
194     def test_text(self):
195         self.field_roundtrip('text', textwrap.dedent("""\
196             You must obey the dance commander
197             Givin' out the order for fun
198             You must obey the dance commander
199             You know that he's the only one
200             Who gives the orders here,
201             Alright
202             Who gives the orders here,
203             Alright
204
205             It would be awesome
206             If we could dance-a
207             It would be awesome, yeah
208             Let's take the chance-a
209             It would be awesome, yeah
210             Let's start the show
211             Because you never know
212             You never know
213             You never know until you go"""))
214
215     def test_m2o(self):
216         """ the M2O field conversion (from html) is markedly different from
217         others as it directly writes into the m2o and returns nothing at all.
218         """
219         model = 'website.converter.test'
220         field = 'many2one'
221
222         Sub = self.registry('website.converter.test.sub')
223         sub_id = Sub.create(self.cr, self.uid, {'name': "Foo"})
224
225         Model = self.registry(model)
226         id = Model.create(self.cr, self.uid, {field: sub_id})
227         [record] = Model.browse(self.cr, self.uid, [id])
228
229         e = etree.Element('span')
230         field_value = 'record.%s' % field
231         e.set('t-field', field_value)
232
233         rendered = self.registry('website.qweb').render_tag_field(
234             e, {'field': field_value}, '', ir_qweb.QWebContext(self.cr, self.uid, {
235                 'record': record,
236             }, context={'inherit_branding': True}))
237
238         element = html.fromstring(rendered, parser=html.HTMLParser(encoding='utf-8'))
239         # emulate edition
240         element.text = "New content"
241
242         converter = self.registry('website.qweb').get_converter_for(
243             element.get('data-oe-type'))
244
245         value_back = converter.from_html(
246             self.cr, self.uid, model, Model._fields[field], element)
247
248         self.assertIsNone(
249             value_back, "the m2o converter should return None to avoid spurious"
250                         " or useless writes on the parent record")
251
252         self.assertEqual(
253             Sub.browse(self.cr, self.uid, sub_id).name,
254             "New content",
255             "element edition should have been written directly to the m2o record"
256         )
257
258 class TestTitleToSlug(unittest2.TestCase):
259     """
260     Those tests should pass with or without python-slugify
261     See website/models/website.py slugify method
262     """
263     def test_spaces(self):
264         self.assertEqual(
265             "spaces",
266             slugify(u"   spaces   ")
267         )
268
269     def test_unicode(self):
270         self.assertEqual(
271             "heterogeneite",
272             slugify(u"hétérogénéité")
273         )
274
275     def test_underscore(self):
276         self.assertEqual(
277             "one-two",
278             slugify(u"one_two")
279         )
280
281     def test_caps(self):
282         self.assertEqual(
283             "camelcase",
284             slugify(u"CamelCase")
285         )
286
287     def test_special_chars(self):
288         self.assertEqual(
289             "o-d-o-o",
290             slugify(u"o!#d{|\o/@~o&%^?")
291         )
292
293     def test_str_to_unicode(self):
294         self.assertEqual(
295             "espana",
296             slugify("España")
297         )
298
299     def test_numbers(self):
300         self.assertEqual(
301             "article-1",
302             slugify(u"Article 1")
303         )
304
305     def test_all(self):
306         self.assertEqual(
307             "do-you-know-martine-a-la-plage",
308             slugify(u"Do YOU know 'Martine à la plage' ?")
309         )