from odoo import Command from odoo.exceptions import ValidationError from odoo.tests import common from odoo.tools import SetDefinitions @common.tagged('at_install', 'groups') class TestGroupsObject(common.BaseCase): @classmethod def setUpClass(cls): super().setUpClass() cls.definitions = SetDefinitions({ 1: {'ref': 'A'}, 2: {'ref': 'A1', 'supersets': [1]}, # A1 <= A 3: {'ref': 'A11', 'supersets': [2]}, # A11 <= A1 4: {'ref': 'A2', 'supersets': [1]}, # A2 <= A 5: {'ref': 'A21', 'supersets': [4]}, # A21 <= A2 6: {'ref': 'A22', 'supersets': [4]}, # A22 <= A2 7: {'ref': 'B'}, 8: {'ref': 'B1', 'supersets': [7]}, # B1 <= B 9: {'ref': 'B11', 'supersets': [8]}, # B11 <= B1 10: {'ref': 'B2', 'supersets': [7]}, # B2 <= B 11: {'ref': 'BX', 'supersets': [7], # BX <= B 'disjoints': [8, 10]}, # BX disjoint from B1, B2 12: {'ref': 'A1B1', 'supersets': [2, 8]}, # A1B1 <= A1, B1 13: {'ref': 'C'}, 14: {'ref': 'D', 'disjoints': [1, 7]}, # D disjoint from A, B 15: {'ref': 'E', 'disjoints': [1, 7, 14]}, # E disjoint from A, B, D 16: {'ref': 'E1', 'supersets': [15]}, # E1 <= E (and thus disjoint from A, B, D) }) def test_groups_1_base(self): A = self.definitions.parse('A') B = self.definitions.parse('B') B1 = self.definitions.parse('B1') self.assertTrue(hash(A), "'Group object must be hashable'") self.assertEqual(str(A), "'A'") self.assertEqual(str(B), "'B'") self.assertEqual(str(B1), "'B1'") def test_groups_2_and(self): A = self.definitions.parse('A') A1 = self.definitions.parse('A1') B = self.definitions.parse('B') B1 = self.definitions.parse('B1') B11 = self.definitions.parse('B11') BX = self.definitions.parse('BX') universe = self.definitions.universe empty = self.definitions.empty self.assertEqual(str(A & B), "'A' & 'B'") self.assertEqual(str(B & A), "'A' & 'B'") self.assertEqual(str(B & BX), "'BX'") self.assertEqual(str(B1 & BX), "~*") self.assertEqual(str(B11 & BX), "~*") self.assertEqual(str(empty & empty), "~*") self.assertEqual(str(A & universe), "'A'") self.assertEqual(str(A & empty), "~*") self.assertEqual(str(A1 & ~A), "~*") self.assertEqual(str(A & A1 & universe), "'A1'") def test_groups_3_or(self): A = self.definitions.parse('A') A1 = self.definitions.parse('A1') B = self.definitions.parse('B') B1 = self.definitions.parse('B1') B11 = self.definitions.parse('B11') B2 = self.definitions.parse('B2') BX = self.definitions.parse('BX') universe = self.definitions.universe empty = self.definitions.empty self.assertEqual(str(A | A), "'A'") self.assertEqual(str(A | B), "'A' | 'B'") self.assertEqual(str(A1 | A), "'A'") self.assertEqual(str(A | A1), "'A'") self.assertEqual(str(A | B1), "'A' | 'B1'") self.assertEqual(str(B | A), "'A' | 'B'") self.assertEqual(str(B | BX), "'B'") self.assertEqual(str(B1 | BX), "'B1' | 'BX'") self.assertEqual(str(B11 | BX), "'B11' | 'BX'") self.assertEqual(str(empty | empty), "~*") self.assertEqual(str(A | B11 | B2), "'A' | 'B11' | 'B2'") self.assertEqual(str(A | B2 | B11), "'A' | 'B11' | 'B2'") self.assertEqual(str(A | empty), "'A'") self.assertEqual(str(A | universe), "*") self.assertEqual(str((A | A1) | empty), "'A'") def test_groups_3_or_and(self): A = self.definitions.parse('A') A1 = self.definitions.parse('A1') A2 = self.definitions.parse('A2') B1 = self.definitions.parse('B1') B2 = self.definitions.parse('B2') universe = self.definitions.universe empty = self.definitions.empty self.assertEqual(str((A & B1) | B2), "('A' & 'B1') | 'B2'") self.assertEqual(str(A | B1 & B2), "'A' | ('B1' & 'B2')") self.assertEqual(str(A | A1 & universe), "'A'") self.assertEqual(str((A1 | A2) & (B1 | B2)), "('A1' & 'B1') | ('A1' & 'B2') | ('A2' & 'B1') | ('A2' & 'B2')") self.assertEqual(str(A | (A1 | empty)), "'A'") self.assertEqual(str((A & A1) | empty), "'A1'") self.assertEqual(str(A & (A1 | empty)), "'A1'") def test_groups_4_gt_lt(self): A = self.definitions.parse('A') A1 = self.definitions.parse('A1') A11 = self.definitions.parse('A11') A2 = self.definitions.parse('A2') A21 = self.definitions.parse('A21') B = self.definitions.parse('B') B1 = self.definitions.parse('B1') B11 = self.definitions.parse('B11') B2 = self.definitions.parse('B2') A1B1 = self.definitions.parse('A1B1') self.assertEqual(A == A, True) self.assertEqual(A == B, False) self.assertEqual(A >= A1, True) self.assertEqual(A >= A, True) self.assertEqual((A & B) >= B, False) self.assertEqual(B1 >= A1B1, True) self.assertEqual(B1 >= (A1 | A1B1), False) # noqa: SIM300 self.assertEqual(B >= (A & B), True) # noqa: SIM300 self.assertEqual(A > B, False) self.assertEqual(A > A1, True) self.assertEqual(A1 > A, False) self.assertEqual(A > A, False) self.assertEqual(A > A11, True) self.assertEqual(A > A2, True) self.assertEqual(A > A21, True) self.assertEqual(A1 > A11, True) self.assertEqual(A2 > A11, False) self.assertEqual(A2 > A21, True) self.assertEqual(A > B1, False) self.assertEqual(A > B11, False) self.assertEqual(A > B2, False) self.assertEqual(A <= A, True) self.assertEqual(A1 <= A, True) self.assertEqual((A & B) <= B, True) self.assertEqual((A & B) <= A, True) self.assertEqual(B1 <= (A1 | A1B1), False) # noqa: SIM300 self.assertEqual(B <= (A & B), False) # noqa: SIM300 self.assertEqual(A <= (A & B), False) # noqa: SIM300 self.assertEqual(A <= (A | B), True) # noqa: SIM300 self.assertEqual(A < B, False) self.assertEqual(A < A1, False) self.assertEqual(A1 < A, True) self.assertEqual(A < A1, False) self.assertEqual(A < A11, False) self.assertEqual(A < A2, False) self.assertEqual(A < A21, False) self.assertEqual(A < B1, False) self.assertEqual(A < B11, False) self.assertEqual(A < B2, False) self.assertEqual(A < (A | B), True) # noqa: SIM300 def test_groups_5_invert(self): A = self.definitions.parse('A') A1 = self.definitions.parse('A1') A2 = self.definitions.parse('A2') B = self.definitions.parse('B') B1 = self.definitions.parse('B1') B11 = self.definitions.parse('B11') B2 = self.definitions.parse('B2') BX = self.definitions.parse('BX') universe = self.definitions.universe empty = self.definitions.empty self.assertEqual(str(~A), "~'A'") self.assertEqual(str(~A1), "~'A1'") self.assertEqual(str(~B), "~'B'") self.assertEqual(str(~universe), "~*") self.assertEqual(str(~empty), "*") self.assertEqual(str(~(A & B)), "~'A' | ~'B'") self.assertEqual(str(~(A | B)), "~'A' & ~'B'") self.assertEqual(str(~A & ~A1), "~'A'") self.assertEqual(str(A | ~A), "*") self.assertEqual(str(~A | ~A1), "~'A1'") self.assertEqual(str(~(A | A1)), "~'A'") self.assertEqual(~(A | A1), ~A & ~A1) self.assertEqual(str(~(A & A1)), "~'A1'") self.assertEqual(~(A & A1), ~A | ~A1) self.assertEqual(str(~(~B1 & ~B2)), "'B1' | 'B2'") self.assertEqual(str(A & ~A), "~*") self.assertEqual(str(A & ~A1), "'A' & ~'A1'") self.assertEqual(str(~A & A), "~*") self.assertEqual(str(~A & A1), "~*") self.assertEqual(str(~A1 & A), "'A' & ~'A1'") self.assertEqual(str(B11 & ~BX), "'B11'") self.assertEqual(str(~B1 & BX), "'BX'") self.assertEqual(str(~B11 & BX), "'BX'") self.assertEqual(str(~((A & B1) | B2)), "(~'A' & ~'B2') | (~'B1' & ~'B2')") self.assertEqual(str(~(A | (B1 & B2))), "(~'A' & ~'B1') | (~'A' & ~'B2')") self.assertEqual(str(~(A | (B2 & B1))), "(~'A' & ~'B1') | (~'A' & ~'B2')") self.assertEqual(str(~((A1 & A2) | (B1 & B2))), "(~'A1' & ~'B1') | (~'A1' & ~'B2') | (~'A2' & ~'B1') | (~'A2' & ~'B2')") self.assertEqual(str(~A & ~B2), "~'A' & ~'B2'") self.assertEqual(str(~(~B1 & ~B2)), "'B1' | 'B2'") self.assertEqual(str(~((A & B) | A1)), "~'A' | (~'A1' & ~'B')") self.assertEqual(str(~(~A | (~A1 & ~B))), "('A' & 'B') | 'A1'") self.assertEqual(str(~~((A & B) | A1)), "('A' & 'B') | 'A1'") def test_groups_6_invert_gt_lt(self): A = self.definitions.parse('A') A1 = self.definitions.parse('A1') self.assertEqual(A < A1, False) self.assertEqual(~A < ~A1, True) self.assertEqual(A > A1, True) self.assertEqual(~A > ~A1, False) self.assertEqual(~A1 > ~A, True) self.assertEqual(A < ~A, False) # noqa: SIM300 self.assertEqual(A < ~A1, False) # noqa: SIM300 self.assertEqual(~A < ~A, False) self.assertEqual(~A < ~A1, True) def test_groups_7_various(self): A = self.definitions.parse('A') A1 = self.definitions.parse('A1') B = self.definitions.parse('B') self.assertEqual(str(~A & (A | B)), "~'A' & 'B'") self.assertEqual(str(A1 & B & ~A), "~*") self.assertEqual(str(A1 & ~A & B), "~*") self.assertEqual(str(~A1 & A & B), "'A' & ~'A1' & 'B'") def test_groups_8_reduce(self): A = self.definitions.parse('A') A1 = self.definitions.parse('A1') A11 = self.definitions.parse('A11') B = self.definitions.parse('B') B1 = self.definitions.parse('B1') B2 = self.definitions.parse('B2') universe = self.definitions.universe empty = self.definitions.empty self.assertEqual(str((A | B) & B), "'B'") self.assertEqual(str((A & B) | (A & ~B)), "'A'") self.assertEqual(str((A & B1 & B2) | (A & B1 & ~B2)), "'A' & 'B1'") self.assertEqual(str((A & ~B2 & B1) | (A & B1 & B2)), "'A' & 'B1'") self.assertEqual(str((A & B1 & ~B2) | (A & ~B1 & B2)), "('A' & 'B1' & ~'B2') | ('A' & ~'B1' & 'B2')") self.assertEqual(str(((B2 & A1) | (B2 & A1 & A11)) | ((B2 & A11) | (~B2 & A1) | (~B2 & A1 & A11))), "'A1'") self.assertEqual(str(~(((B2 & A1) | (B2 & A1 & A11)) | ((B2 & A11) | (~B2 & A1) | (~B2 & A1 & A11)))), "~'A1'") self.assertEqual(str(~((~A & B) | (A & B) | (A & ~B))), "~'A' & ~'B'") self.assertEqual(str((~A & ~B2) & (B1 | B2)), "~'A' & 'B1' & ~'B2'") self.assertEqual(str((~A & ~B2) & ~(~B1 & ~B2)), "~'A' & 'B1' & ~'B2'") self.assertEqual(str(~A & ~B2 & universe), "~'A' & ~'B2'") self.assertEqual(str((~A & ~B2 & universe) & ~(~B1 & ~B2)), "~'A' & 'B1' & ~'B2'") self.assertEqual(str((~A & ~B2 & empty) & ~(~B1 & ~B2)), "~*") self.assertEqual(str((~A & ~B2) & ~(~B1 & ~B2 & empty)), "~'A' & ~'B2'") self.assertEqual(str((~A & B1 & A) & B), "~*") def test_groups_9_distinct(self): A = self.definitions.parse('A') A1 = self.definitions.parse('A1') A11 = self.definitions.parse('A11') A1B1 = self.definitions.parse('A1B1') B = self.definitions.parse('B') B1 = self.definitions.parse('B1') B11 = self.definitions.parse('B11') E = self.definitions.parse('E') E1 = self.definitions.parse('E1') self.assertEqual(A <= E, False) self.assertEqual(A >= E, False) self.assertEqual(A <= ~E, True) # noqa: SIM300 self.assertEqual(A >= ~E, False) # noqa: SIM300 self.assertEqual(A11 <= ~E, True) # noqa: SIM300 self.assertEqual(A11 >= ~E, False) # noqa: SIM300 self.assertEqual(~A >= E, True) self.assertEqual(~A11 >= E, True) self.assertEqual(~A >= ~E, False) self.assertEqual(~A11 >= ~E, False) self.assertEqual(A <= E1, False) self.assertEqual(A >= E1, False) self.assertEqual(A <= ~E1, True) # noqa: SIM300 self.assertEqual(A >= ~E1, False) # noqa: SIM300 self.assertEqual(A11 <= ~E1, True) # noqa: SIM300 self.assertEqual(A11 >= ~E1, False) # noqa: SIM300 self.assertEqual(~A >= E1, True) self.assertEqual(~A11 >= E1, True) self.assertEqual(~A >= ~E1, False) self.assertEqual(~A <= ~E1, False) self.assertEqual(~A11 >= ~E1, False) self.assertEqual(str(B11 & ~E), "'B11'") self.assertEqual(str(~A11 | E), "~'A11'") self.assertEqual(str(~(A1 & A11 & ~E)), "~'A11'") self.assertEqual(str(B1 & E), "~*") self.assertEqual(str(B11 & E), "~*") self.assertEqual(str(B1 | E), "'B1' | 'E'") self.assertEqual(str((B1 & E) | A1B1), "'A1B1'") self.assertEqual(str(A1 & A11 & ~E), "'A11'") self.assertEqual(str(~E & (E | B)), "'B'") self.assertEqual(str((~E & E) | B), "'B'") def test_groups_10_hudge_combine(self): A1 = self.definitions.parse('A1') A11 = self.definitions.parse('A11') B = self.definitions.parse('B') B1 = self.definitions.parse('B1') B2 = self.definitions.parse('B2') A1B1 = self.definitions.parse('A1B1') C = self.definitions.parse('C') D = self.definitions.parse('D') E = self.definitions.parse('E') Z1 = C | B2 | A1 | A11 Z2 = (C) | (C & B2) | (C & B2 & A1) | (C & B2 & A11) | (C & ~B2) | (C & ~B2 & A1) Z3 = (C & ~B2 & A11) | (C & A1) | (C & A1 & B1) | (C & A11) | (C & A11 & B1) | (C & B1) Z4 = (B2 & A1) | (B2 & A1 & A11) | (B2 & A11) | (~B2 & A1) | (~B2 & A1 & A11) Z5 = (~B2 & A11) | (A1) | (A1 & A11) | (A1 & A11 & B1) | (A1 & B1) | (A11) | (A11 & B1) group1 = Z1 & (Z2 | Z3 | Z4 | Z5) self.assertEqual(str(group1), "'A1' | 'C'") self.assertEqual(str(~group1), "~'A1' & ~'C'") self.assertEqual(str(~~group1), "'A1' | 'C'") self.assertEqual(str((~group1).invert_intersect(~A1)), "~'C'") self.assertEqual(str(group1 & B), "('A1' & 'B') | ('B' & 'C')") self.assertEqual(str(~(group1 & B)), "(~'A1' & ~'C') | ~'B'") self.assertEqual(str(~~(group1 & B)), "('A1' & 'B') | ('B' & 'C')") self.assertEqual(str((group1 & B).invert_intersect(B)), "'A1' | 'C'") self.assertFalse((group1 & B).invert_intersect(A1)) self.assertEqual(str(A1 & D), "~*") self.assertEqual(str(group1 & (C | B | D)), "('A1' & 'B') | 'C'") self.assertEqual(str(~(group1 & (C | B | D))), "(~'A1' & ~'C') | (~'B' & ~'C')") group2 = (B1 | D) & (A1B1 | (A1B1 & D) | (A1B1 & D & E) | (A1B1 & E) | E) self.assertEqual(str(group2), "'A1B1'") def test_groups_11_invert_intersect(self): A = self.definitions.parse('A') A1 = self.definitions.parse('A1') A11 = self.definitions.parse('A11') A2 = self.definitions.parse('A2') A21 = self.definitions.parse('A21') A22 = self.definitions.parse('A22') B = self.definitions.parse('B') B1 = self.definitions.parse('B1') B2 = self.definitions.parse('B2') D = self.definitions.parse('D') self.assertEqual(str((A1 & A2).invert_intersect(A2)), "'A1'") self.assertEqual(str((A1 & B1 | A1 & B2).invert_intersect(A1)), "'B1' | 'B2'") self.assertEqual(str((A1 & B1 | A1 & B2 | A1 & A2).invert_intersect(A1)), "'A2' | 'B1' | 'B2'") self.assertEqual(str((A1 & B1 | A2 & B1).invert_intersect(A1 | A2)), "'B1'") self.assertEqual(str((A1 & B1 | A1 & B2 | A2 & B1 | A2 & B2).invert_intersect(A1 | A2)), "'B1' | 'B2'") self.assertEqual(A.invert_intersect(A | B), None) self.assertEqual(A.invert_intersect(A1 | A2), None) self.assertEqual(A.invert_intersect(A | D), None) tests = [ (A2, A1), (B1 | B2, A1), (A2 | B1 | B2, A1), (B1, A1 | A2), (B1 | B2, A1 | A2), (B1 & B2, A1), (A2 & B1 & B2, A1), (B1 & B2, A1 | A2), (A1, B1 & B2), (A1 | A2, B1 & B2), (A1, A2 | B1 & B2), (A11 | A21, A22 | B1 & B2), (A11 & A21, A22 | B1 & B2), (A, A1 | B), (A1 | B, A), ] for a, b in tests: self.assertEqual(str((a & b).invert_intersect(b)), str(a), f'Should invert_intersect: {a & b}\nby: ({b})') def test_groups_matches(self): A = self.definitions.parse('A') A1 = self.definitions.parse('A1') A11 = self.definitions.parse('A11') B = self.definitions.parse('B') C = self.definitions.parse('C') D = self.definitions.parse('D') matching = [ (A, {1, 13}), (A, {1, 2, 3, 13}), (A1, {1, 2, 13}), (A11, {1, 2, 3, 13}), (A | B, {1, 13}), (B | C, {1, 13}), (A1 | B, {1, 2, 13}), (A11 | B, {1, 2, 3, 13}), ((A11 | B) & ~D, {1, 2, 3, 13}), (A & ~A11, {1, 13}), (A & ~A11, {1, 2, 13}), ] for spec, group_ids in matching: self.assertTrue( spec.matches(group_ids), f"user with groups {self.definitions.from_ids(group_ids, keep_subsets=True)} should match {spec}", ) non_matching = [ (A, {13}), (A1, {13}), (A11, {13}), (A | B, {13}), (A & ~C, {13}), (A & ~B & ~C, {13}), ((A11 | B) & ~C, {1, 2, 3, 13}), (A & ~A11, {1, 2, 3, 13}), ] for spec, group_ids in non_matching: self.assertFalse( spec.matches(group_ids), f"user with groups {self.definitions.from_ids(group_ids, keep_subsets=True)} should not match {spec}", ) def test_groups_unknown(self): A = self.definitions.parse('A') U1 = self.definitions.parse('unknown.group1', raise_if_not_found=False) U2 = self.definitions.parse('unknown.group2', raise_if_not_found=False) self.assertEqual(U1, U1) self.assertNotEqual(U1, U2) self.assertEqual(A | U1, U1 | A) self.assertEqual(U1 | U2, U2 | U1) self.assertEqual(A & U1, U1 & A) self.assertEqual(U1 & U2, U2 & U1) self.assertEqual(A | U1 | U2, A | U1 | U2) self.assertEqual(A | U2 | U1, A | U1 | U2) self.assertEqual(U1 | A | U2, A | U1 | U2) self.assertEqual(U1 | A | U2, A | U1 | U2) self.assertEqual(U2 | A | U1, A | U1 | U2) self.assertEqual(U2 | U1 | A, A | U1 | U2) self.assertEqual(A & U1 & U2, A & U1 & U2) self.assertEqual(A & U2 & U1, A & U1 & U2) self.assertEqual(U1 & A & U2, A & U1 & U2) self.assertEqual(U1 & A & U2, A & U1 & U2) self.assertEqual(U2 & A & U1, A & U1 & U2) self.assertEqual(U2 & U1 & A, A & U1 & U2) def test_groups_key(self): A = self.definitions.parse('A') B = self.definitions.parse('B') C = self.definitions.parse('C') U = self.definitions.parse('unknown.group', raise_if_not_found=False) test_cases = [ A, A | B, A & B, A & ~B, (A | B) & ~C, U, A | U | B, ] for groups in test_cases: self.assertIsInstance(groups.key, str) groups1 = self.definitions.from_key(groups.key) self.assertEqual(groups1, groups) self.assertEqual(groups1.key, groups.key) @common.tagged('at_install', 'groups') class TestGroupsOdoo(common.TransactionCase): @classmethod def setUpClass(cls): super().setUpClass() cls.test_group = cls.env['res.groups'].create({ 'name': 'test with implied user', 'implied_ids': [Command.link(cls.env.ref('base.group_user').id)] }) cls.env["ir.model.data"].create({ "module": "base", "name": "base_test_group", "model": "res.groups", "res_id": cls.test_group.id, }) cls.definitions = cls.env['res.groups']._get_group_definitions() def parse_repr(self, group_repr): """ Return the group object from the string (given by the repr of the group object). :param group_repr: str Use | (union) and & (intersection) separator like the python object. intersection it's apply before union. Can use an invertion with ~. """ if not group_repr: return self.definitions.universe res = None for union in group_repr.split('|'): union = union.strip() intersection = None if union.startswith('(') and union.endswith(')'): union = union[1:-1] for xmlid in union.split('&'): xmlid = xmlid.strip() leaf = ~self.definitions.parse(xmlid[1:]) if xmlid.startswith('~') else self.definitions.parse(xmlid) if intersection is None: intersection = leaf else: intersection &= leaf if intersection is None: return self.definitions.universe elif res is None: res = intersection else: res |= intersection return self.definitions.empty if res is None else res def test_groups_1_base(self): parse = self.definitions.parse self.assertEqual(str(parse('base.group_user') & parse('base.group_user')), "'base.group_user'") self.assertEqual(str(parse('base.group_user') & parse('base.group_system')), "'base.group_system'") self.assertEqual(str(parse('base.group_system') & parse('base.group_user')), "'base.group_system'") self.assertEqual(str(parse('base.group_erp_manager') & parse('base.group_system')), "'base.group_system'") self.assertEqual(str(parse('base.group_system') & parse('base.group_allow_export')), "'base.group_system' & 'base.group_allow_export'") self.assertEqual(str(parse('base.group_user') | parse('base.group_user')), "'base.group_user'") self.assertEqual(str(parse('base.group_user') | parse('base.group_system')), "'base.group_user'") self.assertEqual(str(parse('base.group_system') | parse('base.group_public')), "'base.group_system' | 'base.group_public'") self.assertEqual(parse('base.group_system') < parse('base.group_erp_manager'), True) self.assertEqual(parse('base.group_system') < parse('base.group_sanitize_override'), True) self.assertEqual(parse('base.group_erp_manager') < parse('base.group_user'), True) self.assertEqual(parse('!base.group_portal') < parse('!base.group_public'), False) self.assertEqual(parse('base.base_test_group') == parse('base.base_test_group'), True) self.assertEqual(parse('base.group_system') <= parse('base.group_system'), True) self.assertEqual(parse('base.group_public') <= parse('base.group_system'), False) # None ? self.assertEqual(parse('base.group_user') <= parse('base.group_system'), False) self.assertEqual(parse('base.group_system') <= parse('base.group_user'), True) self.assertEqual(parse('base.group_user') <= parse('base.group_portal'), False) self.assertEqual(parse('!base.group_portal') <= parse('!base.group_public'), False) def test_groups_2_from_commat_separator(self): parse = self.definitions.parse self.assertEqual(str(parse('base.group_user,base.group_system') & parse('base.group_system')), "'base.group_system'") self.assertEqual(str(parse('base.group_user,base.group_erp_manager') & parse('base.group_system')), "'base.group_system'") self.assertEqual(str(parse('base.group_user,base.group_portal') & parse('base.group_portal')), "'base.group_portal'") self.assertEqual(str(parse('base.group_user,base.group_portal,base.group_public,base.group_multi_company') & parse('base.group_portal,base.group_public')), "'base.group_portal' | 'base.group_public'") self.assertEqual(str(parse('base.group_system,base.base_test_group') & parse('base.group_user')), "'base.group_system' | 'base.base_test_group'") self.assertEqual(str(parse('base.group_system,base.group_portal') & parse('base.group_user')), "'base.group_system'") self.assertEqual(str(parse('base.group_user') & parse('!base.group_portal,base.group_system')), "'base.group_system'") self.assertEqual(str(parse('!base.group_portal') & parse('base.group_portal,base.group_system')), "'base.group_system'") self.assertEqual(str(parse('base.group_portal,!base.group_user') & parse('base.group_user')), "~*") self.assertEqual(str(parse('!base.group_user') & parse('base.group_portal,base.group_user')), "'base.group_portal'") self.assertEqual(str(parse('base.group_user') & parse('base.group_portal,!base.group_user')), "~*") self.assertEqual(str(parse('!base.group_user') & parse('base.group_portal,!base.group_system')), "'base.group_portal'") self.assertEqual(str(parse('!base.group_user,base.group_allow_export') & parse('base.group_allow_export,!base.group_system')), "~'base.group_user' & 'base.group_allow_export'") self.assertEqual(str(parse('!base.group_user,base.group_portal') & parse('base.group_portal,!base.group_system')), "'base.group_portal'") self.assertEqual(str(parse('!*') & parse('base.group_portal')), "~*") self.assertEqual(str(parse('*') & parse('base.group_portal')), "'base.group_portal'") self.assertEqual(str(parse('base.group_user,!base.group_system') & parse('base.group_erp_manager,base.group_portal')), "'base.group_erp_manager' & ~'base.group_system'") self.assertEqual(str(parse('base.group_user,!base.group_system') & parse('base.group_portal,base.group_erp_manager')), "'base.group_erp_manager' & ~'base.group_system'") self.assertEqual(str(parse('base.group_user') & parse('base.group_portal,base.group_erp_manager,!base.group_system')), "'base.group_erp_manager' & ~'base.group_system'") self.assertEqual(str(parse('base.group_user') & parse('base.group_portal,base.group_system')), "'base.group_system'") self.assertEqual(str(parse('base.group_user,base.group_system') & parse('base.group_portal,base.group_system')), "'base.group_system'") self.assertEqual(str(parse('base.group_user') & parse('base.group_portal,base.group_erp_manager')), "'base.group_erp_manager'") self.assertEqual(str(parse('base.group_user') & parse('base.group_portal,!base.group_system')), "~*") self.assertEqual(str(parse('base.group_user,base.group_system') & parse('base.group_system,base.group_portal')), "'base.group_system'") self.assertEqual(str(parse('base.group_user') & parse('base.group_system,base.group_portal')), "'base.group_system'") self.assertEqual(str(parse('base.group_user,base.group_system') & parse('base.group_allow_export')), "'base.group_user' & 'base.group_allow_export'") self.assertEqual(str(parse('base.group_user,base.group_erp_manager') | parse('base.group_system')), "'base.group_user'") self.assertEqual(str(parse('base.group_user') | parse('base.group_portal,base.group_system')), "'base.group_user' | 'base.group_portal'") self.assertEqual(str(parse('!*') | parse('base.group_user')), "'base.group_user'") self.assertEqual(str(parse('base.group_user') | parse('!*')), "'base.group_user'") self.assertEqual(str(parse('!*') | parse('base.group_user,base.group_portal')), "'base.group_user' | 'base.group_portal'") self.assertEqual(str(parse('*') | parse('base.group_user')), "*") self.assertEqual(str(parse('base.group_user') | parse('*')), "*") self.assertEqual(str(parse('base.group_user,base.group_erp_manager') | parse('base.group_system,base.group_public')), "'base.group_user' | 'base.group_public'") self.assertEqual(parse('base.group_system') < parse('base.group_erp_manager,base.group_sanitize_override'), True) self.assertEqual(parse('!base.group_public,!base.group_portal') < parse('!base.group_public'), True) self.assertEqual(parse('base.group_system,base.base_test_group') == parse('base.group_system,base.base_test_group'), True) self.assertEqual(parse('base.group_system,base.base_test_group') == parse('base.base_test_group,base.group_system'), True) self.assertEqual(parse('base.group_system,base.base_test_group') == parse('base.base_test_group,base.group_public'), False) self.assertEqual(parse('base.group_system,base.base_test_group') == parse('base.base_test_group'), False) self.assertEqual(parse('base.group_user') <= parse('base.group_system,base.group_public'), False) self.assertEqual(parse('base.group_system') <= parse('base.group_user,base.group_public'), True) self.assertEqual(parse('base.group_public') <= parse('base.group_system,base.group_public'), True) self.assertEqual(parse('base.group_system,base.group_public') <= parse('base.group_system,base.group_public'), True) self.assertEqual(parse('base.group_system,base.group_public') <= parse('base.group_user,base.group_public'), True) self.assertEqual(parse('base.group_system,!base.group_public') <= parse('base.group_system'), True) self.assertEqual(parse('base.group_system,!base.group_allow_export') <= parse('base.group_system'), True) self.assertEqual(parse('base.group_system') <= parse('base.group_system,!base.group_allow_export'), False) self.assertEqual(parse('base.group_system') <= parse('base.group_system,!base.group_public'), True) self.assertEqual(parse('base.group_system') == parse('base.group_system,!base.group_public'), True) self.assertEqual(parse('!base.group_public,!base.group_portal') <= parse('!base.group_public'), True) self.assertEqual(parse('base.group_user,!base.group_allow_export') <= parse('base.group_user,!base.group_system,!base.group_allow_export'), False) self.assertEqual(parse('base.group_system,!base.group_portal,!base.group_public') <= parse('base.group_system,!base.group_public'), True) def test_groups_3_from_ref(self): parse = self.parse_repr self.assertEqual(str(parse('base.group_user & base.group_portal | base.group_user & ~base.group_system') & parse('base.group_public')), "~*") self.assertEqual(str(parse('base.group_user & base.group_portal | base.group_user & ~base.group_system') & parse('~base.group_user')), "~*") self.assertEqual(str(parse('base.group_user & base.group_portal | base.group_user & ~base.group_system') & parse('~base.group_user & base.group_portal')), "~*") self.assertEqual(str(parse('base.group_user & base.group_portal | base.group_user & base.group_system') & parse('base.group_user & ~base.group_portal')), "'base.group_system'") self.assertEqual(str(parse('base.group_public & base.group_erp_manager | base.group_public & base.group_portal') & parse('*')), "~*") self.assertEqual(str(parse('base.group_system & base.group_allow_export') & parse('base.group_portal | base.group_system')), "'base.group_system' & 'base.group_allow_export'") self.assertEqual(str(parse('base.group_portal & base.group_erp_manager') | parse('base.group_erp_manager')), "'base.group_erp_manager'") self.assertEqual(parse('base.group_system & base.group_allow_export') < parse('base.group_system'), True) self.assertEqual(parse('base.base_test_group') == parse('base.base_test_group & base.group_user'), True) self.assertEqual(parse('base.group_system | base.base_test_group') == parse('base.group_system & base.group_user | base.base_test_group & base.group_user'), True) self.assertEqual(parse('base.group_public & base.group_allow_export') <= parse('base.group_public'), True) self.assertEqual(parse('base.group_public') <= parse('base.group_public & base.group_allow_export'), False) self.assertEqual(parse('base.group_public & base.group_user') <= parse('base.group_portal'), True) self.assertEqual(parse('base.group_public & base.group_user') <= parse('base.group_public | base.group_user'), True) self.assertEqual(parse('base.group_public & base.group_system') <= parse('base.group_user'), True) self.assertEqual(parse('base.group_public & base.group_system') <= parse('base.group_portal | base.group_user'), True) self.assertEqual(parse('base.group_public & base.group_allow_export') <= parse('~base.group_public'), False) self.assertEqual(parse('base.group_portal & base.group_public | base.group_system & base.group_public') <= parse('base.group_public'), True) self.assertEqual(parse('base.group_portal & base.group_user | base.group_system & base.group_user') <= parse('base.group_user'), True) self.assertEqual(parse('base.group_portal & base.group_system | base.group_user & base.group_system') <= parse('base.group_system'), True) self.assertEqual(parse('base.group_portal & base.group_user | base.group_user & base.group_user') <= parse('base.group_user'), True) self.assertEqual(parse('base.group_portal & base.group_user | base.group_user & base.group_user') <= parse('base.group_user'), True) self.assertEqual(parse('base.group_public') <= parse('base.group_portal & base.group_public | base.group_system & base.group_public'), False) self.assertEqual(parse('base.group_user & base.group_allow_export') <= parse('base.group_user & base.group_system & base.group_allow_export'), False) self.assertEqual(parse('base.group_system & base.group_allow_export') <= parse('base.group_user & base.group_system & base.group_allow_export'), True) self.assertEqual(parse('base.group_system & base.group_allow_export') <= parse('base.group_system'), True) self.assertEqual(parse('base.group_public') >= parse('base.group_portal & base.group_public | base.group_system & base.group_public'), True) self.assertEqual(parse('base.group_user & base.group_public') >= parse('base.group_user & base.group_portal & base.group_public | base.group_user & base.group_system & base.group_public'), True) self.assertEqual(parse('base.group_system & base.group_allow_export') >= parse('base.group_system'), False) self.assertEqual(parse('base.group_system & base.group_allow_export') > parse('base.group_system'), False) def test_groups_4_full_empty(self): user_group_ids = self.env.user._get_group_ids() self.assertFalse(self.definitions.parse('base.group_public').matches(user_group_ids)) self.assertTrue(self.definitions.parse('*').matches(user_group_ids)) self.assertFalse((~self.definitions.parse('*')).matches(user_group_ids)) def test_groups_5_contains_user(self): # user is included into the defined group of users user = self.env['res.users'].create({ 'name': 'A User', 'login': 'a_user', 'email': 'a@user.com', }) tests = [ # group on the user, # groups access, access ('base.group_public', 'base.group_system | base.group_public', True), ('base.group_public,base.group_allow_export', 'base.group_user | base.group_public', True), ('base.group_public', 'base.group_system & base.group_public', False), ('base.group_public', 'base.group_system | base.group_portal', False), ('base.group_public', 'base.group_system & base.group_portal', False), ('base.group_system', 'base.group_system | base.group_public', True), ('base.group_system', 'base.group_system & base.group_public', False), ('base.group_system', 'base.group_user | base.group_system', True), ('base.group_system', 'base.group_user & base.group_system', True), ('base.group_public', 'base.group_user | base.group_system', False), ('base.group_public', 'base.group_user & base.group_system', False), ('base.group_system', 'base.group_system & ~base.group_user', False), ('base.group_portal', 'base.group_system & ~base.group_user', False), ('base.group_user', 'base.group_user & ~base.group_system', True), ('base.group_user', '~base.group_system & base.group_user', True), ('base.group_system', 'base.group_user & ~base.group_system', False), ('base.group_portal', 'base.group_portal & ~base.group_user', True), ('base.group_system', '~base.group_system & base.group_user', False), ('base.group_system', '~base.group_system & ~base.group_user', False), ('base.group_user', 'base.group_user & base.group_sanitize_override & base.group_allow_export', False), ('base.group_system', 'base.group_user & base.group_sanitize_override & base.group_allow_export', False), ('base.group_system,base.group_allow_export', 'base.group_user & base.group_sanitize_override & base.group_allow_export', True), ('base.group_user,base.group_sanitize_override,base.group_allow_export', 'base.group_user & base.group_sanitize_override & base.group_allow_export', True), ('base.group_user', 'base.group_erp_manager | base.group_multi_company', False), ('base.group_user,base.group_erp_manager', 'base.group_erp_manager | base.group_multi_company', True), ] for user_groups, groups, result in tests: user.groups_id = [(6, 0, [self.env.ref(xmlid).id for xmlid in user_groups.split(',')])] self.assertEqual(self.parse_repr(groups).matches(user._get_group_ids()), result, f'User ({user_groups!r}) should {"" if result else "not "}have access to groups: ({groups!r})') def test_groups_6_distinct(self): user = self.env['res.users'].create({ 'name': 'A User', 'login': 'a_user', 'email': 'a@user.com', 'groups_id': self.env.ref('base.group_user').ids, }) with self.assertRaisesRegex(ValidationError, "The user cannot have more than one user types."): user.groups_id = [(4, self.env.ref('base.group_public').id)] with self.assertRaisesRegex(ValidationError, "The user cannot have more than one user types."): user.groups_id = [(4, self.env.ref('base.group_portal').id)]