from openerp import models from openerp.tools import mute_logger from openerp.osv.orm import except_orm from openerp.tests import common class TestAPI(common.TransactionCase): """ test the new API of the ORM """ def assertIsRecordset(self, value, model): self.assertIsInstance(value, models.BaseModel) self.assertEqual(value._name, model) def assertIsRecord(self, value, model): self.assertIsRecordset(value, model) self.assertTrue(len(value) <= 1) def assertIsNull(self, value, model): self.assertIsRecordset(value, model) self.assertFalse(value) @mute_logger('openerp.models') def test_00_query(self): """ Build a recordset, and check its contents. """ domain = [('name', 'ilike', 'j')] ids = self.registry('res.partner').search(self.cr, self.uid, domain) partners = self.env['res.partner'].search(domain) # partners is a collection of browse records corresponding to ids self.assertTrue(ids) self.assertTrue(partners) # partners and its contents are instance of the model self.assertIsRecordset(partners, 'res.partner') for p in partners: self.assertIsRecord(p, 'res.partner') self.assertEqual([p.id for p in partners], ids) self.assertEqual(self.env['res.partner'].browse(ids), partners) @mute_logger('openerp.models') def test_01_query_offset(self): """ Build a recordset with offset, and check equivalence. """ partners1 = self.env['res.partner'].search([], offset=10) partners2 = self.env['res.partner'].search([])[10:] self.assertIsRecordset(partners1, 'res.partner') self.assertIsRecordset(partners2, 'res.partner') self.assertEqual(list(partners1), list(partners2)) @mute_logger('openerp.models') def test_02_query_limit(self): """ Build a recordset with offset, and check equivalence. """ partners1 = self.env['res.partner'].search([], limit=10) partners2 = self.env['res.partner'].search([])[:10] self.assertIsRecordset(partners1, 'res.partner') self.assertIsRecordset(partners2, 'res.partner') self.assertEqual(list(partners1), list(partners2)) @mute_logger('openerp.models') def test_03_query_offset_limit(self): """ Build a recordset with offset and limit, and check equivalence. """ partners1 = self.env['res.partner'].search([], offset=3, limit=7) partners2 = self.env['res.partner'].search([])[3:10] self.assertIsRecordset(partners1, 'res.partner') self.assertIsRecordset(partners2, 'res.partner') self.assertEqual(list(partners1), list(partners2)) @mute_logger('openerp.models') def test_04_query_count(self): """ Test the search method with count=True. """ count1 = self.registry('res.partner').search(self.cr, self.uid, [], count=True) count2 = self.env['res.partner'].search([], count=True) self.assertIsInstance(count1, (int, long)) self.assertIsInstance(count2, (int, long)) self.assertEqual(count1, count2) @mute_logger('openerp.models') def test_05_immutable(self): """ Check that a recordset remains the same, even after updates. """ domain = [('name', 'ilike', 'j')] partners = self.env['res.partner'].search(domain) self.assertTrue(partners) ids = map(int, partners) # modify those partners, and check that partners has not changed self.registry('res.partner').write(self.cr, self.uid, ids, {'active': False}) self.assertEqual(ids, map(int, partners)) # redo the search, and check that the result is now empty partners2 = self.env['res.partner'].search(domain) self.assertFalse(partners2) @mute_logger('openerp.models') def test_06_fields(self): """ Check that relation fields return records, recordsets or nulls. """ user = self.registry('res.users').browse(self.cr, self.uid, self.uid) self.assertIsRecord(user, 'res.users') self.assertIsRecord(user.partner_id, 'res.partner') self.assertIsRecordset(user.groups_id, 'res.groups') partners = self.env['res.partner'].search([]) for name, field in partners._fields.iteritems(): if field.type == 'many2one': for p in partners: self.assertIsRecord(p[name], field.comodel_name) elif field.type == 'reference': for p in partners: if p[name]: self.assertIsRecord(p[name], field.comodel_name) elif field.type in ('one2many', 'many2many'): for p in partners: self.assertIsRecordset(p[name], field.comodel_name) @mute_logger('openerp.models') def test_07_null(self): """ Check behavior of null instances. """ # select a partner without a parent partner = self.env['res.partner'].search([('parent_id', '=', False)])[0] # check partner and related null instances self.assertTrue(partner) self.assertIsRecord(partner, 'res.partner') self.assertFalse(partner.parent_id) self.assertIsNull(partner.parent_id, 'res.partner') self.assertIs(partner.parent_id.id, False) self.assertFalse(partner.parent_id.user_id) self.assertIsNull(partner.parent_id.user_id, 'res.users') self.assertIs(partner.parent_id.user_id.name, False) self.assertFalse(partner.parent_id.user_id.groups_id) self.assertIsRecordset(partner.parent_id.user_id.groups_id, 'res.groups') @mute_logger('openerp.models') def test_10_old_old(self): """ Call old-style methods in the old-fashioned way. """ partners = self.env['res.partner'].search([('name', 'ilike', 'j')]) self.assertTrue(partners) ids = map(int, partners) # call method name_get on partners' model, and check its effect res = partners._model.name_get(self.cr, self.uid, ids) self.assertEqual(len(res), len(ids)) self.assertEqual(set(val[0] for val in res), set(ids)) @mute_logger('openerp.models') def test_20_old_new(self): """ Call old-style methods in the new API style. """ partners = self.env['res.partner'].search([('name', 'ilike', 'j')]) self.assertTrue(partners) # call method name_get on partners itself, and check its effect res = partners.name_get() self.assertEqual(len(res), len(partners)) self.assertEqual(set(val[0] for val in res), set(map(int, partners))) @mute_logger('openerp.models') def test_25_old_new(self): """ Call old-style methods on records (new API style). """ partners = self.env['res.partner'].search([('name', 'ilike', 'j')]) self.assertTrue(partners) # call method name_get on partner records, and check its effect for p in partners: res = p.name_get() self.assertTrue(isinstance(res, list) and len(res) == 1) self.assertTrue(isinstance(res[0], tuple) and len(res[0]) == 2) self.assertEqual(res[0][0], p.id) @mute_logger('openerp.models') def test_30_new_old(self): """ Call new-style methods in the old-fashioned way. """ partners = self.env['res.partner'].search([('name', 'ilike', 'j')]) self.assertTrue(partners) ids = map(int, partners) # call method write on partners' model, and check its effect partners._model.write(self.cr, self.uid, ids, {'active': False}) for p in partners: self.assertFalse(p.active) @mute_logger('openerp.models') def test_40_new_new(self): """ Call new-style methods in the new API style. """ partners = self.env['res.partner'].search([('name', 'ilike', 'j')]) self.assertTrue(partners) # call method write on partners itself, and check its effect partners.write({'active': False}) for p in partners: self.assertFalse(p.active) @mute_logger('openerp.models') def test_45_new_new(self): """ Call new-style methods on records (new API style). """ partners = self.env['res.partner'].search([('name', 'ilike', 'j')]) self.assertTrue(partners) # call method write on partner records, and check its effects for p in partners: p.write({'active': False}) for p in partners: self.assertFalse(p.active) @mute_logger('openerp.models') @mute_logger('openerp.addons.base.ir.ir_model') def test_50_environment(self): """ Test environment on records. """ # partners and reachable records are attached to self.env partners = self.env['res.partner'].search([('name', 'ilike', 'j')]) self.assertEqual(partners.env, self.env) for x in (partners, partners[0], partners[0].company_id): self.assertEqual(x.env, self.env) for p in partners: self.assertEqual(p.env, self.env) # check that the current user can read and modify company data partners[0].company_id.name partners[0].company_id.write({'name': 'Fools'}) # create an environment with the demo user demo = self.env['res.users'].search([('login', '=', 'demo')])[0] demo_env = self.env(user=demo) self.assertNotEqual(demo_env, self.env) # partners and related records are still attached to self.env self.assertEqual(partners.env, self.env) for x in (partners, partners[0], partners[0].company_id): self.assertEqual(x.env, self.env) for p in partners: self.assertEqual(p.env, self.env) # create record instances attached to demo_env demo_partners = partners.sudo(demo) self.assertEqual(demo_partners.env, demo_env) for x in (demo_partners, demo_partners[0], demo_partners[0].company_id): self.assertEqual(x.env, demo_env) for p in demo_partners: self.assertEqual(p.env, demo_env) # demo user can read but not modify company data demo_partners[0].company_id.name with self.assertRaises(except_orm): demo_partners[0].company_id.write({'name': 'Pricks'}) # remove demo user from all groups demo.write({'groups_id': [(5,)]}) # demo user can no longer access partner data with self.assertRaises(except_orm): demo_partners[0].company_id.name @mute_logger('openerp.models') def test_55_draft(self): """ Test draft mode nesting. """ env = self.env self.assertFalse(env.in_draft) with env.do_in_draft(): self.assertTrue(env.in_draft) with env.do_in_draft(): self.assertTrue(env.in_draft) with env.do_in_draft(): self.assertTrue(env.in_draft) self.assertTrue(env.in_draft) self.assertTrue(env.in_draft) self.assertFalse(env.in_draft) @mute_logger('openerp.models') def test_60_cache(self): """ Check the record cache behavior """ partners = self.env['res.partner'].search([('child_ids', '!=', False)]) partner1, partner2 = partners[0], partners[1] children1, children2 = partner1.child_ids, partner2.child_ids self.assertTrue(children1) self.assertTrue(children2) # take a child contact child = children1[0] self.assertEqual(child.parent_id, partner1) self.assertIn(child, partner1.child_ids) self.assertNotIn(child, partner2.child_ids) # fetch data in the cache for p in partners: p.name, p.company_id.name, p.user_id.name, p.contact_address self.env.check_cache() # change its parent child.write({'parent_id': partner2.id}) self.env.check_cache() # check recordsets self.assertEqual(child.parent_id, partner2) self.assertNotIn(child, partner1.child_ids) self.assertIn(child, partner2.child_ids) self.assertEqual(set(partner1.child_ids + child), set(children1)) self.assertEqual(set(partner2.child_ids), set(children2 + child)) self.env.check_cache() # delete it child.unlink() self.env.check_cache() # check recordsets self.assertEqual(set(partner1.child_ids), set(children1) - set([child])) self.assertEqual(set(partner2.child_ids), set(children2)) self.env.check_cache() @mute_logger('openerp.models') def test_60_cache_prefetching(self): """ Check the record cache prefetching """ self.env.invalidate_all() # all the records of an instance already have an entry in cache partners = self.env['res.partner'].search([]) partner_ids = self.env.prefetch['res.partner'] self.assertEqual(set(partners.ids), set(partner_ids)) # countries have not been fetched yet; their cache must be empty countries = self.env['res.country'].browse() self.assertFalse(self.env.prefetch['res.country']) # reading ONE partner should fetch them ALL countries |= partners[0].country_id country_cache = self.env.cache[partners._fields['country_id']] self.assertLessEqual(set(partners._ids), set(country_cache)) # read all partners, and check that the cache already contained them country_ids = list(self.env.prefetch['res.country']) for p in partners: countries |= p.country_id self.assertLessEqual(set(countries.ids), set(country_ids)) @mute_logger('openerp.models') def test_70_one(self): """ Check method one(). """ # check with many records ps = self.env['res.partner'].search([('name', 'ilike', 'a')]) self.assertTrue(len(ps) > 1) with self.assertRaises(except_orm): ps.ensure_one() p1 = ps[0] self.assertEqual(len(p1), 1) self.assertEqual(p1.ensure_one(), p1) p0 = self.env['res.partner'].browse() self.assertEqual(len(p0), 0) with self.assertRaises(except_orm): p0.ensure_one() @mute_logger('openerp.models') def test_80_contains(self): """ Test membership on recordset. """ p1 = self.env['res.partner'].search([('name', 'ilike', 'a')], limit=1).ensure_one() ps = self.env['res.partner'].search([('name', 'ilike', 'a')]) self.assertTrue(p1 in ps) @mute_logger('openerp.models') def test_80_set_operations(self): """ Check set operations on recordsets. """ pa = self.env['res.partner'].search([('name', 'ilike', 'a')]) pb = self.env['res.partner'].search([('name', 'ilike', 'b')]) self.assertTrue(pa) self.assertTrue(pb) self.assertTrue(set(pa) & set(pb)) concat = pa + pb self.assertEqual(list(concat), list(pa) + list(pb)) self.assertEqual(len(concat), len(pa) + len(pb)) difference = pa - pb self.assertEqual(len(difference), len(set(difference))) self.assertEqual(set(difference), set(pa) - set(pb)) self.assertLessEqual(difference, pa) intersection = pa & pb self.assertEqual(len(intersection), len(set(intersection))) self.assertEqual(set(intersection), set(pa) & set(pb)) self.assertLessEqual(intersection, pa) self.assertLessEqual(intersection, pb) union = pa | pb self.assertEqual(len(union), len(set(union))) self.assertEqual(set(union), set(pa) | set(pb)) self.assertGreaterEqual(union, pa) self.assertGreaterEqual(union, pb) # one cannot mix different models with set operations ps = pa ms = self.env['ir.ui.menu'].search([]) self.assertNotEqual(ps._name, ms._name) self.assertNotEqual(ps, ms) with self.assertRaises(except_orm): res = ps + ms with self.assertRaises(except_orm): res = ps - ms with self.assertRaises(except_orm): res = ps & ms with self.assertRaises(except_orm): res = ps | ms with self.assertRaises(except_orm): res = ps < ms with self.assertRaises(except_orm): res = ps <= ms with self.assertRaises(except_orm): res = ps > ms with self.assertRaises(except_orm): res = ps >= ms @mute_logger('openerp.models') def test_80_filter(self): """ Check filter on recordsets. """ ps = self.env['res.partner'].search([]) customers = ps.browse([p.id for p in ps if p.customer]) # filter on a single field self.assertEqual(ps.filtered(lambda p: p.customer), customers) self.assertEqual(ps.filtered('customer'), customers) # filter on a sequence of fields self.assertEqual( ps.filtered(lambda p: p.parent_id.customer), ps.filtered('parent_id.customer') ) @mute_logger('openerp.models') def test_80_map(self): """ Check map on recordsets. """ ps = self.env['res.partner'].search([]) parents = ps.browse() for p in ps: parents |= p.parent_id # map a single field self.assertEqual(ps.mapped(lambda p: p.parent_id), parents) self.assertEqual(ps.mapped('parent_id'), parents) # map a sequence of fields self.assertEqual( ps.mapped(lambda p: p.parent_id.name), [p.parent_id.name for p in ps] ) self.assertEqual( ps.mapped('parent_id.name'), [p.name for p in parents] )