2 from openerp import models
3 from openerp.tools import mute_logger
4 from openerp.osv.orm import except_orm
5 from openerp.tests import common
8 class TestAPI(common.TransactionCase):
9 """ test the new API of the ORM """
11 def assertIsRecordset(self, value, model):
12 self.assertIsInstance(value, models.BaseModel)
13 self.assertEqual(value._name, model)
15 def assertIsRecord(self, value, model):
16 self.assertIsRecordset(value, model)
17 self.assertTrue(len(value) <= 1)
19 def assertIsNull(self, value, model):
20 self.assertIsRecordset(value, model)
21 self.assertFalse(value)
23 @mute_logger('openerp.models')
24 def test_00_query(self):
25 """ Build a recordset, and check its contents. """
26 domain = [('name', 'ilike', 'j')]
27 ids = self.registry('res.partner').search(self.cr, self.uid, domain)
28 partners = self.env['res.partner'].search(domain)
30 # partners is a collection of browse records corresponding to ids
32 self.assertTrue(partners)
34 # partners and its contents are instance of the model, and share its ormcache
35 self.assertIsRecordset(partners, 'res.partner')
36 self.assertIs(partners._ormcache, self.env['res.partner']._ormcache)
38 self.assertIsRecord(p, 'res.partner')
39 self.assertIs(p._ormcache, self.env['res.partner']._ormcache)
41 self.assertEqual([p.id for p in partners], ids)
42 self.assertEqual(self.env['res.partner'].browse(ids), partners)
44 @mute_logger('openerp.models')
45 def test_01_query_offset(self):
46 """ Build a recordset with offset, and check equivalence. """
47 partners1 = self.env['res.partner'].search([], offset=10)
48 partners2 = self.env['res.partner'].search([])[10:]
49 self.assertIsRecordset(partners1, 'res.partner')
50 self.assertIsRecordset(partners2, 'res.partner')
51 self.assertEqual(list(partners1), list(partners2))
53 @mute_logger('openerp.models')
54 def test_02_query_limit(self):
55 """ Build a recordset with offset, and check equivalence. """
56 partners1 = self.env['res.partner'].search([], limit=10)
57 partners2 = self.env['res.partner'].search([])[:10]
58 self.assertIsRecordset(partners1, 'res.partner')
59 self.assertIsRecordset(partners2, 'res.partner')
60 self.assertEqual(list(partners1), list(partners2))
62 @mute_logger('openerp.models')
63 def test_03_query_offset_limit(self):
64 """ Build a recordset with offset and limit, and check equivalence. """
65 partners1 = self.env['res.partner'].search([], offset=3, limit=7)
66 partners2 = self.env['res.partner'].search([])[3:10]
67 self.assertIsRecordset(partners1, 'res.partner')
68 self.assertIsRecordset(partners2, 'res.partner')
69 self.assertEqual(list(partners1), list(partners2))
71 @mute_logger('openerp.models')
72 def test_05_immutable(self):
73 """ Check that a recordset remains the same, even after updates. """
74 domain = [('name', 'ilike', 'j')]
75 partners = self.env['res.partner'].search(domain)
76 self.assertTrue(partners)
77 ids = map(int, partners)
79 # modify those partners, and check that partners has not changed
80 self.registry('res.partner').write(self.cr, self.uid, ids, {'active': False})
81 self.assertEqual(ids, map(int, partners))
83 # redo the search, and check that the result is now empty
84 partners2 = self.env['res.partner'].search(domain)
85 self.assertFalse(partners2)
87 @mute_logger('openerp.models')
88 def test_06_fields(self):
89 """ Check that relation fields return records, recordsets or nulls. """
90 user = self.registry('res.users').browse(self.cr, self.uid, self.uid)
91 self.assertIsRecord(user, 'res.users')
92 self.assertIsRecord(user.partner_id, 'res.partner')
93 self.assertIsRecordset(user.groups_id, 'res.groups')
95 partners = self.env['res.partner'].search([])
96 for name, field in partners._fields.iteritems():
97 if field.type == 'many2one':
99 self.assertIsRecord(p[name], field.comodel_name)
100 elif field.type == 'reference':
103 self.assertIsRecord(p[name], field.comodel_name)
104 elif field.type in ('one2many', 'many2many'):
106 self.assertIsRecordset(p[name], field.comodel_name)
108 @mute_logger('openerp.models')
109 def test_07_null(self):
110 """ Check behavior of null instances. """
111 # select a partner without a parent
112 partner = self.env['res.partner'].search([('parent_id', '=', False)])[0]
114 # check partner and related null instances
115 self.assertTrue(partner)
116 self.assertIsRecord(partner, 'res.partner')
118 self.assertFalse(partner.parent_id)
119 self.assertIsNull(partner.parent_id, 'res.partner')
121 self.assertIs(partner.parent_id.id, False)
123 self.assertFalse(partner.parent_id.user_id)
124 self.assertIsNull(partner.parent_id.user_id, 'res.users')
126 self.assertIs(partner.parent_id.user_id.name, False)
128 self.assertFalse(partner.parent_id.user_id.groups_id)
129 self.assertIsRecordset(partner.parent_id.user_id.groups_id, 'res.groups')
131 @mute_logger('openerp.models')
132 def test_10_old_old(self):
133 """ Call old-style methods in the old-fashioned way. """
134 partners = self.env['res.partner'].search([('name', 'ilike', 'j')])
135 self.assertTrue(partners)
136 ids = map(int, partners)
138 # call method name_get on partners' model, and check its effect
139 res = partners._model.name_get(self.cr, self.uid, ids)
140 self.assertEqual(len(res), len(ids))
141 self.assertEqual(set(val[0] for val in res), set(ids))
143 @mute_logger('openerp.models')
144 def test_20_old_new(self):
145 """ Call old-style methods in the new API style. """
146 partners = self.env['res.partner'].search([('name', 'ilike', 'j')])
147 self.assertTrue(partners)
149 # call method name_get on partners itself, and check its effect
150 res = partners.name_get()
151 self.assertEqual(len(res), len(partners))
152 self.assertEqual(set(val[0] for val in res), set(map(int, partners)))
154 @mute_logger('openerp.models')
155 def test_25_old_new(self):
156 """ Call old-style methods on records (new API style). """
157 partners = self.env['res.partner'].search([('name', 'ilike', 'j')])
158 self.assertTrue(partners)
160 # call method name_get on partner records, and check its effect
163 self.assertTrue(isinstance(res, list) and len(res) == 1)
164 self.assertTrue(isinstance(res[0], tuple) and len(res[0]) == 2)
165 self.assertEqual(res[0][0], p.id)
167 @mute_logger('openerp.models')
168 def test_30_new_old(self):
169 """ Call new-style methods in the old-fashioned way. """
170 partners = self.env['res.partner'].search([('name', 'ilike', 'j')])
171 self.assertTrue(partners)
172 ids = map(int, partners)
174 # call method write on partners' model, and check its effect
175 partners._model.write(self.cr, self.uid, ids, {'active': False})
177 self.assertFalse(p.active)
179 @mute_logger('openerp.models')
180 def test_40_new_new(self):
181 """ Call new-style methods in the new API style. """
182 partners = self.env['res.partner'].search([('name', 'ilike', 'j')])
183 self.assertTrue(partners)
185 # call method write on partners itself, and check its effect
186 partners.write({'active': False})
188 self.assertFalse(p.active)
190 @mute_logger('openerp.models')
191 def test_45_new_new(self):
192 """ Call new-style methods on records (new API style). """
193 partners = self.env['res.partner'].search([('name', 'ilike', 'j')])
194 self.assertTrue(partners)
196 # call method write on partner records, and check its effects
198 p.write({'active': False})
200 self.assertFalse(p.active)
202 @mute_logger('openerp.models')
203 @mute_logger('openerp.addons.base.ir.ir_model')
204 def test_50_environment(self):
205 """ Test environment on records. """
206 # partners and reachable records are attached to self.env
207 partners = self.env['res.partner'].search([('name', 'ilike', 'j')])
208 self.assertEqual(partners.env, self.env)
209 for x in (partners, partners[0], partners[0].company_id):
210 self.assertEqual(x.env, self.env)
212 self.assertEqual(p.env, self.env)
214 # check that the current user can read and modify company data
215 partners[0].company_id.name
216 partners[0].company_id.write({'name': 'Fools'})
218 # create an environment with the demo user
219 demo = self.env['res.users'].search([('login', '=', 'demo')])[0]
220 demo_env = self.env(user=demo)
221 self.assertNotEqual(demo_env, self.env)
223 # partners and related records are still attached to self.env
224 self.assertEqual(partners.env, self.env)
225 for x in (partners, partners[0], partners[0].company_id):
226 self.assertEqual(x.env, self.env)
228 self.assertEqual(p.env, self.env)
230 # create record instances attached to demo_env
231 demo_partners = partners.sudo(demo)
232 self.assertEqual(demo_partners.env, demo_env)
233 for x in (demo_partners, demo_partners[0], demo_partners[0].company_id):
234 self.assertEqual(x.env, demo_env)
235 for p in demo_partners:
236 self.assertEqual(p.env, demo_env)
238 # demo user can read but not modify company data
239 demo_partners[0].company_id.name
240 with self.assertRaises(except_orm):
241 demo_partners[0].company_id.write({'name': 'Pricks'})
243 # remove demo user from all groups
244 demo.write({'groups_id': [(5,)]})
246 # demo user can no longer access partner data
247 with self.assertRaises(except_orm):
248 demo_partners[0].company_id.name
250 @mute_logger('openerp.models')
251 def test_55_draft(self):
252 """ Test draft mode nesting. """
254 self.assertFalse(env.in_draft)
255 with env.do_in_draft():
256 self.assertTrue(env.in_draft)
257 with env.do_in_draft():
258 self.assertTrue(env.in_draft)
259 with env.do_in_draft():
260 self.assertTrue(env.in_draft)
261 self.assertTrue(env.in_draft)
262 self.assertTrue(env.in_draft)
263 self.assertFalse(env.in_draft)
265 @mute_logger('openerp.models')
266 def test_60_cache(self):
267 """ Check the record cache behavior """
268 partners = self.env['res.partner'].search([('child_ids', '!=', False)])
269 partner1, partner2 = partners[0], partners[1]
270 children1, children2 = partner1.child_ids, partner2.child_ids
271 self.assertTrue(children1)
272 self.assertTrue(children2)
274 # take a child contact
276 self.assertEqual(child.parent_id, partner1)
277 self.assertIn(child, partner1.child_ids)
278 self.assertNotIn(child, partner2.child_ids)
280 # fetch data in the cache
282 p.name, p.company_id.name, p.user_id.name, p.contact_address
283 self.env.check_cache()
286 child.write({'parent_id': partner2.id})
287 self.env.check_cache()
290 self.assertEqual(child.parent_id, partner2)
291 self.assertNotIn(child, partner1.child_ids)
292 self.assertIn(child, partner2.child_ids)
293 self.assertEqual(set(partner1.child_ids + child), set(children1))
294 self.assertEqual(set(partner2.child_ids), set(children2 + child))
295 self.env.check_cache()
299 self.env.check_cache()
302 self.assertEqual(set(partner1.child_ids), set(children1) - set([child]))
303 self.assertEqual(set(partner2.child_ids), set(children2))
304 self.env.check_cache()
306 @mute_logger('openerp.models')
307 def test_60_cache_prefetching(self):
308 """ Check the record cache prefetching """
309 self.env.invalidate_all()
311 # all the records of an instance already have an entry in cache
312 partners = self.env['res.partner'].search([])
313 partner_ids = self.env.prefetch['res.partner']
314 self.assertEqual(set(partners.ids), set(partner_ids))
316 # countries have not been fetched yet; their cache must be empty
317 countries = self.env['res.country'].browse()
318 self.assertFalse(self.env.prefetch['res.country'])
320 # reading ONE partner should fetch them ALL
321 countries |= partners[0].country_id
322 country_cache = self.env.cache[partners._fields['country_id']]
323 self.assertLessEqual(set(partners._ids), set(country_cache))
325 # read all partners, and check that the cache already contained them
326 country_ids = list(self.env.prefetch['res.country'])
328 countries |= p.country_id
329 self.assertLessEqual(set(countries.ids), set(country_ids))
331 @mute_logger('openerp.models')
332 def test_70_one(self):
333 """ Check method one(). """
334 # check with many records
335 ps = self.env['res.partner'].search([('name', 'ilike', 'a')])
336 self.assertTrue(len(ps) > 1)
337 with self.assertRaises(except_orm):
341 self.assertEqual(len(p1), 1)
342 self.assertEqual(p1.ensure_one(), p1)
344 p0 = self.env['res.partner'].browse()
345 self.assertEqual(len(p0), 0)
346 with self.assertRaises(except_orm):
349 @mute_logger('openerp.models')
350 def test_80_contains(self):
351 """ Test membership on recordset. """
352 p1 = self.env['res.partner'].search([('name', 'ilike', 'a')], limit=1).ensure_one()
353 ps = self.env['res.partner'].search([('name', 'ilike', 'a')])
354 self.assertTrue(p1 in ps)
356 @mute_logger('openerp.models')
357 def test_80_set_operations(self):
358 """ Check set operations on recordsets. """
359 pa = self.env['res.partner'].search([('name', 'ilike', 'a')])
360 pb = self.env['res.partner'].search([('name', 'ilike', 'b')])
363 self.assertTrue(set(pa) & set(pb))
366 self.assertEqual(list(concat), list(pa) + list(pb))
367 self.assertEqual(len(concat), len(pa) + len(pb))
370 self.assertEqual(len(difference), len(set(difference)))
371 self.assertEqual(set(difference), set(pa) - set(pb))
372 self.assertLessEqual(difference, pa)
374 intersection = pa & pb
375 self.assertEqual(len(intersection), len(set(intersection)))
376 self.assertEqual(set(intersection), set(pa) & set(pb))
377 self.assertLessEqual(intersection, pa)
378 self.assertLessEqual(intersection, pb)
381 self.assertEqual(len(union), len(set(union)))
382 self.assertEqual(set(union), set(pa) | set(pb))
383 self.assertGreaterEqual(union, pa)
384 self.assertGreaterEqual(union, pb)
386 # one cannot mix different models with set operations
388 ms = self.env['ir.ui.menu'].search([])
389 self.assertNotEqual(ps._name, ms._name)
390 self.assertNotEqual(ps, ms)
392 with self.assertRaises(except_orm):
394 with self.assertRaises(except_orm):
396 with self.assertRaises(except_orm):
398 with self.assertRaises(except_orm):
400 with self.assertRaises(except_orm):
402 with self.assertRaises(except_orm):
404 with self.assertRaises(except_orm):
406 with self.assertRaises(except_orm):
409 @mute_logger('openerp.models')
410 def test_80_filter(self):
411 """ Check filter on recordsets. """
412 ps = self.env['res.partner'].search([])
413 customers = ps.browse([p.id for p in ps if p.customer])
415 # filter on a single field
416 self.assertEqual(ps.filtered(lambda p: p.customer), customers)
417 self.assertEqual(ps.filtered('customer'), customers)
419 # filter on a sequence of fields
421 ps.filtered(lambda p: p.parent_id.customer),
422 ps.filtered('parent_id.customer')
425 @mute_logger('openerp.models')
426 def test_80_map(self):
427 """ Check map on recordsets. """
428 ps = self.env['res.partner'].search([])
429 parents = ps.browse()
430 for p in ps: parents |= p.parent_id
433 self.assertEqual(ps.mapped(lambda p: p.parent_id), parents)
434 self.assertEqual(ps.mapped('parent_id'), parents)
436 # map a sequence of fields
438 ps.mapped(lambda p: p.parent_id.name),
439 [p.parent_id.name for p in ps]
442 ps.mapped('parent_id.name'),
443 [p.name for p in parents]