class test_backend_register(common.TransactionCase):
    """ Test registration of classes on the Backend"""


    def setUp(self):
        super(test_backend_register, self).setUp()
        self.service = 'calamitorium'
        self.version = '1.14'
        self.parent = Backend(self.service)
        self.backend = Backend(parent=self.parent, version=self.version)
        self.session = ConnectorSession(self.cr,
                                        self.uid)

    def tearDown(self):
        super(test_backend_register, self).setUp()
        BACKENDS.backends.clear()
        del self.backend._class_entries[:]

    def test_register_class(self):
        class BenderBinder(Binder):
            _model_name = 'res.users'

        self.backend.register_class(BenderBinder)
        ref = self.backend.get_class(Binder,
                                     self.session,
                                     'res.users')
        self.assertEqual(ref, BenderBinder)

    def test_register_class_decorator(self):
        @self.backend
        class ZoidbergMapper(ExportMapper):
            _model_name = 'res.users'

        ref = self.backend.get_class(ExportMapper,
                                     self.session,
                                     'res.users')
        self.assertEqual(ref, ZoidbergMapper)

    def test_register_class_parent(self):
        """ It should get the parent's class when no class is defined"""
        @self.parent
        class FryBinder(Binder):
            _model_name = 'res.users'

        ref = self.backend.get_class(Binder,
                                     self.session,
                                     'res.users')
        self.assertEqual(ref, FryBinder)

    def test_no_register_error(self):
        """ Error when asking for a class and none is found"""
        with self.assertRaises(AssertionError):
            ref = self.backend.get_class(BackendAdapter,
                                         self.session,
                                         'res.users')

    def test_get_class_installed_module(self):
        """ Only class from an installed module should be returned """
        class LambdaUnit(ConnectorUnit):
            _model_name = 'res.users'

        @self.backend
        class LambdaYesUnit(LambdaUnit):
            _model_name = 'res.users'

        class LambdaNoUnit(LambdaUnit):
            _model_name = 'res.users'

        # trick the origin of the class, let it think
        # that it comes from the OpenERP module 'not installed module'
        LambdaNoUnit._openerp_module_ = 'not installed module'
        self.backend(LambdaNoUnit)

        matching_cls = self.backend.get_class(LambdaUnit,
                                              self.session,
                                              'res.users')
        self.assertEqual(matching_cls, LambdaYesUnit)

    def test_get_class_replacing_module(self):
        """ Returns the replacing ConnectorUnit"""
        class LambdaUnit(ConnectorUnit):
            _model_name = 'res.users'

        @self.backend
        class LambdaNoUnit(LambdaUnit):
            _model_name = 'res.users'

        @self.backend(replacing=LambdaNoUnit)
        class LambdaYesUnit(LambdaUnit):
            _model_name = 'res.users'

        matching_cls = self.backend.get_class(LambdaUnit,
                                              self.session,
                                              'res.users')
        self.assertEqual(matching_cls, LambdaYesUnit)

    def test_get_class_replacing_uninstalled_module(self):
        """ Does not return the replacing ConnectorUnit of an
        uninstalled module """
        class LambdaUnit(ConnectorUnit):
            _model_name = 'res.users'

        @self.backend
        class LambdaYesUnit(LambdaUnit):
            _model_name = 'res.users'

        class LambdaNoUnit(LambdaUnit):
            _model_name = 'res.users'

        # trick the origin of the class, let it think
        # that it comes from the OpenERP module 'not installed module'
        LambdaNoUnit._openerp_module_ = 'not installed module'
        self.backend(LambdaNoUnit, replacing=LambdaYesUnit)

        matching_cls = self.backend.get_class(LambdaUnit,
                                              self.session,
                                              'res.users')
        self.assertEqual(matching_cls, LambdaYesUnit)

    def test_get_class_replacing_diamond(self):
        """ Replace several classes in a diamond fashion """
        class LambdaUnit(ConnectorUnit):
            _model_name = 'res.users'

        @self.backend
        class LambdaNoUnit(LambdaUnit):
            _model_name = 'res.users'

        @self.backend
        class LambdaNo2Unit(LambdaUnit):
            _model_name = 'res.users'

        @self.backend(replacing=(LambdaNoUnit, LambdaNo2Unit))
        class LambdaYesUnit(LambdaUnit):
            _model_name = 'res.users'

        matching_cls = self.backend.get_class(LambdaUnit,
                                              self.session,
                                              'res.users')
        self.assertEqual(matching_cls, LambdaYesUnit)

    def test_get_class_replacing_unregistered(self):
        """ Replacing an unregistered class raise ValueError """
        class LambdaUnit(ConnectorUnit):
            _model_name = 'res.users'

        with self.assertRaises(ValueError):
            @self.backend(replacing=LambdaUnit)
            class LambdaNoUnit(LambdaUnit):
                _model_name = 'res.users'

    def test_get_class_replacing_self(self):
        """ A class should not be able to replace itself """
        class LambdaUnit(ConnectorUnit):
            _model_name = 'res.users'

        @self.backend
        class LambdaRecurseUnit(LambdaUnit):
            _model_name = 'res.users'

        with self.assertRaises(ValueError):
            self.backend.register_class(LambdaRecurseUnit,
                                        replacing=LambdaRecurseUnit)

    def test_get_class_unregister_deprecated(self):
        """ Unregister is deprecated """
        class LambdaUnit(ConnectorUnit):
            _model_name = 'res.users'
        with self.assertRaises(DeprecationWarning):
            self.backend.unregister_class(LambdaUnit)
