diff options
| author | Raphael Collet <rco@openerp.com> | 2016-05-04 14:18:34 +0200 |
|---|---|---|
| committer | Raphael Collet <rco@openerp.com> | 2016-05-11 11:40:25 +0200 |
| commit | 214a59845f253e1f6604c4fd737fd3e18a50d8a9 (patch) | |
| tree | 90c64e84c00b0eda6407c3355bbf3be6aff87234 | |
| parent | 47c44578baea30c75dcfe520bcea858287b2bb7b (diff) | |
[MIG] base/tests
Convert YAML tests into Python tests:
- translation tests moved to test_translate.py
- test phases tests moved to test_phase.py
- safe_eval tests moved to test_base.py
- parent_store tests moved to test_base.py
- float rounding tests moved to test_float.py
- `ir.rule` tests moved to test_acl.py
- search tests moved to test_expression.py
40 files changed, 2714 insertions, 3272 deletions
diff --git a/addons/mail/tests/test_ir_actions.py b/addons/mail/tests/test_ir_actions.py index bb08fdc7101..3748fdb715b 100644 --- a/addons/mail/tests/test_ir_actions.py +++ b/addons/mail/tests/test_ir_actions.py @@ -12,18 +12,17 @@ class TestServerActionsEmail(TestServerActionsBase): 'name': 'TestTemplate', 'email_from': 'myself@example.com', 'email_to': 'brigitte@example.com', - 'partner_to': '%s' % self.test_partner_id, - 'model_id': self.res_partner_model_id, + 'partner_to': '%s' % self.test_partner.id, + 'model_id': self.res_partner_model.id, 'subject': 'About ${object.name}', 'body_html': '<p>Dear ${object.name}, your parent is ${object.parent_id and object.parent_id.name or "False"}</p>', }) - action = self.env['ir.actions.server'].browse(self.act_id) - action.write({'state': 'email', 'template_id': email_template.id}) - run_res = action.with_context(self.context).run() + self.action.write({'state': 'email', 'template_id': email_template.id}) + run_res = self.action.with_context(self.context).run() self.assertFalse(run_res, 'ir_actions_server: email server action correctly finished should return False') # check an email is waiting for sending mail = self.env['mail.mail'].search([('subject', '=', 'About TestingPartner')]) - self.assertEqual(len(mail.ids), 1, 'ir_actions_server: TODO') + self.assertEqual(len(mail), 1, 'ir_actions_server: TODO') # check email content self.assertEqual(mail.body, '<p>Dear TestingPartner, your parent is False</p>', 'ir_actions_server: TODO') diff --git a/openerp/addons/base/__openerp__.py b/openerp/addons/base/__openerp__.py index 58d93fce011..4cd21782039 100644 --- a/openerp/addons/base/__openerp__.py +++ b/openerp/addons/base/__openerp__.py @@ -72,11 +72,7 @@ The kernel of Odoo, needed for all installation. 'res/res_partner_demo.yml', 'res/res_partner_image_demo.xml', ], - 'test': [ - 'tests/base_test.yml', - 'tests/test_osv_expression.yml', - 'tests/test_ir_rule.yml', # <-- These tests modify/add/delete ir_rules. - ], + 'test': [], 'installable': True, 'auto_install': True, 'post_init_hook': 'post_init', diff --git a/openerp/addons/base/tests/__init__.py b/openerp/addons/base/tests/__init__.py index e9414be9011..fbb2375f3c1 100644 --- a/openerp/addons/base/tests/__init__.py +++ b/openerp/addons/base/tests/__init__.py @@ -4,6 +4,7 @@ import test_base import test_basecase import test_db_cursor import test_expression +import test_float import test_func import test_ir_actions import test_ir_attachment @@ -16,6 +17,7 @@ import test_menu import test_orm import test_ormcache import test_osv +import test_phase import test_qweb import test_res_config import test_res_lang diff --git a/openerp/addons/base/tests/base_test.yml b/openerp/addons/base/tests/base_test.yml deleted file mode 100644 index c7ab7f06ae9..00000000000 --- a/openerp/addons/base/tests/base_test.yml +++ /dev/null @@ -1,337 +0,0 @@ -- | - To check that common dangerous operations are not allowed by the safe_eval mechanism, attempt to - evaluate unauthorized expressions, and verify that they trigger an error. -- - 1. Try a few common expressions to verify they work with safe_eval -- - !python {model: ir.model}: | - from openerp.tools.safe_eval import safe_eval - expected = (1, {"a": 9 * 2}, (True, False, None)) - actual = safe_eval('(1, {"a": 9 * 2}, (True, False, None))') - assert actual == expected, "Simple python expressions are not working with safe_eval" -- - 2. Try simple literal definition to verify it works with literal_eval -- - !python {model: ir.model}: | - import ast - expected = (1, {"a": 9}, (True, False, None)) - actual = ast.literal_eval('(1, {"a": 9}, (True, False, None))') - assert actual == expected, "Simple python expressions are not working with literal_eval" -- - 3. Try arithmetic expression in literal_eval to verify it does not work -- - !python {model: ir.model}: | - import ast - try: - ast.literal_eval('(1, {"a": 2*9}, (True, False, None))') - assert False, "literal_eval should not accept arithmetic expressions" - except ValueError: - pass -- - 4. Try forbidden expressions in literal_eval to verify they are not allowed -- - !python {model: ir.model}: | - import ast - try: - ast.literal_eval('{"a": True.__class__}') - assert False, "literal_eval should accept only literals" - except ValueError: - pass -- - 5. Try forbidden expressions in safe_eval to verify they are not allowed (open) -- - !python {model: ir.model}: | - from openerp.tools.safe_eval import safe_eval - from openerp.tools.misc import mute_logger - try: - with mute_logger('openerp.tools.safe_eval'): - safe_eval('open("/etc/passwd","r")') - assert False, "safe_eval should not allow calling open() builtin" - except ValueError: - pass - -- - "ORM test: verify that parent_store computation are going right" -- - 0. Emulate normal behavior of tree structure storing -- - !python {model: res.partner.category}: | - # pretend the pool has finished loading to avoid deferring parent_store computation - self.pool._init = False - - # Force partner_categ.copy() to copy children - self._fields['child_ids'].copy = True - self._columns['child_ids'].copy = True -- - "1.0 Setup test partner categories: parent root" -- - !record {model: res.partner.category, id: test_categ_root}: - name: Root category -- - "1.1 Setup test partner categories: parent category" -- - !record {model: res.partner.category, id: test_categ_0}: - name: Parent category - parent_id: test_categ_root -- - "1.2 Setup test partner categories: child 1" -- - !record {model: res.partner.category, id: test_categ_1}: - name: Child 1 - parent_id: test_categ_0 -- - "1.3 Setup test partner categories: child 2" -- - !record {model: res.partner.category, id: test_categ_2}: - name: Child 2 - parent_id: test_categ_0 -- - "1.4 Setup test partner categories: child 2-1" -- - !record {model: res.partner.category, id: test_categ_21}: - name: Child 2-1 - parent_id: test_categ_2 -- - 2. Duplicate the parent category and verify that the children have been duplicated too and are below the new parent -- - !python {model: res.partner.category}: | - self._columns['child_ids'].copy = True # force copying children for test - new_id = self.copy(cr, uid, ref('test_categ_0')) - new_struct = self.search(cr, uid, [('parent_id', 'child_of', new_id)]) - assert len(new_struct) == 4, "After duplication, the new object must have the childs records" - old_struct = self.search(cr, uid, [('parent_id', 'child_of', ref('test_categ_0'))]) - assert len(old_struct) == 4, "After duplication, previous record must have old childs records only" - assert (not set(new_struct).intersection(old_struct)), "After duplication, nodes should not be mixed" -- - 3. Duplicate the children then reassign them to the new parent (1st method) and check the parent_store structure. -- - !python {model: res.partner.category}: | - new_child1_id = self.copy(cr, uid, ref('test_categ_1')) - new_child2_id = self.copy(cr, uid, ref('test_categ_2')) - new_id = self.copy(cr, uid, ref('test_categ_0'), {'child_ids': []}) - self.write(cr, uid, [new_child1_id, new_child2_id], {'parent_id': new_id}) - new_struct = self.search(cr, uid, [('parent_id', 'child_of', new_id)]) - assert len(new_struct) == 4, "After duplication, the new object must have the childs records" - old_struct = self.search(cr, uid, [('parent_id', 'child_of', ref('test_categ_0'))]) - assert len(old_struct) == 4, "After duplication, previous record must have old childs records only" - assert (not set(new_struct).intersection(old_struct)), "After duplication, nodes should not be mixed" -- - 4. Duplicate the children then reassign them to the new parent (2nd method) and check the parent_store structure. -- - !python {model: res.partner.category}: | - new_child1_id = self.copy(cr, uid, ref('test_categ_1')) - new_child2_id = self.copy(cr, uid, ref('test_categ_2')) - old_struct = self.search(cr, uid, [('parent_id', 'child_of', ref('test_categ_0'))]) - new_id = self.copy(cr, uid, ref('test_categ_0'), {'child_ids': [(6,0,[new_child1_id, new_child2_id])]}) - new_struct = self.search(cr, uid, [('parent_id', 'child_of', new_id)]) - assert len(new_struct) == 4, "After duplication, the new object must have the childs records" - old_struct = self.search(cr, uid, [('parent_id', 'child_of', ref('test_categ_0'))]) - assert len(old_struct) == 4, "After duplication, previous record must have old childs records only" - assert (not set(new_struct).intersection(old_struct)), "After duplication, nodes should not be mixed" -- - 5. Duplicate the children then reassign them to the new parent (3rd method) and make sure the parent_store structure is still right. -- - !python {model: res.partner.category}: | - new_child1_id = self.copy(cr, uid, ref('test_categ_1')) - new_child2_id = self.copy(cr, uid, ref('test_categ_2')) - new_id = self.copy(cr, uid, ref('test_categ_0'), {'child_ids': []}) - self.write(cr, uid, [new_id], {'child_ids': [(4,new_child1_id), (4,new_child2_id)]}) - new_struct = self.search(cr, uid, [('parent_id', 'child_of', new_id)]) - assert len(new_struct) == 4, "After duplication, the new object must have the childs records" - old_struct = self.search(cr, uid, [('parent_id', 'child_of', ref('test_categ_0'))]) - assert len(old_struct) == 4, "After duplication, previous record must have old childs records only" - assert (not set(new_struct).intersection(old_struct)), "After duplication, nodes should not be mixed" -- - 6. Restore pool state after the test -- - !python {model: res.partner.category}: | - self.pool._init = True - self._fields['child_ids'].copy = False - self._columns['child_ids'].copy = False - -- - "Float precision tests: verify that float rounding methods are working correctly via res.currency" -- - !python {model: res.currency}: | - from openerp.tools import float_repr - from math import log10 - currency = self.browse(cr, uid, ref('base.EUR')) - def try_round(amount, expected, self=self, cr=cr, currency=currency, float_repr=float_repr, - log10=log10): - digits = max(0,-int(log10(currency.rounding))) - result = float_repr(self.round(cr, 1, currency, amount), precision_digits=digits) - assert result == expected, 'Rounding error: got %s, expected %s' % (result, expected) - try_round(2.674,'2.67') - try_round(2.675,'2.68') # in Python 2.7.2, round(2.675,2) gives 2.67 - try_round(-2.675,'-2.68') # in Python 2.7.2, round(2.675,2) gives 2.67 - try_round(0.001,'0.00') - try_round(-0.001,'-0.00') - try_round(0.0049,'0.00') # 0.0049 is closer to 0 than to 0.01, so should round down - try_round(0.005,'0.01') # the rule is to round half away from zero - try_round(-0.005,'-0.01') # the rule is to round half away from zero - - def try_zero(amount, expected, self=self, cr=cr, currency=currency): - assert self.is_zero(cr, 1, currency, amount) == expected, "Rounding error: %s should be zero!" % amount - try_zero(0.01, False) - try_zero(-0.01, False) - try_zero(0.001, True) - try_zero(-0.001, True) - try_zero(0.0046, True) - try_zero(-0.0046, True) - try_zero(2.68-2.675, False) # 2.68 - 2.675 = 0.005 -> rounds to 0.01 - try_zero(2.68-2.676, True) # 2.68 - 2.675 = 0.004 -> rounds to 0.0 - try_zero(2.676-2.68, True) # 2.675 - 2.68 = -0.004 -> rounds to -0.0 - try_zero(2.675-2.68, False) # 2.675 - 2.68 = -0.005 -> rounds to -0.01 - - def try_compare(amount1, amount2, expected, self=self, cr=cr, currency=currency): - assert self.compare_amounts(cr, 1, currency, amount1, amount2) == expected, \ - "Rounding error, compare_amounts(%s,%s) should be %s" % (amount1, amount2, expected) - try_compare(0.001, 0.001, 0) - try_compare(-0.001, -0.001, 0) - try_compare(0.001, 0.002, 0) - try_compare(-0.001, -0.002, 0) - try_compare(2.675, 2.68, 0) - try_compare(2.676, 2.68, 0) - try_compare(-2.676, -2.68, 0) - try_compare(2.674, 2.68, -1) - try_compare(-2.674, -2.68, 1) - try_compare(3, 2.68, 1) - try_compare(-3, -2.68, -1) - try_compare(0.01, 0, 1) - try_compare(-0.01, 0, -1) - -- - "Float precision tests: verify that float rounding methods are working correctly via tools" -- - !python {model: res.currency}: | - from openerp.tools import float_compare, float_is_zero, float_round, float_repr - def try_round(amount, expected, precision_digits=3, float_round=float_round, float_repr=float_repr, rounding_method='HALF-UP'): - result = float_repr(float_round(amount, precision_digits=precision_digits, rounding_method=rounding_method), - precision_digits=precision_digits) - assert result == expected, 'Rounding error: got %s, expected %s' % (result, expected) - try_round(2.6745, '2.675') - try_round(-2.6745, '-2.675') - try_round(2.6744, '2.674') - try_round(-2.6744, '-2.674') - try_round(0.0004, '0.000') - try_round(-0.0004, '-0.000') - try_round(357.4555, '357.456') - try_round(-357.4555, '-357.456') - try_round(457.4554, '457.455') - try_round(-457.4554, '-457.455') - - # Try some rounding value with rounding method UP instead of HALF-UP - # We use 8.175 because when normalizing 8.175 with precision_digits=3 it gives - # us 8175,0000000001234 as value, and if not handle correctly the rounding UP - # value will be incorrect (should be 8,175 and not 8,176) - try_round(8.175, '8.175', rounding_method='UP') - try_round(8.1751, '8.176', rounding_method='UP') - try_round(-8.175, '-8.175', rounding_method='UP') - try_round(-8.1751, '-8.176', rounding_method='UP') - try_round(-6.000, '-6.000', rounding_method='UP') - try_round(1.8, '2', 0, rounding_method='UP') - try_round(-1.8, '-2', 0, rounding_method='UP') - - # Extended float range test, inspired by Cloves Almeida's test on bug #882036. - fractions = [.0, .015, .01499, .675, .67499, .4555, .4555, .45555] - expecteds = ['.00', '.02', '.01', '.68', '.67', '.46', '.456', '.4556'] - precisions = [2, 2, 2, 2, 2, 2, 3, 4] - # Note: max precision for double floats is 53 bits of precision or - # 17 significant decimal digits - for magnitude in range(7): - for i in xrange(len(fractions)): - frac, exp, prec = fractions[i], expecteds[i], precisions[i] - for sign in [-1,1]: - for x in xrange(0,10000,97): - n = x * 10**magnitude - f = sign * (n + frac) - f_exp = ('-' if f != 0 and sign == -1 else '') + str(n) + exp - try_round(f, f_exp, precision_digits=prec) - - - def try_zero(amount, expected, float_is_zero=float_is_zero): - assert float_is_zero(amount, precision_digits=3) == expected, "Rounding error: %s should be zero!" % amount - try_zero(0.0002, True) - try_zero(-0.0002, True) - try_zero(0.00034, True) - try_zero(0.0005, False) - try_zero(-0.0005, False) - try_zero(0.0008, False) - try_zero(-0.0008, False) - - def try_compare(amount1, amount2, expected, float_compare=float_compare): - assert float_compare(amount1, amount2, precision_digits=3) == expected, \ - "Rounding error, compare_amounts(%s,%s) should be %s" % (amount1, amount2, expected) - try_compare(0.0003, 0.0004, 0) - try_compare(-0.0003, -0.0004, 0) - try_compare(0.0002, 0.0005, -1) - try_compare(-0.0002, -0.0005, 1) - try_compare(0.0009, 0.0004, 1) - try_compare(-0.0009, -0.0004, -1) - try_compare(557.4555, 557.4556, 0) - try_compare(-557.4555, -557.4556, 0) - try_compare(657.4444, 657.445, -1) - try_compare(-657.4444, -657.445, 1) - - # Rounding to unusual rounding units (e.g. coin values) - def try_round(amount, expected, precision_rounding=None, float_round=float_round, float_repr=float_repr): - result = float_repr(float_round(amount, precision_rounding=precision_rounding), - precision_digits=2) - assert result == expected, 'Rounding error: got %s, expected %s' % (result, expected) - try_round(-457.4554, '-457.45', precision_rounding=0.05) - try_round(457.444, '457.50', precision_rounding=0.5) - try_round(457.3, '455.00', precision_rounding=5) - try_round(457.5, '460.00', precision_rounding=5) - try_round(457.1, '456.00', precision_rounding=3) - -- - "Float precision tests: check that proper rounding is performed for float persistence" -- - !python {model: res.currency}: | - currency = self.browse(cr, uid, ref('base.EUR')) - res_currency_rate = self.pool.get('res.currency.rate') - from openerp.tools import float_compare, float_is_zero, float_round, float_repr - def try_roundtrip(value, expected, self=self, cr=cr, currency=currency, - res_currency_rate=res_currency_rate): - rate_id = res_currency_rate.create(cr, 1, {'name':'2000-01-01', - 'rate': value, - 'currency_id': currency.id}) - rate = res_currency_rate.read(cr, 1, [rate_id], ['rate'])[0]['rate'] - assert rate == expected, 'Roundtrip error: got %s back from db, expected %s' % (rate, expected) - # res.currency.rate uses 6 digits of precision by default - try_roundtrip(2.6748955, 2.674896) - try_roundtrip(-2.6748955, -2.674896) - try_roundtrip(10000.999999, 10000.999999) - try_roundtrip(-10000.999999, -10000.999999) - -- - "Float precision tests: verify that invalid parameters are forbidden" -- - !python {model: res.currency}: | - from openerp.tools import float_compare, float_is_zero, float_round - try: - float_is_zero(0.01, precision_digits=3, precision_rounding=0.01) - except AssertionError: - pass - try: - float_compare(0.01, 0.02, precision_digits=3, precision_rounding=0.01) - except AssertionError: - pass - try: - float_round(0.01, precision_digits=3, precision_rounding=0.01) - except AssertionError: - pass -- - Test res.groups name search -- - !python {model: res.groups}: | - all_groups = self.search(cr, uid, []) - full_names = [(group.id, group.full_name) for group in self.browse(cr, uid, all_groups)] - group_ids = self.search(cr, uid, [('full_name', 'like', '%Sale%')]) - assert set(group_ids) == set([id for (id, full_name) in full_names if 'Sale' in full_name]), "did not match search for 'Sale'" - group_ids = self.search(cr, uid, [('full_name', 'like', '%Technical%')]) - assert set(group_ids) == set([id for (id, full_name) in full_names if 'Technical' in full_name]), "did not match search for 'Technical'" - group_ids = self.search(cr, uid, [('full_name', 'like', '%Sales /%')]) - assert set(group_ids) == set([id for (id, full_name) in full_names if 'Sales /' in full_name]), "did not match search for 'Sales /'" - group_ids = self.search(cr, uid, [('full_name', 'in', ['Administration / Access Rights','Contact Creation'])]) - assert group_ids, "did not match search for 'Administration / Access Rights' and 'Contact Creation'" diff --git a/openerp/addons/base/tests/test_acl.py b/openerp/addons/base/tests/test_acl.py index d1f5ccd4771..84e851add5b 100644 --- a/openerp/addons/base/tests/test_acl.py +++ b/openerp/addons/base/tests/test_acl.py @@ -1,26 +1,23 @@ -import unittest +# -*- coding: utf-8 -*- +# Part of Odoo. See LICENSE file for full copyright and licensing details. + from lxml import etree -from openerp.exceptions import AccessError -from openerp.tools.misc import mute_logger -from openerp.tests import common +from odoo.exceptions import AccessError +from odoo.tests.common import TransactionCase +from odoo.tools.misc import mute_logger # test group that demo user should not have +USER_DEMO = 'base.user_demo' GROUP_SYSTEM = 'base.group_system' -GROUP_ERP_MANAGER = 'base.group_erp_manager' -class TestACL(common.TransactionCase): +class TestACL(TransactionCase): def setUp(self): super(TestACL, self).setUp() - self.res_currency = self.registry('res.currency') - self.res_partner = self.registry('res.partner') - self.res_users = self.registry('res.users') - self.res_company = self.registry('res.company') - self.demo_uid = self.env.ref('base.user_demo').id + self.demo_user = self.env.ref(USER_DEMO) self.erp_system_group = self.env.ref(GROUP_SYSTEM) - self.erp_manager_group = self.env.ref(GROUP_ERP_MANAGER) def _set_field_groups(self, model, field_name, groups): field = model._fields[field_name] @@ -32,109 +29,103 @@ class TestACL(common.TransactionCase): def test_field_visibility_restriction(self): """Check that model-level ``groups`` parameter effectively restricts access to that field for users who do not belong to one of the explicitly allowed groups""" + currency = self.env['res.currency'].sudo(self.demo_user) + # Verify the test environment first - original_fields = self.res_currency.fields_get(self.cr, self.demo_uid, []) - form_view = self.res_currency.fields_view_get(self.cr, self.demo_uid, False, 'form') + original_fields = currency.fields_get([]) + form_view = currency.fields_view_get(False, 'form') view_arch = etree.fromstring(form_view.get('arch')) - has_group_system = self.res_users.has_group(self.cr, self.demo_uid, GROUP_SYSTEM) + has_group_system = self.demo_user.has_group(GROUP_SYSTEM) self.assertFalse(has_group_system, "`demo` user should not belong to the restricted group before the test") - self.assertTrue('decimal_places' in original_fields, "'decimal_places' field must be properly visible before the test") + self.assertIn('decimal_places', original_fields, "'decimal_places' field must be properly visible before the test") self.assertNotEquals(view_arch.xpath("//field[@name='decimal_places']"), [], "Field 'decimal_places' must be found in view definition before the test") # restrict access to the field and check it's gone - self._set_field_groups(self.res_currency, 'decimal_places', GROUP_SYSTEM) + self._set_field_groups(currency, 'decimal_places', GROUP_SYSTEM) - fields = self.res_currency.fields_get(self.cr, self.demo_uid, []) - form_view = self.res_currency.fields_view_get(self.cr, self.demo_uid, False, 'form') + fields = currency.fields_get([]) + form_view = currency.fields_view_get(False, 'form') view_arch = etree.fromstring(form_view.get('arch')) - self.assertFalse('decimal_places' in fields, "'decimal_places' field should be gone") + self.assertNotIn('decimal_places', fields, "'decimal_places' field should be gone") self.assertEquals(view_arch.xpath("//field[@name='decimal_places']"), [], "Field 'decimal_places' must not be found in view definition") # Make demo user a member of the restricted group and check that the field is back - self.erp_system_group.write({'users': [(4, self.demo_uid)]}) - has_group_system = self.res_users.has_group(self.cr, self.demo_uid, GROUP_SYSTEM) - fields = self.res_currency.fields_get(self.cr, self.demo_uid, []) - form_view = self.res_currency.fields_view_get(self.cr, self.demo_uid, False, 'form') + self.erp_system_group.users += self.demo_user + has_group_system = self.demo_user.has_group(GROUP_SYSTEM) + fields = currency.fields_get([]) + form_view = currency.fields_view_get(False, 'form') view_arch = etree.fromstring(form_view.get('arch')) - #import pprint; pprint.pprint(fields); pprint.pprint(form_view) self.assertTrue(has_group_system, "`demo` user should now belong to the restricted group") - self.assertTrue('decimal_places' in fields, "'decimal_places' field must be properly visible again") + self.assertIn('decimal_places', fields, "'decimal_places' field must be properly visible again") self.assertNotEquals(view_arch.xpath("//field[@name='decimal_places']"), [], "Field 'decimal_places' must be found in view definition again") - #cleanup - self.erp_system_group.write({'users': [(3, self.demo_uid)]}) - @mute_logger('openerp.models') def test_field_crud_restriction(self): "Read/Write RPC access to restricted field should be forbidden" + partner = self.env['res.partner'].browse(1).sudo(self.demo_user) + # Verify the test environment first - has_group_system = self.res_users.has_group(self.cr, self.demo_uid, GROUP_SYSTEM) + has_group_system = self.demo_user.has_group(GROUP_SYSTEM) self.assertFalse(has_group_system, "`demo` user should not belong to the restricted group") - self.assert_(self.res_partner.read(self.cr, self.demo_uid, [1], ['bank_ids'])) - self.assert_(self.res_partner.write(self.cr, self.demo_uid, [1], {'bank_ids': []})) + self.assert_(partner.read(['bank_ids'])) + self.assert_(partner.write({'bank_ids': []})) # Now restrict access to the field and check it's forbidden - self._set_field_groups(self.res_partner, 'bank_ids', GROUP_SYSTEM) + self._set_field_groups(partner, 'bank_ids', GROUP_SYSTEM) with self.assertRaises(AccessError): - self.res_partner.read(self.cr, self.demo_uid, [1], ['bank_ids']) + partner.read(['bank_ids']) with self.assertRaises(AccessError): - self.res_partner.write(self.cr, self.demo_uid, [1], {'bank_ids': []}) + partner.write({'bank_ids': []}) # Add the restricted group, and check that it works again - self.erp_system_group.write({'users': [(4, self.demo_uid)]}) - has_group_system = self.res_users.has_group(self.cr, self.demo_uid, GROUP_SYSTEM) + self.erp_system_group.users += self.demo_user + has_group_system = self.demo_user.has_group(GROUP_SYSTEM) self.assertTrue(has_group_system, "`demo` user should now belong to the restricted group") - self.assert_(self.res_partner.read(self.cr, self.demo_uid, [1], ['bank_ids'])) - self.assert_(self.res_partner.write(self.cr, self.demo_uid, [1], {'bank_ids': []})) - - #cleanup - self.erp_system_group.write({'users': [(3, self.demo_uid)]}) + self.assert_(partner.read(['bank_ids'])) + self.assert_(partner.write({'bank_ids': []})) @mute_logger('openerp.models') def test_fields_browse_restriction(self): """Test access to records having restricted fields""" - self._set_field_groups(self.res_partner, 'email', GROUP_SYSTEM) + partner = self.env['res.partner'].sudo(self.demo_user) + self._set_field_groups(partner, 'email', GROUP_SYSTEM) - pid = self.res_partner.search(self.cr, self.demo_uid, [], limit=1)[0] - part = self.res_partner.browse(self.cr, self.demo_uid, pid) # accessing fields must no raise exceptions... - part.name + partner = partner.search([], limit=1) + partner.name # ... except if they are restricted - with self.assertRaises(AccessError) as cm: + with self.assertRaises(AccessError): with mute_logger('openerp.models'): - part.email - - #Useless because we get the title in the client side now in the chrome.js file(map_title) - #self.assertEqual(cm.exception.args[0], 'Access Error') + partner.email def test_view_create_edit_button_invisibility(self): """ Test form view Create, Edit, Delete button visibility based on access right of model""" methods = ['create', 'edit', 'delete'] - company_view = self.res_company.fields_view_get(self.cr, self.demo_uid, False, 'form') + company = self.env['res.company'].sudo(self.demo_user) + company_view = company.fields_view_get(False, 'form') view_arch = etree.fromstring(company_view['arch']) for method in methods: self.assertEqual(view_arch.get(method), 'false') def test_view_create_edit_button_visibility(self): """ Test form view Create, Edit, Delete button visibility based on access right of model""" + self.erp_system_group.users += self.demo_user methods = ['create', 'edit', 'delete'] - self.erp_manager_group.write({'users': [(4, self.demo_uid)]}) - company_view = self.res_company.fields_view_get(self.cr, self.demo_uid, False, 'form') + company = self.env['res.company'].sudo(self.demo_user) + company_view = company.fields_view_get(False, 'form') view_arch = etree.fromstring(company_view['arch']) for method in methods: self.assertIsNone(view_arch.get(method)) - # cleanup - self.erp_manager_group.write({'users': [(3, self.demo_uid)]}) def test_m2o_field_create_edit_invisibility(self): """ Test many2one field Create and Edit option visibility based on access rights of relation field""" methods = ['create', 'write'] - - company_view = self.res_company.fields_view_get(self.cr, self.demo_uid, False, 'form') + company = self.env['res.company'].sudo(self.demo_user) + company_view = company.fields_view_get(False, 'form') view_arch = etree.fromstring(company_view['arch']) field_node = view_arch.xpath("//field[@name='currency_id']") self.assertTrue(len(field_node), "currency_id field should be in company from view") @@ -143,17 +134,125 @@ class TestACL(common.TransactionCase): def test_m2o_field_create_edit_visibility(self): """ Test many2one field Create and Edit option visibility based on access rights of relation field""" + self.erp_system_group.users += self.demo_user methods = ['create', 'write'] - - self.erp_system_group.write({'users': [(4, self.demo_uid)]}) - company_view = self.res_company.fields_view_get(self.cr, self.demo_uid, False, 'form') + company = self.env['res.company'].sudo(self.demo_user) + company_view = company.fields_view_get(False, 'form') view_arch = etree.fromstring(company_view['arch']) field_node = view_arch.xpath("//field[@name='currency_id']") self.assertTrue(len(field_node), "currency_id field should be in company from view") for method in methods: self.assertEqual(field_node[0].get('can_' + method), 'true') - # cleanup - self.erp_manager_group.write({'users': [(3, self.demo_uid)]}) -if __name__ == '__main__': - unittest.main() + +class TestIrRule(TransactionCase): + + def test_ir_rule(self): + model_res_partner = self.env.ref('base.model_res_partner') + group_user = self.env.ref('base.group_user') + user_demo = self.env.ref('base.user_demo') + + # create an ir_rule for the Employee group with an blank domain + rule1 = self.env['ir.rule'].create({ + 'name': 'test_rule1', + 'model_id': model_res_partner.id, + 'domain_force': False, + 'groups': [(6, 0, group_user.ids)], + }) + + # read as demo user the partners (one blank domain) + partners_demo = self.env['res.partner'].sudo(user_demo) + partners = partners_demo.search([]) + self.assertTrue(partners, "Demo user should see some partner.") + + # same with domain 1=1 + rule1.domain_force = "[(1,'=',1)]" + partners = partners_demo.search([]) + self.assertTrue(partners, "Demo user should see some partner.") + + # same with domain [] + rule1.domain_force = "[]" + partners = partners_demo.search([]) + self.assertTrue(partners, "Demo user should see some partner.") + + # create another ir_rule for the Employee group (to test multiple rules) + rule2 = self.env['ir.rule'].create({ + 'name': 'test_rule2', + 'model_id': model_res_partner.id, + 'domain_force': False, + 'groups': [(6, 0, group_user.ids)], + }) + + # read as demo user with domains [] and blank + partners = partners_demo.search([]) + self.assertTrue(partners, "Demo user should see some partner.") + + # same with domains 1=1 and blank + rule1.domain_force = "[(1,'=',1)]" + partners = partners_demo.search([]) + self.assertTrue(partners, "Demo user should see some partner.") + + # same with domains 1=1 and 1=1 + rule2.domain_force = "[(1,'=',1)]" + partners = partners_demo.search([]) + self.assertTrue(partners, "Demo user should see some partner.") + + # create another ir_rule for the Employee group (to test multiple rules) + rule3 = self.env['ir.rule'].create({ + 'name': 'test_rule3', + 'model_id': model_res_partner.id, + 'domain_force': False, + 'groups': [(6, 0, group_user.ids)], + }) + + # read the partners as demo user + partners = partners_demo.search([]) + self.assertTrue(partners, "Demo user should see some partner.") + + # same with domains 1=1, 1=1 and 1=1 + rule3.domain_force = "[(1,'=',1)]" + partners = partners_demo.search([]) + self.assertTrue(partners, "Demo user should see some partner.") + + # modify the global rule on res_company which triggers a recursive check + # of the rules on company + global_rule = self.env.ref('base.res_company_rule_employee') + global_rule.domain_force = "[('id','child_of',[user.company_id.id])]" + + # read as demo user (exercising the global company rule) + partners = partners_demo.search([]) + self.assertTrue(partners, "Demo user should see some partner.") + + # Modify the ir_rule for employee to have a rule that fordids seeing any + # record. We use a domain with implicit AND operator for later tests on + # normalization. + rule2.domain_force = "[('id','=',False),('name','=',False)]" + + # check that demo user still sees partners, because group-rules are OR'ed + partners = partners_demo.search([]) + self.assertTrue(partners, "Demo user should see some partner.") + + # create a new group with demo user in it, and a complex rule + group_test = self.env['res.groups'].create({ + 'name': 'Test Group', + 'users': [(6, 0, user_demo.ids)], + }) + + # add the rule to the new group, with a domain containing an implicit + # AND operator, which is more tricky because it will have to be + # normalized before combining it + rule3.write({ + 'domain_force': "[('name','!=',False),('id','!=',False)]", + 'groups': [(6, 0, group_test.ids)], + }) + + # read the partners again as demo user, which should give results + partners = partners_demo.search([]) + self.assertTrue(partners, "Demo user should see partners even with the combined rules.") + + # delete global domains (to combine only group domains) + self.env['ir.rule'].search([('groups', '=', False)]).unlink() + + # read the partners as demo user (several group domains, no global domain) + partners = partners_demo.search([]) + self.assertTrue(partners, "Demo user should see some partners.") diff --git a/openerp/addons/base/tests/test_api.py b/openerp/addons/base/tests/test_api.py index 645c5d4ad9b..2c08f9c688c 100644 --- a/openerp/addons/base/tests/test_api.py +++ b/openerp/addons/base/tests/test_api.py @@ -1,8 +1,10 @@ +# -*- coding: utf-8 -*- +# Part of Odoo. See LICENSE file for full copyright and licensing details. -from openerp import models -from openerp.tools import mute_logger -from openerp.tests import common -from openerp.exceptions import AccessError +from odoo import models +from odoo.tools import mute_logger +from odoo.tests import common +from odoo.exceptions import AccessError class TestAPI(common.TransactionCase): @@ -84,7 +86,7 @@ class TestAPI(common.TransactionCase): 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}) + partners.write({'active': False}) self.assertEqual(ids, map(int, partners)) # redo the search, and check that the result is now empty @@ -94,7 +96,7 @@ class TestAPI(common.TransactionCase): @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) + user = self.env.user self.assertIsRecord(user, 'res.users') self.assertIsRecord(user.partner_id, 'res.partner') self.assertIsRecordset(user.groups_id, 'res.groups') diff --git a/openerp/addons/base/tests/test_base.py b/openerp/addons/base/tests/test_base.py index bbd54efa2e9..45910803b95 100644 --- a/openerp/addons/base/tests/test_base.py +++ b/openerp/addons/base/tests/test_base.py @@ -1,80 +1,113 @@ +# -*- coding: utf-8 -*- +# Part of Odoo. See LICENSE file for full copyright and licensing details. + +import ast import unittest -import openerp.tests.common as common -from openerp.exceptions import ValidationError +from odoo.exceptions import ValidationError +from odoo.tests.common import TransactionCase +from odoo.tools import mute_logger +from odoo.tools.safe_eval import safe_eval -class test_base(common.TransactionCase): - def setUp(self): - super(test_base,self).setUp() - self.res_partner = self.registry('res.partner') - self.res_users = self.registry('res.users') - self.res_partner_title = self.registry('res.partner.title') - - # samples use effective TLDs from the Mozilla public suffix - # list at http://publicsuffix.org - self.samples = [ - ('"Raoul Grosbedon" <raoul@chirurgiens-dentistes.fr> ', 'Raoul Grosbedon', 'raoul@chirurgiens-dentistes.fr'), - ('ryu+giga-Sushi@aizubange.fukushima.jp', '', 'ryu+giga-Sushi@aizubange.fukushima.jp'), - ('Raoul chirurgiens-dentistes.fr', 'Raoul chirurgiens-dentistes.fr', ''), - (" Raoul O'hara <!@historicalsociety.museum>", "Raoul O'hara", '!@historicalsociety.museum') - ] +class TestSafeEval(unittest.TestCase): + + def test_01_safe_eval(self): + """ Try a few common expressions to verify they work with safe_eval """ + expected = (1, {"a": 9 * 2}, (True, False, None)) + actual = safe_eval('(1, {"a": 9 * 2}, (True, False, None))') + self.assertEqual(actual, expected, "Simple python expressions are not working with safe_eval") + + def test_02_literal_eval(self): + """ Try simple literal definition to verify it works with literal_eval """ + expected = (1, {"a": 9}, (True, False, None)) + actual = ast.literal_eval('(1, {"a": 9}, (True, False, None))') + self.assertEqual(actual, expected, "Simple python expressions are not working with literal_eval") + + def test_03_literal_eval_arithmetic(self): + """ Try arithmetic expression in literal_eval to verify it does not work """ + with self.assertRaises(ValueError): + ast.literal_eval('(1, {"a": 2*9}, (True, False, None))') + + def test_04_literal_eval_forbidden(self): + """ Try forbidden expressions in literal_eval to verify they are not allowed """ + with self.assertRaises(ValueError): + ast.literal_eval('{"a": True.__class__}') + + @mute_logger('openerp.tools.safe_eval') + def test_05_safe_eval_forbiddon(self): + """ Try forbidden expressions in safe_eval to verify they are not allowed (open) """ + with self.assertRaises(ValueError): + safe_eval('open("/etc/passwd","r")') + + +# samples use effective TLDs from the Mozilla public suffix +# list at http://publicsuffix.org +SAMPLES = [ + ('"Raoul Grosbedon" <raoul@chirurgiens-dentistes.fr> ', 'Raoul Grosbedon', 'raoul@chirurgiens-dentistes.fr'), + ('ryu+giga-Sushi@aizubange.fukushima.jp', '', 'ryu+giga-Sushi@aizubange.fukushima.jp'), + ('Raoul chirurgiens-dentistes.fr', 'Raoul chirurgiens-dentistes.fr', ''), + (" Raoul O'hara <!@historicalsociety.museum>", "Raoul O'hara", '!@historicalsociety.museum'), +] + +class TestBase(TransactionCase): def test_00_res_partner_name_create(self): - cr, uid = self.cr, self.uid - parse = self.res_partner._parse_partner_name - for text, name, mail in self.samples: - self.assertEqual((name,mail), parse(text), 'Partner name parsing failed') - partner_id, dummy = self.res_partner.name_create(cr, uid, text) - partner = self.res_partner.browse(cr, uid, partner_id) + res_partner = self.env['res.partner'] + parse = res_partner._parse_partner_name + for text, name, mail in SAMPLES: + self.assertEqual((name, mail), parse(text), 'Partner name parsing failed') + partner_id, dummy = res_partner.name_create(text) + partner = res_partner.browse(partner_id) self.assertEqual(name or mail, partner.name, 'Partner name incorrect') self.assertEqual(mail or False, partner.email, 'Partner email incorrect') def test_10_res_partner_find_or_create(self): - cr,uid = self.cr, self.uid - email = self.samples[0][0] - partner_id, dummy = self.res_partner.name_create(cr, uid, email) - found_id = self.res_partner.find_or_create(cr, uid, email) + res_partner = self.env['res.partner'] + email = SAMPLES[0][0] + partner_id, dummy = res_partner.name_create(email) + found_id = res_partner.find_or_create(email) self.assertEqual(partner_id, found_id, 'find_or_create failed') - partner_id2, dummy2 = self.res_partner.name_create(cr, uid, 'sarah.john@connor.com') - found_id2 = self.res_partner.find_or_create(cr, uid, 'john@connor.com') + partner_id2, dummy2 = res_partner.name_create('sarah.john@connor.com') + found_id2 = res_partner.find_or_create('john@connor.com') self.assertNotEqual(partner_id2, found_id2, 'john@connor.com match sarah.john@connor.com') - new_id = self.res_partner.find_or_create(cr, uid, self.samples[1][0]) + new_id = res_partner.find_or_create(SAMPLES[1][0]) self.assertTrue(new_id > partner_id, 'find_or_create failed - should have created new one') - new_id2 = self.res_partner.find_or_create(cr, uid, self.samples[2][0]) + new_id2 = res_partner.find_or_create(SAMPLES[2][0]) self.assertTrue(new_id2 > new_id, 'find_or_create failed - should have created new one again') def test_15_res_partner_name_search(self): - cr,uid = self.cr, self.uid - for name, active in [ + res_partner = self.env['res.partner'] + DATA = [ ('"A Raoul Grosbedon" <raoul@chirurgiens-dentistes.fr>', False), ('B Raoul chirurgiens-dentistes.fr', True), ("C Raoul O'hara <!@historicalsociety.museum>", True), ('ryu+giga-Sushi@aizubange.fukushima.jp', True), - ]: - partner_id, dummy = self.res_partner.name_create(cr, uid, name, context={'default_active': active}) - partners = self.res_partner.name_search(cr, uid, 'Raoul') + ] + for name, active in DATA: + partner_id, dummy = res_partner.with_context(default_active=active).name_create(name) + partners = res_partner.name_search('Raoul') self.assertEqual(len(partners), 2, 'Incorrect search number result for name_search') - partners = self.res_partner.name_search(cr, uid, 'Raoul', limit=1) + partners = res_partner.name_search('Raoul', limit=1) self.assertEqual(len(partners), 1, 'Incorrect search number result for name_search with a limit') self.assertEqual(partners[0][1], 'B Raoul chirurgiens-dentistes.fr', 'Incorrect partner returned, should be the first active') def test_20_res_partner_address_sync(self): - cr, uid = self.cr, self.uid - ghoststep = self.res_partner.browse(cr, uid, self.res_partner.create(cr, uid, - {'name': 'GhostStep', - 'is_company': True, - 'street': 'Main Street, 10', - 'phone': '123456789', - 'email': 'info@ghoststep.com', - 'vat': 'BE0477472701', - 'type': 'contact'})) - p1 = self.res_partner.browse(cr, uid, self.res_partner.name_create(cr, uid, 'Denis Bladesmith <denis.bladesmith@ghoststep.com>')[0]) + res_partner = self.env['res.partner'] + ghoststep = res_partner.create({ + 'name': 'GhostStep', + 'is_company': True, + 'street': 'Main Street, 10', + 'phone': '123456789', + 'email': 'info@ghoststep.com', + 'vat': 'BE0477472701', + 'type': 'contact', + }) + p1 = res_partner.browse(res_partner.name_create('Denis Bladesmith <denis.bladesmith@ghoststep.com>')[0]) self.assertEqual(p1.type, 'contact', 'Default type must be "contact"') p1phone = '123456789#34' p1.write({'phone': p1phone, 'parent_id': ghoststep.id}) - p1.refresh() self.assertEqual(p1.street, ghoststep.street, 'Address fields must be synced') self.assertEqual(p1.phone, p1phone, 'Phone should be preserved after address sync') self.assertEqual(p1.type, 'contact', 'Type should be preserved after address sync') @@ -84,13 +117,11 @@ class test_base(common.TransactionCase): p1street = 'Different street, 42' p1.write({'street': p1street, 'type': 'invoice'}) - p1.refresh(), ghoststep.refresh() self.assertEqual(p1.street, p1street, 'Address fields must not be synced after turning sync off') self.assertNotEqual(ghoststep.street, p1street, 'Parent address must never be touched') # turn on sync again p1.write({'type': 'contact'}) - p1.refresh() self.assertEqual(p1.street, ghoststep.street, 'Address fields must be synced again') self.assertEqual(p1.phone, p1phone, 'Phone should be preserved after address sync') self.assertEqual(p1.type, 'contact', 'Type should be preserved after address sync') @@ -99,213 +130,197 @@ class test_base(common.TransactionCase): # Modify parent, sync to children ghoststreet = 'South Street, 25' ghoststep.write({'street': ghoststreet}) - p1.refresh() self.assertEqual(p1.street, ghoststreet, 'Address fields must be synced automatically') self.assertEqual(p1.phone, p1phone, 'Phone should not be synced') self.assertEqual(p1.email, 'denis.bladesmith@ghoststep.com', 'Email should be preserved after sync') p1street = 'My Street, 11' p1.write({'street': p1street}) - ghoststep.refresh() self.assertEqual(ghoststep.street, ghoststreet, 'Touching contact should never alter parent') def test_30_res_partner_first_contact_sync(self): """ Test initial creation of company/contact pair where contact address gets copied to company """ - cr, uid = self.cr, self.uid - ironshield = self.res_partner.browse(cr, uid, self.res_partner.name_create(cr, uid, 'IronShield')[0]) + res_partner = self.env['res.partner'] + ironshield = res_partner.browse(res_partner.name_create('IronShield')[0]) self.assertFalse(ironshield.is_company, 'Partners are not companies by default') self.assertEqual(ironshield.type, 'contact', 'Default type must be "contact"') ironshield.write({'type': 'contact'}) - p1 = self.res_partner.browse(cr, uid, self.res_partner.create(cr, uid, - {'name': 'Isen Hardearth', - 'street': 'Strongarm Avenue, 12', - 'parent_id': ironshield.id})) + + p1 = res_partner.create({ + 'name': 'Isen Hardearth', + 'street': 'Strongarm Avenue, 12', + 'parent_id': ironshield.id, + }) self.assertEquals(p1.type, 'contact', 'Default type must be "contact", not the copied parent type') - ironshield.refresh() self.assertEqual(ironshield.street, p1.street, 'Address fields should be copied to company') - def test_40_res_partner_address_getc(self): + def test_40_res_partner_address_get(self): """ Test address_get address resolution mechanism: it should first go down through descendants, stopping when encountering another is_copmany entity, then go up, stopping again at the first is_company entity or the root ancestor and if nothing matches, it should use the provided partner itself """ - cr, uid = self.cr, self.uid - elmtree = self.res_partner.browse(cr, uid, self.res_partner.name_create(cr, uid, 'Elmtree')[0]) - branch1 = self.res_partner.browse(cr, uid, self.res_partner.create(cr, uid, {'name': 'Branch 1', - 'parent_id': elmtree.id, - 'is_company': True})) - leaf10 = self.res_partner.browse(cr, uid, self.res_partner.create(cr, uid, {'name': 'Leaf 10', - 'parent_id': branch1.id, - 'type': 'invoice'})) - branch11 = self.res_partner.browse(cr, uid, self.res_partner.create(cr, uid, {'name': 'Branch 11', - 'parent_id': branch1.id, - 'type': 'other'})) - leaf111 = self.res_partner.browse(cr, uid, self.res_partner.create(cr, uid, {'name': 'Leaf 111', - 'parent_id': branch11.id, - 'type': 'delivery'})) + res_partner = self.env['res.partner'] + elmtree = res_partner.browse(res_partner.name_create('Elmtree')[0]) + branch1 = res_partner.create({'name': 'Branch 1', + 'parent_id': elmtree.id, + 'is_company': True}) + leaf10 = res_partner.create({'name': 'Leaf 10', + 'parent_id': branch1.id, + 'type': 'invoice'}) + branch11 = res_partner.create({'name': 'Branch 11', + 'parent_id': branch1.id, + 'type': 'other'}) + leaf111 = res_partner.create({'name': 'Leaf 111', + 'parent_id': branch11.id, + 'type': 'delivery'}) branch11.write({'is_company': False}) # force is_company after creating 1rst child - branch2 = self.res_partner.browse(cr, uid, self.res_partner.create(cr, uid, {'name': 'Branch 2', - 'parent_id': elmtree.id, - 'is_company': True})) - leaf21 = self.res_partner.browse(cr, uid, self.res_partner.create(cr, uid, {'name': 'Leaf 21', - 'parent_id': branch2.id, - 'type': 'delivery'})) - leaf22 = self.res_partner.browse(cr, uid, self.res_partner.create(cr, uid, {'name': 'Leaf 22', - 'parent_id': branch2.id})) - leaf23 = self.res_partner.browse(cr, uid, self.res_partner.create(cr, uid, {'name': 'Leaf 23', - 'parent_id': branch2.id, - 'type': 'contact'})) + branch2 = res_partner.create({'name': 'Branch 2', + 'parent_id': elmtree.id, + 'is_company': True}) + leaf21 = res_partner.create({'name': 'Leaf 21', + 'parent_id': branch2.id, + 'type': 'delivery'}) + leaf22 = res_partner.create({'name': 'Leaf 22', + 'parent_id': branch2.id}) + leaf23 = res_partner.create({'name': 'Leaf 23', + 'parent_id': branch2.id, + 'type': 'contact'}) # go up, stop at branch1 - self.assertEqual(self.res_partner.address_get(cr, uid, [leaf111.id], ['delivery', 'invoice', 'contact', 'other']), + self.assertEqual(leaf111.address_get(['delivery', 'invoice', 'contact', 'other']), {'delivery': leaf111.id, 'invoice': leaf10.id, 'contact': branch1.id, 'other': branch11.id}, 'Invalid address resolution') - self.assertEqual(self.res_partner.address_get(cr, uid, [branch11.id], ['delivery', 'invoice', 'contact', 'other']), + self.assertEqual(branch11.address_get(['delivery', 'invoice', 'contact', 'other']), {'delivery': leaf111.id, 'invoice': leaf10.id, 'contact': branch1.id, 'other': branch11.id}, 'Invalid address resolution') # go down, stop at at all child companies - self.assertEqual(self.res_partner.address_get(cr, uid, [elmtree.id], ['delivery', 'invoice', 'contact', 'other']), + self.assertEqual(elmtree.address_get(['delivery', 'invoice', 'contact', 'other']), {'delivery': elmtree.id, 'invoice': elmtree.id, 'contact': elmtree.id, 'other': elmtree.id}, 'Invalid address resolution') # go down through children - self.assertEqual(self.res_partner.address_get(cr, uid, [branch1.id], ['delivery', 'invoice', 'contact', 'other']), + self.assertEqual(branch1.address_get(['delivery', 'invoice', 'contact', 'other']), {'delivery': leaf111.id, 'invoice': leaf10.id, 'contact': branch1.id, 'other': branch11.id}, 'Invalid address resolution') - self.assertEqual(self.res_partner.address_get(cr, uid, [branch2.id], ['delivery', 'invoice', 'contact', 'other']), + self.assertEqual(branch2.address_get(['delivery', 'invoice', 'contact', 'other']), {'delivery': leaf21.id, 'invoice': branch2.id, 'contact': branch2.id, 'other': branch2.id}, 'Invalid address resolution. Company is the first encountered contact, therefore default for unfound addresses.') # go up then down through siblings - self.assertEqual(self.res_partner.address_get(cr, uid, [leaf21.id], ['delivery', 'invoice', 'contact', 'other']), + self.assertEqual(leaf21.address_get(['delivery', 'invoice', 'contact', 'other']), {'delivery': leaf21.id, 'invoice': branch2.id, 'contact': branch2.id, 'other': branch2.id}, 'Invalid address resolution, should scan commercial entity ancestor and its descendants') - self.assertEqual(self.res_partner.address_get(cr, uid, [leaf22.id], ['delivery', 'invoice', 'contact', 'other']), + self.assertEqual(leaf22.address_get(['delivery', 'invoice', 'contact', 'other']), {'delivery': leaf21.id, 'invoice': leaf22.id, 'contact': leaf22.id, 'other': leaf22.id}, 'Invalid address resolution, should scan commercial entity ancestor and its descendants') - self.assertEqual(self.res_partner.address_get(cr, uid, [leaf23.id], ['delivery', 'invoice', 'contact', 'other']), + self.assertEqual(leaf23.address_get(['delivery', 'invoice', 'contact', 'other']), {'delivery': leaf21.id, 'invoice': leaf23.id, 'contact': leaf23.id, 'other': leaf23.id}, 'Invalid address resolution, `default` should only override if no partner with specific type exists') # empty adr_pref means only 'contact' - self.assertEqual(self.res_partner.address_get(cr, uid, [elmtree.id], []), + self.assertEqual(elmtree.address_get([]), {'contact': elmtree.id}, 'Invalid address resolution, no contact means commercial entity ancestor') - self.assertEqual(self.res_partner.address_get(cr, uid, [leaf111.id], []), + self.assertEqual(leaf111.address_get([]), {'contact': branch1.id}, 'Invalid address resolution, no contact means finding contact in ancestors') branch11.write({'type': 'contact'}) - self.assertEqual(self.res_partner.address_get(cr, uid, [leaf111.id], []), + self.assertEqual(leaf111.address_get([]), {'contact': branch11.id}, 'Invalid address resolution, branch11 should now be contact') - - def test_50_res_partner_commercial_sync(self): - cr, uid = self.cr, self.uid - p0 = self.res_partner.browse(cr, uid, self.res_partner.create(cr, uid, - {'name': 'Sigurd Sunknife', - 'email': 'ssunknife@gmail.com'})) - sunhelm = self.res_partner.browse(cr, uid, self.res_partner.create(cr, uid, - {'name': 'Sunhelm', - 'is_company': True, - 'street': 'Rainbow Street, 13', - 'phone': '1122334455', - 'email': 'info@sunhelm.com', - 'vat': 'BE0477472701', - 'child_ids': [(4, p0.id), - (0, 0, {'name': 'Alrik Greenthorn', - 'email': 'agr@sunhelm.com'})], - })) - p1 = self.res_partner.browse(cr, uid, self.res_partner.create(cr, uid, - {'name': 'Otto Blackwood', - 'email': 'otto.blackwood@sunhelm.com', - 'parent_id': sunhelm.id})) - p11 = self.res_partner.browse(cr, uid, self.res_partner.create(cr, uid, - {'name': 'Gini Graywool', - 'email': 'ggr@sunhelm.com', - 'parent_id': p1.id})) - p2 = self.res_partner.browse(cr, uid, self.res_partner.search(cr, uid, - [('email', '=', 'agr@sunhelm.com')])[0]) - self.res_partner.write(cr, uid, sunhelm.id, {'child_ids': [(0, 0, {'name': 'Ulrik Greenthorn', - 'email': 'ugr@sunhelm.com'})]}) - p3 = self.res_partner.browse(cr, uid, self.res_partner.search(cr, uid, - [('email', '=', 'ugr@sunhelm.com')])[0]) + def test_50_res_partner_commercial_sync(self): + res_partner = self.env['res.partner'] + p0 = res_partner.create({'name': 'Sigurd Sunknife', + 'email': 'ssunknife@gmail.com'}) + sunhelm = res_partner.create({'name': 'Sunhelm', + 'is_company': True, + 'street': 'Rainbow Street, 13', + 'phone': '1122334455', + 'email': 'info@sunhelm.com', + 'vat': 'BE0477472701', + 'child_ids': [(4, p0.id), + (0, 0, {'name': 'Alrik Greenthorn', + 'email': 'agr@sunhelm.com'})]}) + p1 = res_partner.create({'name': 'Otto Blackwood', + 'email': 'otto.blackwood@sunhelm.com', + 'parent_id': sunhelm.id}) + p11 = res_partner.create({'name': 'Gini Graywool', + 'email': 'ggr@sunhelm.com', + 'parent_id': p1.id}) + p2 = res_partner.search([('email', '=', 'agr@sunhelm.com')], limit=1) + sunhelm.write({'child_ids': [(0, 0, {'name': 'Ulrik Greenthorn', + 'email': 'ugr@sunhelm.com'})]}) + p3 = res_partner.search([('email', '=', 'ugr@sunhelm.com')], limit=1) for p in (p0, p1, p11, p2, p3): - p.refresh() self.assertEquals(p.commercial_partner_id, sunhelm, 'Incorrect commercial entity resolution') self.assertEquals(p.vat, sunhelm.vat, 'Commercial fields must be automatically synced') sunhelmvat = 'BE0123456789' sunhelm.write({'vat': sunhelmvat}) for p in (p0, p1, p11, p2, p3): - p.refresh() self.assertEquals(p.vat, sunhelmvat, 'Commercial fields must be automatically and recursively synced') p1vat = 'BE0987654321' p1.write({'vat': p1vat}) for p in (sunhelm, p0, p11, p2, p3): - p.refresh() self.assertEquals(p.vat, sunhelmvat, 'Sync to children should only work downstream and on commercial entities') # promote p1 to commercial entity - p1.write({ - 'parent_id': sunhelm.id, - 'is_company': True, - 'name': 'Sunhelm Subsidiary'}) - p1.refresh() + p1.write({'parent_id': sunhelm.id, + 'is_company': True, + 'name': 'Sunhelm Subsidiary'}) self.assertEquals(p1.vat, p1vat, 'Setting is_company should stop auto-sync of commercial fields') self.assertEquals(p1.commercial_partner_id, p1, 'Incorrect commercial entity resolution after setting is_company') # writing on parent should not touch child commercial entities sunhelmvat2 = 'BE0112233445' sunhelm.write({'vat': sunhelmvat2}) - p1.refresh() self.assertEquals(p1.vat, p1vat, 'Setting is_company should stop auto-sync of commercial fields') - p0.refresh() self.assertEquals(p0.vat, sunhelmvat2, 'Commercial fields must be automatically synced') def test_60_read_group(self): - cr, uid = self.cr, self.uid - title_sir = self.res_partner_title.create(cr, uid, {'name': 'Sir...'}) - title_lady = self.res_partner_title.create(cr, uid, {'name': 'Lady...'}) + title_sir = self.env['res.partner.title'].create({'name': 'Sir...'}) + title_lady = self.env['res.partner.title'].create({'name': 'Lady...'}) test_users = [ - {'name': 'Alice', 'login': 'alice', 'color': 1, 'function': 'Friend', 'date': '2015-03-28', 'title': title_lady}, - {'name': 'Alice', 'login': 'alice2', 'color': 0, 'function': 'Friend', 'date': '2015-01-28', 'title': title_lady}, - {'name': 'Bob', 'login': 'bob', 'color': 2, 'function': 'Friend', 'date': '2015-03-02', 'title': title_sir}, - {'name': 'Eve', 'login': 'eve', 'color': 3, 'function': 'Eavesdropper', 'date': '2015-03-20', 'title': title_lady}, - {'name': 'Nab', 'login': 'nab', 'color': -3, 'function': '5$ Wrench', 'date': '2014-09-10', 'title': title_sir}, - {'name': 'Nab', 'login': 'nab-she', 'color': 6, 'function': '5$ Wrench', 'date': '2014-01-02', 'title': title_lady}, + {'name': 'Alice', 'login': 'alice', 'color': 1, 'function': 'Friend', 'date': '2015-03-28', 'title': title_lady.id}, + {'name': 'Alice', 'login': 'alice2', 'color': 0, 'function': 'Friend', 'date': '2015-01-28', 'title': title_lady.id}, + {'name': 'Bob', 'login': 'bob', 'color': 2, 'function': 'Friend', 'date': '2015-03-02', 'title': title_sir.id}, + {'name': 'Eve', 'login': 'eve', 'color': 3, 'function': 'Eavesdropper', 'date': '2015-03-20', 'title': title_lady.id}, + {'name': 'Nab', 'login': 'nab', 'color': -3, 'function': '5$ Wrench', 'date': '2014-09-10', 'title': title_sir.id}, + {'name': 'Nab', 'login': 'nab-she', 'color': 6, 'function': '5$ Wrench', 'date': '2014-01-02', 'title': title_lady.id}, ] - ids = [self.res_users.create(cr, uid, u) for u in test_users] - domain = [('id', 'in', ids)] + res_users = self.env['res.users'] + user_ids = [res_users.create(vals).id for vals in test_users] + domain = [('id', 'in', user_ids)] # group on local char field without domain and without active_test (-> empty WHERE clause) - groups_data = self.res_users.read_group(cr, uid, [], fields=['login'], groupby=['login'], orderby='login DESC', context={'active_test': False}) + groups_data = res_users.with_context(active_test=False).read_group([], fields=['login'], groupby=['login'], orderby='login DESC') self.assertGreater(len(groups_data), 6, "Incorrect number of results when grouping on a field") # group on local char field with limit - groups_data = self.res_users.read_group(cr, uid, domain, fields=['login'], groupby=['login'], orderby='login DESC', limit=3, offset=3) + groups_data = res_users.read_group(domain, fields=['login'], groupby=['login'], orderby='login DESC', limit=3, offset=3) self.assertEqual(len(groups_data), 3, "Incorrect number of results when grouping on a field with limit") self.assertEqual(['bob', 'alice2', 'alice'], [g['login'] for g in groups_data], 'Result mismatch') # group on inherited char field, aggregate on int field (second groupby ignored on purpose) - groups_data = self.res_users.read_group(cr, uid, domain, fields=['name', 'color', 'function'], groupby=['function', 'login']) + groups_data = res_users.read_group(domain, fields=['name', 'color', 'function'], groupby=['function', 'login']) self.assertEqual(len(groups_data), 3, "Incorrect number of results when grouping on a field") self.assertEqual(['5$ Wrench', 'Eavesdropper', 'Friend'], [g['function'] for g in groups_data], 'incorrect read_group order') for group_data in groups_data: @@ -313,210 +328,186 @@ class test_base(common.TransactionCase): self.assertEqual(group_data['color'], 3, "Incorrect sum for aggregated data for the column 'color'") # group on inherited char field, reverse order - groups_data = self.res_users.read_group(cr, uid, domain, fields=['name', 'color'], groupby='name', orderby='name DESC') + groups_data = res_users.read_group(domain, fields=['name', 'color'], groupby='name', orderby='name DESC') self.assertEqual(['Nab', 'Eve', 'Bob', 'Alice'], [g['name'] for g in groups_data], 'Incorrect ordering of the list') # group on int field, default ordering - groups_data = self.res_users.read_group(cr, uid, domain, fields=['color'], groupby='color') + groups_data = res_users.read_group(domain, fields=['color'], groupby='color') self.assertEqual([-3, 0, 1, 2, 3, 6], [g['color'] for g in groups_data], 'Incorrect ordering of the list') # multi group, second level is int field, should still be summed in first level grouping - groups_data = self.res_users.read_group(cr, uid, domain, fields=['name', 'color'], groupby=['name', 'color'], orderby='name DESC') + groups_data = res_users.read_group(domain, fields=['name', 'color'], groupby=['name', 'color'], orderby='name DESC') self.assertEqual(['Nab', 'Eve', 'Bob', 'Alice'], [g['name'] for g in groups_data], 'Incorrect ordering of the list') self.assertEqual([3, 3, 2, 1], [g['color'] for g in groups_data], 'Incorrect ordering of the list') # group on inherited char field, multiple orders with directions - groups_data = self.res_users.read_group(cr, uid, domain, fields=['name', 'color'], groupby='name', orderby='color DESC, name') + groups_data = res_users.read_group(domain, fields=['name', 'color'], groupby='name', orderby='color DESC, name') self.assertEqual(len(groups_data), 4, "Incorrect number of results when grouping on a field") self.assertEqual(['Eve', 'Nab', 'Bob', 'Alice'], [g['name'] for g in groups_data], 'Incorrect ordering of the list') self.assertEqual([1, 2, 1, 2], [g['name_count'] for g in groups_data], 'Incorrect number of results') # group on inherited date column (res_partner.date) -> Year-Month, default ordering - groups_data = self.res_users.read_group(cr, uid, domain, fields=['function', 'color', 'date'], groupby=['date']) + groups_data = res_users.read_group(domain, fields=['function', 'color', 'date'], groupby=['date']) self.assertEqual(len(groups_data), 4, "Incorrect number of results when grouping on a field") self.assertEqual(['January 2014', 'September 2014', 'January 2015', 'March 2015'], [g['date'] for g in groups_data], 'Incorrect ordering of the list') self.assertEqual([1, 1, 1, 3], [g['date_count'] for g in groups_data], 'Incorrect number of results') # group on inherited date column (res_partner.date) -> Year-Month, custom order - groups_data = self.res_users.read_group(cr, uid, domain, fields=['function', 'color', 'date'], groupby=['date'], orderby='date DESC') + groups_data = res_users.read_group(domain, fields=['function', 'color', 'date'], groupby=['date'], orderby='date DESC') self.assertEqual(len(groups_data), 4, "Incorrect number of results when grouping on a field") self.assertEqual(['March 2015', 'January 2015', 'September 2014', 'January 2014'], [g['date'] for g in groups_data], 'Incorrect ordering of the list') self.assertEqual([3, 1, 1, 1], [g['date_count'] for g in groups_data], 'Incorrect number of results') # group on inherited many2one (res_partner.title), default order - groups_data = self.res_users.read_group(cr, uid, domain, fields=['function', 'color', 'title'], groupby=['title']) + groups_data = res_users.read_group(domain, fields=['function', 'color', 'title'], groupby=['title']) self.assertEqual(len(groups_data), 2, "Incorrect number of results when grouping on a field") # m2o is returned as a (id, label) pair - self.assertEqual([(title_lady, 'Lady...'), (title_sir, 'Sir...')], [g['title'] for g in groups_data], 'Incorrect ordering of the list') + self.assertEqual([(title_lady.id, 'Lady...'), (title_sir.id, 'Sir...')], [g['title'] for g in groups_data], 'Incorrect ordering of the list') self.assertEqual([4, 2], [g['title_count'] for g in groups_data], 'Incorrect number of results') self.assertEqual([10, -1], [g['color'] for g in groups_data], 'Incorrect aggregation of int column') # group on inherited many2one (res_partner.title), reversed natural order - groups_data = self.res_users.read_group(cr, uid, domain, fields=['function', 'color', 'title'], groupby=['title'], orderby="title desc") + groups_data = res_users.read_group(domain, fields=['function', 'color', 'title'], groupby=['title'], orderby="title desc") self.assertEqual(len(groups_data), 2, "Incorrect number of results when grouping on a field") # m2o is returned as a (id, label) pair - self.assertEqual([(title_sir, 'Sir...'), (title_lady, 'Lady...')], [g['title'] for g in groups_data], 'Incorrect ordering of the list') + self.assertEqual([(title_sir.id, 'Sir...'), (title_lady.id, 'Lady...')], [g['title'] for g in groups_data], 'Incorrect ordering of the list') self.assertEqual([2, 4], [g['title_count'] for g in groups_data], 'Incorrect number of results') self.assertEqual([-1, 10], [g['color'] for g in groups_data], 'Incorrect aggregation of int column') # group on inherited many2one (res_partner.title), multiple orders with m2o in second position - groups_data = self.res_users.read_group(cr, uid, domain, fields=['function', 'color', 'title'], groupby=['title'], orderby="color desc, title desc") + groups_data = res_users.read_group(domain, fields=['function', 'color', 'title'], groupby=['title'], orderby="color desc, title desc") self.assertEqual(len(groups_data), 2, "Incorrect number of results when grouping on a field") # m2o is returned as a (id, label) pair - self.assertEqual([(title_lady, 'Lady...'), (title_sir, 'Sir...')], [g['title'] for g in groups_data], 'Incorrect ordering of the result') + self.assertEqual([(title_lady.id, 'Lady...'), (title_sir.id, 'Sir...')], [g['title'] for g in groups_data], 'Incorrect ordering of the result') self.assertEqual([4, 2], [g['title_count'] for g in groups_data], 'Incorrect number of results') self.assertEqual([10, -1], [g['color'] for g in groups_data], 'Incorrect aggregation of int column') # group on inherited many2one (res_partner.title), ordered by other inherited field (color) - groups_data = self.res_users.read_group(cr, uid, domain, fields=['function', 'color', 'title'], groupby=['title'], orderby='color') + groups_data = res_users.read_group(domain, fields=['function', 'color', 'title'], groupby=['title'], orderby='color') self.assertEqual(len(groups_data), 2, "Incorrect number of results when grouping on a field") # m2o is returned as a (id, label) pair - self.assertEqual([(title_sir, 'Sir...'), (title_lady, 'Lady...')], [g['title'] for g in groups_data], 'Incorrect ordering of the list') + self.assertEqual([(title_sir.id, 'Sir...'), (title_lady.id, 'Lady...')], [g['title'] for g in groups_data], 'Incorrect ordering of the list') self.assertEqual([2, 4], [g['title_count'] for g in groups_data], 'Incorrect number of results') self.assertEqual([-1, 10], [g['color'] for g in groups_data], 'Incorrect aggregation of int column') -class test_partner_recursion(common.TransactionCase): +class TestPartnerRecursion(TransactionCase): def setUp(self): - super(test_partner_recursion,self).setUp() - self.res_partner = self.registry('res.partner') - cr, uid = self.cr, self.uid - self.p1 = self.res_partner.name_create(cr, uid, 'Elmtree')[0] - self.p2 = self.res_partner.create(cr, uid, {'name': 'Elmtree Child 1', 'parent_id': self.p1}) - self.p3 = self.res_partner.create(cr, uid, {'name': 'Elmtree Grand-Child 1.1', 'parent_id': self.p2}) + super(TestPartnerRecursion,self).setUp() + res_partner = self.env['res.partner'] + self.p1 = res_partner.browse(res_partner.name_create('Elmtree')[0]) + self.p2 = res_partner.create({'name': 'Elmtree Child 1', 'parent_id': self.p1.id}) + self.p3 = res_partner.create({'name': 'Elmtree Grand-Child 1.1', 'parent_id': self.p2.id}) # split 101, 102, 103 tests to force SQL rollback between them def test_101_res_partner_recursion(self): - cr, uid, p1, p3 = self.cr, self.uid, self.p1, self.p3 - self.assertRaises(ValidationError, self.res_partner.write, cr, uid, [p1], {'parent_id': p3}) + with self.assertRaises(ValidationError): + self.p1.write({'parent_id': self.p3.id}) def test_102_res_partner_recursion(self): - cr, uid, p2, p3 = self.cr, self.uid, self.p2, self.p3 - self.assertRaises(ValidationError, self.res_partner.write, cr, uid, [p2], {'parent_id': p3}) + with self.assertRaises(ValidationError): + self.p2.write({'parent_id': self.p3.id}) def test_103_res_partner_recursion(self): - cr, uid, p3 = self.cr, self.uid, self.p3 - self.assertRaises(ValidationError, self.res_partner.write, cr, uid, [p3], {'parent_id': p3}) + with self.assertRaises(ValidationError): + self.p3.write({'parent_id': self.p3.id}) def test_104_res_partner_recursion_indirect_cycle(self): """ Indirect hacky write to create cycle in children """ - cr, uid, p2, p3 = self.cr, self.uid, self.p2, self.p3 - p3b = self.res_partner.create(cr, uid, {'name': 'Elmtree Grand-Child 1.2', 'parent_id': self.p2}) - self.assertRaises(ValidationError, self.res_partner.write, cr, uid, [p2], - {'child_ids': [(1, p3, {'parent_id': p3b}), (1, p3b, {'parent_id': p3})]}) + p3b = self.p1.create({'name': 'Elmtree Grand-Child 1.2', 'parent_id': self.p2.id}) + with self.assertRaises(ValidationError): + self.p2.write({'child_ids': [(1, self.p3.id, {'parent_id': p3b.id}), + (1, p3b.id, {'parent_id': self.p3.id})]}) def test_110_res_partner_recursion_multi_update(self): """ multi-write on several partners in same hierarchy must not trigger a false cycle detection """ - cr, uid, p1, p2, p3 = self.cr, self.uid, self.p1, self.p2, self.p3 - self.assertTrue(self.res_partner.write(cr, uid, [p1,p2,p3], {'phone': '123456'})) + ps = self.p1 + self.p2 + self.p3 + self.assertTrue(ps.write({'phone': '123456'})) + -class test_translation(common.TransactionCase): +class TestParentStore(TransactionCase): + """ Verify that parent_store computation is done right """ def setUp(self): - super(test_translation, self).setUp() - self.res_category = self.registry('res.partner.category') - self.ir_translation = self.registry('ir.translation') - cr, uid = self.cr, self.uid - self.registry('ir.translation').load_module_terms(cr, ['base'], ['fr_FR']) - self.cat_id = self.res_category.create(cr, uid, {'name': 'Customers'}) - self.ir_translation.create(cr, uid, {'name': 'res.partner.category,name', 'module':'base', - 'value': 'Clients', 'res_id': self.cat_id, 'lang':'fr_FR', 'state':'translated', 'type': 'model'}) - - def test_101_create_translated_record(self): - cr, uid = self.cr, self.uid - - no_context_cat = self.res_category.browse(cr, uid, self.cat_id) - self.assertEqual(no_context_cat.name, 'Customers', "Error in basic name_get") - - fr_context_cat = self.res_category.browse(cr, uid, self.cat_id, context={'lang':'fr_FR'}) - self.assertEqual(fr_context_cat.name, 'Clients', "Translation not found") - - def test_102_duplicate_record(self): - cr, uid = self.cr, self.uid - self.new_cat_id = self.res_category.copy(cr, uid, self.cat_id, context={'lang':'fr_FR'}) - - no_context_cat = self.res_category.browse(cr, uid, self.new_cat_id) - self.assertEqual(no_context_cat.name, 'Customers', "Duplication did not set untranslated value") - - fr_context_cat = self.res_category.browse(cr, uid, self.new_cat_id, context={'lang':'fr_FR'}) - self.assertEqual(fr_context_cat.name, 'Clients', "Did not found translation for initial value") - - def test_103_duplicate_record_fr(self): - cr, uid = self.cr, self.uid - self.new_fr_cat_id = self.res_category.copy(cr, uid, self.cat_id, default={'name': 'Clients (copie)'}, context={'lang':'fr_FR'}) - - no_context_cat = self.res_category.browse(cr, uid, self.new_fr_cat_id) - self.assertEqual(no_context_cat.name, 'Customers', "Duplication erased original untranslated value") - - fr_context_cat = self.res_category.browse(cr, uid, self.new_fr_cat_id, context={'lang':'fr_FR'}) - self.assertEqual(fr_context_cat.name, 'Clients (copie)', "Did not used default value for translated value") - - def test_104_orderby_translated_field(self): - """ Test search ordered by a translated field. """ - # create a category with a French translation - category = self.env['res.partner.category'].create({'name': 'Padawans'}) - category_fr = category.with_context(lang='fr_FR') - category_fr.write({'name': 'Apprentis'}) - # search for categories, and sort them by (translated) name - categories = category_fr.search([('id', 'in', [self.cat_id, category.id])], order='name') - self.assertEqual(categories.ids, [category.id, self.cat_id], - "Search ordered by translated name should return Padawans (Apprentis) before Customers (Clients)") - -test_state = None -#: Stores state information across multiple test classes -def setUpModule(): - global test_state - test_state = {} -def tearDownModule(): - global test_state - test_state = None - -class TestPhaseInstall00(unittest.TestCase): - """ - WARNING: Relies on tests being run in alphabetical order - """ - @classmethod - def setUpClass(cls): - cls.state = None - - def test_00_setup(self): - type(self).state = 'init' - - @common.at_install(False) - def test_01_no_install(self): - type(self).state = 'error' - - def test_02_check(self): - self.assertEqual( - self.state, 'init', - "Testcase state should not have been transitioned from 00") - -class TestPhaseInstall01(unittest.TestCase): - at_install = False - - def test_default_norun(self): - self.fail("An unmarket test in a non-at-install case should not run") - - @common.at_install(True) - def test_set_run(self): - test_state['set_at_install'] = True - -class TestPhaseInstall02(unittest.TestCase): - """ - Can't put the check for test_set_run in the same class: if - @common.at_install does not work for test_set_run, it won't work for - the other one either. Thus move checking of whether test_set_run has - correctly run indeed to a separate class. - - Warning: relies on *classes* being run in alphabetical order in test - modules - """ - def test_check_state(self): - self.assertTrue( - test_state.get('set_at_install'), - "The flag should be set if local overriding of runstate") - -if __name__ == '__main__': - unittest.main() + super(TestParentStore, self).setUp() + # pretend the pool has finished loading to avoid deferring parent_store computation + self.patch(self.registry, '_init', False) + + # force res_partner_category.copy() to copy children + category = self.env['res.partner.category'] + self.patch(category._fields['child_ids'], 'copy', True) + self.patch(category._columns['child_ids'], 'copy', True) + + # setup categories + self.root = category.create({'name': 'Root category'}) + self.cat0 = category.create({'name': 'Parent category', 'parent_id': self.root.id}) + self.cat1 = category.create({'name': 'Child 1', 'parent_id': self.cat0.id}) + self.cat2 = category.create({'name': 'Child 2', 'parent_id': self.cat0.id}) + self.cat21 = category.create({'name': 'Child 2-1', 'parent_id': self.cat2.id}) + + def test_duplicate_parent(self): + """ Duplicate the parent category and verify that the children have been duplicated too """ + new_cat0 = self.cat0.copy() + new_struct = new_cat0.search([('parent_id', 'child_of', new_cat0.id)]) + self.assertEqual(len(new_struct), 4, "After duplication, the new object must have the childs records") + old_struct = new_cat0.search([('parent_id', 'child_of', self.cat0.id)]) + self.assertEqual(len(old_struct), 4, "After duplication, previous record must have old childs records only") + self.assertFalse(new_struct & old_struct, "After duplication, nodes should not be mixed") + + def test_duplicate_children_01(self): + """ Duplicate the children then reassign them to the new parent (1st method). """ + new_cat1 = self.cat1.copy() + new_cat2 = self.cat2.copy() + new_cat0 = self.cat0.copy({'child_ids': []}) + (new_cat1 + new_cat2).write({'parent_id': new_cat0.id}) + new_struct = new_cat0.search([('parent_id', 'child_of', new_cat0.id)]) + self.assertEqual(len(new_struct), 4, "After duplication, the new object must have the childs records") + old_struct = new_cat0.search([('parent_id', 'child_of', self.cat0.id)]) + self.assertEqual(len(old_struct), 4, "After duplication, previous record must have old childs records only") + self.assertFalse(new_struct & old_struct, "After duplication, nodes should not be mixed") + + def test_duplicate_children_02(self): + """ Duplicate the children then reassign them to the new parent (2nd method). """ + new_cat1 = self.cat1.copy() + new_cat2 = self.cat2.copy() + new_cat0 = self.cat0.copy({'child_ids': [(6, 0, (new_cat1 + new_cat2).ids)]}) + new_struct = new_cat0.search([('parent_id', 'child_of', new_cat0.id)]) + self.assertEqual(len(new_struct), 4, "After duplication, the new object must have the childs records") + old_struct = new_cat0.search([('parent_id', 'child_of', self.cat0.id)]) + self.assertEqual(len(old_struct), 4, "After duplication, previous record must have old childs records only") + self.assertFalse(new_struct & old_struct, "After duplication, nodes should not be mixed") + + def test_duplicate_children_03(self): + """ Duplicate the children then reassign them to the new parent (3rd method). """ + new_cat1 = self.cat1.copy() + new_cat2 = self.cat2.copy() + new_cat0 = self.cat0.copy({'child_ids': []}) + new_cat0.write({'child_ids': [(4, new_cat1.id), (4, new_cat2.id)]}) + new_struct = new_cat0.search([('parent_id', 'child_of', new_cat0.id)]) + self.assertEqual(len(new_struct), 4, "After duplication, the new object must have the childs records") + old_struct = new_cat0.search([('parent_id', 'child_of', self.cat0.id)]) + self.assertEqual(len(old_struct), 4, "After duplication, previous record must have old childs records only") + self.assertFalse(new_struct & old_struct, "After duplication, nodes should not be mixed") + + +class TestGroups(TransactionCase): + + def test_res_groups_fullname_search(self): + all_groups = self.env['res.groups'].search([]) + + groups = all_groups.search([('full_name', 'like', '%Sale%')]) + self.assertItemsEqual(groups.ids, [g.id for g in all_groups if 'Sale' in g.full_name], + "did not match search for 'Sale'") + + groups = all_groups.search([('full_name', 'like', '%Technical%')]) + self.assertItemsEqual(groups.ids, [g.id for g in all_groups if 'Technical' in g.full_name], + "did not match search for 'Technical'") + + groups = all_groups.search([('full_name', 'like', '%Sales /%')]) + self.assertItemsEqual(groups.ids, [g.id for g in all_groups if 'Sales /' in g.full_name], + "did not match search for 'Sales /'") + + groups = all_groups.search([('full_name', 'in', ['Administration / Access Rights','Contact Creation'])]) + self.assertTrue(groups, "did not match search for 'Administration / Access Rights' and 'Contact Creation'") diff --git a/openerp/addons/base/tests/test_basecase.py b/openerp/addons/base/tests/test_basecase.py index 42b47749bf7..8bd78f860fa 100644 --- a/openerp/addons/base/tests/test_basecase.py +++ b/openerp/addons/base/tests/test_basecase.py @@ -1,86 +1,72 @@ # -*- coding: utf-8 -*- -import unittest +# Part of Odoo. See LICENSE file for full copyright and licensing details. -from openerp.tests import common +from odoo.tests import common -class test_single_transaction_case(common.SingleTransactionCase): + +class TestSingleTransactionCase(common.SingleTransactionCase): """ Check the whole-class transaction behavior of SingleTransactionCase. """ def test_00(self): - """Create a partner.""" - cr, uid = self.cr, self.uid - self.registry('res.partner').create(cr, uid, {'name': 'test_per_class_teardown_partner'}) - ids = self.registry('res.partner').search(cr, uid, [('name', '=', 'test_per_class_teardown_partner')]) - self.assertEqual(1, len(ids), "Test partner not found.") + """ Create a partner. """ + self.env['res.partner'].create({'name': 'test_per_class_teardown_partner'}) + partners = self.env['res.partner'].search([('name', '=', 'test_per_class_teardown_partner')]) + self.assertEqual(1, len(partners), "Test partner not found.") def test_01(self): - """Find the created partner.""" - cr, uid = self.cr, self.uid - ids = self.registry('res.partner').search(cr, uid, [('name', '=', 'test_per_class_teardown_partner')]) - self.assertEqual(1, len(ids), "Test partner not found.") + """ Find the created partner. """ + partners = self.env['res.partner'].search([('name', '=', 'test_per_class_teardown_partner')]) + self.assertEqual(1, len(partners), "Test partner not found.") def test_20a(self): """ Create a partner with a XML ID """ - cr, uid = self.cr, self.uid - res_partner = self.registry('res.partner') - ir_model_data = self.registry('ir.model.data') - pid, _ = res_partner.name_create(cr, uid, 'Mr Blue') - ir_model_data.create(cr, uid, {'name': 'test_partner_blue', - 'module': 'base', - 'model': 'res.partner', - 'res_id': pid}) + pid, _ = self.env['res.partner'].name_create('Mr Blue') + self.env['ir.model.data'].create({'name': 'test_partner_blue', + 'module': 'base', + 'model': 'res.partner', + 'res_id': pid}) + def test_20b(self): """ Resolve xml id with ref() and browse_ref() """ - cr, uid = self.cr, self.uid - res_partner = self.registry('res.partner') xid = 'base.test_partner_blue' - p_ref = self.ref(xid) - self.assertTrue(p_ref, "ref() should resolve xid to database ID") - partner = res_partner.browse(cr, uid, p_ref) - p_browse_ref = self.browse_ref(xid) - self.assertEqual(partner, p_browse_ref, "browse_ref() should resolve xid to browse records") - + partner = self.env.ref(xid) + pid = self.ref(xid) + self.assertTrue(pid, "ref() should resolve xid to database ID") + self.assertEqual(pid, partner.id, "ref() is not consistent with env.ref()") + partner2 = self.browse_ref(xid) + self.assertEqual(partner, partner2, "browse_ref() should resolve xid to browse records") -class test_transaction_case(common.TransactionCase): +class TestTransactionCase(common.TransactionCase): """ Check the per-method transaction behavior of TransactionCase. """ def test_00(self): - """Create a partner.""" - cr, uid = self.cr, self.uid - ids = self.registry('res.partner').search(cr, uid, [('name', '=', 'test_per_class_teardown_partner')]) - self.assertEqual(0, len(ids), "Test partner found.") - self.registry('res.partner').create(cr, uid, {'name': 'test_per_class_teardown_partner'}) - ids = self.registry('res.partner').search(cr, uid, [('name', '=', 'test_per_class_teardown_partner')]) - self.assertEqual(1, len(ids), "Test partner not found.") + """ Create a partner. """ + partners = self.env['res.partner'].search([('name', '=', 'test_per_class_teardown_partner')]) + self.assertEqual(0, len(partners), "Test partner found.") + self.env['res.partner'].create({'name': 'test_per_class_teardown_partner'}) + partners = self.env['res.partner'].search([('name', '=', 'test_per_class_teardown_partner')]) + self.assertEqual(1, len(partners), "Test partner not found.") def test_01(self): - """Don't find the created partner.""" - cr, uid = self.cr, self.uid - ids = self.registry('res.partner').search(cr, uid, [('name', '=', 'test_per_class_teardown_partner')]) - self.assertEqual(0, len(ids), "Test partner found.") - + """ Don't find the created partner. """ + partners = self.env['res.partner'].search([('name', '=', 'test_per_class_teardown_partner')]) + self.assertEqual(0, len(partners), "Test partner found.") def test_20a(self): """ Create a partner with a XML ID then resolve xml id with ref() and browse_ref() """ - cr, uid = self.cr, self.uid - res_partner = self.registry('res.partner') - ir_model_data = self.registry('ir.model.data') - pid, _ = res_partner.name_create(cr, uid, 'Mr Yellow') - ir_model_data.create(cr, uid, {'name': 'test_partner_yellow', - 'module': 'base', - 'model': 'res.partner', - 'res_id': pid}) + pid, _ = self.env['res.partner'].name_create('Mr Yellow') + self.env['ir.model.data'].create({'name': 'test_partner_yellow', + 'module': 'base', + 'model': 'res.partner', + 'res_id': pid}) xid = 'base.test_partner_yellow' - p_ref = self.ref(xid) - self.assertEquals(p_ref, pid, "ref() should resolve xid to database ID") - partner = res_partner.browse(cr, uid, pid) - p_browse_ref = self.browse_ref(xid) - self.assertEqual(partner, p_browse_ref, "browse_ref() should resolve xid to browse records") - -if __name__ == '__main__': - unittest.main() + partner = self.env.ref(xid) + pid = self.ref(xid) + self.assertEquals(pid, partner.id, "ref() should resolve xid to database ID") + partner2 = self.browse_ref(xid) + self.assertEqual(partner, partner2, "browse_ref() should resolve xid to browse records") diff --git a/openerp/addons/base/tests/test_db_cursor.py b/openerp/addons/base/tests/test_db_cursor.py index 9fa61493f99..c58c6c3fccc 100644 --- a/openerp/addons/base/tests/test_db_cursor.py +++ b/openerp/addons/base/tests/test_db_cursor.py @@ -1,18 +1,19 @@ # -*- coding: utf-8 -*- +# Part of Odoo. See LICENSE file for full copyright and licensing details. import unittest -import openerp -from openerp.tools.misc import mute_logger -from openerp.tests import common +import odoo +from odoo.tests import common +from odoo.tools.misc import mute_logger ADMIN_USER_ID = common.ADMIN_USER_ID def registry(): - return openerp.modules.registry.RegistryManager.get(common.get_db_name()) + return odoo.registry(common.get_db_name()) -class test_cr_execute(unittest.TestCase): +class TestExecute(unittest.TestCase): """ Try cr.execute with wrong parameters """ @mute_logger('openerp.sql_db') diff --git a/openerp/addons/base/tests/test_expression.py b/openerp/addons/base/tests/test_expression.py index e3b94aac3b3..62f42f92bdd 100644 --- a/openerp/addons/base/tests/test_expression.py +++ b/openerp/addons/base/tests/test_expression.py @@ -1,128 +1,99 @@ -import unittest +# -*- coding: utf-8 -*- +# Part of Odoo. See LICENSE file for full copyright and licensing details. -import openerp -import openerp.osv.expression as expression -from openerp.osv.expression import get_unaccent_wrapper -from openerp.osv.orm import BaseModel -import openerp.tests.common as common +import psycopg2 -class test_expression(common.TransactionCase): +from odoo.models import BaseModel +from odoo.tests.common import TransactionCase +from odoo.tools import mute_logger +import odoo.osv.expression as expression - def _reinit_mock(self): - self.query_list = list() - - def _mock_base_model_where_calc(self, model, *args, **kwargs): - """ Mock build_email to be able to test its values. Store them into - some internal variable for latter processing. """ - self.query_list.append(self._base_model_where_calc(model, *args, **kwargs)) - # return the lastly stored query, the one the ORM wants to perform - return self.query_list[-1] - - def setUp(self): - super(test_expression, self).setUp() - # Mock BaseModel._where_calc(), to be able to proceed to some tests about generated expression - self._reinit_mock() - self._base_model_where_calc = BaseModel._where_calc - BaseModel._where_calc = lambda model, cr, uid, args, context: self._mock_base_model_where_calc(model, cr, uid, args, context) - def tearDown(self): - # Remove mocks - BaseModel._where_calc = self._base_model_where_calc - super(test_expression, self).tearDown() +class TestExpression(TransactionCase): def test_00_in_not_in_m2m(self): - registry, cr, uid = self.registry, self.cr, self.uid - # Create 4 partners with no category, or one or two categories (out of two categories). + categories = self.env['res.partner.category'] + cat_a = categories.create({'name': 'test_expression_category_A'}) + cat_b = categories.create({'name': 'test_expression_category_B'}) - categories = registry('res.partner.category') - cat_a = categories.create(cr, uid, {'name': 'test_expression_category_A'}) - cat_b = categories.create(cr, uid, {'name': 'test_expression_category_B'}) - - partners = registry('res.partner') - a = partners.create(cr, uid, {'name': 'test_expression_partner_A', 'category_id': [(6, 0, [cat_a])]}) - b = partners.create(cr, uid, {'name': 'test_expression_partner_B', 'category_id': [(6, 0, [cat_b])]}) - ab = partners.create(cr, uid, {'name': 'test_expression_partner_AB', 'category_id': [(6, 0, [cat_a, cat_b])]}) - c = partners.create(cr, uid, {'name': 'test_expression_partner_C'}) + partners = self.env['res.partner'] + a = partners.create({'name': 'test_expression_partner_A', 'category_id': [(6, 0, [cat_a.id])]}) + b = partners.create({'name': 'test_expression_partner_B', 'category_id': [(6, 0, [cat_b.id])]}) + ab = partners.create({'name': 'test_expression_partner_AB', 'category_id': [(6, 0, [cat_a.id, cat_b.id])]}) + c = partners.create({'name': 'test_expression_partner_C'}) # The tests. # On a one2many or many2many field, `in` should be read `contains` (and # `not in` should be read `doesn't contain`. - with_a = partners.search(cr, uid, [('category_id', 'in', [cat_a])]) - self.assertEqual(set([a, ab]), set(with_a), "Search for category_id in cat_a failed.") + with_a = partners.search([('category_id', 'in', [cat_a.id])]) + self.assertEqual(a + ab, with_a, "Search for category_id in cat_a failed.") - with_b = partners.search(cr, uid, [('category_id', 'in', [cat_b])]) - self.assertEqual(set([ab, b]), set(with_b), "Search for category_id in cat_b failed.") + with_b = partners.search([('category_id', 'in', [cat_b.id])]) + self.assertEqual(b + ab, with_b, "Search for category_id in cat_b failed.") # Partners with the category A or the category B. - with_a_or_b = partners.search(cr, uid, [('category_id', 'in', [cat_a, cat_b])]) - self.assertEqual(set([ab, a, b]), set(with_a_or_b), "Search for category_id contains cat_a or cat_b failed.") + with_a_or_b = partners.search([('category_id', 'in', [cat_a.id, cat_b.id])]) + self.assertEqual(a + b + ab, with_a_or_b, "Search for category_id contains cat_a or cat_b failed.") # Show that `contains list` is really `contains element or contains element`. - with_a_or_with_b = partners.search(cr, uid, ['|', ('category_id', 'in', [cat_a]), ('category_id', 'in', [cat_b])]) - self.assertEqual(set([ab, a, b]), set(with_a_or_with_b), "Search for category_id contains cat_a or contains cat_b failed.") + with_a_or_with_b = partners.search(['|', ('category_id', 'in', [cat_a.id]), ('category_id', 'in', [cat_b.id])]) + self.assertEqual(a + b + ab, with_a_or_with_b, "Search for category_id contains cat_a or contains cat_b failed.") # If we change the OR in AND... - with_a_and_b = partners.search(cr, uid, [('category_id', 'in', [cat_a]), ('category_id', 'in', [cat_b])]) - self.assertEqual(set([ab]), set(with_a_and_b), "Search for category_id contains cat_a and cat_b failed.") + with_a_and_b = partners.search([('category_id', 'in', [cat_a.id]), ('category_id', 'in', [cat_b.id])]) + self.assertEqual(ab, with_a_and_b, "Search for category_id contains cat_a and cat_b failed.") # Partners without category A and without category B. - without_a_or_b = partners.search(cr, uid, [('category_id', 'not in', [cat_a, cat_b])]) - self.assertTrue(all(i not in without_a_or_b for i in [a, b, ab]), "Search for category_id doesn't contain cat_a or cat_b failed (1).") + without_a_or_b = partners.search([('category_id', 'not in', [cat_a.id, cat_b.id])]) + self.assertFalse(without_a_or_b & (a + b + ab), "Search for category_id doesn't contain cat_a or cat_b failed (1).") self.assertTrue(c in without_a_or_b, "Search for category_id doesn't contain cat_a or cat_b failed (2).") # Show that `doesn't contain list` is really `doesn't contain element and doesn't contain element`. - without_a_and_without_b = partners.search(cr, uid, [('category_id', 'not in', [cat_a]), ('category_id', 'not in', [cat_b])]) - self.assertTrue(all(i not in without_a_and_without_b for i in [a, b, ab]), "Search for category_id doesn't contain cat_a and cat_b failed (1).") + without_a_and_without_b = partners.search([('category_id', 'not in', [cat_a.id]), ('category_id', 'not in', [cat_b.id])]) + self.assertFalse(without_a_and_without_b & (a + b + ab), "Search for category_id doesn't contain cat_a and cat_b failed (1).") self.assertTrue(c in without_a_and_without_b, "Search for category_id doesn't contain cat_a and cat_b failed (2).") # We can exclude any partner containing the category A. - without_a = partners.search(cr, uid, [('category_id', 'not in', [cat_a])]) + without_a = partners.search([('category_id', 'not in', [cat_a.id])]) self.assertTrue(a not in without_a, "Search for category_id doesn't contain cat_a failed (1).") self.assertTrue(ab not in without_a, "Search for category_id doesn't contain cat_a failed (2).") - self.assertTrue(set([b, c]).issubset(set(without_a)), "Search for category_id doesn't contain cat_a failed (3).") + self.assertLessEqual(b + c, without_a, "Search for category_id doesn't contain cat_a failed (3).") # (Obviously we can do the same for cateory B.) - without_b = partners.search(cr, uid, [('category_id', 'not in', [cat_b])]) + without_b = partners.search([('category_id', 'not in', [cat_b.id])]) self.assertTrue(b not in without_b, "Search for category_id doesn't contain cat_b failed (1).") self.assertTrue(ab not in without_b, "Search for category_id doesn't contain cat_b failed (2).") - self.assertTrue(set([a, c]).issubset(set(without_b)), "Search for category_id doesn't contain cat_b failed (3).") - - # We can't express the following: Partners with a category different than A. - # with_any_other_than_a = ... - # self.assertTrue(a not in with_any_other_than_a, "Search for category_id with any other than cat_a failed (1).") - # self.assertTrue(ab in with_any_other_than_a, "Search for category_id with any other than cat_a failed (2).") + self.assertLessEqual(a + c, without_b, "Search for category_id doesn't contain cat_b failed (3).") def test_05_not_str_m2m(self): - registry, cr, uid = self.registry, self.cr, self.uid - - partners = registry('res.partner') - categories = registry('res.partner.category') + partners = self.env['res.partner'] + categories = self.env['res.partner.category'] - cats = {} - for cat in 'A B AB'.split(): - cats[cat] = categories.create(cr, uid, {'name': cat}) + cids = {} + for name in 'A B AB'.split(): + cids[name] = categories.create({'name': name}).id - _partners = { + partners_config = { '0': [], - 'a': [cats['A']], - 'b': [cats['B']], - 'ab': [cats['AB']], - 'a b': [cats['A'], cats['B']], - 'b ab': [cats['B'], cats['AB']], + 'a': [cids['A']], + 'b': [cids['B']], + 'ab': [cids['AB']], + 'a b': [cids['A'], cids['B']], + 'b ab': [cids['B'], cids['AB']], } pids = {} - for p in _partners: - pids[p] = partners.create(cr, uid, {'name': p, 'category_id': [(6, 0, _partners[p])]}) + for name, cat_ids in partners_config.iteritems(): + pids[name] = partners.create({'name': name, 'category_id': [(6, 0, cat_ids)]}).id base_domain = [('id', 'in', pids.values())] def test(op, value, expected): - ids = set(partners.search(cr, uid, base_domain + [('category_id', op, value)])) - expected_ids = set(map(pids.__getitem__, expected)) - self.assertSetEqual(ids, expected_ids, '%s %r should return %r' % (op, value, expected)) + found_ids = partners.search(base_domain + [('category_id', op, value)]).ids + expected_ids = [pids[name] for name in expected] + self.assertItemsEqual(found_ids, expected_ids, '%s %r should return %r' % (op, value, expected)) test('=', 'A', ['a', 'a b']) test('!=', 'B', ['0', 'a', 'ab']) @@ -130,73 +101,573 @@ class test_expression(common.TransactionCase): test('not ilike', 'B', ['0', 'a']) test('not like', 'AB', ['0', 'a', 'b', 'a b']) - def test_10_expression_parse(self): + def test_10_hierarchy_in_m2m(self): + Partner = self.env['res.partner'] + Category = self.env['res.partner.category'] + + # search through m2m relation + partners = Partner.search([('category_id', 'child_of', self.ref('base.res_partner_category_0'))]) + self.assertTrue(partners) + + # setup test partner categories + categ_root = Category.create({'name': 'Root category'}) + categ_0 = Category.create({'name': 'Parent category', 'parent_id': categ_root.id}) + categ_1 = Category.create({'name': 'Child1', 'parent_id': categ_0.id}) + + # test hierarchical search in m2m with child id (list of ids) + cats = Category.search([('id', 'child_of', categ_root.ids)]) + self.assertEqual(len(cats), 3) + + # test hierarchical search in m2m with child id (single id) + cats = Category.search([('id', 'child_of', categ_root.id)]) + self.assertEqual(len(cats), 3) + + # test hierarchical search in m2m with child ids + cats = Category.search([('id', 'child_of', (categ_0 + categ_1).ids)]) + self.assertEqual(len(cats), 2) + + # test hierarchical search in m2m with child ids + cats = Category.search([('id', 'child_of', categ_0.ids)]) + self.assertEqual(len(cats), 2) + + # test hierarchical search in m2m with child ids + cats = Category.search([('id', 'child_of', categ_1.ids)]) + self.assertEqual(len(cats), 1) + + # test hierarchical search in m2m with parent id (list of ids) + cats = Category.search([('id', 'parent_of', categ_1.ids)]) + self.assertEqual(len(cats), 3) + + # test hierarchical search in m2m with parent id (single id) + cats = Category.search([('id', 'parent_of', categ_1.id)]) + self.assertEqual(len(cats), 3) + + # test hierarchical search in m2m with parent ids + cats = Category.search([('id', 'parent_of', (categ_root + categ_0).ids)]) + self.assertEqual(len(cats), 2) + + # test hierarchical search in m2m with parent ids + cats = Category.search([('id', 'parent_of', categ_0.ids)]) + self.assertEqual(len(cats), 2) + + # test hierarchical search in m2m with parent ids + cats = Category.search([('id', 'parent_of', categ_root.ids)]) + self.assertEqual(len(cats), 1) + + def test_10_equivalent_id(self): + # equivalent queries + Currency = self.env['res.currency'] + non_currency_id = max(Currency.search([]).ids) + 1003 + res_0 = Currency.search([]) + res_1 = Currency.search([('name', 'not like', 'probably_unexisting_name')]) + self.assertEqual(res_0, res_1) + res_2 = Currency.search([('id', 'not in', [non_currency_id])]) + self.assertEqual(res_0, res_2) + res_3 = Currency.search([('id', 'not in', [])]) + self.assertEqual(res_0, res_3) + res_4 = Currency.search([('id', '!=', False)]) + self.assertEqual(res_0, res_4) + + # equivalent queries, integer and string + Partner = self.env['res.partner'] + all_partners = Partner.search([]) + self.assertTrue(len(all_partners) > 1) + one = all_partners[0] + others = all_partners[1:] + + res_1 = Partner.search([('id', '=', one.id)]) + self.assertEqual(one, res_1) + # Partner.search([('id', '!=', others)]) # not permitted + res_2 = Partner.search([('id', 'not in', others.ids)]) + self.assertEqual(one, res_2) + res_3 = Partner.search(['!', ('id', '!=', one.id)]) + self.assertEqual(one, res_3) + res_4 = Partner.search(['!', ('id', 'in', others.ids)]) + self.assertEqual(one, res_4) + # res_5 = Partner.search([('id', 'in', one)]) # TODO make it permitted, just like for child_of + # self.assertEqual(one, res_5) + res_6 = Partner.search([('id', 'in', [one.id])]) + self.assertEqual(one, res_6) + res_7 = Partner.search([('name', '=', one.name)]) + self.assertEqual(one, res_7) + res_8 = Partner.search([('name', 'in', [one.name])]) + # res_9 = Partner.search([('name', 'in', one.name)]) # TODO + + def test_15_m2o(self): + Partner = self.env['res.partner'] + + # testing equality with name + partners = Partner.search([('parent_id', '=', 'Agrolait')]) + self.assertTrue(partners) + + # testing the in operator with name + partners = Partner.search([('parent_id', 'in', 'Agrolait')]) + self.assertTrue(partners) + + # testing the in operator with a list of names + partners = Partner.search([('parent_id', 'in', ['Agrolait', 'ASUStek'])]) + self.assertTrue(partners) + + # check if many2one works with empty search list + partners = Partner.search([('company_id', 'in', [])]) + self.assertFalse(partners) + + # create new company with partners, and partners with no company + company2 = self.env['res.company'].create({'name': 'Acme 2'}) + for i in xrange(4): + Partner.create({'name': 'P of Acme %s' % i, 'company_id': company2.id}) + for i in xrange(4): + Partner.create({'name': 'P of All %s' % i, 'company_id': False}) + + # check if many2one works with negative empty list + all_partners = Partner.search([]) + res_partners = Partner.search(['|', ('company_id', 'not in', []), ('company_id', '=', False)]) + self.assertEqual(all_partners, res_partners, "not in [] fails") + + # check that many2one will pick the correct records with a list + partners = Partner.search([('company_id', 'in', [False])]) + self.assertTrue(len(partners) >= 4, "We should have at least 4 partners with no company") + + # check that many2one will exclude the correct records with a list + partners = Partner.search([('company_id', 'not in', [1])]) + self.assertTrue(len(partners) >= 4, "We should have at least 4 partners not related to company #1") + + # check that many2one will exclude the correct records with a list and False + partners = Partner.search(['|', ('company_id', 'not in', [1]), + ('company_id', '=', False)]) + self.assertTrue(len(partners) >= 8, "We should have at least 8 partners not related to company #1") + + # check that multi-level expressions also work + partners = Partner.search([('company_id.partner_id', 'in', [])]) + self.assertFalse(partners) + + # check that multi-level expressions with negative op work + all_partners = Partner.search([('company_id', '!=', False)]) + res_partners = Partner.search([('company_id.partner_id', 'not in', [])]) + self.assertEqual(all_partners, res_partners, "not in [] fails") + + # Test the '(not) like/in' behavior. res.partner and its parent_id + # column are used because parent_id is a many2one, allowing to test the + # Null value, and there are actually some null and non-null values in + # the demo data. + all_partners = Partner.search([]) + non_partner_id = max(all_partners.ids) + 1 + + with_parent = all_partners.filtered(lambda p: p.parent_id) + without_parent = all_partners.filtered(lambda p: not p.parent_id) + with_website = all_partners.filtered(lambda p: p.website) + + # We treat null values differently than in SQL. For instance in SQL: + # SELECT id FROM res_partner WHERE parent_id NOT IN (0) + # will return only the records with non-null parent_id. + # SELECT id FROM res_partner WHERE parent_id IN (0) + # will return expectedly nothing (our ids always begin at 1). + # This means the union of those two results will give only some + # records, but not all present in database. + # + # When using domains and the ORM's search method, we think it is + # more intuitive that the union returns all the records, and that + # a domain like ('parent_id', 'not in', [0]) will return all + # the records. For instance, if you perform a search for the companies + # that don't have OpenERP has a parent company, you expect to find, + # among others, the companies that don't have parent company. + # + + # existing values be treated similarly if we simply check that some + # existing value belongs to them. + res_0 = Partner.search([('parent_id', 'not like', 'probably_unexisting_name')]) # get all rows, included null parent_id + self.assertEqual(res_0, all_partners) + res_1 = Partner.search([('parent_id', 'not in', [non_partner_id])]) # get all rows, included null parent_id + self.assertEqual(res_1, all_partners) + res_2 = Partner.search([('parent_id', '!=', False)]) # get rows with not null parent_id, deprecated syntax + self.assertEqual(res_2, with_parent) + res_3 = Partner.search([('parent_id', 'not in', [])]) # get all rows, included null parent_id + self.assertEqual(res_3, all_partners) + res_4 = Partner.search([('parent_id', 'not in', [False])]) # get rows with not null parent_id + self.assertEqual(res_4, with_parent) + res_4b = Partner.search([('parent_id', 'not ilike', '')]) # get only rows without parent + self.assertEqual(res_4b, without_parent) + + # The results of these queries, when combined with queries 0..4 must + # give the whole set of ids. + res_5 = Partner.search([('parent_id', 'like', 'probably_unexisting_name')]) + self.assertFalse(res_5) + res_6 = Partner.search([('parent_id', 'in', [non_partner_id])]) + self.assertFalse(res_6) + res_7 = Partner.search([('parent_id', '=', False)]) + self.assertEqual(res_7, without_parent) + res_8 = Partner.search([('parent_id', 'in', [])]) + self.assertFalse(res_8) + res_9 = Partner.search([('parent_id', 'in', [False])]) + self.assertEqual(res_9, without_parent) + res_9b = Partner.search([('parent_id', 'ilike', '')]) # get those with a parent + self.assertEqual(res_9b, with_parent) + + # These queries must return exactly the results than the queries 0..4, + # i.e. not ... in ... must be the same as ... not in ... . + res_10 = Partner.search(['!', ('parent_id', 'like', 'probably_unexisting_name')]) + self.assertEqual(res_0, res_10) + res_11 = Partner.search(['!', ('parent_id', 'in', [non_partner_id])]) + self.assertEqual(res_1, res_11) + res_12 = Partner.search(['!', ('parent_id', '=', False)]) + self.assertEqual(res_2, res_12) + res_13 = Partner.search(['!', ('parent_id', 'in', [])]) + self.assertEqual(res_3, res_13) + res_14 = Partner.search(['!', ('parent_id', 'in', [False])]) + self.assertEqual(res_4, res_14) + + # Testing many2one field is not enough, a regular char field is tested + res_15 = Partner.search([('website', 'in', [])]) + self.assertFalse(res_15) + res_16 = Partner.search([('website', 'not in', [])]) + self.assertEqual(res_16, all_partners) + res_17 = Partner.search([('website', '!=', False)]) + self.assertEqual(res_17, with_website) + + # check behavior for required many2one fields: currency_id is required + companies = self.env['res.company'].search([]) + res_101 = companies.search([('currency_id', 'not ilike', '')]) # get no companies + self.assertFalse(res_101) + res_102 = companies.search([('currency_id', 'ilike', '')]) # get all companies + self.assertEqual(res_102, companies) + + def test_in_operator(self): + """ check that we can use the 'in' operator for plain fields """ + menus = self.env['ir.ui.menu'].search([('sequence', 'in', [1, 2, 10, 20])]) + self.assertTrue(menus) + + def test_15_o2m(self): + Partner = self.env['res.partner'] + + # test one2many operator with empty search list + partners = Partner.search([('child_ids', 'in', [])]) + self.assertFalse(partners) + + # test one2many operator with False + partners = Partner.search([('child_ids', '=', False)]) + for partner in partners: + self.assertFalse(partner.child_ids) + + # verify domain evaluation for one2many != False and one2many == False + categories = self.env['res.partner.category'].search([]) + parents = categories.search([('child_ids', '!=', False)]) + self.assertEqual(parents, categories.filtered(lambda c: c.child_ids)) + leafs = categories.search([('child_ids', '=', False)]) + self.assertEqual(leafs, categories.filtered(lambda c: not c.child_ids)) + + # test many2many operator with empty search list + partners = Partner.search([('category_id', 'in', [])]) + self.assertFalse(partners) + + # test many2many operator with False + partners = Partner.search([('category_id', '=', False)]) + for partner in partners: + self.assertFalse(partner.category_id) + + # filtering on nonexistent value across x2many should return nothing + partners = Partner.search([('child_ids.city', '=', 'foo')]) + self.assertFalse(partners) + + def test_15_equivalent_one2many_1(self): + Company = self.env['res.company'] + company3 = Company.create({'name': 'Acme 3'}) + company4 = Company.create({'name': 'Acme 4', 'parent_id': company3.id}) + + # one2many towards same model + res_1 = Company.search([('child_ids', 'in', company3.child_ids.ids)]) # any company having a child of company3 as child + self.assertEqual(res_1, company3) + res_2 = Company.search([('child_ids', 'in', company3.child_ids[0].ids)]) # any company having the first child of company3 as child + self.assertEqual(res_2, company3) + + # child_of x returns x and its children (direct or not). + expected = company3 + company4 + res_1 = Company.search([('id', 'child_of', [company3.id])]) + self.assertEqual(res_1, expected) + res_2 = Company.search([('id', 'child_of', company3.id)]) + self.assertEqual(res_2, expected) + res_3 = Company.search([('id', 'child_of', [company3.name])]) + self.assertEqual(res_3, expected) + res_4 = Company.search([('id', 'child_of', company3.name)]) + self.assertEqual(res_4, expected) + + # parent_of x returns x and its parents (direct or not). + expected = company3 + company4 + res_1 = Company.search([('id', 'parent_of', [company4.id])]) + self.assertEqual(res_1, expected) + res_2 = Company.search([('id', 'parent_of', company4.id)]) + self.assertEqual(res_2, expected) + res_3 = Company.search([('id', 'parent_of', [company4.name])]) + self.assertEqual(res_3, expected) + res_4 = Company.search([('id', 'parent_of', company4.name)]) + self.assertEqual(res_4, expected) + + # try testing real subsets with IN/NOT IN + Partner = self.env['res.partner'] + Users = self.env['res.users'] + p1, _ = Partner.name_create("Dédé Boitaclou") + p2, _ = Partner.name_create("Raoulette Pizza O'poil") + u1a = Users.create({'login': 'dbo', 'partner_id': p1}).id + u1b = Users.create({'login': 'dbo2', 'partner_id': p1}).id + u2 = Users.create({'login': 'rpo', 'partner_id': p2}).id + self.assertEqual([p1], Partner.search([('user_ids', 'in', u1a)]).ids, "o2m IN accept single int on right side") + self.assertEqual([p1], Partner.search([('user_ids', '=', 'Dédé Boitaclou')]).ids, "o2m NOT IN matches none on the right side") + self.assertEqual([], Partner.search([('user_ids', 'in', [10000])]).ids, "o2m NOT IN matches none on the right side") + self.assertEqual([p1,p2], Partner.search([('user_ids', 'in', [u1a,u2])]).ids, "o2m IN matches any on the right side") + all_ids = Partner.search([]).ids + self.assertEqual(set(all_ids) - set([p1]), set(Partner.search([('user_ids', 'not in', u1a)]).ids), "o2m NOT IN matches none on the right side") + self.assertEqual(set(all_ids) - set([p1]), set(Partner.search([('user_ids', '!=', 'Dédé Boitaclou')]).ids), "o2m NOT IN matches none on the right side") + self.assertEqual(set(all_ids) - set([p1,p2]), set(Partner.search([('user_ids', 'not in', [u1b, u2])]).ids), "o2m NOT IN matches none on the right side") + + def test_15_equivalent_one2many_2(self): + Currency = self.env['res.currency'] + CurrencyRate = self.env['res.currency.rate'] + + # create a currency and a currency rate + currency = Currency.create({'name': 'ZZZ', 'symbol': 'ZZZ', 'rounding': 1.0}) + currency_rate = CurrencyRate.create({'name': '2010-01-01', 'currency_id': currency.id, 'rate': 1.0}) + non_currency_id = currency_rate.id + 1000 + default_currency = Currency.browse(1) + + # search the currency via its rates one2many (the one2many must point back at the currency) + currency_rate1 = CurrencyRate.search([('name', 'not like', 'probably_unexisting_name')]) + currency_rate2 = CurrencyRate.search([('id', 'not in', [non_currency_id])]) + self.assertEqual(currency_rate1, currency_rate2) + currency_rate3 = CurrencyRate.search([('id', 'not in', [])]) + self.assertEqual(currency_rate1, currency_rate3) + + # one2many towards another model + res_3 = Currency.search([('rate_ids', 'in', default_currency.rate_ids.ids)]) # currencies having a rate of main currency + self.assertEqual(res_3, default_currency) + res_4 = Currency.search([('rate_ids', 'in', default_currency.rate_ids[0].ids)]) # currencies having first rate of main currency + self.assertEqual(res_4, default_currency) + res_5 = Currency.search([('rate_ids', 'in', default_currency.rate_ids[0].id)]) # currencies having first rate of main currency + self.assertEqual(res_5, default_currency) + # res_6 = Currency.search([('rate_ids', 'in', [default_currency.rate_ids[0].name])]) + # res_7 = Currency.search([('rate_ids', '=', default_currency.rate_ids[0].name)]) + # res_8 = Currency.search([('rate_ids', 'like', default_currency.rate_ids[0].name)]) + + res_9 = Currency.search([('rate_ids', 'like', 'probably_unexisting_name')]) + self.assertFalse(res_9) + # Currency.search([('rate_ids', 'unexisting_op', 'probably_unexisting_name')]) # TODO expected exception + + # get the currencies referenced by some currency rates using a weird negative domain + res_10 = Currency.search([('rate_ids', 'not like', 'probably_unexisting_name')]) + res_11 = Currency.search([('rate_ids', 'not in', [non_currency_id])]) + self.assertEqual(res_10, res_11) + res_12 = Currency.search([('rate_ids', '!=', False)]) + self.assertEqual(res_10, res_12) + res_13 = Currency.search([('rate_ids', 'not in', [])]) + self.assertEqual(res_10, res_13) + + def test_20_expression_parse(self): # TDE note: those tests have been added when refactoring the expression.parse() method. - # They come in addition to the already existing test_osv_expression.yml; maybe some tests + # They come in addition to the already existing tests; maybe some tests # will be a bit redundant - registry, cr, uid = self.registry, self.cr, self.uid - users_obj = registry('res.users') + Users = self.env['res.users'] # Create users - a = users_obj.create(cr, uid, {'name': 'test_A', 'login': 'test_A'}) - b1 = users_obj.create(cr, uid, {'name': 'test_B', 'login': 'test_B'}) - b1_user = users_obj.browse(cr, uid, [b1])[0] - b2 = users_obj.create(cr, uid, {'name': 'test_B2', 'login': 'test_B2', 'parent_id': b1_user.partner_id.id}) + a = Users.create({'name': 'test_A', 'login': 'test_A'}) + b1 = Users.create({'name': 'test_B', 'login': 'test_B'}) + b2 = Users.create({'name': 'test_B2', 'login': 'test_B2', 'parent_id': b1.partner_id.id}) # Test1: simple inheritance - user_ids = users_obj.search(cr, uid, [('name', 'like', 'test')]) - self.assertEqual(set(user_ids), set([a, b1, b2]), 'searching through inheritance failed') - user_ids = users_obj.search(cr, uid, [('name', '=', 'test_B')]) - self.assertEqual(set(user_ids), set([b1]), 'searching through inheritance failed') + users = Users.search([('name', 'like', 'test')]) + self.assertEqual(users, a + b1 + b2, 'searching through inheritance failed') + users = Users.search([('name', '=', 'test_B')]) + self.assertEqual(users, b1, 'searching through inheritance failed') # Test2: inheritance + relational fields - user_ids = users_obj.search(cr, uid, [('child_ids.name', 'like', 'test_B')]) - self.assertEqual(set(user_ids), set([b1]), 'searching through inheritance failed') + users = Users.search([('child_ids.name', 'like', 'test_B')]) + self.assertEqual(users, b1, 'searching through inheritance failed') # Special =? operator mean "is equal if right is set, otherwise always True" - user_ids = users_obj.search(cr, uid, [('name', 'like', 'test'), ('parent_id', '=?', False)]) - self.assertEqual(set(user_ids), set([a, b1, b2]), '(x =? False) failed') - user_ids = users_obj.search(cr, uid, [('name', 'like', 'test'), ('parent_id', '=?', b1_user.partner_id.id)]) - self.assertEqual(set(user_ids), set([b2]), '(x =? id) failed') + users = Users.search([('name', 'like', 'test'), ('parent_id', '=?', False)]) + self.assertEqual(users, a + b1 + b2, '(x =? False) failed') + users = Users.search([('name', 'like', 'test'), ('parent_id', '=?', b1.partner_id.id)]) + self.assertEqual(users, b2, '(x =? id) failed') + + def test_30_normalize_domain(self): + norm_domain = domain = ['&', (1, '=', 1), ('a', '=', 'b')] + self.assertEqual(norm_domain, expression.normalize_domain(domain), "Normalized domains should be left untouched") + domain = [('x', 'in', ['y', 'z']), ('a.v', '=', 'e'), '|', '|', ('a', '=', 'b'), '!', ('c', '>', 'd'), ('e', '!=', 'f'), ('g', '=', 'h')] + norm_domain = ['&', '&', '&'] + domain + self.assertEqual(norm_domain, expression.normalize_domain(domain), "Non-normalized domains should be properly normalized") + + def test_40_negating_long_expression(self): + source = ['!', '&', ('user_id', '=', 4), ('partner_id', 'in', [1, 2])] + expect = ['|', ('user_id', '!=', 4), ('partner_id', 'not in', [1, 2])] + self.assertEqual(expression.distribute_not(source), expect, + "distribute_not on expression applied wrongly") + + pos_leaves = [[('a', 'in', [])], [('d', '!=', 3)]] + neg_leaves = [[('a', 'not in', [])], [('d', '=', 3)]] + + source = expression.OR([expression.AND(pos_leaves)] * 1000) + expect = source + self.assertEqual(expression.distribute_not(source), expect, + "distribute_not on long expression without negation operator should not alter it") + + source = ['!'] + source + expect = expression.AND([expression.OR(neg_leaves)] * 1000) + self.assertEqual(expression.distribute_not(source), expect, + "distribute_not on long expression applied wrongly") + + def test_accent(self): + if not self.registry.has_unaccent: + return + Company = self.env['res.company'] + helene = Company.create({'name': u'Hélène'}) + self.assertEqual(helene, Company.search([('name','ilike','Helene')])) + self.assertEqual(helene, Company.search([('name','ilike','hélène')])) + self.assertNotIn(helene, Company.search([('name','not ilike','Helene')])) + self.assertNotIn(helene, Company.search([('name','not ilike','hélène')])) + + def test_like_wildcards(self): + # check that =like/=ilike expressions are working on an untranslated field + Partner = self.env['res.partner'] + partners = Partner.search([('name', '=like', 'A_U_TeK')]) + self.assertTrue(len(partners) == 1, "Must match one partner (ASUSTeK)") + partners = Partner.search([('name', '=ilike', 'c%')]) + self.assertTrue(len(partners) >= 1, "Must match one partner (China Export)") + + # check that =like/=ilike expressions are working on translated field + Country = self.env['res.country'] + countries = Country.search([('name', '=like', 'Ind__')]) + self.assertTrue(len(countries) == 1, "Must match India only") + countries = Country.search([('name', '=ilike', 'z%')]) + self.assertTrue(len(countries) == 3, "Must match only countries with names starting with Z (currently 3)") + + def test_translate_search(self): + Country = self.env['res.country'] + belgium = self.env.ref('base.be') + domains = [ + [('name', '=', 'Belgium')], + [('name', 'ilike', 'Belgi')], + [('name', 'in', ['Belgium', 'Care Bears'])], + ] + + for domain in domains: + countries = Country.search(domain) + self.assertEqual(countries, belgium) + + def test_long_table_alias(self): + # To test the 64 characters limit for table aliases in PostgreSQL + self.patch_order('res.users', 'partner_id') + self.patch_order('res.partner', 'commercial_partner_id,company_id,name') + self.patch_order('res.company', 'parent_id') + self.env['res.users'].search([('name', '=', 'test')]) + + @mute_logger('openerp.sql_db') + def test_invalid(self): + """ verify that invalid expressions are refused, even for magic fields """ + Country = self.env['res.country'] + + with self.assertRaises(ValueError): + Country.search([('does_not_exist', '=', 'foo')]) + + with self.assertRaises(ValueError): + Country.search([('create_date', '>>', 'foo')]) + + with self.assertRaises(psycopg2.DataError): + Country.search([('create_date', '=', "1970-01-01'); --")]) + + def test_active(self): + # testing for many2many field with category vendor and active=False + Partner = self.env['res.partner'] + vals = { + 'name': 'OpenERP Test', + 'active': False, + 'category_id': [(6, 0, [self.ref("base.res_partner_category_1")])], + 'child_ids': [(0, 0, {'name': 'address of OpenERP Test', 'country_id': self.ref("base.be")})], + } + Partner.create(vals) + partner = Partner.search([('category_id', 'ilike', 'vendor'), ('active', '=', False)]) + self.assertTrue(partner, "Record not Found with category vendor and active False.") + + # testing for one2many field with country Belgium and active=False + partner = Partner.search([('child_ids.country_id','=','Belgium'),('active','=',False)]) + self.assertTrue(partner, "Record not Found with country Belgium and active False.") + + def test_lp1071710(self): + """ Check that we can exclude translated fields (bug lp:1071710) """ + # first install french language + self.env['ir.translation'].load_module_terms(['base'], ['fr_FR']) + + # actual test + Country = self.env['res.country'] + be = self.env.ref('base.be') + not_be = Country.with_context(lang='fr_FR').search([('name', '!=', 'Belgique')]) + self.assertNotIn(be, not_be) + + # indirect search via m2o + Partner = self.env['res.partner'] + agrolait = Partner.search([('name', '=', 'Agrolait')]) - def test_20_auto_join(self): - registry, cr, uid = self.registry, self.cr, self.uid - unaccent = get_unaccent_wrapper(cr) + not_be = Partner.search([('country_id', '!=', 'Belgium')]) + self.assertNotIn(agrolait, not_be) + + not_be = Partner.with_context(lang='fr_FR').search([('country_id', '!=', 'Belgique')]) + self.assertNotIn(agrolait, not_be) + + +class TestAutoJoin(TransactionCase): + + def setUp(self): + super(TestAutoJoin, self).setUp() + # Mock BaseModel._where_calc(), to be able to proceed to some tests about generated expression + self._reinit_mock() + BaseModel_where_calc = BaseModel._where_calc + + def _where_calc(model, *args, **kwargs): + """ Mock `_where_calc` to be able to test its results. Store them + into some internal variable for latter processing. """ + query = BaseModel_where_calc(model, *args, **kwargs) + self.query_list.append(query) + return query + + self.patch(BaseModel, '_where_calc', _where_calc) + + def _reinit_mock(self): + self.query_list = [] + + def test_auto_join(self): + unaccent = expression.get_unaccent_wrapper(self.cr) # Get models - partner_obj = registry('res.partner') - state_obj = registry('res.country.state') - bank_obj = registry('res.partner.bank') + partner_obj = self.env['res.partner'] + state_obj = self.env['res.country.state'] + bank_obj = self.env['res.partner.bank'] # Get test columns - partner_state_id_col = partner_obj._columns.get('state_id') # many2one on res.partner to res.country.state - partner_parent_id_col = partner_obj._columns.get('parent_id') # many2one on res.partner to res.partner - state_country_id_col = state_obj._columns.get('country_id') # many2one on res.country.state on res.country - partner_child_ids_col = partner_obj._columns.get('child_ids') # one2many on res.partner to res.partner - partner_bank_ids_col = partner_obj._columns.get('bank_ids') # one2many on res.partner to res.partner.bank - category_id_col = partner_obj._columns.get('category_id') # many2many on res.partner to res.partner.category + def patch_auto_join(model, fname, value): + self.patch(model._fields[fname], 'auto_join', value) + self.patch(model._columns[fname], '_auto_join', value) + + def patch_domain(model, fname, value): + self.patch(model._fields[fname], 'domain', value) + self.patch(model._columns[fname], '_domain', value) # Get country/state data - country_us_id = registry('res.country').search(cr, uid, [('code', 'like', 'US')])[0] - state_ids = registry('res.country.state').search(cr, uid, [('country_id', '=', country_us_id)], limit=2) + country_us = self.env['res.country'].search([('code', 'like', 'US')], limit=1) + states = self.env['res.country.state'].search([('country_id', '=', country_us.id)], limit=2) # Create demo data: partners and bank object - p_a = partner_obj.create(cr, uid, {'name': 'test__A', 'state_id': state_ids[0]}) - p_b = partner_obj.create(cr, uid, {'name': 'test__B', 'state_id': state_ids[1]}) - p_aa = partner_obj.create(cr, uid, {'name': 'test__AA', 'parent_id': p_a, 'state_id': state_ids[0]}) - p_ab = partner_obj.create(cr, uid, {'name': 'test__AB', 'parent_id': p_a, 'state_id': state_ids[1]}) - p_ba = partner_obj.create(cr, uid, {'name': 'test__BA', 'parent_id': p_b, 'state_id': state_ids[0]}) - b_aa = bank_obj.create(cr, uid, {'acc_number': '123', 'acc_type': 'bank', 'partner_id': p_aa}) - b_ab = bank_obj.create(cr, uid, {'acc_number': '456', 'acc_type': 'bank', 'partner_id': p_ab}) - b_ba = bank_obj.create(cr, uid, {'acc_number': '789', 'acc_type': 'bank', 'partner_id': p_ba}) + p_a = partner_obj.create({'name': 'test__A', 'state_id': states[0].id}) + p_b = partner_obj.create({'name': 'test__B', 'state_id': states[1].id}) + p_aa = partner_obj.create({'name': 'test__AA', 'parent_id': p_a.id, 'state_id': states[0].id}) + p_ab = partner_obj.create({'name': 'test__AB', 'parent_id': p_a.id, 'state_id': states[1].id}) + p_ba = partner_obj.create({'name': 'test__BA', 'parent_id': p_b.id, 'state_id': states[0].id}) + b_aa = bank_obj.create({'acc_number': '123', 'acc_type': 'bank', 'partner_id': p_aa.id}) + b_ab = bank_obj.create({'acc_number': '456', 'acc_type': 'bank', 'partner_id': p_ab.id}) + b_ba = bank_obj.create({'acc_number': '789', 'acc_type': 'bank', 'partner_id': p_ba.id}) # -------------------------------------------------- # Test1: basics about the attribute # -------------------------------------------------- - category_id_col._auto_join = True - self.assertRaises(NotImplementedError, partner_obj.search, cr, uid, [('category_id.name', '=', 'foo')]) - category_id_col._auto_join = False + patch_auto_join(partner_obj, 'category_id', True) + with self.assertRaises(NotImplementedError): + partner_obj.search([('category_id.name', '=', 'foo')]) # -------------------------------------------------- # Test2: one2many @@ -206,9 +677,9 @@ class test_expression(common.TransactionCase): # Do: one2many without _auto_join self._reinit_mock() - partner_ids = partner_obj.search(cr, uid, [('bank_ids.sanitized_acc_number', 'like', name_test)]) + partners = partner_obj.search([('bank_ids.sanitized_acc_number', 'like', name_test)]) # Test result - self.assertEqual(set(partner_ids), set([p_aa]), + self.assertEqual(partners, p_aa, "_auto_join off: ('bank_ids.sanitized_acc_number', 'like', '..'): incorrect result") # Test produced queries self.assertEqual(len(self.query_list), 3, @@ -221,32 +692,32 @@ class test_expression(common.TransactionCase): self.assertIn(expected, sql_query[1], "_auto_join off: ('bank_ids.sanitized_acc_number', 'like', '..') first query incorrect where condition") - self.assertEqual(set(['%' + name_test + '%']), set(sql_query[2]), + self.assertEqual(['%' + name_test + '%'], sql_query[2], "_auto_join off: ('bank_ids.sanitized_acc_number', 'like', '..') first query incorrect parameter") sql_query = self.query_list[2].get_sql() self.assertIn('res_partner', sql_query[0], "_auto_join off: ('bank_ids.sanitized_acc_number', 'like', '..') third query incorrect main table") self.assertIn('"res_partner"."id" in (%s)', sql_query[1], "_auto_join off: ('bank_ids.sanitized_acc_number', 'like', '..') third query incorrect where condition") - self.assertEqual(set([p_aa]), set(sql_query[2]), + self.assertIn(p_aa.id, sql_query[2], "_auto_join off: ('bank_ids.sanitized_acc_number', 'like', '..') third query incorrect parameter") # Do: cascaded one2many without _auto_join self._reinit_mock() - partner_ids = partner_obj.search(cr, uid, [('child_ids.bank_ids.id', 'in', [b_aa, b_ba])]) + partners = partner_obj.search([('child_ids.bank_ids.id', 'in', [b_aa.id, b_ba.id])]) # Test result - self.assertEqual(set(partner_ids), set([p_a, p_b]), + self.assertEqual(partners, p_a + p_b, "_auto_join off: ('child_ids.bank_ids.id', 'in', [..]): incorrect result") # Test produced queries self.assertEqual(len(self.query_list), 5, "_auto_join off: ('child_ids.bank_ids.id', 'in', [..]) should produce 5 queries (1 in res_partner_bank, 4 on res_partner)") # Do: one2many with _auto_join - partner_bank_ids_col._auto_join = True + patch_auto_join(partner_obj, 'bank_ids', True) self._reinit_mock() - partner_ids = partner_obj.search(cr, uid, [('bank_ids.sanitized_acc_number', 'like', '12')]) + partners = partner_obj.search([('bank_ids.sanitized_acc_number', 'like', name_test)]) # Test result - self.assertEqual(set(partner_ids), set([p_aa]), + self.assertEqual(partners, p_aa, "_auto_join on: ('bank_ids.sanitized_acc_number', 'like', '..') incorrect result") # Test produced queries self.assertEqual(len(self.query_list), 1, @@ -263,14 +734,15 @@ class test_expression(common.TransactionCase): self.assertIn('"res_partner"."id"="res_partner__bank_ids"."partner_id"', sql_query[1], "_auto_join on: ('bank_ids.sanitized_acc_number', 'like', '..') query incorrect join condition") - self.assertEqual(set(['%' + name_test + '%']), set(sql_query[2]), + self.assertIn('%' + name_test + '%', sql_query[2], "_auto_join on: ('bank_ids.sanitized_acc_number', 'like', '..') query incorrect parameter") # Do: one2many with _auto_join, test final leaf is an id self._reinit_mock() - partner_ids = partner_obj.search(cr, uid, [('bank_ids.id', 'in', [b_aa, b_ab])]) + bank_ids = [b_aa.id, b_ab.id] + partners = partner_obj.search([('bank_ids.id', 'in', bank_ids)]) # Test result - self.assertEqual(set(partner_ids), set([p_aa, p_ab]), + self.assertEqual(partners, p_aa + p_ab, "_auto_join on: ('bank_ids.id', 'in', [..]) incorrect result") # Test produced queries self.assertEqual(len(self.query_list), 1, @@ -280,15 +752,16 @@ class test_expression(common.TransactionCase): "_auto_join on: ('bank_ids.id', 'in', [..]) query incorrect main table") self.assertIn('"res_partner__bank_ids"."id" in (%s,%s)', sql_query[1], "_auto_join on: ('bank_ids.id', 'in', [..]) query incorrect where condition") - self.assertEqual(set([b_aa, b_ab]), set(sql_query[2]), + self.assertLessEqual(set(bank_ids), set(sql_query[2]), "_auto_join on: ('bank_ids.id', 'in', [..]) query incorrect parameter") # Do: 2 cascaded one2many with _auto_join, test final leaf is an id - partner_child_ids_col._auto_join = True + patch_auto_join(partner_obj, 'child_ids', True) self._reinit_mock() - partner_ids = partner_obj.search(cr, uid, [('child_ids.bank_ids.id', 'in', [b_aa, b_ba])]) + bank_ids = [b_aa.id, b_ba.id] + partners = partner_obj.search([('child_ids.bank_ids.id', 'in', bank_ids)]) # Test result - self.assertEqual(set(partner_ids), set([p_a, p_b]), + self.assertEqual(partners, p_a + p_b, "_auto_join on: ('child_ids.bank_ids.id', 'not in', [..]): incorrect result") # # Test produced queries self.assertEqual(len(self.query_list), 1, @@ -306,31 +779,30 @@ class test_expression(common.TransactionCase): "_auto_join on: ('child_ids.bank_ids.id', 'in', [..]) query incorrect join condition") self.assertIn('"res_partner__child_ids"."id"="res_partner__child_ids__bank_ids"."partner_id"', sql_query[1], "_auto_join on: ('child_ids.bank_ids.id', 'in', [..]) query incorrect join condition") - self.assertEqual(set([b_aa, b_ba]), set(sql_query[2][-2:]), + self.assertLessEqual(set(bank_ids), set(sql_query[2][-2:]), "_auto_join on: ('child_ids.bank_ids.id', 'in', [..]) query incorrect parameter") # -------------------------------------------------- # Test3: many2one # -------------------------------------------------- - name_test = 'US' # Do: many2one without _auto_join self._reinit_mock() - partner_ids = partner_obj.search(cr, uid, [('state_id.country_id.code', 'like', name_test)]) + partners = partner_obj.search([('state_id.country_id.code', 'like', name_test)]) # Test result: at least our added data + demo data - self.assertTrue(set([p_a, p_b, p_aa, p_ab, p_ba]).issubset(set(partner_ids)), + self.assertLessEqual(p_a + p_b + p_aa + p_ab + p_ba, partners, "_auto_join off: ('state_id.country_id.code', 'like', '..') incorrect result") # Test produced queries self.assertEqual(len(self.query_list), 3, "_auto_join off: ('state_id.country_id.code', 'like', '..') should produce 3 queries (1 on res_country, 1 on res_country_state, 1 on res_partner)") # Do: many2one with 1 _auto_join on the first many2one - partner_state_id_col._auto_join = True + patch_auto_join(partner_obj, 'state_id', True) self._reinit_mock() - partner_ids = partner_obj.search(cr, uid, [('state_id.country_id.code', 'like', name_test)]) + partners = partner_obj.search([('state_id.country_id.code', 'like', name_test)]) # Test result: at least our added data + demo data - self.assertTrue(set([p_a, p_b, p_aa, p_ab, p_ba]).issubset(set(partner_ids)), + self.assertLessEqual(p_a + p_b + p_aa + p_ab + p_ba, partners, "_auto_join on for state_id: ('state_id.country_id.code', 'like', '..') incorrect result") # Test produced queries self.assertEqual(len(self.query_list), 2, @@ -356,12 +828,12 @@ class test_expression(common.TransactionCase): "_auto_join on for state_id: ('state_id.country_id.code', 'like', '..') query 2 incorrect join condition") # Do: many2one with 1 _auto_join on the second many2one - partner_state_id_col._auto_join = False - state_country_id_col._auto_join = True + patch_auto_join(partner_obj, 'state_id', False) + patch_auto_join(state_obj, 'country_id', True) self._reinit_mock() - partner_ids = partner_obj.search(cr, uid, [('state_id.country_id.code', 'like', name_test)]) + partners = partner_obj.search([('state_id.country_id.code', 'like', name_test)]) # Test result: at least our added data + demo data - self.assertTrue(set([p_a, p_b, p_aa, p_ab, p_ba]).issubset(set(partner_ids)), + self.assertLessEqual(p_a + p_b + p_aa + p_ab + p_ba, partners, "_auto_join on for country_id: ('state_id.country_id.code', 'like', '..') incorrect result") # Test produced queries self.assertEqual(len(self.query_list), 2, @@ -389,12 +861,12 @@ class test_expression(common.TransactionCase): "_auto_join on for country_id: ('state_id.country_id.code', 'like', '..') query 2 incorrect where condition") # Do: many2one with 2 _auto_join - partner_state_id_col._auto_join = True - state_country_id_col._auto_join = True + patch_auto_join(partner_obj, 'state_id', True) + patch_auto_join(state_obj, 'country_id', True) self._reinit_mock() - partner_ids = partner_obj.search(cr, uid, [('state_id.country_id.code', 'like', name_test)]) + partners = partner_obj.search([('state_id.country_id.code', 'like', name_test)]) # Test result: at least our added data + demo data - self.assertTrue(set([p_a, p_b, p_aa, p_ab, p_ba]).issubset(set(partner_ids)), + self.assertLessEqual(p_a + p_b + p_aa + p_ab + p_ba, partners, "_auto_join on: ('state_id.country_id.code', 'like', '..') incorrect result") # Test produced queries self.assertEqual(len(self.query_list), 1, @@ -415,28 +887,28 @@ class test_expression(common.TransactionCase): "_auto_join on: ('state_id.country_id.code', 'like', '..') query incorrect join condition") self.assertIn('"res_partner__state_id"."country_id"="res_partner__state_id__country_id"."id"', sql_query[1], "_auto_join on: ('state_id.country_id.code', 'like', '..') query incorrect join condition") - self.assertEqual(['%' + name_test + '%'], sql_query[2], + self.assertIn('%' + name_test + '%', sql_query[2], "_auto_join on: ('state_id.country_id.code', 'like', '..') query incorrect parameter") # -------------------------------------------------- # Test4: domain attribute on one2many fields # -------------------------------------------------- - partner_child_ids_col._auto_join = True - partner_bank_ids_col._auto_join = True - partner_child_ids_col._domain = lambda self: ['!', ('name', '=', self._name)] - partner_bank_ids_col._domain = [('sanitized_acc_number', 'like', '2')] + patch_auto_join(partner_obj, 'child_ids', True) + patch_auto_join(partner_obj, 'bank_ids', True) + patch_domain(partner_obj, 'child_ids', lambda self: ['!', ('name', '=', self._name)]) + patch_domain(partner_obj, 'bank_ids', [('sanitized_acc_number', 'like', '2')]) # Do: 2 cascaded one2many with _auto_join, test final leaf is an id self._reinit_mock() - partner_ids = partner_obj.search(cr, uid, ['&', (1, '=', 1), ('child_ids.bank_ids.id', 'in', [b_aa, b_ba])]) + partners = partner_obj.search(['&', (1, '=', 1), ('child_ids.bank_ids.id', 'in', [b_aa.id, b_ba.id])]) # Test result: at least one of our added data - self.assertTrue(set([p_a]).issubset(set(partner_ids)), + self.assertLessEqual(p_a, partners, "_auto_join on one2many with domains incorrect result") - self.assertTrue(set([p_ab, p_ba]) not in set(partner_ids), + self.assertFalse((p_ab + p_ba) & partners, "_auto_join on one2many with domains incorrect result") # Test produced queries that domains effectively present sql_query = self.query_list[0].get_sql() - + expected = "%s::text like %s" % (unaccent('"res_partner__child_ids__bank_ids"."sanitized_acc_number"'), unaccent('%s')) self.assertIn(expected, sql_query[1], "_auto_join on one2many with domains incorrect result") @@ -444,101 +916,44 @@ class test_expression(common.TransactionCase): self.assertIn('"res_partner__child_ids"."name" = %s', sql_query[1], "_auto_join on one2many with domains incorrect result") - partner_child_ids_col._domain = lambda self: [('name', '=', '__%s' % self._name)] + patch_domain(partner_obj, 'child_ids', lambda self: [('name', '=', '__%s' % self._name)]) self._reinit_mock() - partner_ids = partner_obj.search(cr, uid, ['&', (1, '=', 1), ('child_ids.bank_ids.id', 'in', [b_aa, b_ba])]) + partners = partner_obj.search(['&', (1, '=', 1), ('child_ids.bank_ids.id', 'in', [b_aa.id, b_ba.id])]) # Test result: no one - self.assertFalse(partner_ids, + self.assertFalse(partners, "_auto_join on one2many with domains incorrect result") # ---------------------------------------- # Test5: result-based tests # ---------------------------------------- - partner_bank_ids_col._auto_join = False - partner_child_ids_col._auto_join = False - partner_state_id_col._auto_join = False - partner_parent_id_col._auto_join = False - state_country_id_col._auto_join = False - partner_child_ids_col._domain = [] - partner_bank_ids_col._domain = [] + patch_auto_join(partner_obj, 'bank_ids', False) + patch_auto_join(partner_obj, 'child_ids', False) + patch_auto_join(partner_obj, 'state_id', False) + patch_auto_join(partner_obj, 'parent_id', False) + patch_auto_join(state_obj, 'country_id', False) + patch_domain(partner_obj, 'child_ids', []) + patch_domain(partner_obj, 'bank_ids', []) # Do: ('child_ids.state_id.country_id.code', 'like', '..') without _auto_join self._reinit_mock() - partner_ids = partner_obj.search(cr, uid, [('child_ids.state_id.country_id.code', 'like', name_test)]) + partners = partner_obj.search([('child_ids.state_id.country_id.code', 'like', name_test)]) # Test result: at least our added data + demo data - self.assertTrue(set([p_a, p_b]).issubset(set(partner_ids)), + self.assertLessEqual(p_a + p_b, partners, "_auto_join off: ('child_ids.state_id.country_id.code', 'like', '..') incorrect result") # Test produced queries self.assertEqual(len(self.query_list), 5, "_auto_join off: ('child_ids.state_id.country_id.code', 'like', '..') number of queries incorrect") # Do: ('child_ids.state_id.country_id.code', 'like', '..') with _auto_join - partner_child_ids_col._auto_join = True - partner_state_id_col._auto_join = True - state_country_id_col._auto_join = True + patch_auto_join(partner_obj, 'child_ids', True) + patch_auto_join(partner_obj, 'state_id', True) + patch_auto_join(state_obj, 'country_id', True) self._reinit_mock() - partner_ids = partner_obj.search(cr, uid, [('child_ids.state_id.country_id.code', 'like', name_test)]) + partners = partner_obj.search([('child_ids.state_id.country_id.code', 'like', name_test)]) # Test result: at least our added data + demo data - self.assertTrue(set([p_a, p_b]).issubset(set(partner_ids)), + self.assertLessEqual(p_a + p_b, partners, "_auto_join on: ('child_ids.state_id.country_id.code', 'like', '..') incorrect result") # Test produced queries self.assertEqual(len(self.query_list), 1, "_auto_join on: ('child_ids.state_id.country_id.code', 'like', '..') number of queries incorrect") - - # Remove mocks and modifications - partner_bank_ids_col._auto_join = False - partner_child_ids_col._auto_join = False - partner_state_id_col._auto_join = False - partner_parent_id_col._auto_join = False - state_country_id_col._auto_join = False - - def test_30_normalize_domain(self): - expression = openerp.osv.expression - norm_domain = domain = ['&', (1, '=', 1), ('a', '=', 'b')] - assert norm_domain == expression.normalize_domain(domain), "Normalized domains should be left untouched" - domain = [('x', 'in', ['y', 'z']), ('a.v', '=', 'e'), '|', '|', ('a', '=', 'b'), '!', ('c', '>', 'd'), ('e', '!=', 'f'), ('g', '=', 'h')] - norm_domain = ['&', '&', '&'] + domain - assert norm_domain == expression.normalize_domain(domain), "Non-normalized domains should be properly normalized" - - def test_40_negating_long_expression(self): - source = ['!','&',('user_id','=',4),('partner_id','in',[1,2])] - expect = ['|',('user_id','!=',4),('partner_id','not in',[1,2])] - self.assertEqual(expression.distribute_not(source), expect, - "distribute_not on expression applied wrongly") - - pos_leaves = [[('a', 'in', [])], [('d', '!=', 3)]] - neg_leaves = [[('a', 'not in', [])], [('d', '=', 3)]] - - source = expression.OR([expression.AND(pos_leaves)] * 1000) - expect = source - self.assertEqual(expression.distribute_not(source), expect, - "distribute_not on long expression without negation operator should not alter it") - - source = ['!'] + source - expect = expression.AND([expression.OR(neg_leaves)] * 1000) - self.assertEqual(expression.distribute_not(source), expect, - "distribute_not on long expression applied wrongly") - - def test_translate_search(self): - Country = self.registry('res.country') - be = self.ref('base.be') - domains = [ - [('name', '=', 'Belgium')], - [('name', 'ilike', 'Belgi')], - [('name', 'in', ['Belgium', 'Care Bears'])], - ] - - for domain in domains: - ids = Country.search(self.cr, self.uid, domain) - self.assertListEqual([be], ids) - - def test_long_table_alias(self): - # To test the 64 characters limit for table aliases in PostgreSQL - self.patch_order('res.users', 'partner_id') - self.patch_order('res.partner', 'commercial_partner_id,company_id,name') - self.patch_order('res.company', 'parent_id') - self.env['res.users'].search([('name', '=', 'test')]) - -if __name__ == '__main__': - unittest.main() diff --git a/openerp/addons/base/tests/test_float.py b/openerp/addons/base/tests/test_float.py new file mode 100644 index 00000000000..6737cbc63df --- /dev/null +++ b/openerp/addons/base/tests/test_float.py @@ -0,0 +1,177 @@ +# -*- coding: utf-8 -*- +# Part of Odoo. See LICENSE file for full copyright and licensing details. + +from math import log10 + +from odoo.tests.common import TransactionCase +from odoo.tools import float_compare, float_is_zero, float_repr, float_round + + +class TestFloatPrecision(TransactionCase): + """ Tests on float precision. """ + + def test_rounding_02(self): + """ Test rounding methods with 2 digits. """ + currency = self.env.ref('base.EUR') + + def try_round(amount, expected): + digits = max(0, -int(log10(currency.rounding))) + result = float_repr(currency.round(amount), precision_digits=digits) + self.assertEqual(result, expected, 'Rounding error: got %s, expected %s' % (result, expected)) + + try_round(2.674,'2.67') + try_round(2.675,'2.68') # in Python 2.7.2, round(2.675,2) gives 2.67 + try_round(-2.675,'-2.68') # in Python 2.7.2, round(2.675,2) gives 2.67 + try_round(0.001,'0.00') + try_round(-0.001,'-0.00') + try_round(0.0049,'0.00') # 0.0049 is closer to 0 than to 0.01, so should round down + try_round(0.005,'0.01') # the rule is to round half away from zero + try_round(-0.005,'-0.01') # the rule is to round half away from zero + + def try_zero(amount, expected): + self.assertEqual(currency.is_zero(amount), expected, + "Rounding error: %s should be zero!" % amount) + + try_zero(0.01, False) + try_zero(-0.01, False) + try_zero(0.001, True) + try_zero(-0.001, True) + try_zero(0.0046, True) + try_zero(-0.0046, True) + try_zero(2.68-2.675, False) # 2.68 - 2.675 = 0.005 -> rounds to 0.01 + try_zero(2.68-2.676, True) # 2.68 - 2.675 = 0.004 -> rounds to 0.0 + try_zero(2.676-2.68, True) # 2.675 - 2.68 = -0.004 -> rounds to -0.0 + try_zero(2.675-2.68, False) # 2.675 - 2.68 = -0.005 -> rounds to -0.01 + + def try_compare(amount1, amount2, expected): + self.assertEqual(currency.compare_amounts(amount1, amount2), expected, + "Rounding error, compare_amounts(%s,%s) should be %s" % (amount1, amount2, expected)) + + try_compare(0.001, 0.001, 0) + try_compare(-0.001, -0.001, 0) + try_compare(0.001, 0.002, 0) + try_compare(-0.001, -0.002, 0) + try_compare(2.675, 2.68, 0) + try_compare(2.676, 2.68, 0) + try_compare(-2.676, -2.68, 0) + try_compare(2.674, 2.68, -1) + try_compare(-2.674, -2.68, 1) + try_compare(3, 2.68, 1) + try_compare(-3, -2.68, -1) + try_compare(0.01, 0, 1) + try_compare(-0.01, 0, -1) + + def test_rounding_03(self): + """ Test rounding methods with 3 digits. """ + + def try_round(amount, expected, digits=3, method='HALF-UP'): + value = float_round(amount, precision_digits=digits, rounding_method=method) + result = float_repr(value, precision_digits=digits) + self.assertEqual(result, expected, 'Rounding error: got %s, expected %s' % (result, expected)) + + try_round(2.6745, '2.675') + try_round(-2.6745, '-2.675') + try_round(2.6744, '2.674') + try_round(-2.6744, '-2.674') + try_round(0.0004, '0.000') + try_round(-0.0004, '-0.000') + try_round(357.4555, '357.456') + try_round(-357.4555, '-357.456') + try_round(457.4554, '457.455') + try_round(-457.4554, '-457.455') + + # Try some rounding value with rounding method UP instead of HALF-UP + # We use 8.175 because when normalizing 8.175 with precision_digits=3 it gives + # us 8175,0000000001234 as value, and if not handle correctly the rounding UP + # value will be incorrect (should be 8,175 and not 8,176) + try_round(8.175, '8.175', method='UP') + try_round(8.1751, '8.176', method='UP') + try_round(-8.175, '-8.175', method='UP') + try_round(-8.1751, '-8.176', method='UP') + try_round(-6.000, '-6.000', method='UP') + try_round(1.8, '2', 0, method='UP') + try_round(-1.8, '-2', 0, method='UP') + + # Extended float range test, inspired by Cloves Almeida's test on bug #882036. + fractions = [.0, .015, .01499, .675, .67499, .4555, .4555, .45555] + expecteds = ['.00', '.02', '.01', '.68', '.67', '.46', '.456', '.4556'] + precisions = [2, 2, 2, 2, 2, 2, 3, 4] + # Note: max precision for double floats is 53 bits of precision or + # 17 significant decimal digits + for magnitude in range(7): + for i in xrange(len(fractions)): + frac, exp, prec = fractions[i], expecteds[i], precisions[i] + for sign in [-1,1]: + for x in xrange(0,10000,97): + n = x * 10**magnitude + f = sign * (n + frac) + f_exp = ('-' if f != 0 and sign == -1 else '') + str(n) + exp + try_round(f, f_exp, digits=prec) + + def try_zero(amount, expected): + self.assertEqual(float_is_zero(amount, precision_digits=3), expected, + "Rounding error: %s should be zero!" % amount) + + try_zero(0.0002, True) + try_zero(-0.0002, True) + try_zero(0.00034, True) + try_zero(0.0005, False) + try_zero(-0.0005, False) + try_zero(0.0008, False) + try_zero(-0.0008, False) + + def try_compare(amount1, amount2, expected): + self.assertEqual(float_compare(amount1, amount2, precision_digits=3), expected, + "Rounding error, compare_amounts(%s,%s) should be %s" % (amount1, amount2, expected)) + + try_compare(0.0003, 0.0004, 0) + try_compare(-0.0003, -0.0004, 0) + try_compare(0.0002, 0.0005, -1) + try_compare(-0.0002, -0.0005, 1) + try_compare(0.0009, 0.0004, 1) + try_compare(-0.0009, -0.0004, -1) + try_compare(557.4555, 557.4556, 0) + try_compare(-557.4555, -557.4556, 0) + try_compare(657.4444, 657.445, -1) + try_compare(-657.4444, -657.445, 1) + + # Rounding to unusual rounding units (e.g. coin values) + def try_round(amount, expected, precision_rounding=None): + value = float_round(amount, precision_rounding=precision_rounding) + result = float_repr(value, precision_digits=2) + self.assertEqual(result, expected, 'Rounding error: got %s, expected %s' % (result, expected)) + + try_round(-457.4554, '-457.45', precision_rounding=0.05) + try_round(457.444, '457.50', precision_rounding=0.5) + try_round(457.3, '455.00', precision_rounding=5) + try_round(457.5, '460.00', precision_rounding=5) + try_round(457.1, '456.00', precision_rounding=3) + + def test_rounding_04(self): + """ check that proper rounding is performed for float persistence """ + currency = self.env.ref('base.EUR') + currency_rate = self.env['res.currency.rate'] + + def try_roundtrip(value, expected): + rate = currency_rate.create({'name':'2000-01-01', + 'rate': value, + 'currency_id': currency.id}) + self.assertEqual(rate.rate, expected, + 'Roundtrip error: got %s back from db, expected %s' % (rate, expected)) + + # res.currency.rate uses 6 digits of precision by default + try_roundtrip(2.6748955, 2.674896) + try_roundtrip(-2.6748955, -2.674896) + try_roundtrip(10000.999999, 10000.999999) + try_roundtrip(-10000.999999, -10000.999999) + + def test_rounding_invalid(self): + """ verify that invalid parameters are forbidden """ + with self.assertRaises(AssertionError): + float_is_zero(0.01, precision_digits=3, precision_rounding=0.01) + + with self.assertRaises(AssertionError): + float_compare(0.01, 0.02, precision_digits=3, precision_rounding=0.01) + + with self.assertRaises(AssertionError): + float_round(0.01, precision_digits=3, precision_rounding=0.01) diff --git a/openerp/addons/base/tests/test_func.py b/openerp/addons/base/tests/test_func.py index 1be2469666a..ac394cb9b79 100644 --- a/openerp/addons/base/tests/test_func.py +++ b/openerp/addons/base/tests/test_func.py @@ -1,16 +1,17 @@ # -*- coding: utf-8 -*- +# Part of Odoo. See LICENSE file for full copyright and licensing details. + import functools import unittest -from openerp.tools.func import compose -from openerp.tools import frozendict +from odoo.tools import frozendict +from odoo.tools.func import compose + class TestCompose(unittest.TestCase): def test_basic(self): str_add = compose(str, lambda a, b: a + b) - self.assertEqual( - str_add(1, 2), - "3") + self.assertEqual(str_add(1, 2), "3") def test_decorator(self): """ ensure compose() can be partially applied as a decorator @@ -21,6 +22,7 @@ class TestCompose(unittest.TestCase): self.assertEqual(mul(5, 42), u"210") + class TestFrozendict(unittest.TestCase): def test_frozendict_immutable(self): """ Ensure that a frozendict is immutable. """ diff --git a/openerp/addons/base/tests/test_ir_actions.py b/openerp/addons/base/tests/test_ir_actions.py index ee494ad84a7..a03ef2e0d0b 100644 --- a/openerp/addons/base/tests/test_ir_actions.py +++ b/openerp/addons/base/tests/test_ir_actions.py @@ -1,58 +1,50 @@ -import unittest +# -*- coding: utf-8 -*- +# Part of Odoo. See LICENSE file for full copyright and licensing details. -from openerp.exceptions import ValidationError -import openerp.tests.common as common -from openerp.tools import mute_logger +from odoo.exceptions import ValidationError +from odoo.tools import mute_logger +import odoo.tests.common as common +import odoo.workflow class TestServerActionsBase(common.TransactionCase): def setUp(self): super(TestServerActionsBase, self).setUp() - cr, uid = self.cr, self.uid - - # Models - self.ir_actions_server = self.registry('ir.actions.server') - self.ir_actions_client = self.registry('ir.actions.client') - self.ir_values = self.registry('ir.values') - self.ir_model = self.registry('ir.model') - self.ir_model_fields = self.registry('ir.model.fields') - self.res_partner = self.registry('res.partner') - self.res_country = self.registry('res.country') # Data on which we will run the server action - self.test_country_id = self.res_country.create(cr, uid, { + self.test_country = self.env['res.country'].create({ 'name': 'TestingCountry', 'code': 'TY', 'address_format': 'SuperFormat', }) - self.test_country = self.res_country.browse(cr, uid, self.test_country_id) - self.test_partner_id = self.res_partner.create(cr, uid, { + self.test_partner = self.env['res.partner'].create({ 'name': 'TestingPartner', 'city': 'OrigCity', - 'country_id': self.test_country_id, + 'country_id': self.test_country.id, }) - self.test_partner = self.res_partner.browse(cr, uid, self.test_partner_id) self.context = { - 'active_id': self.test_partner_id, 'active_model': 'res.partner', + 'active_id': self.test_partner.id, } # Model data - self.res_partner_model_id = self.ir_model.search(cr, uid, [('model', '=', 'res.partner')])[0] - self.res_partner_name_field_id = self.ir_model_fields.search(cr, uid, [('model', '=', 'res.partner'), ('name', '=', 'name')])[0] - self.res_partner_city_field_id = self.ir_model_fields.search(cr, uid, [('model', '=', 'res.partner'), ('name', '=', 'city')])[0] - self.res_partner_country_field_id = self.ir_model_fields.search(cr, uid, [('model', '=', 'res.partner'), ('name', '=', 'country_id')])[0] - self.res_partner_parent_field_id = self.ir_model_fields.search(cr, uid, [('model', '=', 'res.partner'), ('name', '=', 'parent_id')])[0] - self.res_country_model_id = self.ir_model.search(cr, uid, [('model', '=', 'res.country')])[0] - self.res_country_name_field_id = self.ir_model_fields.search(cr, uid, [('model', '=', 'res.country'), ('name', '=', 'name')])[0] - self.res_country_code_field_id = self.ir_model_fields.search(cr, uid, [('model', '=', 'res.country'), ('name', '=', 'code')])[0] + Model = self.env['ir.model'] + Fields = self.env['ir.model.fields'] + self.res_partner_model = Model.search([('model', '=', 'res.partner')]) + self.res_partner_name_field = Fields.search([('model', '=', 'res.partner'), ('name', '=', 'name')]) + self.res_partner_city_field = Fields.search([('model', '=', 'res.partner'), ('name', '=', 'city')]) + self.res_partner_country_field = Fields.search([('model', '=', 'res.partner'), ('name', '=', 'country_id')]) + self.res_partner_parent_field = Fields.search([('model', '=', 'res.partner'), ('name', '=', 'parent_id')]) + self.res_country_model = Model.search([('model', '=', 'res.country')]) + self.res_country_name_field = Fields.search([('model', '=', 'res.country'), ('name', '=', 'name')]) + self.res_country_code_field = Fields.search([('model', '=', 'res.country'), ('name', '=', 'code')]) # create server action to - self.act_id = self.ir_actions_server.create(cr, uid, { + self.action = self.env['ir.actions.server'].create({ 'name': 'TestAction', 'condition': 'True', - 'model_id': self.res_partner_model_id, + 'model_id': self.res_partner_model.id, 'state': 'code', 'code': 'obj.write({"comment": "MyComment"})', }) @@ -61,346 +53,318 @@ class TestServerActionsBase(common.TransactionCase): class TestServerActions(TestServerActionsBase): def test_00_action(self): - cr, uid = self.cr, self.uid - # Do: eval 'True' condition - self.ir_actions_server.run(cr, uid, [self.act_id], self.context) - self.test_partner.refresh() + self.action.with_context(self.context).run() self.assertEqual(self.test_partner.comment, 'MyComment', 'ir_actions_server: invalid condition check') self.test_partner.write({'comment': False}) # Do: eval False condition, that should be considered as True (void = True) - self.ir_actions_server.write(cr, uid, [self.act_id], {'condition': False}) - self.ir_actions_server.run(cr, uid, [self.act_id], self.context) - self.test_partner.refresh() + self.action.write({'condition': False}) + self.action.with_context(self.context).run() self.assertEqual(self.test_partner.comment, 'MyComment', 'ir_actions_server: invalid condition check') # Do: create contextual action - self.ir_actions_server.create_action(cr, uid, [self.act_id]) + self.action.create_action() # Test: ir_values created - ir_values_ids = self.ir_values.search(cr, uid, [('name', '=', 'Run TestAction')]) - self.assertEqual(len(ir_values_ids), 1, 'ir_actions_server: create_action should have created an entry in ir_values') - ir_value = self.ir_values.browse(cr, uid, ir_values_ids[0]) - self.assertEqual(ir_value.value, 'ir.actions.server,%s' % self.act_id, 'ir_actions_server: created ir_values should reference the server action') - self.assertEqual(ir_value.model, 'res.partner', 'ir_actions_server: created ir_values should be linked to the action base model') + ir_values = self.env['ir.values'].search([('name', '=', 'Run TestAction')]) + self.assertEqual(len(ir_values), 1, 'ir_actions_server: create_action should have created an entry in ir_values') + self.assertEqual(ir_values.value, 'ir.actions.server,%s' % self.action.id, 'ir_actions_server: created ir_values should reference the server action') + self.assertEqual(ir_values.model, 'res.partner', 'ir_actions_server: created ir_values should be linked to the action base model') # Do: remove contextual action - self.ir_actions_server.unlink_action(cr, uid, [self.act_id]) + self.action.unlink_action() # Test: ir_values removed - ir_values_ids = self.ir_values.search(cr, uid, [('name', '=', 'Run TestAction')]) - self.assertEqual(len(ir_values_ids), 0, 'ir_actions_server: unlink_action should remove the ir_values record') + ir_values = self.env['ir.values'].search([('name', '=', 'Run TestAction')]) + self.assertEqual(len(ir_values), 0, 'ir_actions_server: unlink_action should remove the ir_values record') def test_10_code(self): - cr, uid = self.cr, self.uid - self.ir_actions_server.write(cr, uid, self.act_id, { + self.action.write({ 'state': 'code', - 'code': """partner_name = obj.name + '_code' -self.pool["res.partner"].create(cr, uid, {"name": partner_name}, context=context) -workflow""" + 'code': ("partner_name = obj.name + '_code'\n" + "obj.env['res.partner'].create({'name': partner_name})\n" + "workflow"), }) - run_res = self.ir_actions_server.run(cr, uid, [self.act_id], context=self.context) + run_res = self.action.with_context(self.context).run() self.assertFalse(run_res, 'ir_actions_server: code server action correctly finished should return False') - pids = self.res_partner.search(cr, uid, [('name', 'ilike', 'TestingPartner_code')]) - self.assertEqual(len(pids), 1, 'ir_actions_server: 1 new partner should have been created') + partners = self.test_partner.search([('name', 'ilike', 'TestingPartner_code')]) + self.assertEqual(len(partners), 1, 'ir_actions_server: 1 new partner should have been created') def test_20_trigger(self): - cr, uid = self.cr, self.uid + Workflow = self.env['workflow'] + WorkflowActivity = self.env['workflow.activity'] + WorkflowTransition = self.env['workflow.transition'] # Data: code server action (at this point code-based actions should work) - act_id2 = self.ir_actions_server.create(cr, uid, { + action2 = self.action.create({ 'name': 'TestAction2', 'type': 'ir.actions.server', 'condition': 'True', - 'model_id': self.res_partner_model_id, + 'model_id': self.res_partner_model.id, 'state': 'code', 'code': 'obj.write({"comment": "MyComment"})', }) - act_id3 = self.ir_actions_server.create(cr, uid, { + action3 = self.action.create({ 'name': 'TestAction3', 'type': 'ir.actions.server', 'condition': 'True', - 'model_id': self.res_country_model_id, + 'model_id': self.res_country_model.id, 'state': 'code', 'code': 'obj.write({"code": "ZZ"})', }) # Data: create workflows - partner_wf_id = self.registry('workflow').create(cr, uid, { + partner_workflow = Workflow.create({ 'name': 'TestWorkflow', 'osv': 'res.partner', 'on_create': True, }) - partner_act1_id = self.registry('workflow.activity').create(cr, uid, { + partner_activity1 = WorkflowActivity.create({ 'name': 'PartnerStart', - 'wkf_id': partner_wf_id, - 'flow_start': True + 'wkf_id': partner_workflow.id, + 'flow_start': True, }) - partner_act2_id = self.registry('workflow.activity').create(cr, uid, { + partner_activity2 = WorkflowActivity.create({ 'name': 'PartnerTwo', - 'wkf_id': partner_wf_id, + 'wkf_id': partner_workflow.id, 'kind': 'function', 'action': 'True', - 'action_id': act_id2, + 'action_id': action2.id, }) - partner_trs1_id = self.registry('workflow.transition').create(cr, uid, { + partner_transition1 = WorkflowTransition.create({ 'signal': 'partner_trans', - 'act_from': partner_act1_id, - 'act_to': partner_act2_id + 'act_from': partner_activity1.id, + 'act_to': partner_activity2.id, }) - country_wf_id = self.registry('workflow').create(cr, uid, { + country_workflow = Workflow.create({ 'name': 'TestWorkflow', 'osv': 'res.country', 'on_create': True, }) - country_act1_id = self.registry('workflow.activity').create(cr, uid, { + country_activity1 = WorkflowActivity.create({ 'name': 'CountryStart', - 'wkf_id': country_wf_id, - 'flow_start': True + 'wkf_id': country_workflow.id, + 'flow_start': True, }) - country_act2_id = self.registry('workflow.activity').create(cr, uid, { + country_activity2 = WorkflowActivity.create({ 'name': 'CountryTwo', - 'wkf_id': country_wf_id, + 'wkf_id': country_workflow.id, 'kind': 'function', 'action': 'True', - 'action_id': act_id3, + 'action_id': action3.id, }) - country_trs1_id = self.registry('workflow.transition').create(cr, uid, { + country_transition1 = WorkflowTransition.create({ 'signal': 'country_trans', - 'act_from': country_act1_id, - 'act_to': country_act2_id + 'act_from': country_activity1.id, + 'act_to': country_activity2.id, }) # Data: re-create country and partner to benefit from the workflows - self.test_country_id = self.res_country.create(cr, uid, { + country = self.test_country.create({ 'name': 'TestingCountry2', 'code': 'T2', }) - self.test_country = self.res_country.browse(cr, uid, self.test_country_id) - self.test_partner_id = self.res_partner.create(cr, uid, { + partner = self.test_partner.create({ 'name': 'TestingPartner2', - 'country_id': self.test_country_id, + 'country_id': country.id, }) - self.test_partner = self.res_partner.browse(cr, uid, self.test_partner_id) - self.context = { - 'active_id': self.test_partner_id, - 'active_model': 'res.partner', - } + context = dict(self.context, active_id=partner.id) # Run the action on partner object itself ('base') - self.ir_actions_server.write(cr, uid, [self.act_id], { + self.action.write({ 'state': 'trigger', 'use_relational_model': 'base', - 'wkf_model_id': self.res_partner_model_id, - 'wkf_transition_id': partner_trs1_id, + 'wkf_model_id': self.res_partner_model.id, + 'wkf_transition_id': partner_transition1.id, }) - self.ir_actions_server.run(cr, uid, [self.act_id], self.context) - self.test_partner.refresh() - self.assertEqual(self.test_partner.comment, 'MyComment', 'ir_actions_server: incorrect signal trigger') + self.action.with_context(context).run() + self.assertEqual(partner.comment, 'MyComment', 'ir_actions_server: incorrect signal trigger') # Run the action on related country object ('relational') - self.ir_actions_server.write(cr, uid, [self.act_id], { + self.action.write({ 'use_relational_model': 'relational', - 'wkf_model_id': self.res_country_model_id, - 'wkf_field_id': self.res_partner_country_field_id, - 'wkf_transition_id': country_trs1_id, + 'wkf_model_id': self.res_country_model.id, + 'wkf_field_id': self.res_partner_country_field.id, + 'wkf_transition_id': country_transition1.id, }) - self.ir_actions_server.run(cr, uid, [self.act_id], self.context) - self.test_country.refresh() - self.assertEqual(self.test_country.code, 'ZZ', 'ir_actions_server: incorrect signal trigger') + self.action.with_context(context).run() + self.assertEqual(country.code, 'ZZ', 'ir_actions_server: incorrect signal trigger') - # Clear workflow cache, otherwise openerp will try to create workflows even if it has been deleted - from openerp.workflow import clear_cache - clear_cache(cr, uid) + # Clear workflow cache, otherwise odoo will try to create workflows even if it has been deleted + odoo.workflow.clear_cache(self.cr, self.uid) def test_30_client(self): - cr, uid = self.cr, self.uid - client_action_id = self.registry('ir.actions.client').create(cr, uid, { + client_action = self.env['ir.actions.client'].create({ 'name': 'TestAction2', 'tag': 'Test', }) - self.ir_actions_server.write(cr, uid, [self.act_id], { + self.action.write({ 'state': 'client_action', - 'action_id': client_action_id, + 'action_id': client_action.id, }) - res = self.ir_actions_server.run(cr, uid, [self.act_id], context=self.context) + res = self.action.with_context(self.context).run() self.assertEqual(res['name'], 'TestAction2', 'ir_actions_server: incorrect return result for a client action') def test_40_crud_create(self): - cr, uid = self.cr, self.uid _city = 'TestCity' _name = 'TestNew' # Do: create a new record in the same model and link it - self.ir_actions_server.write(cr, uid, [self.act_id], { + self.action.write({ 'state': 'object_create', 'use_create': 'new', 'link_new_record': True, - 'link_field_id': self.res_partner_parent_field_id, - 'fields_lines': [(0, 0, {'col1': self.res_partner_name_field_id, 'value': _name}), - (0, 0, {'col1': self.res_partner_city_field_id, 'value': _city})], + 'link_field_id': self.res_partner_parent_field.id, + 'fields_lines': [(0, 0, {'col1': self.res_partner_name_field.id, 'value': _name}), + (0, 0, {'col1': self.res_partner_city_field.id, 'value': _city})], }) - run_res = self.ir_actions_server.run(cr, uid, [self.act_id], context=self.context) + run_res = self.action.with_context(self.context).run() self.assertFalse(run_res, 'ir_actions_server: create record action correctly finished should return False') # Test: new partner created - pids = self.res_partner.search(cr, uid, [('name', 'ilike', _name)]) - self.assertEqual(len(pids), 1, 'ir_actions_server: TODO') - partner = self.res_partner.browse(cr, uid, pids[0]) + partner = self.test_partner.search([('name', 'ilike', _name)]) + self.assertEqual(len(partner), 1, 'ir_actions_server: TODO') self.assertEqual(partner.city, _city, 'ir_actions_server: TODO') # Test: new partner linked - self.test_partner.refresh() - self.assertEqual(self.test_partner.parent_id.id, pids[0], 'ir_actions_server: TODO') + self.assertEqual(self.test_partner.parent_id, partner, 'ir_actions_server: TODO') # Do: copy current record - self.ir_actions_server.write(cr, uid, [self.act_id], {'fields_lines': [[5]]}) - self.ir_actions_server.write(cr, uid, [self.act_id], { + self.action.write({ 'state': 'object_create', 'use_create': 'copy_current', 'link_new_record': False, - 'fields_lines': [(0, 0, {'col1': self.res_partner_name_field_id, 'value': 'TestCopyCurrent'}), - (0, 0, {'col1': self.res_partner_city_field_id, 'value': 'TestCity'})], + 'fields_lines': [(5,), + (0, 0, {'col1': self.res_partner_name_field.id, 'value': 'TestCopyCurrent'}), + (0, 0, {'col1': self.res_partner_city_field.id, 'value': 'TestCity'})], }) - run_res = self.ir_actions_server.run(cr, uid, [self.act_id], context=self.context) + run_res = self.action.with_context(self.context).run() self.assertFalse(run_res, 'ir_actions_server: create record action correctly finished should return False') # Test: new partner created - pids = self.res_partner.search(cr, uid, [('name', 'ilike', 'TestingPartner (copy)')]) # currently res_partner overrides default['name'] whatever its value - self.assertEqual(len(pids), 1, 'ir_actions_server: TODO') - partner = self.res_partner.browse(cr, uid, pids[0]) + partner = self.test_partner.search([('name', 'ilike', 'TestingPartner (copy)')]) # currently res_partner overrides default['name'] whatever its value + self.assertEqual(len(partner), 1, 'ir_actions_server: TODO') self.assertEqual(partner.city, 'TestCity', 'ir_actions_server: TODO') - self.assertEqual(partner.country_id.id, self.test_partner.country_id.id, 'ir_actions_server: TODO') + self.assertEqual(partner.country_id, self.test_partner.country_id, 'ir_actions_server: TODO') # Do: create a new record in another model - self.ir_actions_server.write(cr, uid, [self.act_id], {'fields_lines': [[5]]}) - self.ir_actions_server.write(cr, uid, [self.act_id], { + self.action.write({ 'state': 'object_create', 'use_create': 'new_other', - 'crud_model_id': self.res_country_model_id, + 'crud_model_id': self.res_country_model.id, 'link_new_record': False, - 'fields_lines': [(0, 0, {'col1': self.res_country_name_field_id, 'value': 'obj.name', 'type': 'equation'}), - (0, 0, {'col1': self.res_country_code_field_id, 'value': 'obj.name[0:2]', 'type': 'equation'})], + 'fields_lines': [(5,), + (0, 0, {'col1': self.res_country_name_field.id, 'value': 'obj.name', 'type': 'equation'}), + (0, 0, {'col1': self.res_country_code_field.id, 'value': 'obj.name[0:2]', 'type': 'equation'})], }) - run_res = self.ir_actions_server.run(cr, uid, [self.act_id], context=self.context) + run_res = self.action.with_context(self.context).run() self.assertFalse(run_res, 'ir_actions_server: create record action correctly finished should return False') # Test: new country created - cids = self.res_country.search(cr, uid, [('name', 'ilike', 'TestingPartner')]) - self.assertEqual(len(cids), 1, 'ir_actions_server: TODO') - country = self.res_country.browse(cr, uid, cids[0]) + country = self.test_country.search([('name', 'ilike', 'TestingPartner')]) + self.assertEqual(len(country), 1, 'ir_actions_server: TODO') self.assertEqual(country.code, 'TE', 'ir_actions_server: TODO') # Do: copy a record in another model - self.ir_actions_server.write(cr, uid, [self.act_id], {'fields_lines': [[5]]}) - self.ir_actions_server.write(cr, uid, [self.act_id], { + self.action.write({ 'state': 'object_create', 'use_create': 'copy_other', - 'crud_model_id': self.res_country_model_id, + 'crud_model_id': self.res_country_model.id, 'link_new_record': False, - 'ref_object': 'res.country,%s' % self.test_country_id, - 'fields_lines': [(0, 0, {'col1': self.res_country_name_field_id, 'value': 'NewCountry', 'type': 'value'}), - (0, 0, {'col1': self.res_country_code_field_id, 'value': 'NY', 'type': 'value'})], + 'ref_object': 'res.country,%s' % self.test_country.id, + 'fields_lines': [(5,), + (0, 0, {'col1': self.res_country_name_field.id, 'value': 'NewCountry', 'type': 'value'}), + (0, 0, {'col1': self.res_country_code_field.id, 'value': 'NY', 'type': 'value'})], }) - run_res = self.ir_actions_server.run(cr, uid, [self.act_id], context=self.context) + run_res = self.action.with_context(self.context).run() self.assertFalse(run_res, 'ir_actions_server: create record action correctly finished should return False') # Test: new country created - cids = self.res_country.search(cr, uid, [('name', 'ilike', 'NewCountry')]) - self.assertEqual(len(cids), 1, 'ir_actions_server: TODO') - country = self.res_country.browse(cr, uid, cids[0]) + country = self.test_country.search([('name', 'ilike', 'NewCountry')]) + self.assertEqual(len(country), 1, 'ir_actions_server: TODO') self.assertEqual(country.code, 'NY', 'ir_actions_server: TODO') self.assertEqual(country.address_format, 'SuperFormat', 'ir_actions_server: TODO') def test_50_crud_write(self): - cr, uid = self.cr, self.uid _name = 'TestNew' # Do: create a new record in the same model and link it - self.ir_actions_server.write(cr, uid, [self.act_id], { + self.action.write({ 'state': 'object_write', 'use_write': 'current', - 'fields_lines': [(0, 0, {'col1': self.res_partner_name_field_id, 'value': _name})], + 'fields_lines': [(0, 0, {'col1': self.res_partner_name_field.id, 'value': _name})], }) - run_res = self.ir_actions_server.run(cr, uid, [self.act_id], context=self.context) + run_res = self.action.with_context(self.context).run() self.assertFalse(run_res, 'ir_actions_server: create record action correctly finished should return False') # Test: new partner created - pids = self.res_partner.search(cr, uid, [('name', 'ilike', _name)]) - self.assertEqual(len(pids), 1, 'ir_actions_server: TODO') - partner = self.res_partner.browse(cr, uid, pids[0]) + partner = self.test_partner.search([('name', 'ilike', _name)]) + self.assertEqual(len(partner), 1, 'ir_actions_server: TODO') self.assertEqual(partner.city, 'OrigCity', 'ir_actions_server: TODO') # Do: copy current record - self.ir_actions_server.write(cr, uid, [self.act_id], {'fields_lines': [[5]]}) - self.ir_actions_server.write(cr, uid, [self.act_id], { + self.action.write({ 'use_write': 'other', - 'crud_model_id': self.res_country_model_id, - 'ref_object': 'res.country,%s' % self.test_country_id, - 'fields_lines': [(0, 0, {'col1': self.res_country_name_field_id, 'value': 'obj.name', 'type': 'equation'})], + 'crud_model_id': self.res_country_model.id, + 'ref_object': 'res.country,%s' % self.test_country.id, + 'fields_lines': [(5,), (0, 0, {'col1': self.res_country_name_field.id, 'value': 'obj.name', 'type': 'equation'})], }) - run_res = self.ir_actions_server.run(cr, uid, [self.act_id], context=self.context) + run_res = self.action.with_context(self.context).run() self.assertFalse(run_res, 'ir_actions_server: create record action correctly finished should return False') # Test: new country created - cids = self.res_country.search(cr, uid, [('name', 'ilike', 'TestNew')]) - self.assertEqual(len(cids), 1, 'ir_actions_server: TODO') + country = self.test_country.search([('name', 'ilike', 'TestNew')]) + self.assertEqual(len(country), 1, 'ir_actions_server: TODO') # Do: copy a record in another model - self.ir_actions_server.write(cr, uid, [self.act_id], {'fields_lines': [[5]]}) - self.ir_actions_server.write(cr, uid, [self.act_id], { + self.action.write({ 'use_write': 'expression', - 'crud_model_id': self.res_country_model_id, + 'crud_model_id': self.res_country_model.id, 'write_expression': 'object.country_id', - 'fields_lines': [(0, 0, {'col1': self.res_country_name_field_id, 'value': 'NewCountry', 'type': 'value'})], + 'fields_lines': [(5,), (0, 0, {'col1': self.res_country_name_field.id, 'value': 'NewCountry', 'type': 'value'})], }) - run_res = self.ir_actions_server.run(cr, uid, [self.act_id], context=self.context) + run_res = self.action.with_context(self.context).run() self.assertFalse(run_res, 'ir_actions_server: create record action correctly finished should return False') # Test: new country created - cids = self.res_country.search(cr, uid, [('name', 'ilike', 'NewCountry')]) - self.assertEqual(len(cids), 1, 'ir_actions_server: TODO') + country = self.test_country.search([('name', 'ilike', 'NewCountry')]) + self.assertEqual(len(country), 1, 'ir_actions_server: TODO') @mute_logger('openerp.addons.base.ir.ir_model', 'openerp.models') def test_60_multi(self): - cr, uid = self.cr, self.uid - # Data: 2 server actions that will be nested - act1_id = self.ir_actions_server.create(cr, uid, { + action1 = self.action.create({ 'name': 'Subaction1', 'sequence': 1, - 'model_id': self.res_partner_model_id, + 'model_id': self.res_partner_model.id, 'state': 'code', 'code': 'action = {"type": "ir.actions.act_window"}', }) - act2_id = self.ir_actions_server.create(cr, uid, { + action2 = self.action.create({ 'name': 'Subaction2', 'sequence': 2, - 'model_id': self.res_partner_model_id, + 'model_id': self.res_partner_model.id, 'state': 'object_create', 'use_create': 'copy_current', }) - act3_id = self.ir_actions_server.create(cr, uid, { + action3 = self.action.create({ 'name': 'Subaction3', 'sequence': 3, - 'model_id': self.res_partner_model_id, + 'model_id': self.res_partner_model.id, 'state': 'code', 'code': 'action = {"type": "ir.actions.act_url"}', }) - self.ir_actions_server.write(cr, uid, [self.act_id], { + self.action.write({ 'state': 'multi', - 'child_ids': [(6, 0, [act1_id, act2_id, act3_id])], + 'child_ids': [(6, 0, [action1.id, action2.id, action3.id])], }) # Do: run the action - res = self.ir_actions_server.run(cr, uid, [self.act_id], context=self.context) + res = self.action.with_context(self.context).run() # Test: new partner created - pids = self.res_partner.search(cr, uid, [('name', 'ilike', 'TestingPartner (copy)')]) # currently res_partner overrides default['name'] whatever its value - self.assertEqual(len(pids), 1, 'ir_actions_server: TODO') + # currently res_partner overrides default['name'] whatever its value + partner = self.test_partner.search([('name', 'ilike', 'TestingPartner (copy)')]) + self.assertEqual(len(partner), 1, 'ir_actions_server: TODO') # Test: action returned self.assertEqual(res.get('type'), 'ir.actions.act_url') # Test loops with self.assertRaises(ValidationError): - self.ir_actions_server.write(cr, uid, [self.act_id], { - 'child_ids': [(6, 0, [self.act_id])] + self.action.write({ + 'child_ids': [(6, 0, [self.action.id])] }) - - -if __name__ == '__main__': - unittest.main() diff --git a/openerp/addons/base/tests/test_ir_attachment.py b/openerp/addons/base/tests/test_ir_attachment.py index 891b38b7dc3..d515cfc354d 100644 --- a/openerp/addons/base/tests/test_ir_attachment.py +++ b/openerp/addons/base/tests/test_ir_attachment.py @@ -1,17 +1,20 @@ +# -*- coding: utf-8 -*- +# Part of Odoo. See LICENSE file for full copyright and licensing details. + import hashlib import os -import openerp -import openerp.tests.common +from odoo.tests.common import TransactionCase HASH_SPLIT = 2 # FIXME: testing implementations detail is not a good idea -class test_ir_attachment(openerp.tests.common.TransactionCase): + +class TestIrAttachment(TransactionCase): def setUp(self): - super(test_ir_attachment, self).setUp() - registry, cr, uid = self.registry, self.cr, self.uid - self.ira = registry('ir.attachment') - self.filestore = self.ira._filestore(cr, uid) + super(TestIrAttachment, self).setUp() + self.Attachment = self.env['ir.attachment'] + self.ira = self.Attachment._model + self.filestore = self.Attachment._filestore() # Blob1 self.blob1 = 'blob1' @@ -20,73 +23,55 @@ class test_ir_attachment(openerp.tests.common.TransactionCase): self.blob1_fname = blob1_hash[:HASH_SPLIT] + '/' + blob1_hash # Blob2 - blob2 = 'blob2' - self.blob2_b64 = blob2.encode('base64') + self.blob2 = 'blob2' + self.blob2_b64 = self.blob2.encode('base64') def test_01_store_in_db(self): - registry, cr, uid = self.registry, self.cr, self.uid - # force storing in database - registry('ir.config_parameter').set_param(cr, uid, 'ir_attachment.location', 'db') + self.env['ir.config_parameter'].set_param('ir_attachment.location', 'db') # 'ir_attachment.location' is undefined test database storage - a1 = self.ira.create(cr, uid, {'name': 'a1', 'datas': self.blob1_b64}) - a1_read = self.ira.read(cr, uid, [a1], ['datas']) - self.assertEqual(a1_read[0]['datas'], self.blob1_b64) + a1 = self.Attachment.create({'name': 'a1', 'datas': self.blob1_b64}) + self.assertEqual(a1.datas, self.blob1_b64) - a1_db_datas = self.ira.browse(cr, uid, a1).db_datas + a1_db_datas = a1.db_datas self.assertEqual(a1_db_datas, self.blob1_b64) def test_02_store_on_disk(self): - registry, cr, uid = self.registry, self.cr, self.uid - - a2 = self.ira.create(cr, uid, {'name': 'a2', 'datas': self.blob1_b64}) - a2_store_fname = self.ira.browse(cr, uid, a2).store_fname - - self.assertEqual(a2_store_fname, self.blob1_fname) - self.assertTrue(os.path.isfile(os.path.join(self.filestore, a2_store_fname))) + a2 = self.Attachment.create({'name': 'a2', 'datas': self.blob1_b64}) + self.assertEqual(a2.store_fname, self.blob1_fname) + self.assertTrue(os.path.isfile(os.path.join(self.filestore, a2.store_fname))) def test_03_no_duplication(self): - registry, cr, uid = self.registry, self.cr, self.uid - - a2 = self.ira.create(cr, uid, {'name': 'a2', 'datas': self.blob1_b64}) - a2_store_fname = self.ira.browse(cr, uid, a2).store_fname - - a3 = self.ira.create(cr, uid, {'name': 'a3', 'datas': self.blob1_b64}) - a3_store_fname = self.ira.browse(cr, uid, a3).store_fname - - self.assertEqual(a3_store_fname, a2_store_fname) + a2 = self.Attachment.create({'name': 'a2', 'datas': self.blob1_b64}) + a3 = self.Attachment.create({'name': 'a3', 'datas': self.blob1_b64}) + self.assertEqual(a3.store_fname, a2.store_fname) def test_04_keep_file(self): - registry, cr, uid = self.registry, self.cr, self.uid - - a2 = self.ira.create(cr, uid, {'name': 'a2', 'datas': self.blob1_b64}) - a3 = self.ira.create(cr, uid, {'name': 'a3', 'datas': self.blob1_b64}) + a2 = self.Attachment.create({'name': 'a2', 'datas': self.blob1_b64}) + a3 = self.Attachment.create({'name': 'a3', 'datas': self.blob1_b64}) - a2_store_fname = self.ira.browse(cr, uid, a2).store_fname - a2_fn = os.path.join(self.filestore, a2_store_fname) + a2_fn = os.path.join(self.filestore, a2.store_fname) - self.ira.unlink(cr, uid, [a3]) + a3.unlink() self.assertTrue(os.path.isfile(a2_fn)) # delete a2 it is unlinked - self.ira.unlink(cr, uid, [a2]) + a2.unlink() self.assertFalse(os.path.isfile(a2_fn)) def test_05_change_data_change_file(self): - registry, cr, uid = self.registry, self.cr, self.uid - - a2 = self.ira.create(cr, uid, {'name': 'a2', 'datas': self.blob1_b64}) - a2_store_fname = self.ira.browse(cr, uid, a2).store_fname - a2_fn = os.path.join(self.filestore, a2_store_fname) + a2 = self.Attachment.create({'name': 'a2', 'datas': self.blob1_b64}) + a2_store_fname1 = a2.store_fname + a2_fn = os.path.join(self.filestore, a2_store_fname1) self.assertTrue(os.path.isfile(a2_fn)) - self.ira.write(cr, uid, [a2], {'datas': self.blob2_b64}) + a2.write({'datas': self.blob2_b64}) self.assertFalse(os.path.isfile(a2_fn)) - new_a2_store_fname = self.ira.browse(cr, uid, a2).store_fname - self.assertNotEqual(a2_store_fname, new_a2_store_fname) + a2_store_fname2 = a2.store_fname + self.assertNotEqual(a2_store_fname1, a2_store_fname2) - new_a2_fn = os.path.join(self.filestore, new_a2_store_fname) - self.assertTrue(os.path.isfile(new_a2_fn)) + a2_fn = os.path.join(self.filestore, a2_store_fname2) + self.assertTrue(os.path.isfile(a2_fn)) diff --git a/openerp/addons/base/tests/test_ir_filters.py b/openerp/addons/base/tests/test_ir_filters.py index 2132fdb946b..d932f16be11 100644 --- a/openerp/addons/base/tests/test_ir_filters.py +++ b/openerp/addons/base/tests/test_ir_filters.py @@ -1,8 +1,8 @@ # -*- coding: utf-8 -*- -import functools +# Part of Odoo. See LICENSE file for full copyright and licensing details. -from openerp import exceptions -from openerp.tests import common +from odoo import exceptions +from odoo.tests.common import TransactionCase, ADMIN_USER_ID def noid(d): """ Removes values that are not relevant for the test comparisons """ @@ -10,17 +10,19 @@ def noid(d): d.pop('action_id', None) return d -class FiltersCase(common.TransactionCase): + +class FiltersCase(TransactionCase): def build(self, model, *args): - Model = self.registry(model) - for vars in args: - Model.create(self.cr, common.ADMIN_USER_ID, vars, {}) + Model = self.env[model].sudo(ADMIN_USER_ID) + for vals in args: + Model.create(vals) + class TestGetFilters(FiltersCase): def setUp(self): super(TestGetFilters, self).setUp() - self.USER = self.registry('res.users').name_search(self.cr, self.uid, 'demo')[0] - self.USER_ID = self.USER[0] + self.USER_NG = self.env['res.users'].name_search('demo')[0] + self.USER_ID = self.USER_NG[0] def test_own_filters(self): self.build( @@ -30,14 +32,13 @@ class TestGetFilters(FiltersCase): dict(name='c', user_id=self.USER_ID, model_id='ir.filters'), dict(name='d', user_id=self.USER_ID, model_id='ir.filters')) - filters = self.registry('ir.filters').get_filters( - self.cr, self.USER_ID, 'ir.filters') + filters = self.env['ir.filters'].sudo(self.USER_ID).get_filters('ir.filters') self.assertItemsEqual(map(noid, filters), [ - dict(name='a', is_default=False, user_id=self.USER, domain='[]', context='{}', sort='[]'), - dict(name='b', is_default=False, user_id=self.USER, domain='[]', context='{}', sort='[]'), - dict(name='c', is_default=False, user_id=self.USER, domain='[]', context='{}', sort='[]'), - dict(name='d', is_default=False, user_id=self.USER, domain='[]', context='{}', sort='[]'), + dict(name='a', is_default=False, user_id=self.USER_NG, domain='[]', context='{}', sort='[]'), + dict(name='b', is_default=False, user_id=self.USER_NG, domain='[]', context='{}', sort='[]'), + dict(name='c', is_default=False, user_id=self.USER_NG, domain='[]', context='{}', sort='[]'), + dict(name='d', is_default=False, user_id=self.USER_NG, domain='[]', context='{}', sort='[]'), ]) def test_global_filters(self): @@ -49,8 +50,7 @@ class TestGetFilters(FiltersCase): dict(name='d', user_id=False, model_id='ir.filters'), ) - filters = self.registry('ir.filters').get_filters( - self.cr, self.USER_ID, 'ir.filters') + filters = self.env['ir.filters'].sudo(self.USER_ID).get_filters('ir.filters') self.assertItemsEqual(map(noid, filters), [ dict(name='a', is_default=False, user_id=False, domain='[]', context='{}', sort='[]'), @@ -63,40 +63,40 @@ class TestGetFilters(FiltersCase): self.build( 'ir.filters', dict(name='a', user_id=False, model_id='ir.filters'), - dict(name='b', user_id=common.ADMIN_USER_ID, model_id='ir.filters'), + dict(name='b', user_id=ADMIN_USER_ID, model_id='ir.filters'), dict(name='c', user_id=self.USER_ID, model_id='ir.filters'), - dict(name='d', user_id=common.ADMIN_USER_ID, model_id='ir.filters') ) + dict(name='d', user_id=ADMIN_USER_ID, model_id='ir.filters') ) - filters = self.registry('ir.filters').get_filters( - self.cr, self.USER_ID, 'ir.filters') + filters = self.env['ir.filters'].sudo(self.USER_ID).get_filters('ir.filters') self.assertItemsEqual(map(noid, filters), [ dict(name='a', is_default=False, user_id=False, domain='[]', context='{}', sort='[]'), - dict(name='c', is_default=False, user_id=self.USER, domain='[]', context='{}', sort='[]'), + dict(name='c', is_default=False, user_id=self.USER_NG, domain='[]', context='{}', sort='[]'), ]) + class TestOwnDefaults(FiltersCase): def setUp(self): super(TestOwnDefaults, self).setUp() - self.USER = self.registry('res.users').name_search(self.cr, self.uid, 'demo')[0] - self.USER_ID = self.USER[0] + self.USER_NG = self.env['res.users'].name_search('demo')[0] + self.USER_ID = self.USER_NG[0] def test_new_no_filter(self): """ When creating a @is_default filter with no existing filter, that new filter gets the default flag """ - Filters = self.registry('ir.filters') - Filters.create_or_replace(self.cr, self.USER_ID, { + Filters = self.env['ir.filters'].sudo(self.USER_ID) + Filters.create_or_replace({ 'name': 'a', 'model_id': 'ir.filters', 'user_id': self.USER_ID, 'is_default': True, }) - filters = Filters.get_filters(self.cr, self.USER_ID, 'ir.filters') + filters = Filters.get_filters('ir.filters') self.assertItemsEqual(map(noid, filters), [ - dict(name='a', user_id=self.USER, is_default=True, + dict(name='a', user_id=self.USER_NG, is_default=True, domain='[]', context='{}', sort='[]') ]) @@ -111,19 +111,19 @@ class TestOwnDefaults(FiltersCase): dict(name='b', user_id=self.USER_ID, model_id='ir.filters'), ) - Filters = self.registry('ir.filters') - Filters.create_or_replace(self.cr, self.USER_ID, { + Filters = self.env['ir.filters'].sudo(self.USER_ID) + Filters.create_or_replace({ 'name': 'c', 'model_id': 'ir.filters', 'user_id': self.USER_ID, 'is_default': True, }) - filters = Filters.get_filters(self.cr, self.USER_ID, 'ir.filters') + filters = Filters.get_filters('ir.filters') self.assertItemsEqual(map(noid, filters), [ - dict(name='a', user_id=self.USER, is_default=False, domain='[]', context='{}', sort='[]'), - dict(name='b', user_id=self.USER, is_default=False, domain='[]', context='{}', sort='[]'), - dict(name='c', user_id=self.USER, is_default=True, domain='[]', context='{}', sort='[]'), + dict(name='a', user_id=self.USER_NG, is_default=False, domain='[]', context='{}', sort='[]'), + dict(name='b', user_id=self.USER_NG, is_default=False, domain='[]', context='{}', sort='[]'), + dict(name='c', user_id=self.USER_NG, is_default=True, domain='[]', context='{}', sort='[]'), ]) def test_new_filter_existing_default(self): @@ -137,19 +137,19 @@ class TestOwnDefaults(FiltersCase): dict(name='b', is_default=True, user_id=self.USER_ID, model_id='ir.filters'), ) - Filters = self.registry('ir.filters') - Filters.create_or_replace(self.cr, self.USER_ID, { + Filters = self.env['ir.filters'].sudo(self.USER_ID) + Filters.create_or_replace({ 'name': 'c', 'model_id': 'ir.filters', 'user_id': self.USER_ID, 'is_default': True, }) - filters = Filters.get_filters(self.cr, self.USER_ID, 'ir.filters') + filters = Filters.get_filters('ir.filters') self.assertItemsEqual(map(noid, filters), [ - dict(name='a', user_id=self.USER, is_default=False, domain='[]', context='{}', sort='[]'), - dict(name='b', user_id=self.USER, is_default=False, domain='[]', context='{}', sort='[]'), - dict(name='c', user_id=self.USER, is_default=True, domain='[]', context='{}', sort='[]'), + dict(name='a', user_id=self.USER_NG, is_default=False, domain='[]', context='{}', sort='[]'), + dict(name='b', user_id=self.USER_NG, is_default=False, domain='[]', context='{}', sort='[]'), + dict(name='c', user_id=self.USER_NG, is_default=True, domain='[]', context='{}', sort='[]'), ]) def test_update_filter_set_default(self): @@ -163,25 +163,26 @@ class TestOwnDefaults(FiltersCase): dict(name='b', is_default=True, user_id=self.USER_ID, model_id='ir.filters'), ) - Filters = self.registry('ir.filters') - Filters.create_or_replace(self.cr, self.USER_ID, { + Filters = self.env['ir.filters'].sudo(self.USER_ID) + Filters.create_or_replace({ 'name': 'a', 'model_id': 'ir.filters', 'user_id': self.USER_ID, 'is_default': True, }) - filters = Filters.get_filters(self.cr, self.USER_ID, 'ir.filters') + filters = Filters.get_filters('ir.filters') self.assertItemsEqual(map(noid, filters), [ - dict(name='a', user_id=self.USER, is_default=True, domain='[]', context='{}', sort='[]'), - dict(name='b', user_id=self.USER, is_default=False, domain='[]', context='{}', sort='[]'), + dict(name='a', user_id=self.USER_NG, is_default=True, domain='[]', context='{}', sort='[]'), + dict(name='b', user_id=self.USER_NG, is_default=False, domain='[]', context='{}', sort='[]'), ]) + class TestGlobalDefaults(FiltersCase): def setUp(self): super(TestGlobalDefaults, self).setUp() - self.USER = self.registry('res.users').name_search(self.cr, self.uid, 'demo')[0] - self.USER_ID = self.USER[0] + self.USER_NG = self.env['res.users'].name_search('demo')[0] + self.USER_ID = self.USER_NG[0] def test_new_filter_not_default(self): """ @@ -194,14 +195,14 @@ class TestGlobalDefaults(FiltersCase): dict(name='b', user_id=False, model_id='ir.filters'), ) - Filters = self.registry('ir.filters') - Filters.create_or_replace(self.cr, self.USER_ID, { + Filters = self.env['ir.filters'].sudo(self.USER_ID) + Filters.create_or_replace({ 'name': 'c', 'model_id': 'ir.filters', 'user_id': False, 'is_default': True, }) - filters = Filters.get_filters(self.cr, self.USER_ID, 'ir.filters') + filters = Filters.get_filters('ir.filters') self.assertItemsEqual(map(noid, filters), [ dict(name='a', user_id=False, is_default=False, domain='[]', context='{}', sort='[]'), @@ -220,9 +221,9 @@ class TestGlobalDefaults(FiltersCase): dict(name='b', is_default=True, user_id=False, model_id='ir.filters'), ) - Filters = self.registry('ir.filters') + Filters = self.env['ir.filters'].sudo(self.USER_ID) with self.assertRaises(exceptions.Warning): - Filters.create_or_replace(self.cr, self.USER_ID, { + Filters.create_or_replace({ 'name': 'c', 'model_id': 'ir.filters', 'user_id': False, @@ -240,10 +241,9 @@ class TestGlobalDefaults(FiltersCase): dict(name='b', is_default=True, user_id=False, model_id='ir.filters'), ) - Filters = self.registry('ir.filters') - + Filters = self.env['ir.filters'].sudo(self.USER_ID) with self.assertRaises(exceptions.Warning): - Filters.create_or_replace(self.cr, self.USER_ID, { + Filters.create_or_replace({ 'name': 'a', 'model_id': 'ir.filters', 'user_id': False, @@ -260,42 +260,37 @@ class TestGlobalDefaults(FiltersCase): dict(name='b', is_default=True, user_id=False, model_id='ir.filters'), ) - Filters = self.registry('ir.filters') + Filters = self.env['ir.filters'].sudo(self.USER_ID) context_value = "{'some_key': True}" - Filters.create_or_replace(self.cr, self.USER_ID, { + Filters.create_or_replace({ 'name': 'b', 'model_id': 'ir.filters', 'user_id': False, 'context': context_value, 'is_default': True, }) - filters = Filters.get_filters(self.cr, self.USER_ID, 'ir.filters') + filters = Filters.get_filters('ir.filters') self.assertItemsEqual(map(noid, filters), [ dict(name='a', user_id=False, is_default=False, domain='[]', context='{}', sort='[]'), dict(name='b', user_id=False, is_default=True, domain='[]', context=context_value, sort='[]'), ]) -from openerp.tests.common import TransactionCase class TestReadGroup(TransactionCase): """Test function read_group with groupby on a many2one field to a model (in test, "user_id" to "res.users") which is ordered by an inherited not stored field (in test, "name" inherited from "res.partners"). """ - - def setUp(self): - super(TestReadGroup, self).setUp() - self.ir_filters_model = self.env['ir.filters'] - self.res_partner_model = self.env['res.partner'] - self.res_users_model = self.env['res.users'] - def test_read_group_1(self): - self.assertEqual(self.res_users_model._order, "name, login", "Model res.users must be ordered by name, login") - self.assertFalse(self.res_users_model._fields['name'].store, "Field name is not stored in res.users") + Users = self.env['res.users'] + self.assertEqual(Users._order, "name, login", "Model res.users must be ordered by name, login") + self.assertFalse(Users._fields['name'].store, "Field name is not stored in res.users") - filter_a = self.ir_filters_model.create(dict(name="Filter_A", model_id="ir.filters")) - filter_b = self.ir_filters_model.create(dict(name="Filter_B", model_id="ir.filters")) + Filters = self.env['ir.filters'] + filter_a = Filters.create(dict(name="Filter_A", model_id="ir.filters")) + filter_b = Filters.create(dict(name="Filter_B", model_id="ir.filters")) filter_b.write(dict(user_id=False)) - res = self.ir_filters_model.read_group([], ['name', 'user_id'], ['user_id']) + + res = Filters.read_group([], ['name', 'user_id'], ['user_id']) self.assertTrue(any(val['user_id'] == False for val in res), "At least one group must contain val['user_id'] == False.") diff --git a/openerp/addons/base/tests/test_ir_rule.yml b/openerp/addons/base/tests/test_ir_rule.yml deleted file mode 100644 index 02fc2e3d3b4..00000000000 --- a/openerp/addons/base/tests/test_ir_rule.yml +++ /dev/null @@ -1,189 +0,0 @@ -- - Exercise ir_rule.py code (and indirectly expression.py). -- - Create an ir_rule for the Employee group (called base.group_user) - with an blank domain. -- - !record {model: ir.rule, id: test_rule}: - model_id: base.model_res_partner - domain_force: False - name: test_rule - groups: - - base.group_user - perm_unlink: 1 - perm_write: 1 - perm_read: 1 - perm_create: 1 -- - Read as demo user the partners (one blank domain). -- - !python {model: res.partner }: | - ids = self.search(cr, ref('base.user_demo'), []) - assert ids, "Demo user should see some partner." -- - Domain is not empty. -- - !record {model: ir.rule, id: test_rule}: - model_id: base.model_res_partner - domain_force: "[(1,'=',1)]" -- - Read as demo user the partners (one 1=1 domain). -- - !python {model: res.partner }: | - ids = self.search(cr, ref('base.user_demo'), []) - assert ids, "Demo user should see some partner." -- - Domain is an empty list. -- - !record {model: ir.rule, id: test_rule}: - model_id: base.model_res_partner - domain_force: "[]" -- - Read as demo user the partners (one [] domain). -- - !python {model: res.partner }: | - ids = self.search(cr, ref('base.user_demo'), []) - assert ids, "Demo user should see some partner." -- - Create another ir_rule for the Employee group (to test rules from - multiple groups). -- - !record {model: ir.rule, id: test_rule2}: - model_id: base.model_res_partner - domain_force: False - name: test_rule2 - groups: - - base.group_user - perm_unlink: 1 - perm_write: 1 - perm_read: 1 - perm_create: 1 -- - Read as demo user the partners (blank and [] domains). -- - !python {model: res.partner }: | - ids = self.search(cr, ref('base.user_demo'), []) - assert ids, "Demo user should see some partner." -- - Domain is not empty. -- - !record {model: ir.rule, id: test_rule}: - model_id: base.model_res_partner - domain_force: "[(1,'=',1)]" -- - Read as demo user the partners (1=1 and blank domain). -- - !python {model: res.partner }: | - ids = self.search(cr, ref('base.user_demo'), []) - assert ids, "Demo user should see some partner." -- - Domain is not empty. -- - !record {model: ir.rule, id: test_rule2}: - model_id: base.model_res_partner - domain_force: "[(1,'=',1)]" -- - Read as demo user the partners (two 1=1 domains). -- - !python {model: res.partner }: | - ids = self.search(cr, ref('base.user_demo'), []) - assert ids, "Demo user should see some partner." -- - Create another ir_rule for the Employee group (to test rules from - multiple groups). -- - !record {model: ir.rule, id: test_rule3}: - model_id: base.model_res_partner - domain_force: False - name: test_rule3 - groups: - - base.group_user - perm_unlink: 1 - perm_write: 1 - perm_read: 1 - perm_create: 1 -- - Read as demo user the partners. -- - !python {model: res.partner }: | - ids = self.search(cr, ref('base.user_demo'), []) - assert ids, "Demo user should see some partner." -- - Domain is not empty. -- - !record {model: ir.rule, id: test_rule3}: - model_id: base.model_res_partner - domain_force: "[(1,'=',1)]" -- - Read as demo user the partners (three 1=1 domains). -- - !python {model: res.partner }: | - ids = self.search(cr, ref('base.user_demo'), []) - assert ids, "Demo user should see some partner." -- - Modify the global rule on res_company which triggers a recursive check - of the rules on company. -- - !record {model: ir.rule, id: res_company_rule_employee}: - domain_force: "[('id','child_of',[user.company_id.id])]" -- - Read as demo user the partners (exercising the global company rule). -- - !python {model: res.partner }: | - ids = self.search(cr, ref('base.user_demo'), []) - assert ids, "Demo user should see some partner." -- - Modify the ir_rule for employee to have a rule that fordids - seeing any record. - We use a domain with implicit AND operator for later tests - on normalization. -- - !record {model: ir.rule, id: test_rule2}: - domain_force: "[('id','=',False),('name','=',False)]" -- - Check that demo user still sees partners, because group-rules are OR'ed. -- - !python {model: res.partner }: | - ids = self.search(cr, ref('base.user_demo'), []) - assert ids, "Demo user should see some partner." -- - Create a new group with demo user in it, and a complex rule. - Demo should still see partners. -- - !record {model: res.groups, id: test_group}: - name: Test Group - users: - - base.user_demo -- - Add the rule to the new group, with a domain containing an implicit AND operator, - which is more tricky because it will have to be normalized before combining it. -- - !record {model: ir.rule, id: test_rule3}: - model_id: base.model_res_partner - domain_force: "[('name', '!=', False),('id', '!=', False)]" - name: test_rule4 - groups: - - test_group - perm_unlink: 1 - perm_write: 1 - perm_read: 1 - perm_create: 1 -- - Read the partners again as demo user, which should give results. -- - !python {model: res.partner }: | - ids = self.search(cr, ref('base.user_demo'), []) - assert ids, "Demo user should see partners even with the combined rules." -- - Delete global domains (to combine only group domains). -- - !python {model: ir.rule}: | - ids = self.search(cr, uid, [('groups','=',False)]) - assert ids, "Demo user should see some partner." - self.unlink(cr, uid, ids) -- - Read as demo user the partners (several group domains, no global domain). -- - !python {model: res.partner }: | - ids = self.search(cr, ref('base.user_demo'), []) - assert ids, "Demo user should see some partner." diff --git a/openerp/addons/base/tests/test_ir_sequence.py b/openerp/addons/base/tests/test_ir_sequence.py index 3d2f891c63e..76db66d7008 100644 --- a/openerp/addons/base/tests/test_ir_sequence.py +++ b/openerp/addons/base/tests/test_ir_sequence.py @@ -1,193 +1,177 @@ # -*- coding: utf-8 -*- -# Run with one of these commands: -# > OPENERP_ADDONS_PATH='../../addons/trunk' OPENERP_PORT=8069 \ -# OPENERP_DATABASE=yy PYTHONPATH=. python tests/test_ir_sequence.py -# > OPENERP_ADDONS_PATH='../../addons/trunk' OPENERP_PORT=8069 \ -# OPENERP_DATABASE=yy nosetests tests/test_ir_sequence.py -# > OPENERP_ADDONS_PATH='../../../addons/trunk' OPENERP_PORT=8069 \ -# OPENERP_DATABASE=yy PYTHONPATH=../:. unit2 test_ir_sequence -# This assume an existing database. +# Part of Odoo. See LICENSE file for full copyright and licensing details. + +from contextlib import contextmanager +import unittest + import psycopg2 import psycopg2.errorcodes -import unittest -import openerp -from openerp.tests import common +import odoo +from odoo.tests import common ADMIN_USER_ID = common.ADMIN_USER_ID -def registry(model): - return openerp.modules.registry.RegistryManager.get(common.get_db_name())[model] - -def cursor(): - return openerp.modules.registry.RegistryManager.get(common.get_db_name()).cursor() +@contextmanager +def environment(): + """ Return an environment with a new cursor for the current database; the + cursor is committed and closed after the context block. + """ + registry = odoo.registry(common.get_db_name()) + with registry.cursor() as cr: + yield odoo.api.Environment(cr, ADMIN_USER_ID, {}) + cr.commit() def drop_sequence(code): - cr = cursor() - s = registry('ir.sequence') - ids = s.search(cr, ADMIN_USER_ID, [('code', '=', code)]) - s.unlink(cr, ADMIN_USER_ID, ids) - cr.commit() - cr.close() - -class test_ir_sequence_standard(unittest.TestCase): + with environment() as env: + seq = env['ir.sequence'].search([('code', '=', code)]) + seq.unlink() + + +class TestIrSequenceStandard(unittest.TestCase): """ A few tests for a 'Standard' (i.e. PostgreSQL) sequence. """ def test_ir_sequence_create(self): """ Try to create a sequence object. """ - cr = cursor() - d = dict(code='test_sequence_type', name='Test sequence') - c = registry('ir.sequence').create(cr, ADMIN_USER_ID, d, {}) - assert c - cr.commit() - cr.close() + with environment() as env: + seq = env['ir.sequence'].create({ + 'code': 'test_sequence_type', + 'name': 'Test sequence', + }) + self.assertTrue(seq) def test_ir_sequence_search(self): """ Try a search. """ - cr = cursor() - ids = registry('ir.sequence').search(cr, ADMIN_USER_ID, [], {}) - assert ids - cr.commit() - cr.close() + with environment() as env: + seqs = env['ir.sequence'].search([]) + self.assertTrue(seqs) def test_ir_sequence_draw(self): """ Try to draw a number. """ - cr = cursor() - n = registry('ir.sequence').next_by_code(cr, ADMIN_USER_ID, 'test_sequence_type', {}) - assert n - cr.commit() - cr.close() + with environment() as env: + n = env['ir.sequence'].next_by_code('test_sequence_type') + self.assertTrue(n) def test_ir_sequence_draw_twice(self): """ Try to draw a number from two transactions. """ - cr0 = cursor() - cr1 = cursor() - n0 = registry('ir.sequence').next_by_code(cr0, ADMIN_USER_ID, 'test_sequence_type', {}) - assert n0 - n1 = registry('ir.sequence').next_by_code(cr1, ADMIN_USER_ID, 'test_sequence_type', {}) - assert n1 - cr0.commit() - cr1.commit() - cr0.close() - cr1.close() + with environment() as env0: + with environment() as env1: + n0 = env0['ir.sequence'].next_by_code('test_sequence_type') + self.assertTrue(n0) + n1 = env1['ir.sequence'].next_by_code('test_sequence_type') + self.assertTrue(n1) @classmethod def tearDownClass(cls): drop_sequence('test_sequence_type') -class test_ir_sequence_no_gap(unittest.TestCase): + +class TestIrSequenceNoGap(unittest.TestCase): """ Copy of the previous tests for a 'No gap' sequence. """ def test_ir_sequence_create_no_gap(self): """ Try to create a sequence object. """ - cr = cursor() - d = dict(code='test_sequence_type_2', name='Test sequence', - implementation='no_gap') - c = registry('ir.sequence').create(cr, ADMIN_USER_ID, d, {}) - assert c - cr.commit() - cr.close() + with environment() as env: + seq = env['ir.sequence'].create({ + 'code': 'test_sequence_type_2', + 'name': 'Test sequence', + 'implementation': 'no_gap', + }) + self.assertTrue(seq) def test_ir_sequence_draw_no_gap(self): """ Try to draw a number. """ - cr = cursor() - n = registry('ir.sequence').next_by_code(cr, ADMIN_USER_ID, 'test_sequence_type_2', {}) - assert n - cr.commit() - cr.close() + with environment() as env: + n = env['ir.sequence'].next_by_code('test_sequence_type_2') + self.assertTrue(n) def test_ir_sequence_draw_twice_no_gap(self): """ Try to draw a number from two transactions. This is expected to not work. """ - cr0 = cursor() - cr1 = cursor() - cr1._default_log_exceptions = False # Prevent logging a traceback - with self.assertRaises(psycopg2.OperationalError) as e: - n0 = registry('ir.sequence').next_by_code(cr0, ADMIN_USER_ID, 'test_sequence_type_2', {}) - assert n0 - n1 = registry('ir.sequence').next_by_code(cr1, ADMIN_USER_ID, 'test_sequence_type_2', {}) - self.assertEqual(e.exception.pgcode, psycopg2.errorcodes.LOCK_NOT_AVAILABLE, msg="postgresql returned an incorrect errcode") - cr0.close() - cr1.close() + with environment() as env0: + with environment() as env1: + env1.cr._default_log_exceptions = False # Prevent logging a traceback + with self.assertRaises(psycopg2.OperationalError) as e: + n0 = env0['ir.sequence'].next_by_code('test_sequence_type_2') + self.assertTrue(n0) + n1 = env1['ir.sequence'].next_by_code('test_sequence_type_2') + self.assertEqual(e.exception.pgcode, psycopg2.errorcodes.LOCK_NOT_AVAILABLE, msg="postgresql returned an incorrect errcode") @classmethod def tearDownClass(cls): drop_sequence('test_sequence_type_2') -class test_ir_sequence_change_implementation(unittest.TestCase): + +class TestIrSequenceChangeImplementation(unittest.TestCase): """ Create sequence objects and change their ``implementation`` field. """ def test_ir_sequence_1_create(self): """ Try to create a sequence object. """ - cr = cursor() - d = dict(code='test_sequence_type_3', name='Test sequence') - c = registry('ir.sequence').create(cr, ADMIN_USER_ID, d, {}) - assert c - d = dict(code='test_sequence_type_4', name='Test sequence', - implementation='no_gap') - c = registry('ir.sequence').create(cr, ADMIN_USER_ID, d, {}) - assert c - cr.commit() - cr.close() + with environment() as env: + seq = env['ir.sequence'].create({ + 'code': 'test_sequence_type_3', + 'name': 'Test sequence', + }) + self.assertTrue(seq) + seq = env['ir.sequence'].create({ + 'code': 'test_sequence_type_4', + 'name': 'Test sequence', + 'implementation': 'no_gap', + }) + self.assertTrue(seq) def test_ir_sequence_2_write(self): - cr = cursor() - ids = registry('ir.sequence').search(cr, ADMIN_USER_ID, - [('code', 'in', ['test_sequence_type_3', 'test_sequence_type_4'])], {}) - registry('ir.sequence').write(cr, ADMIN_USER_ID, ids, - {'implementation': 'standard'}, {}) - registry('ir.sequence').write(cr, ADMIN_USER_ID, ids, - {'implementation': 'no_gap'}, {}) - cr.commit() - cr.close() + with environment() as env: + domain = [('code', 'in', ['test_sequence_type_3', 'test_sequence_type_4'])] + seqs = env['ir.sequence'].search(domain) + seqs.write({'implementation': 'standard'}) + seqs.write({'implementation': 'no_gap'}) def test_ir_sequence_3_unlink(self): - cr = cursor() - ids = registry('ir.sequence').search(cr, ADMIN_USER_ID, - [('code', 'in', ['test_sequence_type_3', 'test_sequence_type_4'])], {}) - registry('ir.sequence').unlink(cr, ADMIN_USER_ID, ids, {}) - cr.commit() - cr.close() + with environment() as env: + domain = [('code', 'in', ['test_sequence_type_3', 'test_sequence_type_4'])] + seqs = env['ir.sequence'].search(domain) + seqs.unlink() @classmethod def tearDownClass(cls): drop_sequence('test_sequence_type_3') drop_sequence('test_sequence_type_4') -class test_ir_sequence_generate(unittest.TestCase): + +class TestIrSequenceGenerate(unittest.TestCase): """ Create sequence objects and generate some values. """ def test_ir_sequence_create(self): """ Try to create a sequence object. """ - cr = cursor() - d = dict(code='test_sequence_type_5', name='Test sequence') - c = registry('ir.sequence').create(cr, ADMIN_USER_ID, d, {}) - assert c - cr.commit() - cr.close() - - cr = cursor() - f = lambda *a: registry('ir.sequence').next_by_code(cr, ADMIN_USER_ID, 'test_sequence_type_5', {}) - assert all(str(x) == f() for x in xrange(1,10)) - cr.commit() - cr.close() + with environment() as env: + seq = env['ir.sequence'].create({ + 'code': 'test_sequence_type_5', + 'name': 'Test sequence', + }) + self.assertTrue(seq) + + with environment() as env: + for i in xrange(1, 10): + n = env['ir.sequence'].next_by_code('test_sequence_type_5') + self.assertEqual(n, str(i)) def test_ir_sequence_create_no_gap(self): """ Try to create a sequence object. """ - cr = cursor() - d = dict(code='test_sequence_type_6', name='Test sequence', implementation='no_gap') - c = registry('ir.sequence').create(cr, ADMIN_USER_ID, d, {}) - assert c - cr.commit() - cr.close() - - cr = cursor() - f = lambda *a: registry('ir.sequence').next_by_code(cr, ADMIN_USER_ID, 'test_sequence_type_6', {}) - assert all(str(x) == f() for x in xrange(1,10)) - cr.commit() - cr.close() + with environment() as env: + seq = env['ir.sequence'].create({ + 'code': 'test_sequence_type_6', + 'name': 'Test sequence', + 'implementation': 'no_gap', + }) + self.assertTrue(seq) + + with environment() as env: + for i in xrange(1, 10): + n = env['ir.sequence'].next_by_code('test_sequence_type_6') + self.assertEqual(n, str(i)) @classmethod def tearDownClass(cls): @@ -195,33 +179,29 @@ class test_ir_sequence_generate(unittest.TestCase): drop_sequence('test_sequence_type_6') -class Test_ir_sequence_init(common.TransactionCase): +class TestIrSequenceInit(common.TransactionCase): def test_00(self): - registry, cr, uid = self.registry, self.cr, self.uid - - # test if read statement return the good number_next value (from postgreSQL sequence and not ir_sequence value) - sequence = registry('ir.sequence') + """ test whether the read method returns the right number_next value + (from postgreSQL sequence and not ir_sequence value) + """ # first creation of sequence (normal) - values = {'number_next': 1, - 'company_id': 1, - 'padding': 4, - 'number_increment': 1, - 'implementation': 'standard', - 'name': 'test-sequence-00'} - seq_id = sequence.create(cr, uid, values) - # Call get next 4 times - sequence.next_by_id(cr, uid, seq_id) - sequence.next_by_id(cr, uid, seq_id) - sequence.next_by_id(cr, uid, seq_id) - read_sequence = sequence.next_by_id(cr, uid, seq_id) - # Read the value of the current sequence - assert read_sequence == "0004", 'The actual sequence value must be 4. reading : %s' % read_sequence - # reset sequence to 1 by write method calling - sequence.write(cr, uid, [seq_id], {'number_next': 1}) + seq = self.env['ir.sequence'].create({ + 'number_next': 1, + 'company_id': 1, + 'padding': 4, + 'number_increment': 1, + 'implementation': 'standard', + 'name': 'test-sequence-00', + }) + # Call next() 4 times, and check the last returned value + seq.next_by_id() + seq.next_by_id() + seq.next_by_id() + n = seq.next_by_id() + self.assertEqual(n, "0004", 'The actual sequence value must be 4. reading : %s' % n) + # reset sequence to 1 by write() + seq.write({'number_next': 1}) # Read the value of the current sequence - read_sequence = sequence.next_by_id(cr, uid, seq_id) - assert read_sequence == "0001", 'The actual sequence value must be 1. reading : %s' % read_sequence - -if __name__ == "__main__": - unittest.main() + n = seq.next_by_id() + self.assertEqual(n, "0001", 'The actual sequence value must be 1. reading : %s' % n) diff --git a/openerp/addons/base/tests/test_ir_sequence_date_range.py b/openerp/addons/base/tests/test_ir_sequence_date_range.py index c2ddc4e4f0f..147b0f26050 100644 --- a/openerp/addons/base/tests/test_ir_sequence_date_range.py +++ b/openerp/addons/base/tests/test_ir_sequence_date_range.py @@ -1,122 +1,142 @@ -import unittest +# -*- coding: utf-8 -*- +# Part of Odoo. See LICENSE file for full copyright and licensing details. -from openerp.tests import common from datetime import date +from odoo.tests.common import SingleTransactionCase +from odoo.tools import DEFAULT_SERVER_DATE_FORMAT as DATE_FORMAT -class test_ir_sequence_date_range_standard(common.SingleTransactionCase): + +class TestIrSequenceDateRangeStandard(SingleTransactionCase): """ A few tests for a 'Standard' (i.e. PostgreSQL) sequence. """ def test_ir_sequence_date_range_1_create(self): """ Try to create a sequence object with date ranges enabled. """ - d = dict(code='test_sequence_date_range', name='Test sequence', use_date_range=True) - c = self.registry('ir.sequence').create(self.cr, self.uid, d, {}) - assert c + seq = self.env['ir.sequence'].create({ + 'code': 'test_sequence_date_range', + 'name': 'Test sequence', + 'use_date_range': True, + }) + self.assertTrue(seq) def test_ir_sequence_date_range_2_change_dates(self): """ Draw numbers to create a first subsequence then change its date range. Then, try to draw a new number adn check a new subsequence was correctly created. """ - year = str(int(date.today().strftime("%Y")) - 1) - dt = "{}-01-16".format(year) - n = self.registry('ir.sequence').next_by_code(self.cr, self.uid, 'test_sequence_date_range', {'ir_sequence_date': dt}) + year = date.today().year - 1 + january = lambda d: date(year, 1, d).strftime(DATE_FORMAT) + + seq16 = self.env['ir.sequence'].with_context({'ir_sequence_date': january(16)}) + n = seq16.next_by_code('test_sequence_date_range') self.assertEqual(n, '1') - n = self.registry('ir.sequence').next_by_code(self.cr, self.uid, 'test_sequence_date_range', {'ir_sequence_date': dt}) + n = seq16.next_by_code('test_sequence_date_range') self.assertEqual(n, '2') + # modify the range of date created - domain = [('sequence_id.code', '=', 'test_sequence_date_range'), ('date_from', '=', '{}-01-01'.format(year))] - seq_date_range_id = self.registry('ir.sequence.date_range').search(self.cr, self.uid, domain, {}) - self.registry('ir.sequence.date_range').write(self.cr, self.uid, seq_date_range_id, {'date_from': '{}-01-18'.format(year)}, {}) - n = self.registry('ir.sequence').next_by_code(self.cr, self.uid, 'test_sequence_date_range', {'ir_sequence_date': dt}) + domain = [('sequence_id.code', '=', 'test_sequence_date_range'), ('date_from', '=', january(1))] + seq_date_range = self.env['ir.sequence.date_range'].search(domain) + seq_date_range.write({'date_from': january(18)}) + n = seq16.next_by_code('test_sequence_date_range') self.assertEqual(n, '1') + # check the newly created sequence stops at the 17th of January - domain = [('sequence_id.code', '=', 'test_sequence_date_range'), ('date_from', '=', '{}-01-01'.format(year))] - seq_date_range_id = self.registry('ir.sequence.date_range').search(self.cr, self.uid, domain, {}) - seq_date_range = self.registry('ir.sequence.date_range').browse(self.cr, self.uid, seq_date_range_id[0]) - self.assertEqual(seq_date_range.date_to, '{}-01-17'.format(year)) + domain = [('sequence_id.code', '=', 'test_sequence_date_range'), ('date_from', '=', january(1))] + seq_date_range = self.env['ir.sequence.date_range'].search(domain) + self.assertEqual(seq_date_range.date_to, january(17)) def test_ir_sequence_date_range_3_unlink(self): - ids = self.registry('ir.sequence').search(self.cr, self.uid, [('code', '=', 'test_sequence_date_range')]) - self.registry('ir.sequence').unlink(self.cr, self.uid, ids) + seq = self.env['ir.sequence'].search([('code', '=', 'test_sequence_date_range')]) + seq.unlink() -class test_ir_sequence_date_range_no_gap(common.SingleTransactionCase): +class TestIrSequenceDateRangeNoGap(SingleTransactionCase): """ Copy of the previous tests for a 'No gap' sequence. """ def test_ir_sequence_date_range_1_create_no_gap(self): """ Try to create a sequence object. """ - d = dict(code='test_sequence_date_range_2', name='Test sequence', - implementation='no_gap', use_date_range=True) - c = self.registry('ir.sequence').create(self.cr, self.uid, d, {}) - assert c + seq = self.env['ir.sequence'].create({ + 'code': 'test_sequence_date_range_2', + 'name': 'Test sequence', + 'use_date_range': True, + 'implementation': 'no_gap', + }) + self.assertTrue(seq) def test_ir_sequence_date_range_2_change_dates(self): """ Draw numbers to create a first subsequence then change its date range. Then, try to draw a new number adn check a new subsequence was correctly created. """ - year = str(int(date.today().strftime("%Y")) - 1) - dt = "{}-01-16".format(year) - n = self.registry('ir.sequence').next_by_code(self.cr, self.uid, 'test_sequence_date_range_2', {'ir_sequence_date': dt}) + year = date.today().year - 1 + january = lambda d: date(year, 1, d).strftime(DATE_FORMAT) + + seq16 = self.env['ir.sequence'].with_context({'ir_sequence_date': january(16)}) + n = seq16.next_by_code('test_sequence_date_range_2') self.assertEqual(n, '1') - n = self.registry('ir.sequence').next_by_code(self.cr, self.uid, 'test_sequence_date_range_2', {'ir_sequence_date': dt}) + n = seq16.next_by_code('test_sequence_date_range_2') self.assertEqual(n, '2') + # modify the range of date created - domain = [('sequence_id.code', '=', 'test_sequence_date_range_2'), ('date_from', '=', '{}-01-01'.format(year))] - seq_date_range_id = self.registry('ir.sequence.date_range').search(self.cr, self.uid, domain, {}) - self.registry('ir.sequence.date_range').write(self.cr, self.uid, seq_date_range_id, {'date_from': '{}-01-18'.format(year)}, {}) - n = self.registry('ir.sequence').next_by_code(self.cr, self.uid, 'test_sequence_date_range_2', {'ir_sequence_date': dt}) + domain = [('sequence_id.code', '=', 'test_sequence_date_range_2'), ('date_from', '=', january(1))] + seq_date_range = self.env['ir.sequence.date_range'].search(domain) + seq_date_range.write({'date_from': january(18)}) + n = seq16.next_by_code('test_sequence_date_range_2') self.assertEqual(n, '1') + # check the newly created sequence stops at the 17th of January - domain = [('sequence_id.code', '=', 'test_sequence_date_range_2'), ('date_from', '=', '{}-01-01'.format(year))] - seq_date_range_id = self.registry('ir.sequence.date_range').search(self.cr, self.uid, domain, {}) - seq_date_range = self.registry('ir.sequence.date_range').browse(self.cr, self.uid, seq_date_range_id[0]) - self.assertEqual(seq_date_range.date_to, '{}-01-17'.format(year)) + domain = [('sequence_id.code', '=', 'test_sequence_date_range_2'), ('date_from', '=', january(1))] + seq_date_range = self.env['ir.sequence.date_range'].search(domain) + self.assertEqual(seq_date_range.date_to, january(17)) def test_ir_sequence_date_range_3_unlink(self): - ids = self.registry('ir.sequence').search(self.cr, self.uid, [('code', '=', 'test_sequence_date_range_2')]) - self.registry('ir.sequence').unlink(self.cr, self.uid, ids) + seq = self.env['ir.sequence'].search([('code', '=', 'test_sequence_date_range_2')]) + seq.unlink() -class test_ir_sequence_date_range_change_implementation(common.SingleTransactionCase): +class TestIrSequenceDateRangeChangeImplementation(SingleTransactionCase): """ Create sequence objects and change their ``implementation`` field. """ def test_ir_sequence_date_range_1_create(self): """ Try to create a sequence object. """ - d = dict(code='test_sequence_date_range_3', name='Test sequence', use_date_range=True) - c = self.registry('ir.sequence').create(self.cr, self.uid, d, {}) - assert c - d = { + seq = self.env['ir.sequence'].create({ + 'code': 'test_sequence_date_range_3', + 'name': 'Test sequence', + 'use_date_range': True, + }) + self.assertTrue(seq) + + seq = self.env['ir.sequence'].create({ 'code': 'test_sequence_date_range_4', 'name': 'Test sequence', + 'use_date_range': True, 'implementation': 'no_gap', - 'use_date_range': True - } - c = self.registry('ir.sequence').create(self.cr, self.uid, d, {}) - assert c + }) + self.assertTrue(seq) def test_ir_sequence_date_range_2_use(self): """ Make some use of the sequences to create some subsequences """ - year = str(int(date.today().strftime("%Y")) - 1) - dt = "{}-01-16".format(year) - f = lambda *a: self.registry('ir.sequence').next_by_code(self.cr, self.uid, 'test_sequence_date_range_3', {}) - assert all(str(x) == f() for x in xrange(1, 5)) - f = lambda *a: self.registry('ir.sequence').next_by_code(self.cr, self.uid, 'test_sequence_date_range_3', {'ir_sequence_date': dt}) - assert all(str(x) == f() for x in xrange(1, 5)) - f = lambda *a: self.registry('ir.sequence').next_by_code(self.cr, self.uid, 'test_sequence_date_range_4', {}) - assert all(str(x) == f() for x in xrange(1, 5)) - f = lambda *a: self.registry('ir.sequence').next_by_code(self.cr, self.uid, 'test_sequence_date_range_4', {'ir_sequence_date': dt}) - assert all(str(x) == f() for x in xrange(1, 5)) + year = date.today().year - 1 + january = lambda d: date(year, 1, d).strftime(DATE_FORMAT) + + seq = self.env['ir.sequence'] + seq16 = self.env['ir.sequence'].with_context({'ir_sequence_date': january(16)}) + + for i in xrange(1, 5): + n = seq.next_by_code('test_sequence_date_range_3') + self.assertEqual(n, str(i)) + for i in xrange(1, 5): + n = seq16.next_by_code('test_sequence_date_range_3') + self.assertEqual(n, str(i)) + for i in xrange(1, 5): + n = seq.next_by_code('test_sequence_date_range_4') + self.assertEqual(n, str(i)) + for i in xrange(1, 5): + n = seq16.next_by_code('test_sequence_date_range_4') + self.assertEqual(n, str(i)) def test_ir_sequence_date_range_3_write(self): """swap the implementation method on both""" - ids = self.registry('ir.sequence').search(self.cr, self.uid, [ - ('code', 'in', ['test_sequence_date_range_3', 'test_sequence_date_range_4']) - ], {}) - self.registry('ir.sequence').write(self.cr, self.uid, ids, {'implementation': 'standard'}) - self.registry('ir.sequence').write(self.cr, self.uid, ids, {'implementation': 'no_gap'}) + domain = [('code', 'in', ['test_sequence_date_range_3', 'test_sequence_date_range_4'])] + seqs = self.env['ir.sequence'].search(domain) + seqs.write({'implementation': 'standard'}) + seqs.write({'implementation': 'no_gap'}) def test_ir_sequence_date_range_4_unlink(self): - ids = self.registry('ir.sequence').search(self.cr, self.uid, [ - ('code', 'in', ['test_sequence_date_range_3', 'test_sequence_date_range_4']) - ], {}) - self.registry('ir.sequence').unlink(self.cr, self.uid, ids, {}) - - -if __name__ == '__main__': - unittest.main() + domain = [('code', 'in', ['test_sequence_date_range_3', 'test_sequence_date_range_4'])] + seqs = self.env['ir.sequence'].search(domain) + seqs.unlink() diff --git a/openerp/addons/base/tests/test_ir_values.py b/openerp/addons/base/tests/test_ir_values.py index 435421ea845..8cdf35e4d40 100644 --- a/openerp/addons/base/tests/test_ir_values.py +++ b/openerp/addons/base/tests/test_ir_values.py @@ -1,98 +1,99 @@ -import unittest +# -*- coding: utf-8 -*- +# Part of Odoo. See LICENSE file for full copyright and licensing details. -import openerp.tests.common as common +from odoo.tests.common import TransactionCase -class test_ir_values(common.TransactionCase): + +class TestIrValues(TransactionCase): def test_00(self): # Create some default value for some (non-existing) model, for all users. - ir_values = self.registry('ir.values') + ir_values = self.env['ir.values'] # use the old API - ir_values.set(self.cr, self.uid, 'default', False, 'my_test_field', - ['unexisting_model'], 'global value') + ir_values.set('default', False, 'my_test_field', ['unexisting_model'], + 'global value') # use the new API - ir_values.set_default(self.cr, self.uid, 'other_unexisting_model', - 'my_other_test_field', 'conditional value', condition='foo=bar') - + ir_values.set_default('other_unexisting_model', 'my_other_test_field', + 'conditional value', condition='foo=bar') # Retrieve them. - ir_values = self.registry('ir.values') # d is a list of triplets (id, name, value) # Old API - d = ir_values.get(self.cr, self.uid, 'default', False, ['unexisting_model']) - assert len(d) == 1, "Only one single value should be retrieved for this model" - assert d[0][1] == 'my_test_field', "Can't retrieve the created default value. (1)" - assert d[0][2] == 'global value', "Can't retrieve the created default value. (2)" + d = ir_values.get('default', False, ['unexisting_model']) + self.assertEqual(len(d), 1, "Only one single value should be retrieved for this model") + self.assertEqual(d[0][1], 'my_test_field', "Can't retrieve the created default value. (1)") + self.assertEqual(d[0][2], 'global value', "Can't retrieve the created default value. (2)") # New API, Conditional version - d = ir_values.get_defaults(self.cr, self.uid, 'other_unexisting_model') - assert len(d) == 0, "No value should be retrieved, the condition is not met" - d = ir_values.get_defaults(self.cr, self.uid, 'other_unexisting_model', condition="foo=eggs") - assert len(d) == 0, 'Condition is not met either, no defaults should be returned' - d = ir_values.get_defaults(self.cr, self.uid, 'other_unexisting_model', condition="foo=bar") - assert len(d) == 1, "Only one single value should be retrieved" - assert d[0][1] == 'my_other_test_field', "Can't retrieve the created default value. (5)" - assert d[0][2] == 'conditional value', "Can't retrieve the created default value. (6)" + d = ir_values.get_defaults('other_unexisting_model') + self.assertEqual(len(d), 0, "No value should be retrieved, the condition is not met") + d = ir_values.get_defaults('other_unexisting_model', condition="foo=eggs") + self.assertEqual(len(d), 0, 'Condition is not met either, no defaults should be returned') + d = ir_values.get_defaults('other_unexisting_model', condition="foo=bar") + self.assertEqual(len(d), 1, "Only one single value should be retrieved") + self.assertEqual(d[0][1], 'my_other_test_field', "Can't retrieve the created default value. (5)") + self.assertEqual(d[0][2], 'conditional value', "Can't retrieve the created default value. (6)") # Do it again but for a specific user. - ir_values = self.registry('ir.values') - ir_values.set(self.cr, self.uid, 'default', False, 'my_test_field',['unexisting_model'], 'specific value', preserve_user=True) + ir_values.set('default', False, 'my_test_field',['unexisting_model'], + 'specific value', preserve_user=True) # Retrieve it and check it is the one for the current user. - ir_values = self.registry('ir.values') - d = ir_values.get(self.cr, self.uid, 'default', False, ['unexisting_model']) - assert len(d) == 1, "Only one default must be returned per field" - assert d[0][1] == 'my_test_field', "Can't retrieve the created default value." - assert d[0][2] == 'specific value', "Can't retrieve the created default value." + + d = ir_values.get('default', False, ['unexisting_model']) + self.assertEqual(len(d), 1, "Only one default must be returned per field") + self.assertEqual(d[0][1], 'my_test_field', "Can't retrieve the created default value.") + self.assertEqual(d[0][2], 'specific value', "Can't retrieve the created default value.") # Create some action bindings for a non-existing model. act_id_1 = self.ref('base.act_values_form_action') act_id_2 = self.ref('base.act_values_form_defaults') act_id_3 = self.ref('base.action_res_company_form') - - ir_values = self.registry('ir.values') - ir_values.set(self.cr, self.uid, 'action', 'tree_but_open', 'OnDblClick Action', ['unexisting_model'], 'ir.actions.act_window,%d' % act_id_1, isobject=True) - ir_values.set(self.cr, self.uid, 'action', 'tree_but_open', 'OnDblClick Action 2', ['unexisting_model'], 'ir.actions.act_window,%d' % act_id_2, isobject=True) - ir_values.set(self.cr, self.uid, 'action', 'client_action_multi', 'Side Wizard', ['unexisting_model'], 'ir.actions.act_window,%d' % act_id_3, isobject=True) - report_ids = self.registry('ir.actions.report.xml').search(self.cr, self.uid, [], {}) - reports = self.registry('ir.actions.report.xml').browse(self.cr, self.uid, report_ids, {}) - report_id = [report.id for report in reports if not report.groups_id][0] # assume at least one - ir_values.set(self.cr, self.uid, 'action', 'client_print_multi', 'Nice Report', ['unexisting_model'], 'ir.actions.report.xml,%d' % report_id, isobject=True) + ir_values.set('action', 'tree_but_open', 'OnDblClick Action', ['unexisting_model'], + 'ir.actions.act_window,%d' % act_id_1, isobject=True) + ir_values.set('action', 'tree_but_open', 'OnDblClick Action 2', ['unexisting_model'], + 'ir.actions.act_window,%d' % act_id_2, isobject=True) + ir_values.set('action', 'client_action_multi', 'Side Wizard', ['unexisting_model'], + 'ir.actions.act_window,%d' % act_id_3, isobject=True) + reports = self.env['ir.actions.report.xml'].search([]) + report_id = next(report.id for report in reports if not report.groups_id) + ir_values.set('action', 'client_print_multi', 'Nice Report', ['unexisting_model'], + 'ir.actions.report.xml,%d' % report_id, isobject=True) # Replace one action binding to set a new name. - ir_values = self.registry('ir.values') - ir_values.set(self.cr, self.uid, 'action', 'tree_but_open', 'OnDblClick Action New', ['unexisting_model'], 'ir.actions.act_window,%d' % act_id_1, isobject=True) + ir_values.set('action', 'tree_but_open', 'OnDblClick Action New', ['unexisting_model'], + 'ir.actions.act_window,%d' % act_id_1, isobject=True) # Retrieve the action bindings and check they're correct - ir_values = self.registry('ir.values') - actions = ir_values.get(self.cr, self.uid, 'action', 'tree_but_open', ['unexisting_model']) - assert len(actions) == 2, "Mismatching number of bound actions" + actions = ir_values.get('action', 'tree_but_open', ['unexisting_model']) + self.assertEqual(len(actions), 2, "Mismatching number of bound actions") #first action - assert len(actions[0]) == 3, "Malformed action definition" - assert actions[0][1] == 'OnDblClick Action 2', 'Bound action does not match definition' - assert isinstance(actions[0][2], dict) and actions[0][2]['id'] == act_id_2, 'Bound action does not match definition' + self.assertEqual(len(actions[0]), 3, "Malformed action definition") + self.assertEqual(actions[0][1], 'OnDblClick Action 2', 'Bound action does not match definition') + self.assertTrue(isinstance(actions[0][2], dict) and actions[0][2]['id'] == act_id_2, + 'Bound action does not match definition') #second action - this ones comes last because it was re-created with a different name - assert len(actions[1]) == 3, "Malformed action definition" - assert actions[1][1] == 'OnDblClick Action New', 'Re-Registering an action should replace it' - assert isinstance(actions[1][2], dict) and actions[1][2]['id'] == act_id_1, 'Bound action does not match definition' - - actions = ir_values.get(self.cr, self.uid, 'action', 'client_action_multi', ['unexisting_model']) - assert len(actions) == 1, "Mismatching number of bound actions" - assert len(actions[0]) == 3, "Malformed action definition" - assert actions[0][1] == 'Side Wizard', 'Bound action does not match definition' - assert isinstance(actions[0][2], dict) and actions[0][2]['id'] == act_id_3, 'Bound action does not match definition' - - actions = ir_values.get(self.cr, self.uid, 'action', 'client_print_multi', ['unexisting_model']) - assert len(actions) == 1, "Mismatching number of bound actions" - assert len(actions[0]) == 3, "Malformed action definition" - assert actions[0][1] == 'Nice Report', 'Bound action does not match definition' - assert isinstance(actions[0][2], dict) and actions[0][2]['id'] == report_id, 'Bound action does not match definition' - -if __name__ == '__main__': - unittest.main() + self.assertEqual(len(actions[1]), 3, "Malformed action definition") + self.assertEqual(actions[1][1], 'OnDblClick Action New', 'Re-Registering an action should replace it') + self.assertTrue(isinstance(actions[1][2], dict) and actions[1][2]['id'] == act_id_1, + 'Bound action does not match definition') + + actions = ir_values.get('action', 'client_action_multi', ['unexisting_model']) + self.assertEqual(len(actions), 1, "Mismatching number of bound actions") + self.assertEqual(len(actions[0]), 3, "Malformed action definition") + self.assertEqual(actions[0][1], 'Side Wizard', 'Bound action does not match definition') + self.assertTrue(isinstance(actions[0][2], dict) and actions[0][2]['id'] == act_id_3, + 'Bound action does not match definition') + + actions = ir_values.get('action', 'client_print_multi', ['unexisting_model']) + self.assertEqual(len(actions), 1, "Mismatching number of bound actions") + self.assertEqual(len(actions[0]), 3, "Malformed action definition") + self.assertEqual(actions[0][1], 'Nice Report', 'Bound action does not match definition') + self.assertTrue(isinstance(actions[0][2], dict) and actions[0][2]['id'] == report_id, + 'Bound action does not match definition') diff --git a/openerp/addons/base/tests/test_mail.py b/openerp/addons/base/tests/test_mail.py index 96e1973ed49..a751b7a76e3 100644 --- a/openerp/addons/base/tests/test_mail.py +++ b/openerp/addons/base/tests/test_mail.py @@ -1,14 +1,11 @@ -#!/usr/bin/env python # -*- coding: utf-8 -*- -# This test can be run stand-alone with something like: -# > PYTHONPATH=. python2 openerp/tests/test_misc.py # Part of Odoo. See LICENSE file for full copyright and licensing details. import cgi import unittest -from openerp.tools import html_sanitize, append_content_to_html, plaintext2html, email_split -import test_mail_examples +from odoo.tools import html_sanitize, append_content_to_html, plaintext2html, email_split +from . import test_mail_examples class TestSanitizer(unittest.TestCase): @@ -325,7 +322,3 @@ class TestEmailTools(unittest.TestCase): ] for text, expected in cases: self.assertEqual(email_split(text), expected, 'email_split is broken') - - -if __name__ == '__main__': - unittest.main() diff --git a/openerp/addons/base/tests/test_mail_examples.py b/openerp/addons/base/tests/test_mail_examples.py index 19cadd6f156..a83e668d940 100644 --- a/openerp/addons/base/tests/test_mail_examples.py +++ b/openerp/addons/base/tests/test_mail_examples.py @@ -1,5 +1,5 @@ -#!/usr/bin/env python # -*- coding: utf-8 -*- +# Part of Odoo. See LICENSE file for full copyright and licensing details. MISC_HTML_SOURCE = """ <font size="2" style="color: rgb(31, 31, 31); font-family: monospace; font-variant: normal; line-height: normal; ">test1</font> @@ -515,4 +515,4 @@ REMOVE_CLASS_IN = [ REMOVE_CLASS_OUT = [ '<div class="modal-backdrop in">', '<div class="modal-content openerp">', - '<div class="modal-header">']
\ No newline at end of file + '<div class="modal-header">'] diff --git a/openerp/addons/base/tests/test_menu.py b/openerp/addons/base/tests/test_menu.py index a4b5315dc82..451b63d5f17 100644 --- a/openerp/addons/base/tests/test_menu.py +++ b/openerp/addons/base/tests/test_menu.py @@ -1,32 +1,30 @@ -import openerp.tests.common as common +# -*- coding: utf-8 -*- +# Part of Odoo. See LICENSE file for full copyright and licensing details. -class test_menu(common.TransactionCase): +from odoo.tests.common import TransactionCase - def setUp(self): - super(test_menu,self).setUp() - self.Menus = self.registry('ir.ui.menu') + +class TestMenu(TransactionCase): def test_00_menu_deletion(self): """Verify that menu deletion works properly when there are child menus, and those are indeed made orphans""" - cr, uid, Menus = self.cr, self.uid, self.Menus - - # Generic trick necessary for search() calls to avoid hidden menus - ctx = {'ir.ui.menu.full_list': True} - - root_id = Menus.create(cr, uid, {'name': 'Test root'}) - child1_id = Menus.create(cr, uid, {'name': 'Test child 1', 'parent_id': root_id}) - child2_id = Menus.create(cr, uid, {'name': 'Test child 2', 'parent_id': root_id}) - child21_id = Menus.create(cr, uid, {'name': 'Test child 2-1', 'parent_id': child2_id}) - - all_ids = [root_id, child1_id, child2_id, child21_id] + Menu = self.env['ir.ui.menu'] + root = Menu.create({'name': 'Test root'}) + child1 = Menu.create({'name': 'Test child 1', 'parent_id': root.id}) + child2 = Menu.create({'name': 'Test child 2', 'parent_id': root.id}) + child21 = Menu.create({'name': 'Test child 2-1', 'parent_id': child2.id}) + all_ids = [root.id, child1.id, child2.id, child21.id] # delete and check that direct children are promoted to top-level # cfr. explanation in menu.unlink() - Menus.unlink(cr, uid, [root_id]) + root.unlink() + + # Generic trick necessary for search() calls to avoid hidden menus + Menu = self.env['ir.ui.menu'].with_context({'ir.ui.menu.full_list': True}) - remaining_ids = Menus.search(cr, uid, [('id', 'in', all_ids)], order="id", context=ctx) - self.assertEqual([child1_id, child2_id, child21_id], remaining_ids) + remaining = Menu.search([('id', 'in', all_ids)], order="id") + self.assertEqual([child1.id, child2.id, child21.id], remaining.ids) - orphan_ids = Menus.search(cr, uid, [('id', 'in', all_ids), ('parent_id', '=', False)], order="id", context=ctx) - self.assertEqual([child1_id, child2_id], orphan_ids) + orphans = Menu.search([('id', 'in', all_ids), ('parent_id', '=', False)], order="id") + self.assertEqual([child1.id, child2.id], orphans.ids) diff --git a/openerp/addons/base/tests/test_misc.py b/openerp/addons/base/tests/test_misc.py index d20a17403ff..0dc48a0f29b 100644 --- a/openerp/addons/base/tests/test_misc.py +++ b/openerp/addons/base/tests/test_misc.py @@ -1,9 +1,12 @@ +# -*- coding: utf-8 -*- +# Part of Odoo. See LICENSE file for full copyright and licensing details. + import unittest -from openerp.tools import misc +from odoo.tools import misc -class test_countingstream(unittest.TestCase): +class TestCountingStream(unittest.TestCase): def test_empty_stream(self): s = misc.CountingStream(iter([])) self.assertEqual(s.index, -1) @@ -32,6 +35,3 @@ class test_countingstream(unittest.TestCase): self.assertEqual(s.index, 0) self.assertIsNone(next(s, None)) self.assertEqual(s.index, 0) - -if __name__ == '__main__': - unittest.main() diff --git a/openerp/addons/base/tests/test_orm.py b/openerp/addons/base/tests/test_orm.py index bfc6e52c470..0fdfb05636c 100644 --- a/openerp/addons/base/tests/test_orm.py +++ b/openerp/addons/base/tests/test_orm.py @@ -1,117 +1,125 @@ -from collections import defaultdict -from openerp.tools import mute_logger -from openerp.tests import common - -UID = common.ADMIN_USER_ID +# -*- coding: utf-8 -*- +# Part of Odoo. See LICENSE file for full copyright and licensing details. +from collections import defaultdict -class TestORM(common.TransactionCase): - """ test special behaviors of ORM CRUD functions - - TODO: use real Exceptions types instead of Exception """ +from odoo.exceptions import AccessError, MissingError +from odoo.tests.common import TransactionCase +from odoo.tools import mute_logger - def setUp(self): - super(TestORM, self).setUp() - cr, uid = self.cr, self.uid - self.partner = self.registry('res.partner') - self.users = self.registry('res.users') - self.p1 = self.partner.name_create(cr, uid, 'W')[0] - self.p2 = self.partner.name_create(cr, uid, 'Y')[0] - self.ir_rule = self.registry('ir.rule') - # sample unprivileged user - employee_gid = self.ref('base.group_user') - self.uid2 = self.users.create(cr, uid, {'name': 'test user', 'login': 'test', 'groups_id': [4,employee_gid]}) +class TestORM(TransactionCase): + """ test special behaviors of ORM CRUD functions """ @mute_logger('openerp.models') - def testAccessDeletedRecords(self): + def test_access_deleted_records(self): """ Verify that accessing deleted records works as expected """ - cr, uid, uid2, p1, p2 = self.cr, self.uid, self.uid2, self.p1, self.p2 - self.partner.unlink(cr, uid, [p1]) + p1 = self.env['res.partner'].create({'name': 'W'}) + p2 = self.env['res.partner'].create({'name': 'Y'}) + p1.unlink() # read() is expected to skip deleted records because our API is not # transactional for a sequence of search()->read() performed from the # client-side... a concurrent deletion could therefore cause spurious # exceptions even when simply opening a list view! # /!\ Using unprileged user to detect former side effects of ir.rules! - self.assertEqual([{'id': p2, 'name': 'Y'}], self.partner.read(cr, uid2, [p1,p2], ['name']), "read() should skip deleted records") - self.assertEqual([], self.partner.read(cr, uid2, [p1], ['name']), "read() should skip deleted records") + user = self.env['res.users'].create({ + 'name': 'test user', + 'login': 'test2', + 'groups_id': [4, self.ref('base.group_user')], + }) + ps = (p1 + p2).sudo(user) + self.assertEqual([{'id': p2.id, 'name': 'Y'}], ps.read(['name']), "read() should skip deleted records") + self.assertEqual([], ps[0].read(['name']), "read() should skip deleted records") # Deleting an already deleted record should be simply ignored - self.assertTrue(self.partner.unlink(cr, uid, [p1]), "Re-deleting should be a no-op") + self.assertTrue(p1.unlink(), "Re-deleting should be a no-op") # Updating an already deleted record should raise, even as admin - with self.assertRaises(Exception): - self.partner.write(cr, uid, [p1], {'name': 'foo'}) + with self.assertRaises(MissingError): + p1.write({'name': 'foo'}) @mute_logger('openerp.models') - def testAccessFilteredRecords(self): + def test_access_filtered_records(self): """ Verify that accessing filtered records works as expected for non-admin user """ - cr, uid, uid2, p1, p2 = self.cr, self.uid, self.uid2, self.p1, self.p2 - partner_model = self.registry('ir.model').search(cr, uid, [('model','=','res.partner')])[0] - self.ir_rule.create(cr, uid, {'name': 'Y is invisible', - 'domain_force': [('id', '!=', p1)], - 'model_id': partner_model}) + p1 = self.env['res.partner'].create({'name': 'W'}) + p2 = self.env['res.partner'].create({'name': 'Y'}) + user = self.env['res.users'].create({ + 'name': 'test user', + 'login': 'test2', + 'groups_id': [4, self.ref('base.group_user')], + }) + + partner_model = self.env['ir.model'].search([('model','=','res.partner')]) + self.env['ir.rule'].create({ + 'name': 'Y is invisible', + 'domain_force': [('id', '!=', p1.id)], + 'model_id': partner_model.id, + }) + # search as unprivileged user - partners = self.partner.search(cr, uid2, []) - self.assertFalse(p1 in partners, "W should not be visible...") - self.assertTrue(p2 in partners, "... but Y should be visible") + partners = self.env['res.partner'].sudo(user).search([]) + self.assertNotIn(p1, partners, "W should not be visible...") + self.assertIn(p2, partners, "... but Y should be visible") # read as unprivileged user - with self.assertRaises(Exception): - self.partner.read(cr, uid2, [p1], ['name']) + with self.assertRaises(AccessError): + p1.sudo(user).read(['name']) # write as unprivileged user - with self.assertRaises(Exception): - self.partner.write(cr, uid2, [p1], {'name': 'foo'}) + with self.assertRaises(AccessError): + p1.sudo(user).write({'name': 'foo'}) # unlink as unprivileged user - with self.assertRaises(Exception): - self.partner.unlink(cr, uid2, [p1]) + with self.assertRaises(AccessError): + p1.sudo(user).unlink() # Prepare mixed case - self.partner.unlink(cr, uid, [p2]) + p2.unlink() # read mixed records: some deleted and some filtered - with self.assertRaises(Exception): - self.partner.read(cr, uid2, [p1,p2], ['name']) + with self.assertRaises(AccessError): + (p1 + p2).sudo(user).read(['name']) # delete mixed records: some deleted and some filtered - with self.assertRaises(Exception): - self.partner.unlink(cr, uid2, [p1,p2]) + with self.assertRaises(AccessError): + (p1 + p2).sudo(user).unlink() - def test_multi_read(self): - record_id = self.partner.create(self.cr, UID, {'name': 'MyPartner1'}) - records = self.partner.read(self.cr, UID, [record_id]) - self.assertIsInstance(records, list) + def test_read(self): + partner = self.env['res.partner'].create({'name': 'MyPartner1'}) + result = partner.read() + self.assertIsInstance(result, list) - def test_one_read(self): - record_id = self.partner.create(self.cr, UID, {'name': 'MyPartner1'}) - record = self.partner.read(self.cr, UID, record_id) - self.assertIsInstance(record, dict) + # special cases for the old API only + result = self.registry('res.partner').read(self.cr, self.uid, [partner.id]) + self.assertIsInstance(result, list) + result = self.registry('res.partner').read(self.cr, self.uid, partner.id) + self.assertIsInstance(result, dict) @mute_logger('openerp.models') def test_search_read(self): + partner = self.env['res.partner'] + # simple search_read - self.partner.create(self.cr, UID, {'name': 'MyPartner1'}) - found = self.partner.search_read(self.cr, UID, [['name', '=', 'MyPartner1']], ['name']) + partner.create({'name': 'MyPartner1'}) + found = partner.search_read([('name', '=', 'MyPartner1')], ['name']) self.assertEqual(len(found), 1) self.assertEqual(found[0]['name'], 'MyPartner1') - self.assertTrue('id' in found[0]) + self.assertIn('id', found[0]) # search_read correct order - self.partner.create(self.cr, UID, {'name': 'MyPartner2'}) - found = self.partner.search_read(self.cr, UID, [['name', 'like', 'MyPartner']], ['name'], order="name") + partner.create({'name': 'MyPartner2'}) + found = partner.search_read([('name', 'like', 'MyPartner')], ['name'], order="name") self.assertEqual(len(found), 2) self.assertEqual(found[0]['name'], 'MyPartner1') self.assertEqual(found[1]['name'], 'MyPartner2') - found = self.partner.search_read(self.cr, UID, [['name', 'like', 'MyPartner']], ['name'], order="name desc") + found = partner.search_read([('name', 'like', 'MyPartner')], ['name'], order="name desc") self.assertEqual(len(found), 2) self.assertEqual(found[0]['name'], 'MyPartner2') self.assertEqual(found[1]['name'], 'MyPartner1') # search_read that finds nothing - found = self.partner.search_read(self.cr, UID, [['name', '=', 'Does not exists']], ['name']) + found = partner.search_read([('name', '=', 'Does not exists')], ['name']) self.assertEqual(len(found), 0) def test_exists(self): - partner = self.partner.browse(self.cr, UID, []) + partner = self.env['res.partner'] # check that records obtained from search exist recs = partner.search([]) @@ -123,7 +131,7 @@ class TestORM(common.TransactionCase): self.assertFalse(recs.exists()) def test_groupby_date(self): - partners = dict( + partners_data = dict( A='2012-11-19', B='2012-12-17', C='2012-12-31', @@ -133,42 +141,37 @@ class TestORM(common.TransactionCase): G='2013-02-11', ) - all_partners = [] - partners_by_day = defaultdict(set) - partners_by_month = defaultdict(set) - partners_by_year = defaultdict(set) - - for name, date in partners.items(): - p = self.partner.create(self.cr, UID, dict(name=name, date=date)) - all_partners.append(p) - partners_by_day[date].add(p) - partners_by_month[date.rsplit('-', 1)[0]].add(p) - partners_by_year[date.split('-', 1)[0]].add(p) - - def read_group(interval, domain=None): - main_domain = [('id', 'in', all_partners)] - if domain: - domain = ['&'] + main_domain + domain - else: - domain = main_domain - - rg = self.partner.read_group(self.cr, self.uid, domain, ['date'], 'date' + ':' + interval) + partner_ids = [] + partner_ids_by_day = defaultdict(list) + partner_ids_by_month = defaultdict(list) + partner_ids_by_year = defaultdict(list) + + partners = self.env['res.partner'] + for name, date in partners_data.items(): + p = partners.create(dict(name=name, date=date)) + partner_ids.append(p.id) + partner_ids_by_day[date].append(p.id) + partner_ids_by_month[date.rsplit('-', 1)[0]].append(p.id) + partner_ids_by_year[date.split('-', 1)[0]].append(p.id) + + def read_group(interval): + domain = [('id', 'in', partner_ids)] result = {} - for r in rg: - result[r['date:' + interval]] = set(self.partner.search(self.cr, self.uid, r['__domain'])) + for grp in partners.read_group(domain, ['date'], ['date:' + interval]): + result[grp['date:' + interval]] = partners.search(grp['__domain']) return result - self.assertEqual(len(read_group('day')), len(partners_by_day)) - self.assertEqual(len(read_group('month')), len(partners_by_month)) - self.assertEqual(len(read_group('year')), len(partners_by_year)) + self.assertEqual(len(read_group('day')), len(partner_ids_by_day)) + self.assertEqual(len(read_group('month')), len(partner_ids_by_month)) + self.assertEqual(len(read_group('year')), len(partner_ids_by_year)) - rg = self.partner.read_group(self.cr, self.uid, [('id', 'in', all_partners)], - ['date'], ['date:month', 'date:day'], lazy=False) - self.assertEqual(len(rg), len(all_partners)) + res = partners.read_group([('id', 'in', partner_ids)], ['date'], + ['date:month', 'date:day'], lazy=False) + self.assertEqual(len(res), len(partner_ids)) def test_write_duplicate(self): - cr, uid, p1 = self.cr, self.uid, self.p1 - self.partner.write(cr, uid, [p1, p1], {'name': 'X'}) + p1 = self.env['res.partner'].create({'name': 'W'}) + (p1 + p1).write({'name': 'X'}) def test_m2m_store_trigger(self): group_user = self.env.ref('base.group_user') @@ -187,110 +190,93 @@ class TestORM(common.TransactionCase): self.assertTrue(user.share) -class TestInherits(common.TransactionCase): +class TestInherits(TransactionCase): """ test the behavior of the orm for models that use _inherits; specifically: res.users, that inherits from res.partner """ - def setUp(self): - super(TestInherits, self).setUp() - self.partner = self.registry('res.partner') - self.user = self.registry('res.users') - def test_default(self): """ `default_get` cannot return a dictionary or a new id """ - defaults = self.user.default_get(self.cr, UID, ['partner_id']) + defaults = self.env['res.users'].default_get(['partner_id']) if 'partner_id' in defaults: self.assertIsInstance(defaults['partner_id'], (bool, int, long)) def test_create(self): """ creating a user should automatically create a new partner """ - partners_before = self.partner.search(self.cr, UID, []) - foo_id = self.user.create(self.cr, UID, {'name': 'Foo', 'login': 'foo', 'password': 'foo'}) - foo = self.user.browse(self.cr, UID, foo_id) + partners_before = self.env['res.partner'].search([]) + user_foo = self.env['res.users'].create({'name': 'Foo', 'login': 'foo'}) - self.assertNotIn(foo.partner_id.id, partners_before) + self.assertNotIn(user_foo.partner_id, partners_before) def test_create_with_ancestor(self): """ creating a user with a specific 'partner_id' should not create a new partner """ - par_id = self.partner.create(self.cr, UID, {'name': 'Foo'}) - partners_before = self.partner.search(self.cr, UID, []) - foo_id = self.user.create(self.cr, UID, {'partner_id': par_id, 'login': 'foo', 'password': 'foo'}) - partners_after = self.partner.search(self.cr, UID, []) + partner_foo = self.env['res.partner'].create({'name': 'Foo'}) + partners_before = self.env['res.partner'].search([]) + user_foo = self.env['res.users'].create({'partner_id': partner_foo.id, 'login': 'foo'}) + partners_after = self.env['res.partner'].search([]) - self.assertEqual(set(partners_before), set(partners_after)) - - foo = self.user.browse(self.cr, UID, foo_id) - self.assertEqual(foo.name, 'Foo') - self.assertEqual(foo.partner_id.id, par_id) + self.assertEqual(partners_before, partners_after) + self.assertEqual(user_foo.name, 'Foo') + self.assertEqual(user_foo.partner_id, partner_foo) @mute_logger('openerp.models') def test_read(self): """ inherited fields should be read without any indirection """ - foo_id = self.user.create(self.cr, UID, {'name': 'Foo', 'login': 'foo', 'password': 'foo'}) - foo_values, = self.user.read(self.cr, UID, [foo_id]) - partner_id = foo_values['partner_id'][0] - partner_values, = self.partner.read(self.cr, UID, [partner_id]) - self.assertEqual(foo_values['name'], partner_values['name']) + user_foo = self.env['res.users'].create({'name': 'Foo', 'login': 'foo'}) + user_values, = user_foo.read() + partner_values, = user_foo.partner_id.read() - foo = self.user.browse(self.cr, UID, foo_id) - self.assertEqual(foo.name, foo.partner_id.name) + self.assertEqual(user_values['name'], partner_values['name']) + self.assertEqual(user_foo.name, user_foo.partner_id.name) @mute_logger('openerp.models') def test_copy(self): """ copying a user should automatically copy its partner, too """ - foo_id = self.user.create(self.cr, UID, { + user_foo = self.env['res.users'].create({ 'name': 'Foo', 'login': 'foo', - 'password': 'foo', 'supplier': True, }) - foo_before, = self.user.read(self.cr, UID, [foo_id]) + foo_before, = user_foo.read() del foo_before['__last_update'] - bar_id = self.user.copy(self.cr, UID, foo_id, { - 'login': 'bar', - 'password': 'bar', - }) - foo_after, = self.user.read(self.cr, UID, [foo_id]) + user_bar = user_foo.copy({'login': 'bar'}) + foo_after, = user_foo.read() del foo_after['__last_update'] self.assertEqual(foo_before, foo_after) - foo, bar = self.user.browse(self.cr, UID, [foo_id, bar_id]) - self.assertEqual(bar.name, 'Foo (copy)') - self.assertEqual(bar.login, 'bar') - self.assertEqual(foo.supplier, bar.supplier) - self.assertNotEqual(foo.id, bar.id) - self.assertNotEqual(foo.partner_id.id, bar.partner_id.id) + self.assertEqual(user_bar.name, 'Foo (copy)') + self.assertEqual(user_bar.login, 'bar') + self.assertEqual(user_foo.supplier, user_bar.supplier) + self.assertNotEqual(user_foo.id, user_bar.id) + self.assertNotEqual(user_foo.partner_id.id, user_bar.partner_id.id) @mute_logger('openerp.models') def test_copy_with_ancestor(self): """ copying a user with 'parent_id' in defaults should not duplicate the partner """ - foo_id = self.user.create(self.cr, UID, {'name': 'Foo', 'login': 'foo', 'password': 'foo', + user_foo = self.env['res.users'].create({'name': 'Foo', 'login': 'foo', 'password': 'foo', 'login_date': '2016-01-01', 'signature': 'XXX'}) - par_id = self.partner.create(self.cr, UID, {'name': 'Bar'}) + partner_bar = self.env['res.partner'].create({'name': 'Bar'}) - foo_before, = self.user.read(self.cr, UID, [foo_id]) + foo_before, = user_foo.read() del foo_before['__last_update'] del foo_before['login_date'] - partners_before = self.partner.search(self.cr, UID, []) - bar_id = self.user.copy(self.cr, UID, foo_id, {'partner_id': par_id, 'login': 'bar'}) - foo_after, = self.user.read(self.cr, UID, [foo_id]) + partners_before = self.env['res.partner'].search([]) + user_bar = user_foo.copy({'partner_id': partner_bar.id, 'login': 'bar'}) + foo_after, = user_foo.read() del foo_after['__last_update'] del foo_after['login_date'] - partners_after = self.partner.search(self.cr, UID, []) + partners_after = self.env['res.partner'].search([]) self.assertEqual(foo_before, foo_after) - self.assertEqual(set(partners_before), set(partners_after)) - - foo, bar = self.user.browse(self.cr, UID, [foo_id, bar_id]) - self.assertNotEqual(foo.id, bar.id) - self.assertEqual(bar.partner_id.id, par_id) - self.assertEqual(bar.login, 'bar', "login is given from copy parameters") - self.assertFalse(bar.password, "password should not be copied from original record") - self.assertEqual(bar.name, 'Bar', "name is given from specific partner") - self.assertEqual(bar.signature, foo.signature, "signature should be copied") + self.assertEqual(partners_before, partners_after) + self.assertNotEqual(user_foo.id, user_bar.id) + self.assertEqual(user_bar.partner_id.id, partner_bar.id) + self.assertEqual(user_bar.login, 'bar', "login is given from copy parameters") + self.assertFalse(user_bar.password, "password should not be copied from original record") + self.assertEqual(user_bar.name, 'Bar', "name is given from specific partner") + self.assertEqual(user_bar.signature, user_foo.signature, "signature should be copied") CREATE = lambda values: (0, False, values) @@ -301,11 +287,8 @@ LINK_TO = lambda id: (4, id, False) DELETE_ALL = lambda: (5, False, False) REPLACE_WITH = lambda ids: (6, False, ids) -def sorted_by_id(list_of_dicts): - "sort dictionaries by their 'id' field; useful for comparisons" - return sorted(list_of_dicts, key=lambda d: d.get('id')) -class TestO2MSerialization(common.TransactionCase): +class TestO2MSerialization(TransactionCase): """ test the orm method 'write' on one2many fields """ def setUp(self): @@ -314,136 +297,121 @@ class TestO2MSerialization(common.TransactionCase): def test_no_command(self): " empty list of commands yields an empty list of records " - results = self.partner.resolve_2many_commands( - self.cr, UID, 'child_ids', []) - + results = self.env['res.partner'].resolve_2many_commands('child_ids', []) self.assertEqual(results, []) def test_CREATE_commands(self): " returns the VALUES dict as-is " values = [{'foo': 'bar'}, {'foo': 'baz'}, {'foo': 'baq'}] - results = self.partner.resolve_2many_commands( - self.cr, UID, 'child_ids', map(CREATE, values)) - + results = self.env['res.partner'].resolve_2many_commands('child_ids', map(CREATE, values)) self.assertEqual(results, values) def test_LINK_TO_command(self): " reads the records from the database, records are returned with their ids. " ids = [ - self.partner.create(self.cr, UID, {'name': 'foo'}), - self.partner.create(self.cr, UID, {'name': 'bar'}), - self.partner.create(self.cr, UID, {'name': 'baz'}) + self.env['res.partner'].create({'name': 'foo'}).id, + self.env['res.partner'].create({'name': 'bar'}).id, + self.env['res.partner'].create({'name': 'baz'}).id, ] commands = map(LINK_TO, ids) - results = self.partner.resolve_2many_commands( - self.cr, UID, 'child_ids', commands, ['name']) - - self.assertEqual(sorted_by_id(results), sorted_by_id([ + results = self.env['res.partner'].resolve_2many_commands('child_ids', commands, ['name']) + self.assertItemsEqual(results, [ {'id': ids[0], 'name': 'foo'}, {'id': ids[1], 'name': 'bar'}, - {'id': ids[2], 'name': 'baz'} - ])) + {'id': ids[2], 'name': 'baz'}, + ]) def test_bare_ids_command(self): " same as the equivalent LINK_TO commands " ids = [ - self.partner.create(self.cr, UID, {'name': 'foo'}), - self.partner.create(self.cr, UID, {'name': 'bar'}), - self.partner.create(self.cr, UID, {'name': 'baz'}) + self.env['res.partner'].create({'name': 'foo'}).id, + self.env['res.partner'].create({'name': 'bar'}).id, + self.env['res.partner'].create({'name': 'baz'}).id, ] - results = self.partner.resolve_2many_commands( - self.cr, UID, 'child_ids', ids, ['name']) - - self.assertEqual(sorted_by_id(results), sorted_by_id([ + results = self.env['res.partner'].resolve_2many_commands('child_ids', ids, ['name']) + self.assertItemsEqual(results, [ {'id': ids[0], 'name': 'foo'}, {'id': ids[1], 'name': 'bar'}, - {'id': ids[2], 'name': 'baz'} - ])) + {'id': ids[2], 'name': 'baz'}, + ]) def test_UPDATE_command(self): " take the in-db records and merge the provided information in " - id_foo = self.partner.create(self.cr, UID, {'name': 'foo'}) - id_bar = self.partner.create(self.cr, UID, {'name': 'bar'}) - id_baz = self.partner.create(self.cr, UID, {'name': 'baz', 'city': 'tag'}) - - results = self.partner.resolve_2many_commands( - self.cr, UID, 'child_ids', [ - LINK_TO(id_foo), - UPDATE(id_bar, {'name': 'qux', 'city': 'tagtag'}), - UPDATE(id_baz, {'name': 'quux'}) - ], ['name', 'city']) - - self.assertEqual(sorted_by_id(results), sorted_by_id([ - {'id': id_foo, 'name': 'foo', 'city': False}, - {'id': id_bar, 'name': 'qux', 'city': 'tagtag'}, - {'id': id_baz, 'name': 'quux', 'city': 'tag'} - ])) + foo = self.env['res.partner'].create({'name': 'foo'}) + bar = self.env['res.partner'].create({'name': 'bar'}) + baz = self.env['res.partner'].create({'name': 'baz', 'city': 'tag'}) + commands = [ + LINK_TO(foo.id), + UPDATE(bar.id, {'name': 'qux', 'city': 'tagtag'}), + UPDATE(baz.id, {'name': 'quux'}), + ] + + results = self.env['res.partner'].resolve_2many_commands('child_ids', commands, ['name', 'city']) + self.assertItemsEqual(results, [ + {'id': foo.id, 'name': 'foo', 'city': False}, + {'id': bar.id, 'name': 'qux', 'city': 'tagtag'}, + {'id': baz.id, 'name': 'quux', 'city': 'tag'}, + ]) def test_DELETE_command(self): " deleted records are not returned at all. " ids = [ - self.partner.create(self.cr, UID, {'name': 'foo'}), - self.partner.create(self.cr, UID, {'name': 'bar'}), - self.partner.create(self.cr, UID, {'name': 'baz'}) + self.env['res.partner'].create({'name': 'foo'}).id, + self.env['res.partner'].create({'name': 'bar'}).id, + self.env['res.partner'].create({'name': 'baz'}).id, ] - commands = [DELETE(ids[0]), DELETE(ids[1]), DELETE(ids[2])] - - results = self.partner.resolve_2many_commands( - self.cr, UID, 'child_ids', commands, ['name']) + commands = map(DELETE, ids) + results = self.env['res.partner'].resolve_2many_commands('child_ids', commands, ['name']) self.assertEqual(results, []) def test_mixed_commands(self): ids = [ - self.partner.create(self.cr, UID, {'name': name}) + self.env['res.partner'].create({'name': name}).id for name in ['NObar', 'baz', 'qux', 'NOquux', 'NOcorge', 'garply'] ] + commands = [ + CREATE({'name': 'foo'}), + UPDATE(ids[0], {'name': 'bar'}), + LINK_TO(ids[1]), + DELETE(ids[2]), + UPDATE(ids[3], {'name': 'quux',}), + UPDATE(ids[4], {'name': 'corge'}), + CREATE({'name': 'grault'}), + LINK_TO(ids[5]), + ] - results = self.partner.resolve_2many_commands( - self.cr, UID, 'child_ids', [ - CREATE({'name': 'foo'}), - UPDATE(ids[0], {'name': 'bar'}), - LINK_TO(ids[1]), - DELETE(ids[2]), - UPDATE(ids[3], {'name': 'quux',}), - UPDATE(ids[4], {'name': 'corge'}), - CREATE({'name': 'grault'}), - LINK_TO(ids[5]) - ], ['name']) - - self.assertEqual(sorted_by_id(results), sorted_by_id([ + results = self.env['res.partner'].resolve_2many_commands('child_ids', commands, ['name']) + self.assertItemsEqual(results, [ {'name': 'foo'}, {'id': ids[0], 'name': 'bar'}, {'id': ids[1], 'name': 'baz'}, {'id': ids[3], 'name': 'quux'}, {'id': ids[4], 'name': 'corge'}, {'name': 'grault'}, - {'id': ids[5], 'name': 'garply'} - ])) + {'id': ids[5], 'name': 'garply'}, + ]) def test_LINK_TO_pairs(self): "LINK_TO commands can be written as pairs, instead of triplets" ids = [ - self.partner.create(self.cr, UID, {'name': 'foo'}), - self.partner.create(self.cr, UID, {'name': 'bar'}), - self.partner.create(self.cr, UID, {'name': 'baz'}) + self.env['res.partner'].create({'name': 'foo'}).id, + self.env['res.partner'].create({'name': 'bar'}).id, + self.env['res.partner'].create({'name': 'baz'}).id, ] - commands = map(lambda id: (4, id), ids) - - results = self.partner.resolve_2many_commands( - self.cr, UID, 'child_ids', commands, ['name']) + commands = [(4, id) for id in ids] - self.assertEqual(sorted_by_id(results), sorted_by_id([ + results = self.env['res.partner'].resolve_2many_commands('child_ids', commands, ['name']) + self.assertItemsEqual(results, [ {'id': ids[0], 'name': 'foo'}, {'id': ids[1], 'name': 'bar'}, - {'id': ids[2], 'name': 'baz'} - ])) + {'id': ids[2], 'name': 'baz'}, + ]) def test_singleton_commands(self): "DELETE_ALL can appear as a singleton" - results = self.partner.resolve_2many_commands( - self.cr, UID, 'child_ids', [DELETE_ALL()], ['name']) - + commands = [DELETE_ALL()] + results = self.env['res.partner'].resolve_2many_commands('child_ids', commands, ['name']) self.assertEqual(results, []) diff --git a/openerp/addons/base/tests/test_ormcache.py b/openerp/addons/base/tests/test_ormcache.py index c6f27aa39db..3f281cb5582 100644 --- a/openerp/addons/base/tests/test_ormcache.py +++ b/openerp/addons/base/tests/test_ormcache.py @@ -1,8 +1,11 @@ +# -*- coding: utf-8 -*- +# Part of Odoo. See LICENSE file for full copyright and licensing details. -from openerp.tests import common -from openerp.tools import get_cache_key_counter +from odoo.tests.common import TransactionCase +from odoo.tools import get_cache_key_counter -class TestOrmcache(common.TransactionCase): + +class TestOrmcache(TransactionCase): def test_ormcache(self): """ Test the effectiveness of the ormcache() decorator. """ IMD = self.env['ir.model.data'] diff --git a/openerp/addons/base/tests/test_osv.py b/openerp/addons/base/tests/test_osv.py index 22b5572d543..65bf315f67c 100644 --- a/openerp/addons/base/tests/test_osv.py +++ b/openerp/addons/base/tests/test_osv.py @@ -2,7 +2,8 @@ # Part of Odoo. See LICENSE file for full copyright and licensing details. import unittest -from openerp.osv.query import Query + +from odoo.osv.query import Query class QueryTestCase(unittest.TestCase): diff --git a/openerp/addons/base/tests/test_osv_expression.yml b/openerp/addons/base/tests/test_osv_expression.yml deleted file mode 100644 index 9e0a003cf3a..00000000000 --- a/openerp/addons/base/tests/test_osv_expression.yml +++ /dev/null @@ -1,632 +0,0 @@ -- - Testing for hierarchical search in M2M -- - !python {model: res.partner }: | - ids = self.search(cr, uid, [('category_id', 'child_of',ref('res_partner_category_0'))]) - assert len(ids) >= 1, ids -- - "1.0 Setup test partner categories: parent root" -- - !record {model: res.partner.category, id: categ_root}: - name: Root category -- - "1.1 Setup test partner categories: parent category" -- - !record {model: res.partner.category, id: categ_0}: - name: Parent category - parent_id: categ_root -- - "1.2 Setup test partner categories: child 1" -- - !record {model: res.partner.category, id: categ_1}: - name: Child 1 - parent_id: categ_0 -- - Test hierarchical search in M2M with child ID (list of ids) -- - !python {model: res.partner.category }: | - ids = self.search(cr, uid, [('id', 'child_of',[ref('categ_root')])]) - assert len(ids) == 3, ids -- - Test hierarchical search in M2M with child ID (single id) -- - !python {model: res.partner.category }: | - ids = self.search(cr, uid, [('id', 'child_of',ref('categ_root'))]) - assert len(ids) == 3, ids -- - Test hierarchical search in M2M with child IDs -- - !python {model: res.partner.category }: | - ids = self.search(cr, uid, [('id', 'child_of',[ref('categ_1'), ref('categ_0')])]) - assert len(ids) == 2, ids -- - Test hierarchical search in M2M with child IDs -- - !python {model: res.partner.category }: | - ids = self.search(cr, uid, [('id', 'child_of',[ref('categ_0')])]) - assert len(ids) == 2, ids -- - Test hierarchical search in M2M with child IDs -- - !python {model: res.partner.category }: | - ids = self.search(cr, uid, [('id', 'child_of',[ref('categ_1')])]) - assert len(ids) == 1, ids -- - Test hierarchical search in M2M with parent ID (list of ids) -- - !python {model: res.partner.category }: | - ids = self.search(cr, uid, [('id', 'parent_of',[ref('categ_1')])]) - assert len(ids) == 3, ids -- - Test hierarchical search in M2M with parent ID (single id) -- - !python {model: res.partner.category }: | - ids = self.search(cr, uid, [('id', 'parent_of',ref('categ_1'))]) - assert len(ids) == 3, ids -- - Test hierarchical search in M2M with parent IDs -- - !python {model: res.partner.category }: | - ids = self.search(cr, uid, [('id', 'parent_of',[ref('categ_root'), ref('categ_0')])]) - assert len(ids) == 2, ids -- - Test hierarchical search in M2M with parent IDs -- - !python {model: res.partner.category }: | - ids = self.search(cr, uid, [('id', 'parent_of',[ref('categ_0')])]) - assert len(ids) == 2, ids -- - Test hierarchical search in M2M with parent IDs -- - !python {model: res.partner.category }: | - ids = self.search(cr, uid, [('id', 'parent_of',[ref('categ_1')])]) - assert len(ids) == 3, ids -- - Test hierarchical search in M2M with parent IDs -- - !python {model: res.partner.category }: | - ids = self.search(cr, uid, [('id', 'parent_of',[ref('categ_root')])]) - assert len(ids) == 1, ids -- - Testing that some domain expressions work -- - !python {model: res.partner }: | - ids = self.search(cr, uid, [('parent_id','=','Agrolait')]) - assert len(ids) >= 1, ids -- - Trying the "in" operator, for scalar value -- - !python {model: res.partner }: | - ids = self.search(cr, uid, [('parent_id','in','Agrolait')]) - assert len(ids) >= 1, ids -- - Trying the "in" operator for list value -- - !python {model: res.partner }: | - ids = self.search(cr, uid, [('parent_id','in',['Agrolait','ASUStek'])]) - assert len(ids) >= 1, ids -- - Check we can use "in" operator for plain fields. -- - !python {model: ir.ui.menu }: | - ids = self.search(cr, uid, [('sequence','in',[1, 2, 10, 20])]) - assert len(ids) >= 1, ids -- - Test one2many operator with empty search list -- - !assert {model: res.partner, search: "[('child_ids', 'in', [])]", count: 0, string: "Ids should be empty"} -- - Test one2many operator with False -- - !assert {model: res.partner, search: "[('child_ids', '=', False)]"}: - - list(child_ids) == [] -- - Test many2many operator with empty search list -- - !assert {model: res.partner, search: "[('category_id', 'in', [])]", count: 0, string: "Ids should be empty"} -- - Test many2many operator with False -- - !assert {model: res.partner, search: "[('category_id', '=', False)]"}: - - list(category_id) == [] -- - Filtering on invalid value across x2many relationship should return an empty set -- - !assert {model: res.partner, search: "[('child_ids.city','=','foo')]", count: 0, string: "Searching for address.city = foo should give empty results"} -- - Check if many2one works with empty search list -- - !assert {model: res.partner, search: "[('company_id','in', [])]", count: 0, string: "Searching for company_id in [] should be empty!" } -- - For the sake of the following tests, I will create a second company -- - !record {model: res.company, id: ymltest_company2}: - name: Acme 2 -- - And create a few partners with that company or no company -- - !python {model: res.partner }: | - for r in range(4): - self.create(cr, uid, { 'name': 'P of Acme %d' % r, - 'company_id': ref('ymltest_company2') }) - for r in range(4): - self.create(cr, uid, { 'name': 'P of All %d' % r, - 'company_id': False }) -- - Check if many2one works with negative empty list -- - !python {model: res.partner }: | - all_ids = self.search(cr, uid, []) - all_ids.sort() - res_ids = self.search(cr, uid,['|',('company_id','not in', []), ('company_id','=',False)]) - res_ids.sort() - assert all_ids == res_ids, "not in [] fails" -- - Check that many2one will pick the correct records with a list -- - !python {model: res.partner }: | - res_ids = self.search(cr, uid, [('company_id', 'in', [False,])]) - assert len(res_ids) >= 4, "We created 4 partners w/company, why find %d? %r" % \ - (len(res_ids), res_ids) -- - Check that many2one will exclude the correct records with a list -- - !python {model: res.partner }: | - # assuming that the default company is #1 - res_ids = self.search(cr, uid, [('company_id', 'not in', [1])]) - assert len(res_ids) >= 4, "We should have found 4 records at least, only have %d! %r" % \ - (len(res_ids), res_ids) -- - Check that we exclude the correct records, + False -- - !python {model: res.partner }: | - # assuming that the default company is #1 - res_ids = self.search(cr, uid, ['|', ('company_id', 'not in', [1]), ('company_id', '=', False)]) - assert len(res_ids) >= 8, "We should have found 8 records at least, only have %d! %r" % \ - (len(res_ids), res_ids) -- - Check that multi-level expressions also work -- - !python {model: res.partner }: | - res_ids = self.search(cr, uid, [('company_id.partner_id', 'in', [])]) - assert res_ids == [], "Searching an empty set should return empty result, not %r" % res_ids -- - Check that multi-level expressions with negative op work -- - !python {model: res.partner }: | - all_ids = self.search(cr, uid, [('company_id', '!=', False)]) - all_ids.sort() - res_ids = self.search(cr, uid, [('company_id.partner_id', 'not in', [])]) - res_ids.sort() - assert res_ids == all_ids, "Searching against empty set failed, returns %r" % res_ids -- - Test the '(not) like/in' behavior. res.partner and its parent_id column are used because - parent_id is a many2one, allowing to test the Null value, and there are actually some - null and non-null values in the demo data. -- - !python {model: res.partner }: | - partner_ids = self.search(cr, uid, []) - partner_ids.sort() - max_partner_id = max(partner_ids) - - # Grab test sample data without using a normal - # search domain, because we want to test these later, - # so we can't rely on them! - partners = self.browse(cr, uid, partner_ids) - with_parent = [] - without_parent = [] - with_website = [] - for x in partners: - if x.parent_id: - with_parent.append(x.id) - else: - without_parent.append(x.id) - if x.website: - with_website.append(x.id) - with_parent.sort() - without_parent.sort() - with_website.sort() - - # We treat null values differently than in SQL. For instance in SQL: - # SELECT id FROM res_partner WHERE parent_id NOT IN (0) - # will return only the records with non-null parent_id. - # SELECT id FROM res_partner WHERE parent_id IN (0) - # will return expectedly nothing (our ids always begin at 1). - # This means the union of those two results will give only some - # records, but not all present in database. - # - # When using domains and the ORM's search method, we think it is - # more intuitive that the union returns all the records, and that - # a domain like ('parent_id', 'not in', [0]) will return all - # the records. For instance, if you perform a search for the companies - # that don't have OpenERP has a parent company, you expect to find, - # among others, the companies that don't have parent company. - # - - # existing values be treated similarly if we simply check that some - # existing value belongs to them. - - res_0 = self.search(cr, uid, [('parent_id', 'not like', 'probably_unexisting_name')]) # get all rows, included null parent_id - res_0.sort() - res_1 = self.search(cr, uid, [('parent_id', 'not in', [max_partner_id + 1])]) # get all rows, included null parent_id - res_1.sort() - res_2 = self.search(cr, uid, [('parent_id', '!=', False)]) # get rows with not null parent_id, deprecated syntax - res_2.sort() - res_3 = self.search(cr, uid, [('parent_id', 'not in', [])]) # get all rows, included null parent_id - res_3.sort() - res_4 = self.search(cr, uid, [('parent_id', 'not in', [False])]) # get rows with not null parent_id - res_4.sort() - res_4b = self.search(cr, uid, [('parent_id', 'not ilike', '')]) # get only rows without parent - res_4b.sort() - assert res_0 == partner_ids, 'res0: expected %r, got %r' % (partner_ids, res_0) - assert res_1 == partner_ids, 'res1: expected %r, got %r' % (partner_ids, res_1) - assert res_2 == with_parent, 'res2: expected %r, got %r' % (with_parent, res_2) - assert res_3 == partner_ids, 'res3: expected %r, got %r' % (partner_ids, res_3) - assert res_4 == with_parent, 'res4: expected %r, got %r' % (with_parent, res_4) - assert res_4b == without_parent, 'res4b: expected %r, got %r' % (without_parent, res_4b) - # The results of these queries, when combined with queries 0..4 must - # give the whole set of ids. - res_5 = self.search(cr, uid, [('parent_id', 'like', 'probably_unexisting_name')]) - res_5.sort() - res_6 = self.search(cr, uid, [('parent_id', 'in', [max_partner_id + 1])]) - res_6.sort() - res_7 = self.search(cr, uid, [('parent_id', '=', False)]) - res_7.sort() - res_8 = self.search(cr, uid, [('parent_id', 'in', [])]) - res_8.sort() - res_9 = self.search(cr, uid, [('parent_id', 'in', [False])]) - res_9.sort() - res_9b = self.search(cr, uid, [('parent_id', 'ilike', '')]) # get those with a parent - res_9b.sort() - - assert res_5 == [], 'res5: expected %r, got %r' % ([], res_5) - assert res_6 == [], 'res6: expected %r, got %r' % ([], res_6) - assert res_7 == without_parent, 'res7: expected %r, got %r' % (without_parent, res_7) - assert res_8 == [], 'res8: expected %r, got %r' % ([], res_8) - assert res_9 == without_parent, 'res9: expected %r, got %r' % (without_parent, res_9) - assert res_9b == with_parent, 'res9b: expected %r, got %r' % (with_parent, res_9b) - # These queries must return exactly the results than the queries 0..4, - # i.e. not ... in ... must be the same as ... not in ... . - res_10 = self.search(cr, uid, ['!', ('parent_id', 'like', 'probably_unexisting_name')]) - res_10.sort() - res_11 = self.search(cr, uid, ['!', ('parent_id', 'in', [max_partner_id + 1])]) - res_11.sort() - res_12 = self.search(cr, uid, ['!', ('parent_id', '=', False)]) - res_12.sort() - res_13 = self.search(cr, uid, ['!', ('parent_id', 'in', [])]) - res_13.sort() - res_14 = self.search(cr, uid, ['!', ('parent_id', 'in', [False])]) - res_14.sort() - assert res_0 == res_10 - assert res_1 == res_11 - assert res_2 == res_12 - assert res_3 == res_13 - assert res_4 == res_14 - - # Testing many2one field is not enough, a regular char field is tested - # with in [] and must not return any result. - res_15 = self.search(cr, uid, [('website', 'in', [])]) - assert res_15 == [] - # not in [] must return everything. - res_16 = self.search(cr, uid, [('website', 'not in', [])]) - res_16.sort() - assert res_16 == partner_ids - - res_17 = self.search(cr, uid, [('website', '!=', False)]) - res_17.sort() - assert res_17 == with_website - -- - Check behavior for required many2one fields -- - !python {model: res.company }: | - company_ids = sorted(self.search(cr, uid, [])) - # currency_id is required - res_101 = sorted(self.search(cr, uid, [('currency_id', 'not ilike', '')])) # get no companies - res_102 = sorted(self.search(cr, uid, [('currency_id', 'ilike', '')])) # get all companies - assert res_101 == [], 'res_101: expected %r, got %r' % ([], res_101) - assert res_102 == company_ids, 'res_102: expected %r, got %r' % (company_ids, res_102) -- - Verify domain evaluation for `one2many != False` -- - !python {model: res.partner.category }: | - all_ids = self.search(cr, uid, []) - parent_categs = set([c.parent_id.id for c in self.browse(cr, uid, all_ids) if c.parent_id]) - result = set(self.search(cr, uid, [('child_ids', '!=', False)])) - assert result and result == parent_categs, "Got %r, expected %r" % (result, parent_categs) -- - Verify domain evaluation for `one2many == False` -- - !python {model: res.partner.category }: | - all_ids = self.search(cr, uid, []) - parent_categs = set([c.parent_id.id for c in self.browse(cr, uid, all_ids) if c.parent_id]) - leaf_categs = set(all_ids) - parent_categs - result = set(self.search(cr, uid, [('child_ids', '=', False)])) - assert result and result == leaf_categs, "Got %r, expected %r" % (result, leaf_categs) -- - Equivalent queries. -- - !python {model: res.currency }: | - max_currency_id = max(self.search(cr, uid, [])) - res_0 = self.search(cr, uid, []) - res_1 = self.search(cr, uid, [('name', 'not like', 'probably_unexisting_name')]) - res_2 = self.search(cr, uid, [('id', 'not in', [max_currency_id + 1003])]) - res_3 = self.search(cr, uid, [('id', 'not in', [])]) - res_4 = self.search(cr, uid, [('id', '!=', False)]) - res_0.sort() - res_1.sort() - res_2.sort() - res_3.sort() - res_4.sort() - assert res_0 == res_1 - assert res_0 == res_2 - assert res_0 == res_3 - assert res_0 == res_4 -- - Equivalent queries, integer and string. -- - !python {model: res.partner }: | - all_ids = self.search(cr, uid, []) - if len(all_ids) > 1: - one = all_ids[0] - record = self.browse(cr, uid, one) - others = all_ids[1:] - res_1 = self.search(cr, uid, [('id', '=', one)]) - # self.search(cr, uid, [('id', '!=', others)]) # not permitted - res_2 = self.search(cr, uid, [('id', 'not in', others)]) - res_3 = self.search(cr, uid, ['!', ('id', '!=', one)]) - res_4 = self.search(cr, uid, ['!', ('id', 'in', others)]) - # res_5 = self.search(cr, uid, [('id', 'in', one)]) # TODO make it permitted, just like for child_of - res_6 = self.search(cr, uid, [('id', 'in', [one])]) - res_7 = self.search(cr, uid, [('name', '=', record.name)]) - res_8 = self.search(cr, uid, [('name', 'in', [record.name])]) - # res_9 = self.search(cr, uid, [('name', 'in', record.name)]) # TODO - assert [one] == res_1 - assert [one] == res_2 - assert [one] == res_3 - assert [one] == res_4 - #assert [one] == res_5 - assert [one] == res_6 - assert [one] == res_7 -- - Need a company with a parent_id. -- - !record {model: res.company, id: ymltest_company3}: - name: Acme 3 -- - Need a company with a parent_id. -- - !record {model: res.company, id: ymltest_company4}: - name: Acme 4 - parent_id: ymltest_company3 -- - Equivalent queries, one2many. -- - !python {model: res.company }: | - company = self.browse(cr, uid, ref('ymltest_company3')) - - # one2many towards same model - res_1 = self.search(cr, uid, [('child_ids', 'in', [x.id for x in company.child_ids])]) # any company having a child of company3 as child - res_2 = self.search(cr, uid, [('child_ids', 'in', [company.child_ids[0].id])]) # any company having the first child of company3 as child - assert res_1 == [ref('ymltest_company3')], "res_1" - assert res_2 == [ref('ymltest_company3')], "res_2" - - # try testing real subsets with IN/NOT IN - res_partner = self.pool.get('res.partner') - res_users = self.pool.get('res.users') - p1, _ = res_partner.name_create(cr, uid, "Dédé Boitaclou") - p2, _ = res_partner.name_create(cr, uid, "Raoulette Pizza O'poil") - u1a = res_users.create(cr, uid, {'login': 'dbo', 'partner_id': p1}) - u1b = res_users.create(cr, uid, {'login': 'dbo2', 'partner_id': p1}) - u2 = res_users.create(cr, uid, {'login': 'rpo', 'partner_id': p2}) - assert [p1] == res_partner.search(cr, uid, [('user_ids', 'in', u1a)]), "o2m IN accept single int on right side" - assert [p1] == res_partner.search(cr, uid, [('user_ids', '=', 'Dédé Boitaclou')]), "o2m NOT IN matches none on the right side" - assert [] == res_partner.search(cr, uid, [('user_ids', 'in', [10000])]), "o2m NOT IN matches none on the right side" - assert [p1,p2] == res_partner.search(cr, uid, [('user_ids', 'in', [u1a,u2])]), "o2m IN matches any on the right side" - all_partners = res_partner.search(cr, uid, []) - assert (set(all_partners) - set([p1])) == set(res_partner.search(cr, uid, [('user_ids', 'not in', u1a)])), "o2m NOT IN matches none on the right side" - assert (set(all_partners) - set([p1])) == set(res_partner.search(cr, uid, [('user_ids', '!=', 'Dédé Boitaclou')])), "o2m NOT IN matches none on the right side" - assert (set(all_partners) - set([p1,p2])) == set(res_partner.search(cr, uid, [('user_ids', 'not in', [u1b, u2])])), "o2m NOT IN matches none on the right side" - - - - - - - # child_of x returns x and its children (direct or not). - company = self.browse(cr, uid, ref('ymltest_company3')) - expected = [ref('ymltest_company3'), ref('ymltest_company4')] - expected.sort() - res_1 = self.search(cr, uid, [('id', 'child_of', [ref('ymltest_company3')])]) - res_1.sort() - res_2 = self.search(cr, uid, [('id', 'child_of', ref('ymltest_company3'))]) - res_2.sort() - res_3 = self.search(cr, uid, [('id', 'child_of', [company.name])]) - res_3.sort() - res_4 = self.search(cr, uid, [('id', 'child_of', company.name)]) - res_4.sort() - assert res_1 == expected - assert res_2 == expected - assert res_3 == expected - assert res_4 == expected - - # parent_of x returns x and its parents (direct or not). - company = self.browse(cr, uid, ref('ymltest_company4')) - expected = [ref('ymltest_company4'), ref('ymltest_company3')] - expected.sort() - res_1 = self.search(cr, uid, [('id', 'parent_of', [ref('ymltest_company4')])]) - res_1.sort() - res_2 = self.search(cr, uid, [('id', 'parent_of', ref('ymltest_company4'))]) - res_2.sort() - res_3 = self.search(cr, uid, [('id', 'parent_of', [company.name])]) - res_3.sort() - res_4 = self.search(cr, uid, [('id', 'parent_of', company.name)]) - res_4.sort() - assert res_1 == expected - assert res_2 == expected - assert res_3 == expected - assert res_4 == expected -- - Equivalent queries, one2many. -- - !python {model: res.currency }: | - # Create a currency and a currency rate - res_currency = self.pool['res.currency'] - res_currency_rate = self.pool['res.currency.rate'] - currency = res_currency.create(cr, uid, {'name': 'ZZZ', 'symbol': 'ZZZ', 'rounding': 1.0}) - currency_rate = self.pool['res.currency.rate'].create(cr, uid, {'name': '2010-01-01', 'currency_id': currency, 'rate': 1.0}) - - # Search the currency via its rates one2many (the one2many must point back at the currency). - max_currency_rate_id = max(res_currency_rate.search(cr, uid, [])) - currency_rate1 = res_currency_rate.search(cr, uid, [('name', 'not like', 'probably_unexisting_name')]) - currency_rate2 = res_currency_rate.search(cr, uid, [('id', 'not in', [max_currency_rate_id + 1003])]) - currency_rate3 = res_currency_rate.search(cr, uid, [('id', 'not in', [])]) - assert currency_rate1 == currency_rate2 == currency_rate3, 'All 3 results should be the same : empty' - default_currency = self.browse(cr, uid, 1) - - # one2many towards another model - res_3 = self.search(cr, uid, [('rate_ids', 'in', [x.id for x in default_currency.rate_ids])]) # currencies having a rate of main currency - res_4 = self.search(cr, uid, [('rate_ids', 'in', [default_currency.rate_ids[0].id])]) # currencies having first rate of main currency - res_5 = self.search(cr, uid, [('rate_ids', 'in', default_currency.rate_ids[0].id)]) # currencies having first rate of main currency - # res_6 = self.search(cr, uid, [('rate_ids', 'in', [default_currency.rate_ids[0].name])]) - # res_7 = self.search(cr, uid, [('rate_ids', '=', default_currency.rate_ids[0].name)]) - # res_8 = self.search(cr, uid, [('rate_ids', 'like', default_currency.rate_ids[0].name)]) - - res_9 = self.search(cr, uid, [('rate_ids', 'like', 'probably_unexisting_name')]) - # self.search(cr, uid, [('rate_ids', 'unexisting_op', 'probably_unexisting_name')]) # TODO expected exception - assert res_3 == [1], "res_3" - assert res_4 == [1], "res_4" - assert res_5 == [1], "res_5" - # assert res_7 == [1], "res_7" - # assert res_8 == [1], "res_8" - assert res_9 == [], "res_9" - - # get the currencies referenced by some currency rates using a weird negative domain - res_10 = self.search(cr, uid, [('rate_ids', 'not like', 'probably_unexisting_name')]) - res_11 = self.search(cr, uid, [('rate_ids', 'not in', [max_currency_rate_id + 1])]) - res_12 = self.search(cr, uid, [('rate_ids', '!=', False)]) - res_13 = self.search(cr, uid, [('rate_ids', 'not in', [])]) - res_10.sort() - res_11.sort() - res_12.sort() - res_13.sort() - assert res_10 == res_11, 'res_11' - assert res_10 == res_12, 'res_12' - assert res_10 == res_13, 'res_13' -- - Unaccent. Create a company with an accent in its name. -- - !record {model: res.company, id: ymltest_unaccent_company}: - name: Hélène -- - Test the unaccent-enabled 'ilike'. -- - !python {model: res.company}: | - if self.pool.has_unaccent: - ids = self.search(cr, uid, [('name','ilike','Helene')], {}) - assert ids == [ref('ymltest_unaccent_company')] - ids = self.search(cr, uid, [('name','ilike','hélène')], {}) - assert ids == [ref('ymltest_unaccent_company')] - ids = self.search(cr, uid, [('name','not ilike','Helene')], {}) - assert ref('ymltest_unaccent_company') not in ids - ids = self.search(cr, uid, [('name','not ilike','hélène')], {}) - assert ref('ymltest_unaccent_company') not in ids -- - Check that =like/=ilike expressions (no wildcard variants of like/ilike) are working on an untranslated field. -- - !python {model: res.partner }: | - all_ids = self.search(cr, uid, [('name', '=like', 'A_U_TeK')]) - assert len(all_ids) == 1, "Must match one partner (ASUSTeK), got %r"%all_ids - all_ids = self.search(cr, uid, [('name', '=ilike', 'c%')]) - assert len(all_ids) >= 1, "Must match one partner (China Export), got %r"%all_ids -- - Check that =like/=ilike expressions (no wildcard variants of like/ilike) are working on translated field. -- - !python {model: res.country }: | - all_ids = self.search(cr, uid, [('name', '=like', 'Ind__')]) - assert len(all_ids) == 1, "Must match India only, got %r"%all_ids - all_ids = self.search(cr, uid, [('name', '=ilike', 'z%')]) - assert len(all_ids) == 3, "Must match only countries with names starting with Z (currently 3), got %r"%all_ids -- - Use the create_date column on res.country (which doesn't declare it in _columns). -- - !python {model: res.country }: | - ids = self.search(cr, uid, [('create_date', '<', '2001-01-01 12:00:00')]) - - -- - Verify that invalid expressions are refused, even for magic fields -- - !python {model: res.country }: | - try: - self.search(cr, uid, [('does_not_exist', '=', 'foo')]) - raise AssertionError('Invalid fields should not be accepted') - except ValueError: - pass - - try: - self.search(cr, uid, [('create_date', '>>', 'foo')]) - raise AssertionError('Invalid operators should not be accepted') - except ValueError: - pass - - import psycopg2 - try: - cr._default_log_exceptions = False - cr.execute('SAVEPOINT expression_failure_test') - self.search(cr, uid, [('create_date', '=', "1970-01-01'); --")]) - # if the above search gives no error, the operand was not escaped! - cr.execute('RELEASE SAVEPOINT expression_failure_test') - raise AssertionError('Operands should always be SQL escaped') - except psycopg2.DataError: - # Should give: 'DataError: invalid input syntax for type timestamp' or similar - cr.execute('ROLLBACK TO SAVEPOINT expression_failure_test') -- - Testing for Many2Many field with category vendor and active=False -- - !python {model: res.partner }: | - vals = {'category_id': [(6, 0, [ref("base.res_partner_category_1")])], - 'name': 'OpenERP Test', - 'active': False, - 'child_ids': [(0, 0, {'name': 'address of OpenERP Test', 'country_id': ref("base.be")})] - } - self.create(cr, uid, vals, context=context) - res_ids = self.search(cr, uid, [('category_id', 'ilike', 'vendor'), ('active', '=', False)]) - assert len(res_ids) != 0, "Record not Found with category vendor and active False." -- - Testing for One2Many field with country Belgium and active=False -- - !python {model: res.partner }: | - res_ids = self.search(cr, uid, [('child_ids.country_id','=','Belgium'),('active','=',False)]) - assert len(res_ids) != 0, "Record not Found with country Belgium and active False." -- - Check that we can exclude translated fields (bug lp:1071710) -- - !python {model: res.country}: | - # first install french language - Modules = self.pool.get('ir.module.module') - base = Modules.browse(cr, uid, Modules.search(cr, uid, [('name', '=', 'base')])[0]) - - # hack: mark module as installed to allow install of the translation - base_state = base.state - base.write({'state': 'installed'}) - base.update_translations('fr_FR') - base.write({'state': base_state}) - - # tests - be_id = self.search(cr, uid, [('name', '=', 'Belgium')])[0] - - ctx = {'lang': 'fr_FR'} - not_be = self.search(cr, uid, [('name', '!=', 'Belgique')], context=ctx) - - assert be_id not in not_be, "Search match failed" - - # indirect search via m2o - Partners = self.pool.get('res.partner') - agrolait = Partners.search(cr, uid, [('name', '=', 'Agrolait')])[0] - - not_be = Partners.search(cr, uid, [('country_id', '!=', 'Belgium')]) - assert agrolait not in not_be, "Search match failed (m2o)" - - not_be = Partners.search(cr, uid, [('country_id', '!=', 'Belgique')], context=ctx) - assert agrolait not in not_be, "Search match failed (m2o)" diff --git a/openerp/addons/base/tests/test_phase.py b/openerp/addons/base/tests/test_phase.py new file mode 100644 index 00000000000..09f6e1e64e5 --- /dev/null +++ b/openerp/addons/base/tests/test_phase.py @@ -0,0 +1,64 @@ +# -*- coding: utf-8 -*- +# Part of Odoo. See LICENSE file for full copyright and licensing details. + +import unittest + +from odoo.tests import common + + +#: Stores state information across multiple test classes +test_state = None + +def setUpModule(): + global test_state + test_state = {} + +def tearDownModule(): + global test_state + test_state = None + + +class TestPhaseInstall00(unittest.TestCase): + """ + WARNING: Relies on tests being run in alphabetical order + """ + @classmethod + def setUpClass(cls): + cls.state = None + + def test_00_setup(self): + type(self).state = 'init' + + @common.at_install(False) + def test_01_no_install(self): + type(self).state = 'error' + + def test_02_check(self): + self.assertEqual(self.state, 'init', + "Testcase state should not have been transitioned from 00") + + +class TestPhaseInstall01(unittest.TestCase): + at_install = False + + def test_default_norun(self): + self.fail("An unmarket test in a non-at-install case should not run") + + @common.at_install(True) + def test_set_run(self): + test_state['set_at_install'] = True + + +class TestPhaseInstall02(unittest.TestCase): + """ + Can't put the check for test_set_run in the same class: if + @common.at_install does not work for test_set_run, it won't work for + the other one either. Thus move checking of whether test_set_run has + correctly run indeed to a separate class. + + Warning: relies on *classes* being run in alphabetical order in test + modules + """ + def test_check_state(self): + self.assertTrue(test_state.get('set_at_install'), + "The flag should be set if local overriding of runstate") diff --git a/openerp/addons/base/tests/test_qweb.py b/openerp/addons/base/tests/test_qweb.py index 01e6626c10b..e7de2c3c3b3 100644 --- a/openerp/addons/base/tests/test_qweb.py +++ b/openerp/addons/base/tests/test_qweb.py @@ -1,92 +1,78 @@ # -*- coding: utf-8 -*- +# Part of Odoo. See LICENSE file for full copyright and licensing details. + import cgi +import collections import json import os.path -import glob import re -import collections from lxml import etree -import openerp.modules -from openerp.addons.base.ir.ir_qweb import QWebContext, FileSystemLoader -from openerp.tests import common +from odoo.addons.base.ir.ir_qweb import QWebContext, FileSystemLoader +from odoo.modules import get_module_resource +from odoo.tests.common import TransactionCase -class TestQWebTField(common.TransactionCase): + +class TestQWebTField(TransactionCase): def setUp(self): super(TestQWebTField, self).setUp() - self.env = self.env(context={'inherit_branding': True}) - self.engine = self.env['ir.qweb'] + self.env_branding = self.env(context={'inherit_branding': True}) + self.engine = self.env_branding['ir.qweb'] def context(self, values): - return QWebContext(self.env, values) + return QWebContext(self.env_branding, values) def test_trivial(self): field = etree.Element('span', {'t-field': u'company.name'}) + company = self.env['res.company'].create({'name': "My Test Company"}) - Companies = self.registry('res.company') - company_id = Companies.create(self.cr, self.uid, { - 'name': "My Test Company" - }) - result = self.engine.render_node(field, self.context({ - 'company': Companies.browse(self.cr, self.uid, company_id), - })) - + result = self.engine.render_node(field, self.context({'company': company})) self.assertEqual( result, '<span data-oe-model="res.company" data-oe-id="%d" ' 'data-oe-field="name" data-oe-type="char" ' 'data-oe-expression="company.name">%s</span>' % ( - company_id, - "My Test Company",)) + company.id, + "My Test Company", + ), + ) def test_i18n(self): field = etree.Element('span', {'t-field': u'company.name'}) - - Companies = self.registry('res.company') s = u"Testing «ταБЬℓσ»: 1<2 & 4+1>3, now 20% off!" - company_id = Companies.create(self.cr, self.uid, { - 'name': s, - }) - result = self.engine.render_node(field, self.context({ - 'company': Companies.browse(self.cr, self.uid, company_id), - })) + company = self.env['res.company'].create({'name': s}) + result = self.engine.render_node(field, self.context({'company': company})) self.assertEqual( result, '<span data-oe-model="res.company" data-oe-id="%d" ' 'data-oe-field="name" data-oe-type="char" ' 'data-oe-expression="company.name">%s</span>' % ( - company_id, - cgi.escape(s.encode('utf-8')),)) + company.id, + cgi.escape(s.encode('utf-8')), + ), + ) def test_reject_crummy_tags(self): field = etree.Element('td', {'t-field': u'company.name'}) - with self.assertRaisesRegexp( - AssertionError, - r'^RTE widgets do not work correctly'): - self.engine.render_node(field, self.context({ - 'company': None - })) + with self.assertRaisesRegexp(AssertionError, r'^RTE widgets do not work correctly'): + self.engine.render_node(field, self.context({'company': None})) def test_reject_t_tag(self): field = etree.Element('t', {'t-field': u'company.name'}) - with self.assertRaisesRegexp( - AssertionError, - r'^t-field can not be used on a t element'): - self.engine.render_node(field, self.context({ - 'company': None - })) + with self.assertRaisesRegexp(AssertionError, r'^t-field can not be used on a t element'): + self.engine.render_node(field, self.context({'company': None})) + -class TestQWeb(common.TransactionCase): - matcher = re.compile('^qweb-test-(.*)\.xml$') +class TestQWeb(TransactionCase): + matcher = re.compile(r'^qweb-test-(.*)\.xml$') @classmethod def get_cases(cls): path = cls.qweb_test_file_path() - return ( cls("test_qweb_{}".format(cls.matcher.match(f).group(1))) for f in os.listdir(path) @@ -94,12 +80,10 @@ class TestQWeb(common.TransactionCase): if f != 'qweb-test-extend.xml' if cls.matcher.match(f) ) + @classmethod def qweb_test_file_path(cls): - path = os.path.dirname( - openerp.modules.get_module_resource( - 'web', 'static', 'lib', 'qweb', 'qweb2.js')) - return path + return os.path.dirname(get_module_resource('web', 'static', 'lib', 'qweb', 'qweb2.js')) def __getattr__(self, item): if not item.startswith('test_qweb_'): @@ -129,9 +113,10 @@ class TestQWeb(common.TransactionCase): self.assertEqual( qweb.render(template, qwebcontext=ctx).strip(), (result or u'').strip().encode('utf-8'), - template + template, ) + def load_tests(loader, suite, _): # can't override TestQWeb.__dir__ because dir() called on *class* not # instance diff --git a/openerp/addons/base/tests/test_res_config.py b/openerp/addons/base/tests/test_res_config.py index 0a6a49efdeb..af919ce4b66 100644 --- a/openerp/addons/base/tests/test_res_config.py +++ b/openerp/addons/base/tests/test_res_config.py @@ -1,13 +1,15 @@ -import unittest +# -*- coding: utf-8 -*- +# Part of Odoo. See LICENSE file for full copyright and licensing details. -import openerp -import openerp.tests.common as common +from odoo import exceptions +from odoo.tests.common import TransactionCase -class test_res_config(common.TransactionCase): + +class TestResConfig(TransactionCase): def setUp(self): - super(test_res_config, self).setUp() - self.res_config = self.registry('res.config.settings') + super(TestResConfig, self).setUp() + self.ResConfig = self.env['res.config.settings'] # Define the test values self.menu_xml_id = 'base.menu_action_res_users' @@ -17,15 +19,13 @@ class test_res_config(common.TransactionCase): # Note: see the get_config_warning() doc for a better example # Fetch the expected values - module_name, menu_xml_id = self.menu_xml_id.split('.') - dummy, menu_id = self.registry('ir.model.data').get_object_reference(self.cr, self.uid, module_name, menu_xml_id) - ir_ui_menu = self.registry('ir.ui.menu').browse(self.cr, self.uid, menu_id, context=None) + menu = self.env.ref(self.menu_xml_id) model_name, field_name = self.full_field_name.rsplit('.', 1) - self.expected_path = ir_ui_menu.complete_name - self.expected_action_id = ir_ui_menu.action.id - self.expected_name = self.registry(model_name).fields_get(self.cr, self.uid, allfields=[field_name], context=None)[field_name]['string'] + self.expected_path = menu.complete_name + self.expected_action_id = menu.action.id + self.expected_name = self.env[model_name].fields_get([field_name])[field_name]['string'] self.expected_final_error_msg = self.error_msg % { 'field:res.partner.lang': self.expected_name, 'menu:base.menu_action_res_users': self.expected_path @@ -36,7 +36,7 @@ class test_res_config(common.TransactionCase): def test_00_get_option_path(self): """ The get_option_path() method should return a tuple containing a string and an integer """ - res = self.res_config.get_option_path(self.cr, self.uid, self.menu_xml_id, context=None) + res = self.ResConfig.get_option_path(self.menu_xml_id) # Check types self.assertIsInstance(res, tuple) @@ -50,7 +50,7 @@ class test_res_config(common.TransactionCase): def test_10_get_option_name(self): """ The get_option_name() method should return a string """ - res = self.res_config.get_option_name(self.cr, self.uid, self.full_field_name, context=None) + res = self.ResConfig.get_option_name(self.full_field_name) # Check type self.assertIsInstance(res, basestring) @@ -60,10 +60,10 @@ class test_res_config(common.TransactionCase): def test_20_get_config_warning(self): """ The get_config_warning() method should return a RedirectWarning """ - res = self.res_config.get_config_warning(self.cr, self.error_msg, context=None) + res = self.ResConfig.get_config_warning(self.error_msg) # Check type - self.assertIsInstance(res, openerp.exceptions.RedirectWarning) + self.assertIsInstance(res, exceptions.RedirectWarning) # Check returned value self.assertEqual(res.args[0], self.expected_final_error_msg) @@ -71,10 +71,10 @@ class test_res_config(common.TransactionCase): def test_30_get_config_warning_wo_menu(self): """ The get_config_warning() method should return a Warning exception """ - res = self.res_config.get_config_warning(self.cr, self.error_msg_wo_menu, context=None) + res = self.ResConfig.get_config_warning(self.error_msg_wo_menu) # Check type - self.assertIsInstance(res, openerp.exceptions.Warning) + self.assertIsInstance(res, exceptions.Warning) # Check returned value self.assertEqual(res.args[0], self.expected_final_error_msg_wo_menu) diff --git a/openerp/addons/base/tests/test_res_lang.py b/openerp/addons/base/tests/test_res_lang.py index c7e591472c5..c6eab4ded78 100644 --- a/openerp/addons/base/tests/test_res_lang.py +++ b/openerp/addons/base/tests/test_res_lang.py @@ -1,11 +1,12 @@ -import unittest +# -*- coding: utf-8 -*- +# Part of Odoo. See LICENSE file for full copyright and licensing details. -import openerp.tests.common as common +from odoo.tests.common import TransactionCase -class test_res_lang(common.TransactionCase): +class test_res_lang(TransactionCase): def test_00_intersperse(self): - from openerp.addons.base.res.res_lang import intersperse + from odoo.addons.base.res.res_lang import intersperse assert intersperse("", []) == ("", 0) assert intersperse("0", []) == ("0", 0) diff --git a/openerp/addons/base/tests/test_res_partner_bank.py b/openerp/addons/base/tests/test_res_partner_bank.py index e9ed9172588..cbf533802a1 100644 --- a/openerp/addons/base/tests/test_res_partner_bank.py +++ b/openerp/addons/base/tests/test_res_partner_bank.py @@ -3,7 +3,8 @@ # Copyright (c) 2015 ACSONE SA/NV (<http://acsone.eu>) -from openerp.tests.common import TransactionCase +from odoo.tests.common import TransactionCase + class TestResPartnerBank(TransactionCase): """Tests acc_number diff --git a/openerp/addons/base/tests/test_search.py b/openerp/addons/base/tests/test_search.py index 000f05a33d8..8fba34ca025 100644 --- a/openerp/addons/base/tests/test_search.py +++ b/openerp/addons/base/tests/test_search.py @@ -1,26 +1,24 @@ -import unittest +# -*- coding: utf-8 -*- +# Part of Odoo. See LICENSE file for full copyright and licensing details. -import openerp.tests.common as common +from odoo.tests.common import TransactionCase -class test_search(common.TransactionCase): +class test_search(TransactionCase): def test_00_search_order(self): - - registry, cr, uid = self.registry, self.cr, self.uid - # Create 6 partners with a given name, and a given creation order to - # ensure the order of their ID. Some are set as unactive to verify they + # ensure the order of their ID. Some are set as inactive to verify they # are by default excluded from the searches and to provide a second # `order` argument. - partners = registry('res.partner') - c = partners.create(cr, uid, {'name': 'test_search_order_C'}) - d = partners.create(cr, uid, {'name': 'test_search_order_D', 'active': False}) - a = partners.create(cr, uid, {'name': 'test_search_order_A'}) - b = partners.create(cr, uid, {'name': 'test_search_order_B'}) - ab = partners.create(cr, uid, {'name': 'test_search_order_AB'}) - e = partners.create(cr, uid, {'name': 'test_search_order_E', 'active': False}) + Partner = self.env['res.partner'] + c = Partner.create({'name': 'test_search_order_C'}) + d = Partner.create({'name': 'test_search_order_D', 'active': False}) + a = Partner.create({'name': 'test_search_order_A'}) + b = Partner.create({'name': 'test_search_order_B'}) + ab = Partner.create({'name': 'test_search_order_AB'}) + e = Partner.create({'name': 'test_search_order_E', 'active': False}) # The tests. @@ -28,116 +26,109 @@ class test_search(common.TransactionCase): # The order of the returned ids should be given by the `order` # parameter of search(). - name_asc = partners.search(cr, uid, [('name', 'like', 'test_search_order%')], order="name asc") - self.assertEqual([a, ab, b, c], name_asc, "Search with 'NAME ASC' order failed.") - name_desc = partners.search(cr, uid, [('name', 'like', 'test_search_order%')], order="name desc") - self.assertEqual([c, b, ab, a], name_desc, "Search with 'NAME DESC' order failed.") - id_asc = partners.search(cr, uid, [('name', 'like', 'test_search_order%')], order="id asc") - self.assertEqual([c, a, b, ab], id_asc, "Search with 'ID ASC' order failed.") - id_desc = partners.search(cr, uid, [('name', 'like', 'test_search_order%')], order="id desc") - self.assertEqual([ab, b, a, c], id_desc, "Search with 'ID DESC' order failed.") + name_asc = Partner.search([('name', 'like', 'test_search_order%')], order="name asc") + self.assertEqual([a, ab, b, c], list(name_asc), "Search with 'NAME ASC' order failed.") + name_desc = Partner.search([('name', 'like', 'test_search_order%')], order="name desc") + self.assertEqual([c, b, ab, a], list(name_desc), "Search with 'NAME DESC' order failed.") + id_asc = Partner.search([('name', 'like', 'test_search_order%')], order="id asc") + self.assertEqual([c, a, b, ab], list(id_asc), "Search with 'ID ASC' order failed.") + id_desc = Partner.search([('name', 'like', 'test_search_order%')], order="id desc") + self.assertEqual([ab, b, a, c], list(id_desc), "Search with 'ID DESC' order failed.") # The inactive records shouldn't be excluded as soon as a condition on # that field is present in the domain. The `order` parameter of # search() should support any legal coma-separated values. - active_asc_id_asc = partners.search(cr, uid, [('name', 'like', 'test_search_order%'), '|', ('active', '=', True), ('active', '=', False)], order="active asc, id asc") - self.assertEqual([d, e, c, a, b, ab], active_asc_id_asc, "Search with 'ACTIVE ASC, ID ASC' order failed.") - active_desc_id_asc = partners.search(cr, uid, [('name', 'like', 'test_search_order%'), '|', ('active', '=', True), ('active', '=', False)], order="active desc, id asc") - self.assertEqual([c, a, b, ab, d, e], active_desc_id_asc, "Search with 'ACTIVE DESC, ID ASC' order failed.") - active_asc_id_desc = partners.search(cr, uid, [('name', 'like', 'test_search_order%'), '|', ('active', '=', True), ('active', '=', False)], order="active asc, id desc") - self.assertEqual([e, d, ab, b, a, c], active_asc_id_desc, "Search with 'ACTIVE ASC, ID DESC' order failed.") - active_desc_id_desc = partners.search(cr, uid, [('name', 'like', 'test_search_order%'), '|', ('active', '=', True), ('active', '=', False)], order="active desc, id desc") - self.assertEqual([ab, b, a, c, e, d], active_desc_id_desc, "Search with 'ACTIVE DESC, ID DESC' order failed.") - id_asc_active_asc = partners.search(cr, uid, [('name', 'like', 'test_search_order%'), '|', ('active', '=', True), ('active', '=', False)], order="id asc, active asc") - self.assertEqual([c, d, a, b, ab, e], id_asc_active_asc, "Search with 'ID ASC, ACTIVE ASC' order failed.") - id_asc_active_desc = partners.search(cr, uid, [('name', 'like', 'test_search_order%'), '|', ('active', '=', True), ('active', '=', False)], order="id asc, active desc") - self.assertEqual([c, d, a, b, ab, e], id_asc_active_desc, "Search with 'ID ASC, ACTIVE DESC' order failed.") - id_desc_active_asc = partners.search(cr, uid, [('name', 'like', 'test_search_order%'), '|', ('active', '=', True), ('active', '=', False)], order="id desc, active asc") - self.assertEqual([e, ab, b, a, d, c], id_desc_active_asc, "Search with 'ID DESC, ACTIVE ASC' order failed.") - id_desc_active_desc = partners.search(cr, uid, [('name', 'like', 'test_search_order%'), '|', ('active', '=', True), ('active', '=', False)], order="id desc, active desc") - self.assertEqual([e, ab, b, a, d, c], id_desc_active_desc, "Search with 'ID DESC, ACTIVE DESC' order failed.") + active_asc_id_asc = Partner.search([('name', 'like', 'test_search_order%'), '|', ('active', '=', True), ('active', '=', False)], order="active asc, id asc") + self.assertEqual([d, e, c, a, b, ab], list(active_asc_id_asc), "Search with 'ACTIVE ASC, ID ASC' order failed.") + active_desc_id_asc = Partner.search([('name', 'like', 'test_search_order%'), '|', ('active', '=', True), ('active', '=', False)], order="active desc, id asc") + self.assertEqual([c, a, b, ab, d, e], list(active_desc_id_asc), "Search with 'ACTIVE DESC, ID ASC' order failed.") + active_asc_id_desc = Partner.search([('name', 'like', 'test_search_order%'), '|', ('active', '=', True), ('active', '=', False)], order="active asc, id desc") + self.assertEqual([e, d, ab, b, a, c], list(active_asc_id_desc), "Search with 'ACTIVE ASC, ID DESC' order failed.") + active_desc_id_desc = Partner.search([('name', 'like', 'test_search_order%'), '|', ('active', '=', True), ('active', '=', False)], order="active desc, id desc") + self.assertEqual([ab, b, a, c, e, d], list(active_desc_id_desc), "Search with 'ACTIVE DESC, ID DESC' order failed.") + id_asc_active_asc = Partner.search([('name', 'like', 'test_search_order%'), '|', ('active', '=', True), ('active', '=', False)], order="id asc, active asc") + self.assertEqual([c, d, a, b, ab, e], list(id_asc_active_asc), "Search with 'ID ASC, ACTIVE ASC' order failed.") + id_asc_active_desc = Partner.search([('name', 'like', 'test_search_order%'), '|', ('active', '=', True), ('active', '=', False)], order="id asc, active desc") + self.assertEqual([c, d, a, b, ab, e], list(id_asc_active_desc), "Search with 'ID ASC, ACTIVE DESC' order failed.") + id_desc_active_asc = Partner.search([('name', 'like', 'test_search_order%'), '|', ('active', '=', True), ('active', '=', False)], order="id desc, active asc") + self.assertEqual([e, ab, b, a, d, c], list(id_desc_active_asc), "Search with 'ID DESC, ACTIVE ASC' order failed.") + id_desc_active_desc = Partner.search([('name', 'like', 'test_search_order%'), '|', ('active', '=', True), ('active', '=', False)], order="id desc, active desc") + self.assertEqual([e, ab, b, a, d, c], list(id_desc_active_desc), "Search with 'ID DESC, ACTIVE DESC' order failed.") def test_10_inherits_m2order(self): - registry, cr, uid = self.registry, self.cr, self.uid - users_obj = registry('res.users') + Users = self.env['res.users'] # Find Employee group - group_employee_ref = self.registry('ir.model.data').get_object_reference(cr, uid, 'base', 'group_user') - group_employee_id = group_employee_ref and group_employee_ref[1] or False + group_employee = self.env.ref('base.group_user') # Get country/state data - country_us_id = registry('res.country').search(cr, uid, [('code', 'like', 'US')])[0] - state_ids = registry('res.country.state').search(cr, uid, [('country_id', '=', country_us_id)], limit=2) - country_be_id = registry('res.country').search(cr, uid, [('code', 'like', 'BE')])[0] + country_be = self.env.ref('base.be') + country_us = self.env.ref('base.us') + states_us = country_us.state_ids[:2] # Create test users - search_user = users_obj.create(cr, uid, {'name': '__search', 'login': '__search', 'groups_id': [(6, 0, [group_employee_id])]}) - a = users_obj.create(cr, uid, {'name': '__test_A', 'login': '__test_A', 'country_id': country_be_id, 'state_id': country_be_id}) - b = users_obj.create(cr, uid, {'name': '__test_B', 'login': '__a_test_B', 'country_id': country_us_id, 'state_id': state_ids[1]}) - c = users_obj.create(cr, uid, {'name': '__test_B', 'login': '__z_test_B', 'country_id': country_us_id, 'state_id': state_ids[0]}) + u = Users.create({'name': '__search', 'login': '__search', 'groups_id': [(6, 0, [group_employee.id])]}) + a = Users.create({'name': '__test_A', 'login': '__test_A', 'country_id': country_be.id, 'state_id': country_be.id}) + b = Users.create({'name': '__test_B', 'login': '__a_test_B', 'country_id': country_us.id, 'state_id': states_us[1].id}) + c = Users.create({'name': '__test_B', 'login': '__z_test_B', 'country_id': country_us.id, 'state_id': states_us[0].id}) + + # Search as search user + Users = Users.sudo(u) # Do: search on res.users, order on a field on res.partner to try inherits'd fields, then res.users - user_ids = users_obj.search(cr, search_user, [], order='name asc, login desc') - expected_ids = [search_user, a, c, b] - test_user_ids = filter(lambda x: x in expected_ids, user_ids) - self.assertEqual(test_user_ids, expected_ids, 'search on res_users did not provide expected ids or expected order') + expected_ids = [u.id, a.id, c.id, b.id] + user_ids = Users.search([('id', 'in', expected_ids)], order='name asc, login desc').ids + self.assertEqual(user_ids, expected_ids, 'search on res_users did not provide expected ids or expected order') # Do: order on many2one and inherits'd fields - user_ids = users_obj.search(cr, search_user, [], order='state_id asc, country_id desc, name asc, login desc') - expected_ids = [c, b, a, search_user] - test_user_ids = filter(lambda x: x in expected_ids, user_ids) - self.assertEqual(test_user_ids, expected_ids, 'search on res_users did not provide expected ids or expected order') + expected_ids = [c.id, b.id, a.id, u.id] + user_ids = Users.search([('id', 'in', expected_ids)], order='state_id asc, country_id desc, name asc, login desc').ids + self.assertEqual(user_ids, expected_ids, 'search on res_users did not provide expected ids or expected order') # Do: order on many2one and inherits'd fields - user_ids = users_obj.search(cr, search_user, [], order='country_id desc, state_id desc, name asc, login desc') - expected_ids = [search_user, b, c, a] - test_user_ids = filter(lambda x: x in expected_ids, user_ids) - self.assertEqual(test_user_ids, expected_ids, 'search on res_users did not provide expected ids or expected order') + expected_ids = [u.id, b.id, c.id, a.id] + user_ids = Users.search([('id', 'in', expected_ids)], order='country_id desc, state_id desc, name asc, login desc').ids + self.assertEqual(user_ids, expected_ids, 'search on res_users did not provide expected ids or expected order') # Do: order on many2one, but not by specifying in order parameter of search, but by overriding _order of res_users self.patch_order('res.users', 'country_id desc, name asc, login desc') - user_ids = users_obj.search(cr, search_user, []) - expected_ids = [search_user, c, b, a] - test_user_ids = filter(lambda x: x in expected_ids, user_ids) - self.assertEqual(test_user_ids, expected_ids, 'search on res_users did not provide expected ids or expected order') + expected_ids = [u.id, c.id, b.id, a.id] + user_ids = Users.search([('id', 'in', expected_ids)]).ids + self.assertEqual(user_ids, expected_ids, 'search on res_users did not provide expected ids or expected order') def test_11_indirect_inherits_m2o_order(self): - registry, cr, uid = self.registry, self.cr, self.uid - Cron = registry('ir.cron') - Users = registry('res.users') + Cron = self.env['ir.cron'] + Users = self.env['res.users'] user_ids = {} cron_ids = {} for u in 'BAC': - user_ids[u] = Users.create(cr, uid, {'name': u, 'login': u}) - cron_ids[u] = Cron.create(cr, uid, {'name': u, 'user_id': user_ids[u]}) + user_ids[u] = Users.create({'name': u, 'login': u}).id + cron_ids[u] = Cron.create({'name': u, 'user_id': user_ids[u]}).id - ids = Cron.search(cr, uid, [('id', 'in', cron_ids.values())], order='user_id') + ids = Cron.search([('id', 'in', cron_ids.values())], order='user_id').ids expected_ids = [cron_ids[l] for l in 'ABC'] self.assertEqual(ids, expected_ids) def test_12_m2o_order_loop_self(self): - registry, cr, uid = self.registry, self.cr, self.uid - - Cats = registry('ir.module.category') - ids = {} + Cats = self.env['ir.module.category'] + cat_ids = {} def create(name, **kw): - ids[name] = Cats.create(cr, uid, dict(kw, name=name)) + cat_ids[name] = Cats.create(dict(kw, name=name)).id self.patch_order('ir.module.category', 'parent_id desc, name') create('A') - create('B', parent_id=ids['A']) - create('C', parent_id=ids['A']) + create('B', parent_id=cat_ids['A']) + create('C', parent_id=cat_ids['A']) create('D') - create('E', parent_id=ids['D']) - create('F', parent_id=ids['D']) + create('E', parent_id=cat_ids['D']) + create('F', parent_id=cat_ids['D']) - expected_order = [ids[x] for x in 'ADEFBC'] - domain = [('id', 'in', ids.values())] - search_result = Cats.search(cr, uid, domain) - self.assertEqual(search_result, expected_order) + expected_ids = [cat_ids[x] for x in 'ADEFBC'] + found_ids = Cats.search([('id', 'in', cat_ids.values())]).ids + self.assertEqual(found_ids, expected_ids) def test_13_m2o_order_loop_multi(self): Users = self.env['res.users'] @@ -154,11 +145,6 @@ class test_search(common.TransactionCase): u3 = Users.create(dict(name='C', login='c', **kw)).id u4 = Users.sudo(user=u2).create(dict(name='D', login='z', **kw)).id - expected_order = [u2, u4, u3, u1] - - domain = [('id', 'in', [u1, u2, u3, u4])] - search_result = list(Users.search(domain)._ids) - self.assertEqual(search_result, expected_order) - -if __name__ == '__main__': - unittest.main() + expected_ids = [u2, u4, u3, u1] + found_ids = Users.search([('id', 'in', expected_ids)]).ids + self.assertEqual(found_ids, expected_ids) diff --git a/openerp/addons/base/tests/test_translate.py b/openerp/addons/base/tests/test_translate.py index d6944cd24dd..fac2ec78284 100644 --- a/openerp/addons/base/tests/test_translate.py +++ b/openerp/addons/base/tests/test_translate.py @@ -1,9 +1,11 @@ # -*- coding: utf-8 -*- # Part of Odoo. See LICENSE file for full copyright and licensing details. -from lxml.etree import XMLSyntaxError import unittest -from openerp.tools.translate import quote, unquote, xml_translate, html_translate + +from odoo.tools.translate import quote, unquote, xml_translate, html_translate +from odoo.tests.common import TransactionCase + class TranslationToolsTestCase(unittest.TestCase): @@ -167,3 +169,56 @@ class TranslationToolsTestCase(unittest.TestCase): self.assertEquals(result, """<i class="fa-check"/>""") result = html_translate(lambda term: term, source) self.assertEquals(result, source) + + +class TestTranslation(TransactionCase): + + def setUp(self): + super(TestTranslation, self).setUp() + self.env['ir.translation'].load_module_terms(['base'], ['fr_FR']) + self.customers = self.env['res.partner.category'].create({'name': 'Customers'}) + self.env['ir.translation'].create({ + 'type': 'model', + 'name': 'res.partner.category,name', + 'module':'base', + 'lang': 'fr_FR', + 'res_id': self.customers.id, + 'value': 'Clients', + 'state': 'translated', + }) + + def test_101_create_translated_record(self): + category = self.customers.with_context({}) + self.assertEqual(category.name, 'Customers', "Error in basic name_get") + + category_fr = category.with_context({'lang': 'fr_FR'}) + self.assertEqual(category_fr.name, 'Clients', "Translation not found") + + def test_102_duplicate_record(self): + category = self.customers.with_context({'lang': 'fr_FR'}).copy() + + category_no = category.with_context({}) + self.assertEqual(category_no.name, 'Customers', "Duplication did not set untranslated value") + + category_fr = category.with_context({'lang': 'fr_FR'}) + self.assertEqual(category_fr.name, 'Clients', "Did not found translation for initial value") + + def test_103_duplicate_record_fr(self): + category = self.customers.with_context({'lang': 'fr_FR'}).copy({'name': 'Clients (copie)'}) + + category_no = category.with_context({}) + self.assertEqual(category_no.name, 'Customers', "Duplication erased original untranslated value") + + category_fr = category.with_context({'lang': 'fr_FR'}) + self.assertEqual(category_fr.name, 'Clients (copie)', "Did not used default value for translated value") + + def test_104_orderby_translated_field(self): + """ Test search ordered by a translated field. """ + # create a category with a French translation + padawans = self.env['res.partner.category'].create({'name': 'Padawans'}) + padawans_fr = padawans.with_context(lang='fr_FR') + padawans_fr.write({'name': 'Apprentis'}) + # search for categories, and sort them by (translated) name + categories = padawans_fr.search([('id', 'in', [self.customers.id, padawans.id])], order='name') + self.assertEqual(categories.ids, [padawans.id, self.customers.id], + "Search ordered by translated name should return Padawans (Apprentis) before Customers (Clients)") diff --git a/openerp/addons/base/tests/test_uninstall.py b/openerp/addons/base/tests/test_uninstall.py index 8bb658d61ba..f1d9aef9d8a 100644 --- a/openerp/addons/base/tests/test_uninstall.py +++ b/openerp/addons/base/tests/test_uninstall.py @@ -1,57 +1,31 @@ # -*- coding: utf-8 -*- -# This assumes an existing but uninitialized database. -import unittest - -import openerp -from openerp import SUPERUSER_ID -import common +# Part of Odoo. See LICENSE file for full copyright and licensing details. -ADMIN_USER_ID = common.ADMIN_USER_ID - -def registry(model): - return openerp.modules.registry.RegistryManager.get(common.get_db_name())[model] +# This assumes an existing but uninitialized database. -def cursor(): - return openerp.modules.registry.RegistryManager.get(common.get_db_name()).cursor() +from contextlib import contextmanager +import unittest -def get_module(module_name): - registry = openerp.modules.registry.RegistryManager.get(common.get_db_name()) - return registry.get(module_name) +from openerp import api, registry, SUPERUSER_ID +from openerp.tests import common +from openerp.modules.registry import RegistryManager -def reload_registry(): - openerp.modules.registry.RegistryManager.new( - common.get_db_name(), update_module=True) -def search_registry(model_name, domain): - cr = cursor() - model = registry(model_name) - record_ids = model.search(cr, SUPERUSER_ID, domain, {}) - cr.close() - return record_ids +@contextmanager +def environment(): + """ Return an environment with a new cursor for the current database; the + cursor is committed and closed after the context block. + """ + reg = registry(common.get_db_name()) + with reg.cursor() as cr: + yield api.Environment(cr, SUPERUSER_ID, {}) + cr.commit() -def install_module(module_name): - ir_module_module = registry('ir.module.module') - cr = cursor() - module_ids = ir_module_module.search(cr, SUPERUSER_ID, - [('name', '=', module_name)], {}) - assert len(module_ids) == 1 - ir_module_module.button_install(cr, SUPERUSER_ID, module_ids, {}) - cr.commit() - cr.close() - reload_registry() -def uninstall_module(module_name): - ir_module_module = registry('ir.module.module') - cr = cursor() - module_ids = ir_module_module.search(cr, SUPERUSER_ID, - [('name', '=', module_name)], {}) - assert len(module_ids) == 1 - ir_module_module.button_uninstall(cr, SUPERUSER_ID, module_ids, {}) - cr.commit() - cr.close() - reload_registry() +MODULE = 'test_uninstall' +MODEL = 'test_uninstall.model' -class test_uninstall(unittest.TestCase): +class TestUninstall(unittest.TestCase): """ Test the install/uninstall of a test module. The module is available in `openerp.tests` which should be present in the addons-path. @@ -59,26 +33,29 @@ class test_uninstall(unittest.TestCase): def test_01_install(self): """ Check a few things showing the module is installed. """ - install_module('test_uninstall') - assert get_module('test_uninstall.model') - - assert search_registry('ir.model.data', - [('module', '=', 'test_uninstall')]) + with environment() as env: + module = env['ir.module.module'].search([('name', '=', MODULE)]) + assert len(module) == 1 + module.button_install() + RegistryManager.new(common.get_db_name(), update_module=True) - assert search_registry('ir.model.fields', - [('model', '=', 'test_uninstall.model')]) + with environment() as env: + self.assertIn('test_uninstall.model', env.registry) + self.assertTrue(env['ir.model.data'].search([('module', '=', MODULE)])) + self.assertTrue(env['ir.model.fields'].search([('model', '=', MODEL)])) def test_02_uninstall(self): """ Check a few things showing the module is uninstalled. """ - uninstall_module('test_uninstall') - assert not get_module('test_uninstall.model') - - assert not search_registry('ir.model.data', - [('module', '=', 'test_uninstall')]) - - assert not search_registry('ir.model.fields', - [('model', '=', 'test_uninstall.model')]) - + with environment() as env: + module = env['ir.module.module'].search([('name', '=', MODULE)]) + assert len(module) == 1 + module.button_uninstall() + RegistryManager.new(common.get_db_name(), update_module=True) + + with environment() as env: + self.assertNotIn('test_uninstall.model', env.registry) + self.assertFalse(env['ir.model.data'].search([('module', '=', MODULE)])) + self.assertFalse(env['ir.model.fields'].search([('model', '=', MODEL)])) if __name__ == '__main__': diff --git a/openerp/addons/base/tests/test_user_has_group.py b/openerp/addons/base/tests/test_user_has_group.py index e13d04f5f6f..be326976d8d 100644 --- a/openerp/addons/base/tests/test_user_has_group.py +++ b/openerp/addons/base/tests/test_user_has_group.py @@ -1,7 +1,10 @@ # -*- coding: utf-8 -*- -import openerp.tests +# Part of Odoo. See LICENSE file for full copyright and licensing details. -class TestHasGroup(openerp.tests.TransactionCase): +from odoo.tests.common import TransactionCase + + +class TestHasGroup(TransactionCase): def setUp(self): super(TestHasGroup, self).setUp() diff --git a/openerp/addons/base/tests/test_view_validation.py b/openerp/addons/base/tests/test_view_validation.py index 68d35e38d1c..963f737ae4d 100644 --- a/openerp/addons/base/tests/test_view_validation.py +++ b/openerp/addons/base/tests/test_view_validation.py @@ -1,13 +1,15 @@ -# This test can be run stand-alone with something like: -# > PYTHONPATH=. python2 openerp/tests/test_view_validation.py +# -*- coding: utf-8 -*- +# Part of Odoo. See LICENSE file for full copyright and licensing details. + from lxml import etree from StringIO import StringIO import unittest -from openerp.tools.view_validation import (valid_page_in_book, valid_att_in_form, valid_type_in_colspan, - valid_type_in_col, valid_att_in_field, valid_att_in_label, - valid_field_in_graph, valid_field_in_tree - ) +from odoo.tools.view_validation import ( + valid_page_in_book, valid_att_in_form, valid_type_in_colspan, + valid_type_in_col, valid_att_in_field, valid_att_in_label, + valid_field_in_graph, valid_field_in_tree, +) invalid_form = etree.parse(StringIO('''\ <form> @@ -92,7 +94,7 @@ valid_tree = etree.parse(StringIO('''\ ''')).getroot() -class test_view_validation(unittest.TestCase): +class TestViewValidation(unittest.TestCase): """ Test the view validation code (but not the views themselves). """ def test_page_validation(self): @@ -125,7 +127,3 @@ class test_view_validation(unittest.TestCase): def test_col_datatype_validation(self): assert not valid_type_in_col(invalid_form) assert valid_type_in_col(valid_form) - - -if __name__ == '__main__': - unittest.main() diff --git a/openerp/addons/base/tests/test_views.py b/openerp/addons/base/tests/test_views.py index a4ef571f59a..1a3488d96c9 100644 --- a/openerp/addons/base/tests/test_views.py +++ b/openerp/addons/base/tests/test_views.py @@ -1,36 +1,22 @@ -# -*- encoding: utf-8 -*- -from functools import partial -import itertools +# -*- coding: utf-8 -*- +# Part of Odoo. See LICENSE file for full copyright and licensing details. -import unittest +from functools import partial +from itertools import izip_longest -from lxml import etree as ET +from lxml import etree from lxml.builder import E - from psycopg2 import IntegrityError -from openerp.tests import common -import openerp.tools +from odoo.tests import common +from odoo.tools import mute_logger -Field = E.field class ViewCase(common.TransactionCase): def setUp(self): super(ViewCase, self).setUp() - self.addTypeEqualityFunc(ET._Element, self.assertTreesEqual) - self.Views = self.registry('ir.ui.view') - - def browse(self, id, context=None): - return self.Views.browse(self.cr, self.uid, id, context=context) - def create(self, value, context=None): - return self.Views.create(self.cr, self.uid, value, context=context) - - def read_combined(self, id): - return self.Views.read_combined( - self.cr, self.uid, - id, ['arch'], - context={'check_view_ids': self.Views.search(self.cr, self.uid, [])} - ) + self.addTypeEqualityFunc(etree._Element, self.assertTreesEqual) + self.View = self.env['ir.ui.view'] def assertTreesEqual(self, n1, n2, msg=None): self.assertEqual(n1.tag, n2.tag, msg) @@ -41,7 +27,7 @@ class ViewCase(common.TransactionCase): # equality (!?!?!?!) self.assertEqual(dict(n1.attrib), dict(n2.attrib), msg) - for c1, c2 in itertools.izip_longest(n1, n2): + for c1, c2 in izip_longest(n1, n2): self.assertEqual(c1, c2, msg) @@ -50,63 +36,65 @@ class TestNodeLocator(common.TransactionCase): The node locator returns None when it can not find a node, and the first match when it finds something (no jquery-style node sets) """ - def setUp(self): - super(TestNodeLocator, self).setUp() - self.Views = self.registry('ir.ui.view') def test_no_match_xpath(self): """ xpath simply uses the provided @expr pattern to find a node """ - node = self.Views.locate_node( + node = self.env['ir.ui.view'].locate_node( E.root(E.foo(), E.bar(), E.baz()), - E.xpath(expr="//qux")) + E.xpath(expr="//qux"), + ) self.assertIsNone(node) def test_match_xpath(self): bar = E.bar() - node = self.Views.locate_node( + node = self.env['ir.ui.view'].locate_node( E.root(E.foo(), bar, E.baz()), - E.xpath(expr="//bar")) + E.xpath(expr="//bar"), + ) self.assertIs(node, bar) - def test_no_match_field(self): """ A field spec will match by @name against all fields of the view """ - node = self.Views.locate_node( + node = self.env['ir.ui.view'].locate_node( E.root(E.foo(), E.bar(), E.baz()), - Field(name="qux")) + E.field(name="qux"), + ) self.assertIsNone(node) - node = self.Views.locate_node( - E.root(Field(name="foo"), Field(name="bar"), Field(name="baz")), - Field(name="qux")) + node = self.env['ir.ui.view'].locate_node( + E.root(E.field(name="foo"), E.field(name="bar"), E.field(name="baz")), + E.field(name="qux"), + ) self.assertIsNone(node) def test_match_field(self): - bar = Field(name="bar") - node = self.Views.locate_node( - E.root(Field(name="foo"), bar, Field(name="baz")), - Field(name="bar")) + bar = E.field(name="bar") + node = self.env['ir.ui.view'].locate_node( + E.root(E.field(name="foo"), bar, E.field(name="baz")), + E.field(name="bar"), + ) self.assertIs(node, bar) - def test_no_match_other(self): """ Non-xpath non-fields are matched by node name first """ - node = self.Views.locate_node( + node = self.env['ir.ui.view'].locate_node( E.root(E.foo(), E.bar(), E.baz()), - E.qux()) + E.qux(), + ) self.assertIsNone(node) def test_match_other(self): bar = E.bar() - node = self.Views.locate_node( + node = self.env['ir.ui.view'].locate_node( E.root(E.foo(), bar, E.baz()), - E.bar()) + E.bar(), + ) self.assertIs(bar, node) def test_attribute_mismatch(self): @@ -114,27 +102,31 @@ class TestNodeLocator(common.TransactionCase): Non-xpath non-field are filtered by matching attributes on spec and matched nodes """ - node = self.Views.locate_node( + node = self.env['ir.ui.view'].locate_node( E.root(E.foo(attr='1'), E.bar(attr='2'), E.baz(attr='3')), - E.bar(attr='5')) + E.bar(attr='5'), + ) self.assertIsNone(node) def test_attribute_filter(self): match = E.bar(attr='2') - node = self.Views.locate_node( + node = self.env['ir.ui.view'].locate_node( E.root(E.bar(attr='1'), match, E.root(E.bar(attr='3'))), - E.bar(attr='2')) + E.bar(attr='2'), + ) self.assertIs(node, match) def test_version_mismatch(self): """ A @version on the spec will be matched against the view's version """ - node = self.Views.locate_node( + node = self.env['ir.ui.view'].locate_node( E.root(E.foo(attr='1'), version='4'), - E.foo(attr='1', version='3')) + E.foo(attr='1', version='3'), + ) self.assertIsNone(node) + class TestViewInheritance(ViewCase): def arch_for(self, name, view_type='form', parent=None): """ Generates a trivial view of the specified ``view_type``. @@ -157,7 +149,7 @@ class TestViewInheritance(ViewCase): E.attribute(name, name='string'), position='attributes' ) - return ET.tostring(element) + return etree.tostring(element) def makeView(self, name, parent=None, arch=None): """ Generates a basic ir.ui.view with the provided name, parent and arch. @@ -172,76 +164,65 @@ class TestViewInheritance(ViewCase): :returns: the created view's id. :rtype: int """ - view_id = self.View.create(self.cr, self.uid, { + view = self.View.create({ 'model': self.model, 'name': name, 'arch': arch or self.arch_for(name, parent=parent), 'inherit_id': parent, 'priority': 5, # higher than default views }) - self.ids[name] = view_id - return view_id + self.view_ids[name] = view.id + return view def setUp(self): super(TestViewInheritance, self).setUp() + self.patch(self.registry, '_init', False) + self.model = 'ir.ui.view.custom' - self.View = self.registry('ir.ui.view') - self._init = self.View.pool._init - self.View.pool._init = False - self.ids = {} + self.view_ids = {} a = self.makeView("A") - a1 = self.makeView("A1", a) - a11 = self.makeView("A11", a1) - self.makeView("A111", a11) - self.makeView("A12", a1) - a2 = self.makeView("A2", a) - self.makeView("A21", a2) - a22 = self.makeView("A22", a2) - self.makeView("A221", a22) + a1 = self.makeView("A1", a.id) + a11 = self.makeView("A11", a1.id) + self.makeView("A111", a11.id) + self.makeView("A12", a1.id) + a2 = self.makeView("A2", a.id) + self.makeView("A21", a2.id) + a22 = self.makeView("A22", a2.id) + self.makeView("A221", a22.id) b = self.makeView('B', arch=self.arch_for("B", 'tree')) - self.makeView('B1', b, arch=self.arch_for("B1", 'tree', parent=b)) + self.makeView('B1', b.id, arch=self.arch_for("B1", 'tree', parent=b)) c = self.makeView('C', arch=self.arch_for("C", 'tree')) - self.View.write(self.cr, self.uid, c, {'priority': 1}) - - def tearDown(self): - self.View.pool._init = self._init - super(TestViewInheritance, self).tearDown() + c.write({'priority': 1}) def test_get_inheriting_views_arch(self): - self.assertEqual(self.View.get_inheriting_views_arch( - self.cr, self.uid, self.ids['A'], self.model), [ - (self.arch_for('A1', parent=True), self.ids['A1']), - (self.arch_for('A2', parent=True), self.ids['A2']), + self.assertEqual( + self.View.get_inheriting_views_arch(self.view_ids['A'], self.model), [ + (self.arch_for('A1', parent=True), self.view_ids['A1']), + (self.arch_for('A2', parent=True), self.view_ids['A2']), ]) - self.assertEqual(self.View.get_inheriting_views_arch( - self.cr, self.uid, self.ids['A21'], self.model), + self.assertEqual( + self.View.get_inheriting_views_arch(self.view_ids['A21'], self.model), []) - self.assertEqual(self.View.get_inheriting_views_arch( - self.cr, self.uid, self.ids['A11'], self.model), - [(self.arch_for('A111', parent=True), self.ids['A111'])]) + self.assertEqual( + self.View.get_inheriting_views_arch(self.view_ids['A11'], self.model), + [(self.arch_for('A111', parent=True), self.view_ids['A111'])]) def test_default_view(self): - default = self.View.default_view( - self.cr, self.uid, model=self.model, view_type='form') - self.assertEqual(default, self.ids['A']) + default = self.View.default_view(model=self.model, view_type='form') + self.assertEqual(default, self.view_ids['A']) - default_tree = self.View.default_view( - self.cr, self.uid, model=self.model, view_type='tree') - self.assertEqual(default_tree, self.ids['C']) + default_tree = self.View.default_view(model=self.model, view_type='tree') + self.assertEqual(default_tree, self.view_ids['C']) def test_no_default_view(self): - self.assertFalse( - self.View.default_view( - self.cr, self.uid, model='does.not.exist', view_type='form')) + self.assertFalse(self.View.default_view(model='does.not.exist', view_type='form')) + self.assertFalse(self.View.default_view(model=self.model, view_type='graph')) - self.assertFalse( - self.View.default_view( - self.cr, self.uid, model=self.model, view_type='graph')) class TestApplyInheritanceSpecs(ViewCase): """ Applies a sequence of inheritance specification nodes to a base @@ -252,143 +233,123 @@ class TestApplyInheritanceSpecs(ViewCase): """ def setUp(self): super(TestApplyInheritanceSpecs, self).setUp() - self.View = self.registry('ir.ui.view') self.base_arch = E.form( - Field(name="target"), + E.field(name="target"), string="Title") def test_replace(self): - spec = Field( - Field(name="replacement"), + spec = E.field( + E.field(name="replacement"), name="target", position="replace") - self.View.apply_inheritance_specs(self.cr, self.uid, - self.base_arch, - spec, None) + self.View.apply_inheritance_specs(self.base_arch, spec, None) self.assertEqual( self.base_arch, - E.form(Field(name="replacement"), string="Title")) + E.form(E.field(name="replacement"), string="Title")) def test_delete(self): - spec = Field(name="target", position="replace") + spec = E.field(name="target", position="replace") - self.View.apply_inheritance_specs(self.cr, self.uid, - self.base_arch, - spec, None) + self.View.apply_inheritance_specs(self.base_arch, spec, None) self.assertEqual( self.base_arch, E.form(string="Title")) def test_insert_after(self): - spec = Field( - Field(name="inserted"), + spec = E.field( + E.field(name="inserted"), name="target", position="after") - self.View.apply_inheritance_specs(self.cr, self.uid, - self.base_arch, - spec, None) + self.View.apply_inheritance_specs(self.base_arch, spec, None) self.assertEqual( self.base_arch, E.form( - Field(name="target"), - Field(name="inserted"), + E.field(name="target"), + E.field(name="inserted"), string="Title" )) def test_insert_before(self): - spec = Field( - Field(name="inserted"), + spec = E.field( + E.field(name="inserted"), name="target", position="before") - self.View.apply_inheritance_specs(self.cr, self.uid, - self.base_arch, - spec, None) + self.View.apply_inheritance_specs(self.base_arch, spec, None) self.assertEqual( self.base_arch, E.form( - Field(name="inserted"), - Field(name="target"), + E.field(name="inserted"), + E.field(name="target"), string="Title")) def test_insert_inside(self): - default = Field(Field(name="inserted"), name="target") - spec = Field(Field(name="inserted 2"), name="target", position='inside') + default = E.field(E.field(name="inserted"), name="target") + spec = E.field(E.field(name="inserted 2"), name="target", position='inside') - self.View.apply_inheritance_specs(self.cr, self.uid, - self.base_arch, - default, None) - self.View.apply_inheritance_specs(self.cr, self.uid, - self.base_arch, - spec, None) + self.View.apply_inheritance_specs(self.base_arch, default, None) + self.View.apply_inheritance_specs(self.base_arch, spec, None) self.assertEqual( self.base_arch, E.form( - Field( - Field(name="inserted"), - Field(name="inserted 2"), + E.field( + E.field(name="inserted"), + E.field(name="inserted 2"), name="target"), string="Title")) def test_unpack_data(self): spec = E.data( - Field(Field(name="inserted 0"), name="target"), - Field(Field(name="inserted 1"), name="target"), - Field(Field(name="inserted 2"), name="target"), - Field(Field(name="inserted 3"), name="target"), + E.field(E.field(name="inserted 0"), name="target"), + E.field(E.field(name="inserted 1"), name="target"), + E.field(E.field(name="inserted 2"), name="target"), + E.field(E.field(name="inserted 3"), name="target"), ) - self.View.apply_inheritance_specs(self.cr, self.uid, - self.base_arch, - spec, None) + self.View.apply_inheritance_specs(self.base_arch, spec, None) self.assertEqual( self.base_arch, E.form( - Field( - Field(name="inserted 0"), - Field(name="inserted 1"), - Field(name="inserted 2"), - Field(name="inserted 3"), + E.field( + E.field(name="inserted 0"), + E.field(name="inserted 1"), + E.field(name="inserted 2"), + E.field(name="inserted 3"), name="target"), string="Title")) - @openerp.tools.mute_logger('openerp.addons.base.ir.ir_ui_view') + @mute_logger('openerp.addons.base.ir.ir_ui_view') def test_invalid_position(self): - spec = Field( - Field(name="whoops"), + spec = E.field( + E.field(name="whoops"), name="target", position="serious_series") with self.assertRaises(ValueError): - self.View.apply_inheritance_specs(self.cr, self.uid, - self.base_arch, - spec, None) + self.View.apply_inheritance_specs(self.base_arch, spec, None) - @openerp.tools.mute_logger('openerp.addons.base.ir.ir_ui_view') + @mute_logger('openerp.addons.base.ir.ir_ui_view') def test_incorrect_version(self): # Version ignored on //field elements, so use something else arch = E.form(E.element(foo="42")) spec = E.element( - Field(name="placeholder"), + E.field(name="placeholder"), foo="42", version="7.0") with self.assertRaises(ValueError): - self.View.apply_inheritance_specs(self.cr, self.uid, - arch, - spec, None) + self.View.apply_inheritance_specs(arch, spec, None) - @openerp.tools.mute_logger('openerp.addons.base.ir.ir_ui_view') + @mute_logger('openerp.addons.base.ir.ir_ui_view') def test_target_not_found(self): - spec = Field(name="targut") + spec = E.field(name="targut") with self.assertRaises(ValueError): - self.View.apply_inheritance_specs(self.cr, self.uid, - self.base_arch, - spec, None) + self.View.apply_inheritance_specs(self.base_arch, spec, None) + class TestApplyInheritanceWrapSpecs(ViewCase): def setUp(self): @@ -418,19 +379,19 @@ class TestApplyInheritedArchs(ViewCase): """ Applies a sequence of modificator archs to a base view """ + class TestNoModel(ViewCase): def test_create_view_nomodel(self): - View = self.registry('ir.ui.view') - view_id = View.create(self.cr, self.uid, { + view = self.View.create({ 'name': 'dummy', 'arch': '<template name="foo"/>', 'inherit_id': False, 'type': 'qweb', }) fields = ['name', 'arch', 'type', 'priority', 'inherit_id', 'model'] - [view] = View.read(self.cr, self.uid, [view_id], fields) - self.assertEqual(view, { - 'id': view_id, + [data] = view.read(fields) + self.assertEqual(data, { + 'id': view.id, 'name': 'dummy', 'arch': '<template name="foo"/>', 'type': 'qweb', @@ -459,7 +420,7 @@ class TestNoModel(ViewCase): ARCH = '<template name="foo">%s</template>' TEXT_EN = "Copyright copyrighter" TEXT_FR = u"Copyrighter, tous droits réservés" - view = self.env['ir.ui.view'].create({ + view = self.View.create({ 'name': 'dummy', 'arch': ARCH % TEXT_EN, 'inherit_id': False, @@ -476,22 +437,14 @@ class TestNoModel(ViewCase): view = view.with_context(lang='fr_FR') self.assertEqual(view.arch, ARCH % TEXT_FR) + class TestTemplating(ViewCase): def setUp(self): - import openerp.modules super(TestTemplating, self).setUp() - self._pool = openerp.modules.registry.RegistryManager.get(common.get_db_name()) - self._init = self._pool._init - # fuck off - self._pool._init = False - - def tearDown(self): - self._pool._init = self._init - super(TestTemplating, self).tearDown() + self.patch(self.registry, '_init', False) def test_branding_inherit(self): - Views = self.registry('ir.ui.view') - id = Views.create(self.cr, self.uid, { + view1 = self.View.create({ 'name': "Base view", 'type': 'qweb', 'arch': """<root> @@ -499,26 +452,24 @@ class TestTemplating(ViewCase): </root> """ }) - id2 = Views.create(self.cr, self.uid, { + view2 = self.View.create({ 'name': "Extension", 'type': 'qweb', - 'inherit_id': id, + 'inherit_id': view1.id, 'arch': """<xpath expr="//item" position="before"> <item order="2"/> </xpath> """ }) - arch_string = Views.read_combined( - self.cr, self.uid, id, fields=['arch'], - context={'inherit_branding': True})['arch'] + arch_string = view1.with_context(inherit_branding=True).read_combined(['arch'])['arch'] - arch = ET.fromstring(arch_string) - Views.distribute_branding(arch) + arch = etree.fromstring(arch_string) + self.View.distribute_branding(arch) [initial] = arch.xpath('//item[@order=1]') self.assertEqual( - str(id), + str(view1.id), initial.get('data-oe-id'), "initial should come from the root view") self.assertEqual( @@ -528,7 +479,7 @@ class TestTemplating(ViewCase): [second] = arch.xpath('//item[@order=2]') self.assertEqual( - str(id2), + str(view2.id), second.get('data-oe-id'), "second should come from the extension view") @@ -536,18 +487,17 @@ class TestTemplating(ViewCase): """ Checks that the branding is correctly distributed within a view extension """ - Views = self.registry('ir.ui.view') - id = Views.create(self.cr, self.uid, { + view1 = self.View.create({ 'name': "Base view", 'type': 'qweb', 'arch': """<root> <item order="1"/> </root>""" }) - id2 = Views.create(self.cr, self.uid, { + view2 = self.View.create({ 'name': "Extension", 'type': 'qweb', - 'inherit_id': id, + 'inherit_id': view1.id, 'arch': """<xpath expr="//item" position="before"> <item order="2"> <content t-att-href="foo">bar</content> @@ -555,12 +505,10 @@ class TestTemplating(ViewCase): </xpath>""" }) - arch_string = Views.read_combined( - self.cr, self.uid, id, fields=['arch'], - context={'inherit_branding': True})['arch'] + arch_string = view1.with_context(inherit_branding=True).read_combined(['arch'])['arch'] - arch = ET.fromstring(arch_string) - Views.distribute_branding(arch) + arch = etree.fromstring(arch_string) + self.View.distribute_branding(arch) self.assertEqual( arch, @@ -569,7 +517,7 @@ class TestTemplating(ViewCase): E.content("bar", { 't-att-href': "foo", 'data-oe-model': 'ir.ui.view', - 'data-oe-id': str(id2), + 'data-oe-id': str(view2.id), 'data-oe-field': 'arch', 'data-oe-xpath': '/xpath/item/content[1]', }), { @@ -578,7 +526,7 @@ class TestTemplating(ViewCase): E.item({ 'order': '1', 'data-oe-model': 'ir.ui.view', - 'data-oe-id': str(id), + 'data-oe-id': str(view1.id), 'data-oe-field': 'arch', 'data-oe-xpath': '/root[1]/item[1]', }) @@ -586,8 +534,7 @@ class TestTemplating(ViewCase): ) def test_esc_no_branding(self): - Views = self.registry('ir.ui.view') - id = Views.create(self.cr, self.uid, { + view = self.View.create({ 'name': "Base View", 'type': 'qweb', 'arch': """<root> @@ -595,17 +542,14 @@ class TestTemplating(ViewCase): </root>""", }) - arch_string = Views.read_combined( - self.cr, self.uid, id, fields=['arch'], - context={'inherit_branding': True})['arch'] - arch = ET.fromstring(arch_string) - Views.distribute_branding(arch) + arch_string = view.with_context(inherit_branding=True).read_combined(['arch'])['arch'] + arch = etree.fromstring(arch_string) + self.View.distribute_branding(arch) self.assertEqual(arch, E.root(E.item(E.span({'t-esc': "foo"})))) def test_ignore_unbrand(self): - Views = self.registry('ir.ui.view') - id = Views.create(self.cr, self.uid, { + view1 = self.View.create({ 'name': "Base view", 'type': 'qweb', 'arch': """<root> @@ -614,10 +558,10 @@ class TestTemplating(ViewCase): </item> </root>""" }) - id2 = Views.create(self.cr, self.uid, { + view2 = self.View.create({ 'name': "Extension", 'type': 'qweb', - 'inherit_id': id, + 'inherit_id': view1.id, 'arch': """<xpath expr="//item[@order='1']" position="inside"> <item order="2"> <content t-att-href="foo">bar</content> @@ -625,12 +569,10 @@ class TestTemplating(ViewCase): </xpath>""" }) - arch_string = Views.read_combined( - self.cr, self.uid, id, fields=['arch'], - context={'inherit_branding': True})['arch'] + arch_string = view1.with_context(inherit_branding=True).read_combined(['arch'])['arch'] - arch = ET.fromstring(arch_string) - Views.distribute_branding(arch) + arch = etree.fromstring(arch_string) + self.View.distribute_branding(arch) self.assertEqual( arch, @@ -650,14 +592,14 @@ class TestTemplating(ViewCase): " the main view's" ) -class test_views(ViewCase): + +class TestViews(ViewCase): def test_nonexistent_attribute_removal(self): - Views = self.registry('ir.ui.view') - Views.create(self.cr, self.uid, { + self.View.create({ 'name': 'Test View', 'model': 'ir.ui.view', - 'inherit_id': self.browse_ref('base.view_view_tree').id, + 'inherit_id': self.ref('base.view_view_tree'), 'arch': """<?xml version="1.0"?> <xpath expr="//field[@name='name']" position="attributes"> <attribute name="non_existing_attribute"></attribute> @@ -680,10 +622,8 @@ class test_views(ViewCase): return self.cr.fetchone()[0] def test_custom_view_validation(self): - Views = self.registry('ir.ui.view') model = 'ir.actions.act_url' - - validate = partial(Views._validate_custom_views, self.cr, self.uid, model) + validate = partial(self.View._validate_custom_views, model) # validation of a single view vid = self._insert_view( @@ -727,9 +667,7 @@ class test_views(ViewCase): self.assertTrue(validate()) # inherited view def test_view_inheritance(self): - Views = self.registry('ir.ui.view') - - v1 = Views.create(self.cr, self.uid, { + view1 = self.View.create({ 'name': "bob", 'model': 'ir.ui.view', 'arch': """ @@ -742,10 +680,10 @@ class test_views(ViewCase): </form> """ }) - v2 = Views.create(self.cr, self.uid, { + view2 = self.View.create({ 'name': "edmund", 'model': 'ir.ui.view', - 'inherit_id': v1, + 'inherit_id': view1.id, 'arch': """ <data> <form position="attributes" version="7.0"> @@ -762,10 +700,10 @@ class test_views(ViewCase): </data> """ }) - v3 = Views.create(self.cr, self.uid, { + view3 = self.View.create({ 'name': 'jake', 'model': 'ir.ui.view', - 'inherit_id': v1, + 'inherit_id': view1.id, 'priority': 17, 'arch': """ <footer position="attributes"> @@ -777,16 +715,13 @@ class test_views(ViewCase): """ }) - view = self.registry('ir.ui.view').fields_view_get( - self.cr, self.uid, v2, view_type='form', context={ - # fucking what? - 'check_view_ids': [v2, v3] - }) + view = self.View.with_context(check_view_ids=[view2.id, view3.id]) \ + .fields_view_get(view2.id, view_type='form') self.assertEqual(view['type'], 'form') self.assertEqual( - ET.fromstring( + etree.fromstring( view['arch'], - parser=ET.XMLParser(remove_blank_text=True) + parser=etree.XMLParser(remove_blank_text=True) ), E.form( E.p("Replacement data"), @@ -797,9 +732,7 @@ class test_views(ViewCase): string="Replacement title", version="7.0")) def test_view_inheritance_divergent_models(self): - Views = self.registry('ir.ui.view') - - v1 = Views.create(self.cr, self.uid, { + view1 = self.View.create({ 'name': "bob", 'model': 'ir.ui.view.custom', 'arch': """ @@ -812,10 +745,10 @@ class test_views(ViewCase): </form> """ }) - v2 = Views.create(self.cr, self.uid, { + view2 = self.View.create({ 'name': "edmund", 'model': 'ir.ui.view', - 'inherit_id': v1, + 'inherit_id': view1.id, 'arch': """ <data> <form position="attributes" version="7.0"> @@ -832,10 +765,10 @@ class test_views(ViewCase): </data> """ }) - v3 = Views.create(self.cr, self.uid, { + view3 = self.View.create({ 'name': 'jake', 'model': 'ir.ui.menu', - 'inherit_id': v1, + 'inherit_id': view1.id, 'priority': 17, 'arch': """ <footer position="attributes"> @@ -844,16 +777,13 @@ class test_views(ViewCase): """ }) - view = self.registry('ir.ui.view').fields_view_get( - self.cr, self.uid, v2, view_type='form', context={ - # fucking what? - 'check_view_ids': [v2, v3] - }) + view = self.View.with_context(check_view_ids=[view2.id, view3.id]) \ + .fields_view_get(view2.id, view_type='form') self.assertEqual(view['type'], 'form') self.assertEqual( - ET.fromstring( + etree.fromstring( view['arch'], - parser=ET.XMLParser(remove_blank_text=True) + parser=etree.XMLParser(remove_blank_text=True) ), E.form( E.p("Replacement data"), @@ -862,6 +792,7 @@ class test_views(ViewCase): string="Replacement title", version="7.0" )) + class ViewModeField(ViewCase): """ This should probably, eventually, be folded back into other test case @@ -873,47 +804,47 @@ class ViewModeField(ViewCase): * inherit_id -> mode=extension * not inherit_id -> mode=primary """ - view = self.browse(self.create({ + view = self.View.create({ 'inherit_id': None, 'arch': '<qweb/>' - })) + }) self.assertEqual(view.mode, 'primary') - view2 = self.browse(self.create({ + view2 = self.View.create({ 'inherit_id': view.id, 'arch': '<qweb/>' - })) + }) self.assertEqual(view2.mode, 'extension') - @openerp.tools.mute_logger('openerp.sql_db') + @mute_logger('openerp.sql_db') def testModeExplicit(self): - view = self.browse(self.create({ + view = self.View.create({ 'inherit_id': None, 'arch': '<qweb/>' - })) - view2 = self.browse(self.create({ + }) + view2 = self.View.create({ 'inherit_id': view.id, 'mode': 'primary', 'arch': '<qweb/>' - })) + }) self.assertEqual(view.mode, 'primary') with self.assertRaises(IntegrityError): - self.create({ + self.View.create({ 'inherit_id': None, 'mode': 'extension', 'arch': '<qweb/>' }) - @openerp.tools.mute_logger('openerp.sql_db') + @mute_logger('openerp.sql_db') def testPurePrimaryToExtension(self): """ A primary view with inherit_id=None can't be converted to extension """ - view_pure_primary = self.browse(self.create({ + view_pure_primary = self.View.create({ 'inherit_id': None, 'arch': '<qweb/>' - })) + }) with self.assertRaises(IntegrityError): view_pure_primary.write({'mode': 'extension'}) @@ -921,12 +852,15 @@ class ViewModeField(ViewCase): """ A primary view with an inherit_id can be converted to extension """ - base = self.create({'inherit_id': None, 'arch': '<qweb/>'}) - view = self.browse(self.create({ - 'inherit_id': base, + base = self.View.create({ + 'inherit_id': None, + 'arch': '<qweb/>', + }) + view = self.View.create({ + 'inherit_id': base.id, 'mode': 'primary', 'arch': '<qweb/>' - })) + }) view.write({'mode': 'extension'}) @@ -934,63 +868,68 @@ class ViewModeField(ViewCase): """ An extension view can be converted to primary """ - base = self.create({'inherit_id': None, 'arch': '<qweb/>'}) - view = self.browse(self.create({ - 'inherit_id': base, + base = self.View.create({ + 'inherit_id': None, + 'arch': '<qweb/>', + }) + view = self.View.create({ + 'inherit_id': base.id, 'arch': '<qweb/>' - })) + }) view.write({'mode': 'primary'}) + class TestDefaultView(ViewCase): def testDefaultViewBase(self): - self.create({ + self.View.create({ 'inherit_id': False, 'priority': 10, 'mode': 'primary', 'arch': '<qweb/>', }) - v2 = self.create({ + view2 = self.View.create({ 'inherit_id': False, 'priority': 1, 'mode': 'primary', 'arch': '<qweb/>', }) - default = self.Views.default_view(self.cr, self.uid, False, 'qweb') + default = self.View.default_view(False, 'qweb') self.assertEqual( - default, v2, + default, view2.id, "default_view should get the view with the lowest priority for " "a (model, view_type) pair" ) def testDefaultViewPrimary(self): - v1 = self.create({ + view1 = self.View.create({ 'inherit_id': False, 'priority': 10, 'mode': 'primary', 'arch': '<qweb/>', }) - self.create({ + self.View.create({ 'inherit_id': False, 'priority': 5, 'mode': 'primary', 'arch': '<qweb/>', }) - v3 = self.create({ - 'inherit_id': v1, + view3 = self.View.create({ + 'inherit_id': view1.id, 'priority': 1, 'mode': 'primary', 'arch': '<qweb/>', }) - default = self.Views.default_view(self.cr, self.uid, False, 'qweb') + default = self.View.default_view(False, 'qweb') self.assertEqual( - default, v3, + default, view3.id, "default_view should get the view with the lowest priority for " "a (model, view_type) pair in all the primary tables" ) + class TestViewCombined(ViewCase): """ * When asked for a view, instead of looking for the closest parent with @@ -1003,72 +942,73 @@ class TestViewCombined(ViewCase): def setUp(self): super(TestViewCombined, self).setUp() - self.a1 = self.create({ + self.a1 = self.View.create({ 'model': 'a', 'arch': '<qweb><a1/></qweb>' }) - self.a2 = self.create({ + self.a2 = self.View.create({ 'model': 'a', - 'inherit_id': self.a1, + 'inherit_id': self.a1.id, 'priority': 5, 'arch': '<xpath expr="//a1" position="after"><a2/></xpath>' }) - self.a3 = self.create({ + self.a3 = self.View.create({ 'model': 'a', - 'inherit_id': self.a1, + 'inherit_id': self.a1.id, 'arch': '<xpath expr="//a1" position="after"><a3/></xpath>' }) # mode=primary should be an inheritance boundary in both direction, # even within a model it should not extend the parent - self.a4 = self.create({ + self.a4 = self.View.create({ 'model': 'a', - 'inherit_id': self.a1, + 'inherit_id': self.a1.id, 'mode': 'primary', 'arch': '<xpath expr="//a1" position="after"><a4/></xpath>', }) - self.b1 = self.create({ + self.b1 = self.View.create({ 'model': 'b', - 'inherit_id': self.a3, + 'inherit_id': self.a3.id, 'mode': 'primary', 'arch': '<xpath expr="//a1" position="after"><b1/></xpath>' }) - self.b2 = self.create({ + self.b2 = self.View.create({ 'model': 'b', - 'inherit_id': self.b1, + 'inherit_id': self.b1.id, 'arch': '<xpath expr="//a1" position="after"><b2/></xpath>' }) - self.c1 = self.create({ + self.c1 = self.View.create({ 'model': 'c', - 'inherit_id': self.a1, + 'inherit_id': self.a1.id, 'mode': 'primary', 'arch': '<xpath expr="//a1" position="after"><c1/></xpath>' }) - self.c2 = self.create({ + self.c2 = self.View.create({ 'model': 'c', - 'inherit_id': self.c1, + 'inherit_id': self.c1.id, 'priority': 5, 'arch': '<xpath expr="//a1" position="after"><c2/></xpath>' }) - self.c3 = self.create({ + self.c3 = self.View.create({ 'model': 'c', - 'inherit_id': self.c2, + 'inherit_id': self.c2.id, 'priority': 10, 'arch': '<xpath expr="//a1" position="after"><c3/></xpath>' }) - self.d1 = self.create({ + self.d1 = self.View.create({ 'model': 'd', - 'inherit_id': self.b1, + 'inherit_id': self.b1.id, 'mode': 'primary', 'arch': '<xpath expr="//a1" position="after"><d1/></xpath>' }) def test_basic_read(self): - arch = self.read_combined(self.a1)['arch'] + context = {'check_view_ids': self.View.search([]).ids} + arch = self.a1.with_context(context).read_combined(['arch'])['arch'] self.assertEqual( - ET.fromstring(arch), + etree.fromstring(arch), E.qweb( E.a1(), E.a3(), @@ -1076,9 +1016,10 @@ class TestViewCombined(ViewCase): ), arch) def test_read_from_child(self): - arch = self.read_combined(self.a3)['arch'] + context = {'check_view_ids': self.View.search([]).ids} + arch = self.a3.with_context(context).read_combined(['arch'])['arch'] self.assertEqual( - ET.fromstring(arch), + etree.fromstring(arch), E.qweb( E.a1(), E.a3(), @@ -1086,9 +1027,10 @@ class TestViewCombined(ViewCase): ), arch) def test_read_from_child_primary(self): - arch = self.read_combined(self.a4)['arch'] + context = {'check_view_ids': self.View.search([]).ids} + arch = self.a4.with_context(context).read_combined(['arch'])['arch'] self.assertEqual( - ET.fromstring(arch), + etree.fromstring(arch), E.qweb( E.a1(), E.a4(), @@ -1097,9 +1039,10 @@ class TestViewCombined(ViewCase): ), arch) def test_cross_model_simple(self): - arch = self.read_combined(self.c2)['arch'] + context = {'check_view_ids': self.View.search([]).ids} + arch = self.c2.with_context(context).read_combined(['arch'])['arch'] self.assertEqual( - ET.fromstring(arch), + etree.fromstring(arch), E.qweb( E.a1(), E.c3(), @@ -1110,9 +1053,10 @@ class TestViewCombined(ViewCase): ), arch) def test_cross_model_double(self): - arch = self.read_combined(self.d1)['arch'] + context = {'check_view_ids': self.View.search([]).ids} + arch = self.d1.with_context(context).read_combined(['arch'])['arch'] self.assertEqual( - ET.fromstring(arch), + etree.fromstring(arch), E.qweb( E.a1(), E.d1(), @@ -1122,6 +1066,7 @@ class TestViewCombined(ViewCase): E.a2(), ), arch) + class TestOptionalViews(ViewCase): """ Tests ability to enable/disable inherited views, formerly known as @@ -1130,27 +1075,27 @@ class TestOptionalViews(ViewCase): def setUp(self): super(TestOptionalViews, self).setUp() - self.v0 = self.create({ + self.v0 = self.View.create({ 'model': 'a', 'arch': '<qweb><base/></qweb>', }) - self.v1 = self.create({ + self.v1 = self.View.create({ 'model': 'a', - 'inherit_id': self.v0, + 'inherit_id': self.v0.id, 'active': True, 'priority': 10, 'arch': '<xpath expr="//base" position="after"><v1/></xpath>', }) - self.v2 = self.create({ + self.v2 = self.View.create({ 'model': 'a', - 'inherit_id': self.v0, + 'inherit_id': self.v0.id, 'active': True, 'priority': 9, 'arch': '<xpath expr="//base" position="after"><v2/></xpath>', }) - self.v3 = self.create({ + self.v3 = self.View.create({ 'model': 'a', - 'inherit_id': self.v0, + 'inherit_id': self.v0.id, 'active': False, 'priority': 8, 'arch': '<xpath expr="//base" position="after"><v3/></xpath>' @@ -1159,9 +1104,10 @@ class TestOptionalViews(ViewCase): def test_applied(self): """ mandatory and enabled views should be applied """ - arch = self.read_combined(self.v0)['arch'] + context = {'check_view_ids': self.View.search([]).ids} + arch = self.v0.with_context(context).read_combined(['arch'])['arch'] self.assertEqual( - ET.fromstring(arch), + etree.fromstring(arch), E.qweb( E.base(), E.v1(), @@ -1173,20 +1119,22 @@ class TestOptionalViews(ViewCase): """ Change active states of v2 and v3, check that the results are as expected """ - self.browse(self.v2).toggle() - arch = self.read_combined(self.v0)['arch'] + self.v2.toggle() + context = {'check_view_ids': self.View.search([]).ids} + arch = self.v0.with_context(context).read_combined(['arch'])['arch'] self.assertEqual( - ET.fromstring(arch), + etree.fromstring(arch), E.qweb( E.base(), E.v1(), ) ) - self.browse(self.v3).toggle() - arch = self.read_combined(self.v0)['arch'] + self.v3.toggle() + context = {'check_view_ids': self.View.search([]).ids} + arch = self.v0.with_context(context).read_combined(['arch'])['arch'] self.assertEqual( - ET.fromstring(arch), + etree.fromstring(arch), E.qweb( E.base(), E.v1(), @@ -1194,10 +1142,11 @@ class TestOptionalViews(ViewCase): ) ) - self.browse(self.v2).toggle() - arch = self.read_combined(self.v0)['arch'] + self.v2.toggle() + context = {'check_view_ids': self.View.search([]).ids} + arch = self.v0.with_context(context).read_combined(['arch'])['arch'] self.assertEqual( - ET.fromstring(arch), + etree.fromstring(arch), E.qweb( E.base(), E.v1(), @@ -1206,6 +1155,7 @@ class TestOptionalViews(ViewCase): ) ) + class TestXPathExtentions(common.BaseCase): def test_hasclass(self): tree = E.node( diff --git a/openerp/addons/base/tests/test_xmlrpc.py b/openerp/addons/base/tests/test_xmlrpc.py index 0eca22faa58..c47b51acd93 100644 --- a/openerp/addons/base/tests/test_xmlrpc.py +++ b/openerp/addons/base/tests/test_xmlrpc.py @@ -1,21 +1,23 @@ # -*- coding: utf-8 -*- -import openerp.tests.common +# Part of Odoo. See LICENSE file for full copyright and licensing details. +from odoo.tests import common -class test_xmlrpc(openerp.tests.common.HttpCase): + +class TestXMLRPC(common.HttpCase): at_install = False post_install = True def test_01_xmlrpc_login(self): """ Try to login on the common service. """ - db_name = openerp.tests.common.get_db_name() + db_name = common.get_db_name() uid = self.xmlrpc_common.login(db_name, 'admin', 'admin') self.assertEqual(uid, 1) def test_xmlrpc_ir_model_search(self): """ Try a search on the object service. """ o = self.xmlrpc_object - db_name = openerp.tests.common.get_db_name() + db_name = common.get_db_name() ids = o.execute(db_name, 1, 'admin', 'ir.model', 'search', []) self.assertIsInstance(ids, list) ids = o.execute(db_name, 1, 'admin', 'ir.model', 'search', [], {}) diff --git a/openerp/osv/expression.py b/openerp/osv/expression.py index 6e3d775bc54..97feff79551 100644 --- a/openerp/osv/expression.py +++ b/openerp/osv/expression.py @@ -5,7 +5,7 @@ The main duty of this module is to compile a domain expression into a SQL query. A lot of things should be documented here, but as a first -step in the right direction, some tests in test_osv_expression.yml +step in the right direction, some tests in test_expression.py might give you some additional information. For legacy reasons, a domain uses an inconsistent two-levels abstract |
