273 lines
		
	
	
		
			9.3 KiB
		
	
	
	
		
			Python
		
	
	
			
		
		
	
	
			273 lines
		
	
	
		
			9.3 KiB
		
	
	
	
		
			Python
		
	
	
# -*- coding: utf-8 -*-
 | 
						|
# Copyright 2017 Camptocamp SA
 | 
						|
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html)
 | 
						|
 | 
						|
import mock
 | 
						|
from odoo.addons.component.core import AbstractComponent, Component
 | 
						|
from .common import ComponentRegistryCase
 | 
						|
 | 
						|
 | 
						|
class TestBuildComponent(ComponentRegistryCase):
 | 
						|
    """ Test build of components
 | 
						|
 | 
						|
    All the tests in this suite are based on the same principle with
 | 
						|
    variations:
 | 
						|
 | 
						|
    * Create new Components (classes inheriting from
 | 
						|
      :class:`component.core.Component` or
 | 
						|
      :class:`component.core.AbstractComponent`
 | 
						|
    * Call :meth:`component.core.Component._build_component` on them
 | 
						|
      in order to build the 'final class' composed from all the ``_inherit``
 | 
						|
      and push it in the components registry (``self.comp_registry`` here)
 | 
						|
    * Assert that classes are built, registered, have correct ``__bases__``...
 | 
						|
 | 
						|
    """
 | 
						|
 | 
						|
    def test_no_name(self):
 | 
						|
        """ Ensure that a component has a _name """
 | 
						|
        class Component1(Component):
 | 
						|
            pass
 | 
						|
 | 
						|
        msg = '.*must have a _name.*'
 | 
						|
        with self.assertRaisesRegex(TypeError, msg):
 | 
						|
            Component1._build_component(self.comp_registry)
 | 
						|
 | 
						|
    def test_register(self):
 | 
						|
        """ Able to register components in components registry """
 | 
						|
        class Component1(Component):
 | 
						|
            _name = 'component1'
 | 
						|
 | 
						|
        class Component2(Component):
 | 
						|
            _name = 'component2'
 | 
						|
 | 
						|
        # build the 'final classes' for the components and check that we find
 | 
						|
        # them in the components registry
 | 
						|
        Component1._build_component(self.comp_registry)
 | 
						|
        Component2._build_component(self.comp_registry)
 | 
						|
        self.assertEqual(
 | 
						|
            ['base', 'component1', 'component2'],
 | 
						|
            list(self.comp_registry)
 | 
						|
        )
 | 
						|
 | 
						|
    def test_inherit_bases(self):
 | 
						|
        """ Check __bases__ of Component with _inherit """
 | 
						|
        class Component1(Component):
 | 
						|
            _name = 'component1'
 | 
						|
 | 
						|
        class Component2(Component):
 | 
						|
            _inherit = 'component1'
 | 
						|
 | 
						|
        class Component3(Component):
 | 
						|
            _inherit = 'component1'
 | 
						|
 | 
						|
        Component1._build_component(self.comp_registry)
 | 
						|
        Component2._build_component(self.comp_registry)
 | 
						|
        Component3._build_component(self.comp_registry)
 | 
						|
        self.assertEqual(
 | 
						|
            (Component3,
 | 
						|
             Component2,
 | 
						|
             Component1,
 | 
						|
             self.comp_registry['base']),
 | 
						|
            self.comp_registry['component1'].__bases__
 | 
						|
        )
 | 
						|
 | 
						|
    def test_prototype_inherit_bases(self):
 | 
						|
        """ Check __bases__ of Component with _inherit and different _name """
 | 
						|
        class Component1(Component):
 | 
						|
            _name = 'component1'
 | 
						|
 | 
						|
        class Component2(Component):
 | 
						|
            _name = 'component2'
 | 
						|
            _inherit = 'component1'
 | 
						|
 | 
						|
        class Component3(Component):
 | 
						|
            _name = 'component3'
 | 
						|
            _inherit = 'component1'
 | 
						|
 | 
						|
        class Component4(Component):
 | 
						|
            _name = 'component4'
 | 
						|
            _inherit = ['component2', 'component3']
 | 
						|
 | 
						|
        Component1._build_component(self.comp_registry)
 | 
						|
        Component2._build_component(self.comp_registry)
 | 
						|
        Component3._build_component(self.comp_registry)
 | 
						|
        Component4._build_component(self.comp_registry)
 | 
						|
        self.assertEqual(
 | 
						|
            (Component1,
 | 
						|
             self.comp_registry['base']),
 | 
						|
            self.comp_registry['component1'].__bases__
 | 
						|
        )
 | 
						|
        self.assertEqual(
 | 
						|
            (Component2,
 | 
						|
             self.comp_registry['component1'],
 | 
						|
             self.comp_registry['base']),
 | 
						|
            self.comp_registry['component2'].__bases__
 | 
						|
        )
 | 
						|
        self.assertEqual(
 | 
						|
            (Component3,
 | 
						|
             self.comp_registry['component1'],
 | 
						|
             self.comp_registry['base']),
 | 
						|
            self.comp_registry['component3'].__bases__
 | 
						|
        )
 | 
						|
        self.assertEqual(
 | 
						|
            (Component4,
 | 
						|
             self.comp_registry['component2'],
 | 
						|
             self.comp_registry['component3'],
 | 
						|
             self.comp_registry['base']),
 | 
						|
            self.comp_registry['component4'].__bases__
 | 
						|
        )
 | 
						|
 | 
						|
    def test_custom_build(self):
 | 
						|
        """ Check that we can hook at the end of a Component build """
 | 
						|
        class Component1(Component):
 | 
						|
            _name = 'component1'
 | 
						|
 | 
						|
            @classmethod
 | 
						|
            def _complete_component_build(cls):
 | 
						|
                # This method should be called after the Component
 | 
						|
                # is built, and before it is pushed in the registry
 | 
						|
                cls._build_done = True
 | 
						|
 | 
						|
        Component1._build_component(self.comp_registry)
 | 
						|
        # we inspect that our custom build has been executed
 | 
						|
        self.assertTrue(
 | 
						|
            self.comp_registry['component1']._build_done
 | 
						|
        )
 | 
						|
 | 
						|
    def test_inherit_attrs(self):
 | 
						|
        """ Check attributes inheritance of Components with _inherit """
 | 
						|
        class Component1(Component):
 | 
						|
            _name = 'component1'
 | 
						|
 | 
						|
            msg = 'ping'
 | 
						|
 | 
						|
            def say(self):
 | 
						|
                return 'foo'
 | 
						|
 | 
						|
        class Component2(Component):
 | 
						|
            _name = 'component2'
 | 
						|
            _inherit = 'component1'
 | 
						|
 | 
						|
            msg = 'pong'
 | 
						|
 | 
						|
            def say(self):
 | 
						|
                return super(Component2, self).say() + ' bar'
 | 
						|
 | 
						|
        Component1._build_component(self.comp_registry)
 | 
						|
        Component2._build_component(self.comp_registry)
 | 
						|
        # we initialize the components, normally we should pass
 | 
						|
        # an instance of WorkContext, but we don't need a real one
 | 
						|
        # for this test
 | 
						|
        component1 = self.comp_registry['component1'](mock.Mock())
 | 
						|
        component2 = self.comp_registry['component2'](mock.Mock())
 | 
						|
        self.assertEqual('ping', component1.msg)
 | 
						|
        self.assertEqual('pong', component2.msg)
 | 
						|
        self.assertEqual('foo', component1.say())
 | 
						|
        self.assertEqual('foo bar', component2.say())
 | 
						|
 | 
						|
    def test_duplicate_component(self):
 | 
						|
        """ Check that we can't have 2 components with the same name """
 | 
						|
        class Component1(Component):
 | 
						|
            _name = 'component1'
 | 
						|
 | 
						|
        class Component2(Component):
 | 
						|
            _name = 'component1'
 | 
						|
 | 
						|
        Component1._build_component(self.comp_registry)
 | 
						|
        msg = 'Component.*already exists.*'
 | 
						|
        with self.assertRaisesRegex(TypeError, msg):
 | 
						|
            Component2._build_component(self.comp_registry)
 | 
						|
 | 
						|
    def test_no_parent(self):
 | 
						|
        """ Ensure we can't _inherit a non-existent component """
 | 
						|
        class Component1(Component):
 | 
						|
            _name = 'component1'
 | 
						|
            _inherit = 'component1'
 | 
						|
 | 
						|
        msg = 'Component.*does not exist in registry.*'
 | 
						|
        with self.assertRaisesRegex(TypeError, msg):
 | 
						|
            Component1._build_component(self.comp_registry)
 | 
						|
 | 
						|
    def test_no_parent2(self):
 | 
						|
        """ Ensure we can't _inherit by prototype a non-existent component """
 | 
						|
        class Component1(Component):
 | 
						|
            _name = 'component1'
 | 
						|
 | 
						|
        class Component2(Component):
 | 
						|
            _name = 'component2'
 | 
						|
            _inherit = ['component1', 'component3']
 | 
						|
 | 
						|
        Component1._build_component(self.comp_registry)
 | 
						|
        msg = 'Component.*inherits from non-existing component.*'
 | 
						|
        with self.assertRaisesRegex(TypeError, msg):
 | 
						|
            Component2._build_component(self.comp_registry)
 | 
						|
 | 
						|
    def test_add_inheritance(self):
 | 
						|
        """ Ensure we can add a new inheritance """
 | 
						|
        class Component1(Component):
 | 
						|
            _name = 'component1'
 | 
						|
 | 
						|
        class Component2(Component):
 | 
						|
            _name = 'component2'
 | 
						|
 | 
						|
        class Component2bis(Component):
 | 
						|
            _name = 'component2'
 | 
						|
            _inherit = ['component2', 'component1']
 | 
						|
 | 
						|
        Component1._build_component(self.comp_registry)
 | 
						|
        Component2._build_component(self.comp_registry)
 | 
						|
        Component2bis._build_component(self.comp_registry)
 | 
						|
 | 
						|
        self.assertEqual(
 | 
						|
            (Component2bis,
 | 
						|
             Component2,
 | 
						|
             self.comp_registry['component1'],
 | 
						|
             self.comp_registry['base']),
 | 
						|
            self.comp_registry['component2'].__bases__
 | 
						|
        )
 | 
						|
 | 
						|
    def test_check_parent_component_over_abstract(self):
 | 
						|
        """ Component can inherit from AbstractComponent """
 | 
						|
        class Component1(AbstractComponent):
 | 
						|
            _name = 'component1'
 | 
						|
 | 
						|
        class Component2(Component):
 | 
						|
            _name = 'component2'
 | 
						|
            _inherit = 'component1'
 | 
						|
 | 
						|
        Component1._build_component(self.comp_registry)
 | 
						|
        Component2._build_component(self.comp_registry)
 | 
						|
        self.assertTrue(
 | 
						|
            self.comp_registry['component1']._abstract
 | 
						|
        )
 | 
						|
        self.assertFalse(
 | 
						|
            self.comp_registry['component2']._abstract
 | 
						|
        )
 | 
						|
 | 
						|
    def test_check_parent_abstract_over_component(self):
 | 
						|
        """ Prevent AbstractComponent to inherit from Component """
 | 
						|
        class Component1(Component):
 | 
						|
            _name = 'component1'
 | 
						|
 | 
						|
        class Component2(AbstractComponent):
 | 
						|
            _name = 'component2'
 | 
						|
            _inherit = 'component1'
 | 
						|
 | 
						|
        Component1._build_component(self.comp_registry)
 | 
						|
        msg = '.*cannot inherit from the non-abstract.*'
 | 
						|
        with self.assertRaisesRegex(TypeError, msg):
 | 
						|
            Component2._build_component(self.comp_registry)
 | 
						|
 | 
						|
    def test_check_transform_abstract_to_component(self):
 | 
						|
        """ Prevent AbstractComponent to be transformed to Component """
 | 
						|
        class Component1(AbstractComponent):
 | 
						|
            _name = 'component1'
 | 
						|
 | 
						|
        class Component1bis(Component):
 | 
						|
            _inherit = 'component1'
 | 
						|
 | 
						|
        Component1._build_component(self.comp_registry)
 | 
						|
        msg = '.*transforms the abstract component.*into a non-abstract.*'
 | 
						|
        with self.assertRaisesRegex(TypeError, msg):
 | 
						|
            Component1bis._build_component(self.comp_registry)
 |