[MERGE] forward port of branch 7.0 up to revid 5288 mat@openerp.com-20140423150215...
[odoo/odoo.git] / openerp / addons / base / test / base_test.yml
1 -   |
2     To check that common dangerous operations are not allowed by the safe_eval mechanism, attempt to 
3     evaluate unauthorized expressions, and verify that they trigger an error.
4 -
5     1. Try a few common expressions to verify they work with safe_eval
6 -
7     !python {model: ir.model}: |
8         from openerp.tools.safe_eval import safe_eval
9         expected = (1, {"a": 9 * 2}, (True, False, None))
10         actual = safe_eval('(1, {"a": 9 * 2}, (True, False, None))')
11         assert actual == expected, "Simple python expressions are not working with safe_eval"
12 -
13     2. Try simple literal definition to verify it works with literal_eval
14 -
15     !python {model: ir.model}: |
16         import ast
17         expected = (1, {"a": 9}, (True, False, None))
18         actual = ast.literal_eval('(1, {"a": 9}, (True, False, None))')
19         assert actual == expected, "Simple python expressions are not working with literal_eval"
20 -
21     3. Try arithmetic expression in literal_eval to verify it does not work
22 -
23     !python {model: ir.model}: |
24         import ast
25         try:
26            ast.literal_eval('(1, {"a": 2*9}, (True, False, None))')
27            assert False, "literal_eval should not accept arithmetic expressions"
28         except ValueError:
29            pass
30 -
31     4. Try forbidden expressions in literal_eval to verify they are not allowed
32 -
33     !python {model: ir.model}: |
34         import ast
35         try:
36            ast.literal_eval('{"a": True.__class__}')
37            assert False, "literal_eval should accept only literals"
38         except ValueError:
39            pass
40 -
41     5. Try forbidden expressions in safe_eval to verify they are not allowed (open)
42 -
43     !python {model: ir.model}: |
44         from openerp.tools.safe_eval import safe_eval
45         from openerp.tools.misc import mute_logger
46         try:
47             with mute_logger('openerp.tools.safe_eval'):
48                 safe_eval('open("/etc/passwd","r")')
49             assert False, "safe_eval should not allow calling open() builtin"
50         except ValueError:
51             pass
52
53 -
54     "ORM test: verify that parent_store computation are going right"
55 -
56     0. Emulate normal behavior of tree structure storing
57 -
58     !python {model: res.partner.category}: |
59         # pretend the pool has finished loading to avoid deferring parent_store computation
60         self.pool._init = False
61 -
62     "1.0 Setup test partner categories: parent root"
63 -
64     !record {model: res.partner.category, id: test_categ_root}:
65         name: Root category
66 -
67     "1.1 Setup test partner categories: parent category"
68 -
69     !record {model: res.partner.category, id: test_categ_0}:
70         name: Parent category
71         parent_id: test_categ_root
72 -
73     "1.2 Setup test partner categories: child 1"
74 -
75     !record {model: res.partner.category, id: test_categ_1}:
76         name: Child 1
77         parent_id: test_categ_0
78 -
79     "1.3 Setup test partner categories: child 2"
80 -
81     !record {model: res.partner.category, id: test_categ_2}:
82         name: Child 2
83         parent_id: test_categ_0
84 -
85     "1.4 Setup test partner categories: child 2-1"
86 -
87     !record {model: res.partner.category, id: test_categ_21}:
88         name: Child 2-1
89         parent_id: test_categ_2
90 -
91     2. Duplicate the parent category and verify that the children have been duplicated too and are below the new parent
92 -
93     !python {model: res.partner.category}: |
94         new_id = self.copy(cr, uid, ref('test_categ_0'))
95         new_struct = self.search(cr, uid, [('parent_id', 'child_of', new_id)])
96         assert len(new_struct) == 4, "After duplication, the new object must have the childs records"
97         old_struct = self.search(cr, uid, [('parent_id', 'child_of', ref('test_categ_0'))])
98         assert len(old_struct) == 4, "After duplication, previous record must have old childs records only"
99         assert (not set(new_struct).intersection(old_struct)), "After duplication, nodes should not be mixed"
100 -
101     3. Duplicate the children then reassign them to the new parent (1st method) and check the parent_store structure.
102 -
103     !python {model: res.partner.category}: |
104         new_child1_id = self.copy(cr, uid, ref('test_categ_1'))
105         new_child2_id = self.copy(cr, uid, ref('test_categ_2'))
106         new_id = self.copy(cr, uid, ref('test_categ_0'), {'child_ids': []})
107         self.write(cr, uid, [new_child1_id, new_child2_id], {'parent_id': new_id})
108         new_struct = self.search(cr, uid, [('parent_id', 'child_of', new_id)])
109         assert len(new_struct) == 4, "After duplication, the new object must have the childs records"
110         old_struct = self.search(cr, uid, [('parent_id', 'child_of', ref('test_categ_0'))])
111         assert len(old_struct) == 4, "After duplication, previous record must have old childs records only"
112         assert (not set(new_struct).intersection(old_struct)), "After duplication, nodes should not be mixed"
113 -
114     4. Duplicate the children then reassign them to the new parent (2nd method) and check the parent_store structure.
115 -
116     !python {model: res.partner.category}: |
117         new_child1_id = self.copy(cr, uid, ref('test_categ_1'))
118         new_child2_id = self.copy(cr, uid, ref('test_categ_2'))
119         old_struct = self.search(cr, uid, [('parent_id', 'child_of', ref('test_categ_0'))])
120         new_id = self.copy(cr, uid, ref('test_categ_0'), {'child_ids': [(6,0,[new_child1_id, new_child2_id])]})
121         new_struct = self.search(cr, uid, [('parent_id', 'child_of', new_id)])
122         assert len(new_struct) == 4, "After duplication, the new object must have the childs records"
123         old_struct = self.search(cr, uid, [('parent_id', 'child_of', ref('test_categ_0'))])
124         assert len(old_struct) == 4, "After duplication, previous record must have old childs records only"
125         assert (not set(new_struct).intersection(old_struct)), "After duplication, nodes should not be mixed"
126 -
127     5. Duplicate the children then reassign them to the new parent (3rd method) and make sure the parent_store structure is still right.
128 -
129     !python {model: res.partner.category}: |
130         new_child1_id = self.copy(cr, uid, ref('test_categ_1'))
131         new_child2_id = self.copy(cr, uid, ref('test_categ_2'))
132         new_id = self.copy(cr, uid, ref('test_categ_0'), {'child_ids': []})
133         self.write(cr, uid, [new_id], {'child_ids': [(4,new_child1_id), (4,new_child2_id)]})
134         new_struct = self.search(cr, uid, [('parent_id', 'child_of', new_id)])
135         assert len(new_struct) == 4, "After duplication, the new object must have the childs records"
136         old_struct = self.search(cr, uid, [('parent_id', 'child_of', ref('test_categ_0'))])
137         assert len(old_struct) == 4, "After duplication, previous record must have old childs records only"
138         assert (not set(new_struct).intersection(old_struct)), "After duplication, nodes should not be mixed"
139 -
140     6. Restore pool state after the test
141 -
142     !python {model: res.partner.category}: |
143         self.pool._init = True
144
145 -
146     "Float precision tests: verify that float rounding methods are working correctly via res.currency"
147 -
148     !python {model: res.currency}: |
149         from openerp.tools import float_repr
150         from math import log10
151         currency = self.browse(cr, uid, ref('base.EUR'))
152         def try_round(amount, expected, self=self, cr=cr, currency=currency, float_repr=float_repr,
153                       log10=log10):
154             digits = max(0,-int(log10(currency.rounding)))
155             result = float_repr(self.round(cr, 1, currency, amount), precision_digits=digits)
156             assert result == expected, 'Rounding error: got %s, expected %s' % (result, expected)
157         try_round(2.674,'2.67')
158         try_round(2.675,'2.68')   # in Python 2.7.2, round(2.675,2) gives 2.67
159         try_round(-2.675,'-2.68') # in Python 2.7.2, round(2.675,2) gives 2.67
160         try_round(0.001,'0.00')
161         try_round(-0.001,'-0.00')
162         try_round(0.0049,'0.00')   # 0.0049 is closer to 0 than to 0.01, so should round down
163         try_round(0.005,'0.01')   # the rule is to round half away from zero
164         try_round(-0.005,'-0.01') # the rule is to round half away from zero
165
166         def try_zero(amount, expected, self=self, cr=cr, currency=currency):
167             assert self.is_zero(cr, 1, currency, amount) == expected, "Rounding error: %s should be zero!" % amount
168         try_zero(0.01, False)
169         try_zero(-0.01, False)
170         try_zero(0.001, True)
171         try_zero(-0.001, True)
172         try_zero(0.0046, True)
173         try_zero(-0.0046, True)
174         try_zero(2.68-2.675, False) # 2.68 - 2.675 = 0.005 -> rounds to 0.01
175         try_zero(2.68-2.676, True)  # 2.68 - 2.675 = 0.004 -> rounds to 0.0
176         try_zero(2.676-2.68, True)  # 2.675 - 2.68 = -0.004 -> rounds to -0.0
177         try_zero(2.675-2.68, False) # 2.675 - 2.68 = -0.005 -> rounds to -0.01
178
179         def try_compare(amount1, amount2, expected, self=self, cr=cr, currency=currency):
180             assert self.compare_amounts(cr, 1, currency, amount1, amount2) == expected, \
181                 "Rounding error, compare_amounts(%s,%s) should be %s" % (amount1, amount2, expected)
182         try_compare(0.001, 0.001, 0)
183         try_compare(-0.001, -0.001, 0)
184         try_compare(0.001, 0.002, 0)
185         try_compare(-0.001, -0.002, 0)
186         try_compare(2.675, 2.68, 0)
187         try_compare(2.676, 2.68, 0)
188         try_compare(-2.676, -2.68, 0)
189         try_compare(2.674, 2.68, -1)
190         try_compare(-2.674, -2.68, 1)
191         try_compare(3, 2.68, 1)
192         try_compare(-3, -2.68, -1)
193         try_compare(0.01, 0, 1)
194         try_compare(-0.01, 0, -1)
195
196 -
197     "Float precision tests: verify that float rounding methods are working correctly via tools"
198 -
199     !python {model: res.currency}: |
200         from openerp.tools import float_compare, float_is_zero, float_round, float_repr
201         def try_round(amount, expected, precision_digits=3, float_round=float_round, float_repr=float_repr):
202             result = float_repr(float_round(amount, precision_digits=precision_digits),
203                                 precision_digits=precision_digits)
204             assert result == expected, 'Rounding error: got %s, expected %s' % (result, expected)
205         try_round(2.6745, '2.675')
206         try_round(-2.6745, '-2.675')
207         try_round(2.6744, '2.674')
208         try_round(-2.6744, '-2.674')
209         try_round(0.0004, '0.000')
210         try_round(-0.0004, '-0.000')
211         try_round(357.4555, '357.456')
212         try_round(-357.4555, '-357.456')
213         try_round(457.4554, '457.455')
214         try_round(-457.4554, '-457.455')
215
216         # Extended float range test, inspired by Cloves Almeida's test on bug #882036.
217         fractions = [.0, .015, .01499, .675, .67499, .4555, .4555, .45555]
218         expecteds = ['.00', '.02', '.01', '.68', '.67', '.46', '.456', '.4556']
219         precisions = [2, 2, 2, 2, 2, 2, 3, 4]
220         # Note: max precision for double floats is 53 bits of precision or
221         # 17 significant decimal digits
222         for magnitude in range(7):
223             for i in xrange(len(fractions)):
224                 frac, exp, prec = fractions[i], expecteds[i], precisions[i]
225                 for sign in [-1,1]:
226                     for x in xrange(0,10000,97):
227                         n = x * 10**magnitude
228                         f = sign * (n + frac)
229                         f_exp = ('-' if f != 0 and sign == -1 else '') + str(n) + exp 
230                         try_round(f, f_exp, precision_digits=prec)
231
232
233         def try_zero(amount, expected, float_is_zero=float_is_zero):
234             assert float_is_zero(amount, precision_digits=3) == expected, "Rounding error: %s should be zero!" % amount
235         try_zero(0.0002, True)
236         try_zero(-0.0002, True)
237         try_zero(0.00034, True)
238         try_zero(0.0005, False)
239         try_zero(-0.0005, False)
240         try_zero(0.0008, False)
241         try_zero(-0.0008, False)
242
243         def try_compare(amount1, amount2, expected, float_compare=float_compare):
244             assert float_compare(amount1, amount2, precision_digits=3) == expected, \
245                 "Rounding error, compare_amounts(%s,%s) should be %s" % (amount1, amount2, expected)
246         try_compare(0.0003, 0.0004, 0)
247         try_compare(-0.0003, -0.0004, 0)
248         try_compare(0.0002, 0.0005, -1)
249         try_compare(-0.0002, -0.0005, 1)
250         try_compare(0.0009, 0.0004, 1)
251         try_compare(-0.0009, -0.0004, -1)
252         try_compare(557.4555, 557.4556, 0)
253         try_compare(-557.4555, -557.4556, 0)
254         try_compare(657.4444, 657.445, -1)
255         try_compare(-657.4444, -657.445, 1)
256
257         # Rounding to unusual rounding units (e.g. coin values)
258         def try_round(amount, expected, precision_rounding=None, float_round=float_round, float_repr=float_repr):
259             result = float_repr(float_round(amount, precision_rounding=precision_rounding),
260                                 precision_digits=2)
261             assert result == expected, 'Rounding error: got %s, expected %s' % (result, expected)
262         try_round(-457.4554, '-457.45', precision_rounding=0.05)
263         try_round(457.444, '457.50', precision_rounding=0.5)
264         try_round(457.3, '455.00', precision_rounding=5)
265         try_round(457.5, '460.00', precision_rounding=5)
266         try_round(457.1, '456.00', precision_rounding=3)
267
268 -
269     "Float precision tests: check that proper rounding is performed for float persistence"
270 -
271     !python {model: res.currency}: |
272         currency = self.browse(cr, uid, ref('base.EUR'))
273         res_currency_rate = self.pool.get('res.currency.rate')
274         from openerp.tools import float_compare, float_is_zero, float_round, float_repr
275         def try_roundtrip(value, expected, self=self, cr=cr, currency=currency,
276                           res_currency_rate=res_currency_rate):
277             rate_id = res_currency_rate.create(cr, 1, {'name':'2000-01-01',
278                                                        'rate': value,
279                                                        'currency_id': currency.id})
280             rate = res_currency_rate.read(cr, 1, rate_id, ['rate'])['rate']
281             assert rate == expected, 'Roundtrip error: got %s back from db, expected %s' % (rate, expected)
282         # res.currency.rate uses 6 digits of precision by default
283         try_roundtrip(2.6748955, 2.674896)
284         try_roundtrip(-2.6748955, -2.674896)
285         try_roundtrip(10000.999999, 10000.999999)
286         try_roundtrip(-10000.999999, -10000.999999)
287
288 -
289     "Float precision tests: verify that invalid parameters are forbidden"
290 -
291     !python {model: res.currency}: |
292         from openerp.tools import float_compare, float_is_zero, float_round
293         try:
294             float_is_zero(0.01, precision_digits=3, precision_rounding=0.01)
295         except AssertionError:
296             pass
297         try:
298             float_compare(0.01, 0.02, precision_digits=3, precision_rounding=0.01)
299         except AssertionError:
300             pass
301         try:
302             float_round(0.01, precision_digits=3, precision_rounding=0.01)
303         except AssertionError:
304             pass
305 -
306    Test res.groups name search
307 -
308      !python {model: res.groups}: |
309          all_groups = self.search(cr, uid, [])
310          full_names = [(group.id, group.full_name) for group in self.browse(cr, uid, all_groups)]
311          group_ids = self.search(cr, uid, [('full_name', 'like', '%Sale%')])
312          assert set(group_ids) == set([id for (id, full_name) in full_names if 'Sale' in full_name]), "did not match search for 'Sale'"
313          group_ids = self.search(cr, uid, [('full_name', 'like', '%Technical%')])
314          assert set(group_ids) == set([id for (id, full_name) in full_names if 'Technical' in full_name]), "did not match search for 'Technical'"
315          group_ids = self.search(cr, uid, [('full_name', 'like', '%Sales /%')])
316          assert set(group_ids) == set([id for (id, full_name) in full_names if 'Sales /' in full_name]), "did not match search for 'Sales /'"
317          group_ids = self.search(cr, uid, [('full_name', 'in', ['Administration / Access Rights','Contact Creation'])])
318          assert group_ids, "did not match search for 'Administration / Access Rights' and 'Contact Creation'"