From 20fa9ddb7183707d707a8c703b6f28b02efc80db Mon Sep 17 00:00:00 2001 From: Alex Gaynor Date: Sun, 10 Oct 2010 18:23:39 +0000 Subject: [PATCH] Converted signals tests from doctests to unittests. We have always been at war with doctests. git-svn-id: http://code.djangoproject.com/svn/django/trunk@14131 bcc190cf-cafb-0310-a4f2-bffc1f526a37 --- tests/modeltests/signals/models.py | 133 +------------------------ tests/modeltests/signals/tests.py | 154 ++++++++++++++++++++++++++++- 2 files changed, 152 insertions(+), 135 deletions(-) diff --git a/tests/modeltests/signals/models.py b/tests/modeltests/signals/models.py index 8a500752be..53b8f26606 100644 --- a/tests/modeltests/signals/models.py +++ b/tests/modeltests/signals/models.py @@ -3,7 +3,7 @@ Testing signals before/after saving and deleting. """ from django.db import models -from django.dispatch import receiver + class Person(models.Model): first_name = models.CharField(max_length=20) @@ -18,134 +18,3 @@ class Car(models.Model): def __unicode__(self): return u"%s %s" % (self.make, self.model) - -def pre_save_test(signal, sender, instance, **kwargs): - print 'pre_save signal,', instance - if kwargs.get('raw'): - print 'Is raw' - -def post_save_test(signal, sender, instance, **kwargs): - print 'post_save signal,', instance - if 'created' in kwargs: - if kwargs['created']: - print 'Is created' - else: - print 'Is updated' - if kwargs.get('raw'): - print 'Is raw' - -def pre_delete_test(signal, sender, instance, **kwargs): - print 'pre_delete signal,', instance - print 'instance.id is not None: %s' % (instance.id != None) - -# #8285: signals can be any callable -class PostDeleteHandler(object): - def __call__(self, signal, sender, instance, **kwargs): - print 'post_delete signal,', instance - print 'instance.id is None: %s' % (instance.id == None) - -post_delete_test = PostDeleteHandler() - -__test__ = {'API_TESTS':""" - -# Save up the number of connected signals so that we can check at the end -# that all the signals we register get properly unregistered (#9989) ->>> pre_signals = (len(models.signals.pre_save.receivers), -... len(models.signals.post_save.receivers), -... len(models.signals.pre_delete.receivers), -... len(models.signals.post_delete.receivers)) - ->>> models.signals.pre_save.connect(pre_save_test) ->>> models.signals.post_save.connect(post_save_test) ->>> models.signals.pre_delete.connect(pre_delete_test) ->>> models.signals.post_delete.connect(post_delete_test) - -# throw a decorator syntax receiver into the mix ->>> @receiver(models.signals.pre_save) -... def pre_save_decorator_test(signal, sender, instance, **kwargs): -... print "pre_save signal decorator,", instance - -# throw a decorator syntax receiver into the mix ->>> @receiver(models.signals.pre_save, sender=Car) -... def pre_save_decorator_sender_test(signal, sender, instance, **kwargs): -... print "pre_save signal decorator sender,", instance - ->>> p1 = Person(first_name='John', last_name='Smith') ->>> p1.save() -pre_save signal, John Smith -pre_save signal decorator, John Smith -post_save signal, John Smith -Is created - ->>> p1.first_name = 'Tom' ->>> p1.save() -pre_save signal, Tom Smith -pre_save signal decorator, Tom Smith -post_save signal, Tom Smith -Is updated - -# Car signal (sender defined) ->>> c1 = Car(make="Volkswagon", model="Passat") ->>> c1.save() -pre_save signal, Volkswagon Passat -pre_save signal decorator, Volkswagon Passat -pre_save signal decorator sender, Volkswagon Passat -post_save signal, Volkswagon Passat -Is created - -# Calling an internal method purely so that we can trigger a "raw" save. ->>> p1.save_base(raw=True) -pre_save signal, Tom Smith -Is raw -pre_save signal decorator, Tom Smith -post_save signal, Tom Smith -Is updated -Is raw - ->>> p1.delete() -pre_delete signal, Tom Smith -instance.id is not None: True -post_delete signal, Tom Smith -instance.id is None: False - ->>> p2 = Person(first_name='James', last_name='Jones') ->>> p2.id = 99999 ->>> p2.save() -pre_save signal, James Jones -pre_save signal decorator, James Jones -post_save signal, James Jones -Is created - ->>> p2.id = 99998 ->>> p2.save() -pre_save signal, James Jones -pre_save signal decorator, James Jones -post_save signal, James Jones -Is created - ->>> p2.delete() -pre_delete signal, James Jones -instance.id is not None: True -post_delete signal, James Jones -instance.id is None: False - ->>> Person.objects.all() -[] - ->>> models.signals.post_delete.disconnect(post_delete_test) ->>> models.signals.pre_delete.disconnect(pre_delete_test) ->>> models.signals.post_save.disconnect(post_save_test) ->>> models.signals.pre_save.disconnect(pre_save_test) ->>> models.signals.pre_save.disconnect(pre_save_decorator_test) ->>> models.signals.pre_save.disconnect(pre_save_decorator_sender_test, sender=Car) - -# Check that all our signals got disconnected properly. ->>> post_signals = (len(models.signals.pre_save.receivers), -... len(models.signals.post_save.receivers), -... len(models.signals.pre_delete.receivers), -... len(models.signals.post_delete.receivers)) - ->>> pre_signals == post_signals -True - -"""} diff --git a/tests/modeltests/signals/tests.py b/tests/modeltests/signals/tests.py index 329636c306..2b71609160 100644 --- a/tests/modeltests/signals/tests.py +++ b/tests/modeltests/signals/tests.py @@ -1,6 +1,19 @@ from django.db.models import signals +from django.dispatch import receiver from django.test import TestCase -from modeltests.signals.models import Person + +from models import Person, Car + + +# #8285: signals can be any callable +class PostDeleteHandler(object): + def __init__(self, data): + self.data = data + + def __call__(self, signal, sender, instance, **kwargs): + self.data.append( + (instance, instance.id is None) + ) class MyReceiver(object): def __init__(self, param): @@ -12,6 +25,142 @@ class MyReceiver(object): signal.disconnect(receiver=self, sender=sender) class SignalTests(TestCase): + def test_basic(self): + # Save up the number of connected signals so that we can check at the + # end that all the signals we register get properly unregistered (#9989) + pre_signals = ( + len(signals.pre_save.receivers), + len(signals.post_save.receivers), + len(signals.pre_delete.receivers), + len(signals.post_delete.receivers), + ) + + data = [] + + def pre_save_test(signal, sender, instance, **kwargs): + data.append( + (instance, kwargs.get("raw", False)) + ) + signals.pre_save.connect(pre_save_test) + + def post_save_test(signal, sender, instance, **kwargs): + data.append( + (instance, kwargs.get("created"), kwargs.get("raw", False)) + ) + signals.post_save.connect(post_save_test) + + def pre_delete_test(signal, sender, instance, **kwargs): + data.append( + (instance, instance.id is None) + ) + signals.pre_delete.connect(pre_delete_test) + + post_delete_test = PostDeleteHandler(data) + signals.post_delete.connect(post_delete_test) + + # throw a decorator syntax receiver into the mix + @receiver(signals.pre_save) + def pre_save_decorator_test(signal, sender, instance, **kwargs): + data.append(instance) + + @receiver(signals.pre_save, sender=Car) + def pre_save_decorator_sender_test(signal, sender, instance, **kwargs): + data.append(instance) + + p1 = Person(first_name="John", last_name="Smith") + self.assertEqual(data, []) + p1.save() + self.assertEqual(data, [ + (p1, False), + p1, + (p1, True, False), + ]) + data[:] = [] + + p1.first_name = "Tom" + p1.save() + self.assertEqual(data, [ + (p1, False), + p1, + (p1, False, False), + ]) + data[:] = [] + + # Car signal (sender defined) + c1 = Car(make="Volkswagon", model="Passat") + c1.save() + self.assertEqual(data, [ + (c1, False), + c1, + c1, + (c1, True, False), + ]) + data[:] = [] + + # Calling an internal method purely so that we can trigger a "raw" save. + p1.save_base(raw=True) + self.assertEqual(data, [ + (p1, True), + p1, + (p1, False, True), + ]) + data[:] = [] + + p1.delete() + self.assertEqual(data, [ + (p1, False), + (p1, False), + ]) + data[:] = [] + + p2 = Person(first_name="James", last_name="Jones") + p2.id = 99999 + p2.save() + self.assertEqual(data, [ + (p2, False), + p2, + (p2, True, False), + ]) + data[:] = [] + + p2.id = 99998 + p2.save() + self.assertEqual(data, [ + (p2, False), + p2, + (p2, True, False), + ]) + data[:] = [] + + p2.delete() + self.assertEqual(data, [ + (p2, False), + (p2, False) + ]) + + self.assertQuerysetEqual( + Person.objects.all(), [ + "James Jones", + ], + unicode + ) + + signals.post_delete.disconnect(post_delete_test) + signals.pre_delete.disconnect(pre_delete_test) + signals.post_save.disconnect(post_save_test) + signals.pre_save.disconnect(pre_save_test) + signals.pre_save.disconnect(pre_save_decorator_test) + signals.pre_save.disconnect(pre_save_decorator_sender_test, sender=Car) + + # Check that all our signals got disconnected properly. + post_signals = ( + len(signals.pre_save.receivers), + len(signals.post_save.receivers), + len(signals.pre_delete.receivers), + len(signals.post_delete.receivers), + ) + self.assertEqual(pre_signals, post_signals) + def test_disconnect_in_dispatch(self): """ Test that signals that disconnect when being called don't mess future @@ -21,8 +170,7 @@ class SignalTests(TestCase): signals.post_save.connect(sender=Person, receiver=a) signals.post_save.connect(sender=Person, receiver=b) p = Person.objects.create(first_name='John', last_name='Smith') - + self.failUnless(a._run) self.failUnless(b._run) self.assertEqual(signals.post_save.receivers, []) -