# Copyright 2018 Simone Orsi - Camptocamp SA # License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html). from operator import attrgetter class TestMixin: """Mixin to setup fake models for tests. Usage - the model: class FakeModel(models.Model, TestMixin): _name = 'fake.model' name = fields.Char() Usage - the test klass: @classmethod def setUpClass(cls): super().setUpClass() FakeModel._test_setup_model(cls.env) @classmethod def tearDownClass(cls): FakeModel._test_teardown_model(cls.env) super().tearDownClass() """ # Generate xmlids # This is needed if you want to load data tied to a test model via xid. _test_setup_gen_xid = False # If you extend a real model (ie: res.partner) you must enable this # to not delete the model on tear down. _test_teardown_no_delete = False # You can add custom fields to real models (eg: res.partner). # In this case you must delete them to leave registry and model clean. # This is mandatory for relational fields that link a fake model. _test_purge_fields = [] @classmethod def _test_setup_models(cls, env, model_clses): """ Setup models at the same time if one fake model ref to another in relational field. ex : many2one fields in this case we should don't use manual=True as an option in field. """ for model_cls in model_clses: model_cls._build_model(env.registry, env.cr) env.registry.setup_models(env.cr) ctx = dict(env.context, update_custom_fields=True) if cls._test_setup_gen_xid: ctx["module"] = cls._module env.registry.init_models( env.cr, [model_cls._name for model_cls in model_clses], ctx ) @classmethod def _test_setup_model(cls, env): """Initialize it.""" cls._build_model(env.registry, env.cr) env.registry.setup_models(env.cr) ctx = dict(env.context, update_custom_fields=True) if cls._test_setup_gen_xid: ctx["module"] = cls._module env.registry.init_models(env.cr, [cls._name], ctx) @classmethod def _test_teardown_model(cls, env): """Cleanup registry and real models.""" for fname in cls._test_purge_fields: model = env[cls._name] if fname in model: model._pop_field(fname) if not getattr(cls, "_test_teardown_no_delete", False): del env.registry.models[cls._name] # here we must remove the model from list of children of inherited # models parents = cls._inherit parents = [parents] if isinstance(parents, str) else (parents or []) # keep a copy to be sure to not modify the original _inherit parents = list(parents) parents.extend(cls._inherits.keys()) parents.append("base") funcs = [ attrgetter(kind + "_children") for kind in ["_inherits", "_inherit"] ] for parent in parents: for func in funcs: children = func(env.registry[parent]) if cls._name in children: # at this stage our cls is referenced as children of # parent -> must un reference it children.remove(cls._name) def _test_get_model_id(self): self.env.cr.execute("SELECT id FROM ir_model WHERE model = %s", (self._name,)) res = self.env.cr.fetchone() return res[0] if res else None def _test_create_ACL(self, **kw): model_id = self._test_get_model_id() if not model_id: self._reflect() model_id = self._test_get_model_id() if model_id: vals = self._test_ACL_values(model_id) vals.update(kw) self.env["ir.model.access"].create(vals) def _test_ACL_values(self, model_id): values = { "name": "Fake ACL for %s" % self._name, "model_id": model_id, "perm_read": 1, "perm_create": 1, "perm_write": 1, "perm_unlink": 1, "active": True, } return values