class test_backend_register(common.TransactionCase):
    """ Test registration of classes on the Backend"""
    def setUp(self):
        super(test_backend_register, self).setUp()
        self.service = 'calamitorium'
        self.version = '1.14'
        self.parent = Backend(self.service)
        self.backend = Backend(parent=self.parent, version=self.version)
        self.session = ConnectorSession(self.cr, self.uid)

    def tearDown(self):
        super(test_backend_register, self).tearDown()
        BACKENDS.backends.clear()
        del self.backend._class_entries[:]

    def test_register_class(self):
        class BenderBinder(Binder):
            _model_name = 'res.users'

        self.backend.register_class(BenderBinder)
        ref = self.backend.get_class(Binder, self.session, 'res.users')
        self.assertEqual(ref, BenderBinder)

    def test_register_class_decorator(self):
        @self.backend
        class ZoidbergMapper(ExportMapper):
            _model_name = 'res.users'

        ref = self.backend.get_class(ExportMapper, self.session, 'res.users')
        self.assertEqual(ref, ZoidbergMapper)

    def test_register_class_parent(self):
        """ It should get the parent's class when no class is defined"""
        @self.parent
        class FryBinder(Binder):
            _model_name = 'res.users'

        ref = self.backend.get_class(Binder, self.session, 'res.users')
        self.assertEqual(ref, FryBinder)

    def test_no_register_error(self):
        """ Error when asking for a class and none is found"""
        with self.assertRaises(NoConnectorUnitError):
            self.backend.get_class(BackendAdapter, self.session, 'res.users')

    def test_get_class_installed_module(self):
        """ Only class from an installed module should be returned """
        class LambdaUnit(ConnectorUnit):
            _model_name = 'res.users'

        @self.backend
        class LambdaYesUnit(LambdaUnit):
            _model_name = 'res.users'

        class LambdaNoUnit(LambdaUnit):
            _model_name = 'res.users'

        # trick the origin of the class, let it think
        # that it comes from the OpenERP module 'not installed module'
        LambdaNoUnit._openerp_module_ = 'not installed module'
        self.backend(LambdaNoUnit)

        matching_cls = self.backend.get_class(LambdaUnit, self.session,
                                              'res.users')
        self.assertEqual(matching_cls, LambdaYesUnit)

    def test_get_class_replacing_module(self):
        """ Returns the replacing ConnectorUnit"""
        class LambdaUnit(ConnectorUnit):
            _model_name = 'res.users'

        @self.backend
        class LambdaNoUnit(LambdaUnit):
            _model_name = 'res.users'

        @self.backend(replacing=LambdaNoUnit)
        class LambdaYesUnit(LambdaUnit):
            _model_name = 'res.users'

        matching_cls = self.backend.get_class(LambdaUnit, self.session,
                                              'res.users')
        self.assertEqual(matching_cls, LambdaYesUnit)

    def test_get_class_replacing_uninstalled_module(self):
        """ Does not return the replacing ConnectorUnit of an
        uninstalled module """
        class LambdaUnit(ConnectorUnit):
            _model_name = 'res.users'

        @self.backend
        class LambdaYesUnit(LambdaUnit):
            _model_name = 'res.users'

        class LambdaNoUnit(LambdaUnit):
            _model_name = 'res.users'

        # trick the origin of the class, let it think
        # that it comes from the OpenERP module 'not installed module'
        LambdaNoUnit._openerp_module_ = 'not installed module'
        self.backend(LambdaNoUnit, replacing=LambdaYesUnit)

        matching_cls = self.backend.get_class(LambdaUnit, self.session,
                                              'res.users')
        self.assertEqual(matching_cls, LambdaYesUnit)

    def test_get_class_replacing_diamond(self):
        """ Replace several classes in a diamond fashion """
        class LambdaUnit(ConnectorUnit):
            _model_name = 'res.users'

        @self.backend
        class LambdaNoUnit(LambdaUnit):
            _model_name = 'res.users'

        @self.backend
        class LambdaNo2Unit(LambdaUnit):
            _model_name = 'res.users'

        @self.backend(replacing=(LambdaNoUnit, LambdaNo2Unit))
        class LambdaYesUnit(LambdaUnit):
            _model_name = 'res.users'

        matching_cls = self.backend.get_class(LambdaUnit, self.session,
                                              'res.users')
        self.assertEqual(matching_cls, LambdaYesUnit)

    def test_get_class_replacing_unregistered(self):
        """ Replacing an unregistered class raise ValueError """
        class LambdaUnit(ConnectorUnit):
            _model_name = 'res.users'

        with self.assertRaises(ValueError):

            @self.backend(replacing=LambdaUnit)
            class LambdaNoUnit(LambdaUnit):
                _model_name = 'res.users'

    def test_get_class_replacing_self(self):
        """ A class should not be able to replace itself """
        class LambdaUnit(ConnectorUnit):
            _model_name = 'res.users'

        @self.backend
        class LambdaRecurseUnit(LambdaUnit):
            _model_name = 'res.users'

        with self.assertRaises(ValueError):
            self.backend.register_class(LambdaRecurseUnit,
                                        replacing=LambdaRecurseUnit)

    def test_get_class_unregister_deprecated(self):
        """ Unregister is deprecated """
        class LambdaUnit(ConnectorUnit):
            _model_name = 'res.users'

        with self.assertRaises(DeprecationWarning):
            self.backend.unregister_class(LambdaUnit)