diff options
| author | Raphael Collet <rco@openerp.com> | 2014-07-06 16:44:26 +0200 |
|---|---|---|
| committer | Antony Lesuisse <al@openerp.com> | 2014-07-06 17:05:41 +0200 |
| commit | cbe2dbb672a6c55d86f2e515f9d1cdfee426ef80 (patch) | |
| tree | d6ff62b719fce32392397783c961b734b1e4c50e /openerp/addons/test_new_api/tests/test_new_fields.py | |
| parent | d78192c489d3be66cd6487b39f5ce7ba4733a187 (diff) | |
[MERGE] new v8 api by rco
A squashed merge is required as the conversion of the apiculture branch from
bzr to git was not correctly done. The git history contains irrelevant blobs
and commits. This branch brings a lot of changes and fixes, too many to list
exhaustively.
- New orm api, objects are now used instead of ids
- Environements to encapsulates cr uid context while maintaining backward compatibility
- Field compute attribute is a new object oriented way to define function fields
- Shared browse record cache
- New onchange protocol
- Optional copy flag on fields
- Documentation update
- Dead code cleanup
- Lots of fixes
Diffstat (limited to 'openerp/addons/test_new_api/tests/test_new_fields.py')
| -rw-r--r-- | openerp/addons/test_new_api/tests/test_new_fields.py | 393 |
1 files changed, 393 insertions, 0 deletions
diff --git a/openerp/addons/test_new_api/tests/test_new_fields.py b/openerp/addons/test_new_api/tests/test_new_fields.py new file mode 100644 index 00000000000..14ff358cc90 --- /dev/null +++ b/openerp/addons/test_new_api/tests/test_new_fields.py @@ -0,0 +1,393 @@ +# +# test cases for new-style fields +# +from datetime import date, datetime +from collections import defaultdict + +from openerp.tests import common +from openerp.exceptions import except_orm + + +class TestNewFields(common.TransactionCase): + + def test_00_basics(self): + """ test accessing new fields """ + # find a discussion + discussion = self.env.ref('test_new_api.discussion_0') + + # read field as a record attribute or as a record item + self.assertIsInstance(discussion.name, basestring) + self.assertIsInstance(discussion['name'], basestring) + self.assertEqual(discussion['name'], discussion.name) + + # read it with method read() + values = discussion.read(['name'])[0] + self.assertEqual(values['name'], discussion.name) + + def test_01_basic_get_assertion(self): + """ test item getter """ + # field access works on single record + record = self.env.ref('test_new_api.message_0_0') + self.assertEqual(len(record), 1) + ok = record.body + + # field access fails on multiple records + records = self.env['test_new_api.message'].search([]) + assert len(records) > 1 + with self.assertRaises(except_orm): + faulty = records.body + + def test_01_basic_set_assertion(self): + """ test item setter """ + # field assignment works on single record + record = self.env.ref('test_new_api.message_0_0') + self.assertEqual(len(record), 1) + record.body = 'OK' + + # field assignment fails on multiple records + records = self.env['test_new_api.message'].search([]) + assert len(records) > 1 + with self.assertRaises(except_orm): + records.body = 'Faulty' + + def test_10_computed(self): + """ check definition of computed fields """ + # by default function fields are not stored and readonly + field = self.env['test_new_api.message']._fields['size'] + self.assertFalse(field.store) + self.assertTrue(field.readonly) + + field = self.env['test_new_api.message']._fields['name'] + self.assertTrue(field.store) + self.assertTrue(field.readonly) + + def test_10_non_stored(self): + """ test non-stored fields """ + # find messages + for message in self.env['test_new_api.message'].search([]): + # check definition of field + self.assertEqual(message.size, len(message.body or '')) + + # check recomputation after record is modified + size = message.size + message.write({'body': (message.body or '') + "!!!"}) + self.assertEqual(message.size, size + 3) + + # special case: computed field without dependency must be computed + record = self.env['test_new_api.mixed'].create({}) + self.assertTrue(record.now) + + def test_11_stored(self): + """ test stored fields """ + # find the demo discussion + discussion = self.env.ref('test_new_api.discussion_0') + self.assertTrue(len(discussion.messages) > 0) + + # check messages + name0 = discussion.name or "" + for message in discussion.messages: + self.assertEqual(message.name, "[%s] %s" % (name0, message.author.name)) + + # modify discussion name, and check again messages + discussion.name = name1 = 'Talking about stuff...' + for message in discussion.messages: + self.assertEqual(message.name, "[%s] %s" % (name1, message.author.name)) + + # switch message from discussion, and check again + name2 = 'Another discussion' + discussion2 = discussion.copy({'name': name2}) + message2 = discussion.messages[0] + message2.discussion = discussion2 + for message in discussion2.messages: + self.assertEqual(message.name, "[%s] %s" % (name2, message.author.name)) + + def test_12_recursive(self): + """ test recursively dependent fields """ + Category = self.env['test_new_api.category'] + abel = Category.create({'name': 'Abel'}) + beth = Category.create({'name': 'Bethany'}) + cath = Category.create({'name': 'Catherine'}) + dean = Category.create({'name': 'Dean'}) + ewan = Category.create({'name': 'Ewan'}) + finn = Category.create({'name': 'Finnley'}) + gabe = Category.create({'name': 'Gabriel'}) + + cath.parent = finn.parent = gabe + abel.parent = beth.parent = cath + dean.parent = ewan.parent = finn + + self.assertEqual(abel.display_name, "Gabriel / Catherine / Abel") + self.assertEqual(beth.display_name, "Gabriel / Catherine / Bethany") + self.assertEqual(cath.display_name, "Gabriel / Catherine") + self.assertEqual(dean.display_name, "Gabriel / Finnley / Dean") + self.assertEqual(ewan.display_name, "Gabriel / Finnley / Ewan") + self.assertEqual(finn.display_name, "Gabriel / Finnley") + self.assertEqual(gabe.display_name, "Gabriel") + + ewan.parent = cath + self.assertEqual(ewan.display_name, "Gabriel / Catherine / Ewan") + + cath.parent = finn + self.assertEqual(ewan.display_name, "Gabriel / Finnley / Catherine / Ewan") + + def test_12_cascade(self): + """ test computed field depending on computed field """ + message = self.env.ref('test_new_api.message_0_0') + message.invalidate_cache() + double_size = message.double_size + self.assertEqual(double_size, message.size) + + def test_13_inverse(self): + """ test inverse computation of fields """ + Category = self.env['test_new_api.category'] + abel = Category.create({'name': 'Abel'}) + beth = Category.create({'name': 'Bethany'}) + cath = Category.create({'name': 'Catherine'}) + dean = Category.create({'name': 'Dean'}) + ewan = Category.create({'name': 'Ewan'}) + finn = Category.create({'name': 'Finnley'}) + gabe = Category.create({'name': 'Gabriel'}) + self.assertEqual(ewan.display_name, "Ewan") + + ewan.display_name = "Abel / Bethany / Catherine / Erwan" + + self.assertEqual(beth.parent, abel) + self.assertEqual(cath.parent, beth) + self.assertEqual(ewan.parent, cath) + self.assertEqual(ewan.name, "Erwan") + + def test_14_search(self): + """ test search on computed fields """ + discussion = self.env.ref('test_new_api.discussion_0') + + # determine message sizes + sizes = set(message.size for message in discussion.messages) + + # search for messages based on their size + for size in sizes: + messages0 = self.env['test_new_api.message'].search( + [('discussion', '=', discussion.id), ('size', '<=', size)]) + + messages1 = self.env['test_new_api.message'].browse() + for message in discussion.messages: + if message.size <= size: + messages1 += message + + self.assertEqual(messages0, messages1) + + def test_15_constraint(self): + """ test new-style Python constraints """ + discussion = self.env.ref('test_new_api.discussion_0') + + # remove oneself from discussion participants: we can no longer create + # messages in discussion + discussion.participants -= self.env.user + with self.assertRaises(Exception): + self.env['test_new_api.message'].create({'discussion': discussion.id, 'body': 'Whatever'}) + + # put back oneself into discussion participants: now we can create + # messages in discussion + discussion.participants += self.env.user + self.env['test_new_api.message'].create({'discussion': discussion.id, 'body': 'Whatever'}) + + def test_20_float(self): + """ test float fields """ + record = self.env['test_new_api.mixed'].create({}) + + # assign value, and expect rounding + record.write({'number': 2.4999999999999996}) + self.assertEqual(record.number, 2.50) + + # same with field setter + record.number = 2.4999999999999996 + self.assertEqual(record.number, 2.50) + + def test_21_date(self): + """ test date fields """ + record = self.env['test_new_api.mixed'].create({}) + + # one may assign False or None + record.date = None + self.assertFalse(record.date) + + # one may assign date and datetime objects + record.date = date(2012, 05, 01) + self.assertEqual(record.date, '2012-05-01') + + record.date = datetime(2012, 05, 01, 10, 45, 00) + self.assertEqual(record.date, '2012-05-01') + + # one may assign dates in the default format, and it must be checked + record.date = '2012-05-01' + self.assertEqual(record.date, '2012-05-01') + + with self.assertRaises(ValueError): + record.date = '12-5-1' + + def test_22_selection(self): + """ test selection fields """ + record = self.env['test_new_api.mixed'].create({}) + + # one may assign False or None + record.lang = None + self.assertFalse(record.lang) + + # one may assign a value, and it must be checked + for language in self.env['res.lang'].search([]): + record.lang = language.code + with self.assertRaises(ValueError): + record.lang = 'zz_ZZ' + + def test_23_relation(self): + """ test relation fields """ + demo = self.env.ref('base.user_demo') + message = self.env.ref('test_new_api.message_0_0') + + # check environment of record and related records + self.assertEqual(message.env, self.env) + self.assertEqual(message.discussion.env, self.env) + + demo_env = self.env(user=demo) + self.assertNotEqual(demo_env, self.env) + + # check environment of record and related records + self.assertEqual(message.env, self.env) + self.assertEqual(message.discussion.env, self.env) + + # "migrate" message into demo_env, and check again + demo_message = message.sudo(demo) + self.assertEqual(demo_message.env, demo_env) + self.assertEqual(demo_message.discussion.env, demo_env) + + # assign record's parent to a record in demo_env + message.discussion = message.discussion.copy({'name': 'Copy'}) + + # both message and its parent field must be in self.env + self.assertEqual(message.env, self.env) + self.assertEqual(message.discussion.env, self.env) + + def test_24_reference(self): + """ test reference fields. """ + record = self.env['test_new_api.mixed'].create({}) + + # one may assign False or None + record.reference = None + self.assertFalse(record.reference) + + # one may assign a user or a partner... + record.reference = self.env.user + self.assertEqual(record.reference, self.env.user) + record.reference = self.env.user.partner_id + self.assertEqual(record.reference, self.env.user.partner_id) + # ... but no record from a model that starts with 'ir.' + with self.assertRaises(ValueError): + record.reference = self.env['ir.model'].search([], limit=1) + + def test_25_related(self): + """ test related fields. """ + message = self.env.ref('test_new_api.message_0_0') + discussion = message.discussion + + # by default related fields are not stored + field = message._fields['discussion_name'] + self.assertFalse(field.store) + self.assertTrue(field.readonly) + + # check value of related field + self.assertEqual(message.discussion_name, discussion.name) + + # change discussion name, and check result + discussion.name = 'Foo' + self.assertEqual(message.discussion_name, 'Foo') + + # change discussion name via related field, and check result + message.discussion_name = 'Bar' + self.assertEqual(discussion.name, 'Bar') + self.assertEqual(message.discussion_name, 'Bar') + + # search on related field, and check result + search_on_related = self.env['test_new_api.message'].search([('discussion_name', '=', 'Bar')]) + search_on_regular = self.env['test_new_api.message'].search([('discussion.name', '=', 'Bar')]) + self.assertEqual(search_on_related, search_on_regular) + + # check that field attributes are copied + message_field = message.fields_get(['discussion_name'])['discussion_name'] + discussion_field = discussion.fields_get(['name'])['name'] + self.assertEqual(message_field['help'], discussion_field['help']) + + def test_26_inherited(self): + """ test inherited fields. """ + # a bunch of fields are inherited from res_partner + for user in self.env['res.users'].search([]): + partner = user.partner_id + for field in ('is_company', 'name', 'email', 'country_id'): + self.assertEqual(getattr(user, field), getattr(partner, field)) + self.assertEqual(user[field], partner[field]) + + def test_30_read(self): + """ test computed fields as returned by read(). """ + discussion = self.env.ref('test_new_api.discussion_0') + + for message in discussion.messages: + display_name = message.display_name + size = message.size + + data = message.read(['display_name', 'size'])[0] + self.assertEqual(data['display_name'], display_name) + self.assertEqual(data['size'], size) + + def test_40_new(self): + """ test new records. """ + discussion = self.env.ref('test_new_api.discussion_0') + + # create a new message + message = self.env['test_new_api.message'].new() + self.assertFalse(message.id) + + # assign some fields; should have no side effect + message.discussion = discussion + message.body = BODY = "May the Force be with you." + self.assertEqual(message.discussion, discussion) + self.assertEqual(message.body, BODY) + + self.assertNotIn(message, discussion.messages) + + # check computed values of fields + user = self.env.user + self.assertEqual(message.author, user) + self.assertEqual(message.name, "[%s] %s" % (discussion.name, user.name)) + self.assertEqual(message.size, len(BODY)) + + def test_41_defaults(self): + """ test default values. """ + fields = ['discussion', 'body', 'author', 'size'] + defaults = self.env['test_new_api.message'].default_get(fields) + self.assertEqual(defaults, {'author': self.env.uid, 'size': 0}) + + defaults = self.env['test_new_api.mixed'].default_get(['number']) + self.assertEqual(defaults, {'number': 3.14}) + + +class TestMagicFields(common.TransactionCase): + + def test_write_date(self): + record = self.env['test_new_api.discussion'].create({'name': 'Booba'}) + self.assertEqual(record.create_uid, self.env.user) + self.assertEqual(record.write_uid, self.env.user) + + +class TestInherits(common.TransactionCase): + + def test_inherits(self): + """ Check that a many2one field with delegate=True adds an entry in _inherits """ + Talk = self.env['test_new_api.talk'] + self.assertEqual(Talk._inherits, {'test_new_api.discussion': 'parent'}) + self.assertIn('name', Talk._fields) + self.assertEqual(Talk._fields['name'].related, ('parent', 'name')) + + talk = Talk.create({'name': 'Foo'}) + discussion = talk.parent + self.assertTrue(discussion) + self.assertEqual(talk._name, 'test_new_api.talk') + self.assertEqual(discussion._name, 'test_new_api.discussion') + self.assertEqual(talk.name, discussion.name) |
