def test_get_wrapper_object(self):
        d = AutoSignals()
        d.validate_model = MagicMock()
        d.connect_signals = MagicMock()
        d.to_wrap = None

        d.get_wrapped_object()

        self.assertTrue(d.validate_model.called)
        self.assertTrue(d.connect_signals.called)
class TestAutoSignals(object):
    def setup_method(self, method):
        self.decorator = AutoSignals()

    def test_init(self):
        supported_signals = {
            'class_prepared',
            'm2m_changed',
            'post_delete',
            'post_init',
            'post_save',
            'pre_delete',
            'pre_init',
            'pre_save',
        }
        assert self.decorator.getter == 'get_signals'
        assert isinstance(self.decorator.signal_pool, dict)
        assert set(self.decorator.signal_pool) & supported_signals == supported_signals

    def test_validate_model_not_class(self):
        self.decorator.to_wrap = None
        with pytest.raises(TypeError):
            self.decorator.validate_model()

    def test_validate_model_not_django_model(self):
        self.decorator.to_wrap = int
        with pytest.raises(TypeError):
            self.decorator.validate_model()

    def test_validate_model_not_implementing_getter(self):
        class Foo(models.Model):
            class Meta(object):
                app_label = 'foo'

        self.decorator.to_wrap = Foo
        with pytest.raises(AttributeError):
            self.decorator.validate_model()

    def test_validate_model_not_implementing_getter_as_callable(self):
        class Foo(models.Model):
            get_signals = 'foo'

            class Meta(object):
                app_label = 'foo'

        self.decorator.to_wrap = Foo
        with pytest.raises(TypeError):
            self.decorator.validate_model()

    def test_validate_model_valid(self):
        class Foo(models.Model):
            class Meta(object):
                app_label = 'foo'

            @classmethod
            def get_signals(self):
                return []

        self.decorator.to_wrap = Foo
        assert self.decorator.validate_model() is None

    @mock.patch.object(AutoSignals, 'validate_model')
    @mock.patch.object(AutoSignals, 'connect_signals')
    def test_get_wrapper_object(self, mock_connect_signals, mock_validate_model):
        self.decorator.to_wrap = mock.sentinel.to_wrap

        assert self.decorator.get_wrapped_object() is mock.sentinel.to_wrap
        mock_connect_signals.assert_called_once_with()
        mock_validate_model.assert_called_once_with()

    @mock.patch.object(AutoSignals, 'connect_signal')
    def test_connect_signals_list(self, mock_connect_signal):
        def pre_save(sender, instance, *args, **kwwargs):
            pass

        class Foo(models.Model):
            class Meta(object):
                app_label = 'foo'

            @classmethod
            def get_signals(self):
                return [pre_save]

        self.decorator.to_wrap = Foo

        self.decorator.connect_signals()
        mock_connect_signal.assert_called_once_with(pre_save)

    @mock.patch.object(AutoSignals, 'connect_signal')
    def test_connect_signals_single(self, mock_connect_signal):
        def pre_save(sender, instance, *args, **kwwargs):
            pass

        class Foo(models.Model):
            class Meta(object):
                app_label = 'foo'

            @classmethod
            def get_signals(self):
                return pre_save

        self.decorator.to_wrap = Foo

        self.decorator.connect_signals()
        mock_connect_signal.assert_called_once_with(pre_save)

    def test_connect_signal_invalid_type(self):
        self.decorator.to_wrap = mock.sentinel.model

        with pytest.raises(TypeError):
            self.decorator.connect_signal(None)

    def test_connect_signal_no_receiver(self):
        self.decorator.to_wrap = mock.sentinel.model

        with pytest.raises(ValueError):
            self.decorator.connect_signal({})

    def test_connect_signal_cant_determine_signal(self):
        self.decorator.to_wrap = mock.sentinel.model

        def foo(*args, **kwargs):
            pass

        with pytest.raises(ValueError):
            self.decorator.connect_signal(foo)

    def test_connect_signal_invalid_signal(self):
        self.decorator.to_wrap = mock.sentinel.model

        def foo(*args, **kwargs):
            pass

        with pytest.raises(ValueError):
            self.decorator.connect_signal({
                'receiver': foo,
                'signal': 'foo',
            })

    def test_connect_signal_from_callable(self):
        mock_signal = mock.MagicMock()
        self.decorator.to_wrap = mock.sentinel.model
        self.decorator.signal_pool = {'pre_save': mock_signal}

        def foo_pre_save(*args, **kwargs):
            pass

        self.decorator.connect_signal(foo_pre_save)

        mock_signal.connect.assert_called_once_with(
            sender=mock.sentinel.model,
            receiver=foo_pre_save,
        )

    def test_connect_signal_from_dict(self):
        mock_signal = mock.MagicMock()
        self.decorator.to_wrap = mock.sentinel.model
        self.decorator.signal_pool = {'pre_save': mock_signal}

        def foo_pre_save(*args, **kwargs):
            pass

        self.decorator.connect_signal({
            'receiver': foo_pre_save,
            'weak': False,
        })

        mock_signal.connect.assert_called_once_with(
            sender=mock.sentinel.model,
            receiver=foo_pre_save,
            weak=False,
        )