diff options
author | Loic Bistuer <loic.bistuer@sixmedia.com> | 2013-11-19 00:27:09 +0700 |
---|---|---|
committer | Simon Charette <charette.s@gmail.com> | 2013-11-18 12:42:51 -0500 |
commit | 058e4340640fb229a822c4313a710bd59419bd7a (patch) | |
tree | 35ff7666a004610b11d90ed68594772233c0da03 /tests/signals | |
parent | a0f3eeccf3d5a90f9914bfe20b15df05673ea59d (diff) | |
download | django-058e4340640fb229a822c4313a710bd59419bd7a.tar.gz |
Merged the signals and signals_regress test packages.
This patch also made the tests less likely to pollute the global state
in case of failure.
Diffstat (limited to 'tests/signals')
-rw-r--r-- | tests/signals/models.py | 17 | ||||
-rw-r--r-- | tests/signals/tests.py | 314 |
2 files changed, 204 insertions, 127 deletions
diff --git a/tests/signals/models.py b/tests/signals/models.py index 765230a44e..2f76343ecf 100644 --- a/tests/signals/models.py +++ b/tests/signals/models.py @@ -23,3 +23,20 @@ class Car(models.Model): def __str__(self): return "%s %s" % (self.make, self.model) + + +@python_2_unicode_compatible +class Author(models.Model): + name = models.CharField(max_length=20) + + def __str__(self): + return self.name + + +@python_2_unicode_compatible +class Book(models.Model): + name = models.CharField(max_length=20) + authors = models.ManyToManyField(Author) + + def __str__(self): + return self.name diff --git a/tests/signals/tests.py b/tests/signals/tests.py index 1eb2ffb4a3..bb23cdbee4 100644 --- a/tests/signals/tests.py +++ b/tests/signals/tests.py @@ -5,173 +5,233 @@ from django.dispatch import receiver from django.test import TestCase from django.utils import six -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): - self.param = param - self._run = False - - def __call__(self, signal, sender, **kwargs): - self._run = True - signal.disconnect(receiver=self, sender=sender) +from .models import Author, Book, Car, Person class SignalTests(TestCase): - def test_basic(self): + + def setUp(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 = ( + self.pre_signals = ( len(signals.pre_save.receivers), len(signals.post_save.receivers), len(signals.pre_delete.receivers), len(signals.post_delete.receivers), ) + def tearDown(self): + # 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(self.pre_signals, post_signals) + + def test_save_signals(self): data = [] - def pre_save_test(signal, sender, instance, **kwargs): + def pre_save_handler(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): + def post_save_handler(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): + signals.pre_save.connect(pre_save_handler) + signals.post_save.connect(post_save_handler) + try: + p1 = Person.objects.create(first_name="John", last_name="Smith") + + self.assertEqual(data, [ + (p1, False), + (p1, True, False), + ]) + data[:] = [] + + p1.first_name = "Tom" + p1.save() + self.assertEqual(data, [ + (p1, False), + (p1, False, 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, False, True), + ]) + data[:] = [] + + p2 = Person(first_name="James", last_name="Jones") + p2.id = 99999 + p2.save() + self.assertEqual(data, [ + (p2, False), + (p2, True, False), + ]) + data[:] = [] + p2.id = 99998 + p2.save() + self.assertEqual(data, [ + (p2, False), + (p2, True, False), + ]) + finally: + signals.post_delete.disconnect(pre_save_handler) + signals.pre_delete.disconnect(post_save_handler) + + def test_delete_signals(self): + data = [] + + def pre_delete_handler(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) + # #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) + ) + post_delete_handler = PostDeleteHandler(data) + + signals.pre_delete.connect(pre_delete_handler) + signals.post_delete.connect(post_delete_handler) + try: + p1 = Person.objects.create(first_name="John", last_name="Smith") + p1.delete() + self.assertEqual(data, [ + (p1, False), + (p1, False), + ]) + data[:] = [] + + p2 = Person(first_name="James", last_name="Jones") + p2.id = 99999 + p2.save() + p2.id = 99998 + p2.save() + p2.delete() + self.assertEqual(data, [ + (p2, False), + (p2, False) + ]) + data[:] = [] + + self.assertQuerysetEqual( + Person.objects.all(), [ + "James Jones", + ], + six.text_type + ) + finally: + signals.post_delete.disconnect(pre_delete_handler) + signals.pre_delete.disconnect(post_delete_handler) + + def test_decorators(self): + data = [] - # throw a decorator syntax receiver into the mix @receiver(signals.pre_save) - def pre_save_decorator_test(signal, sender, instance, **kwargs): + def decorated_handler(signal, sender, instance, **kwargs): data.append(instance) @receiver(signals.pre_save, sender=Car) - def pre_save_decorator_sender_test(signal, sender, instance, **kwargs): + def decorated_handler_with_sender_arg(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", - ], - six.text_type - ) + try: + c1 = Car.objects.create(make="Volkswagon", model="Passat") + self.assertEqual(data, [c1, c1]) + finally: + signals.post_delete.disconnect(decorated_handler) + signals.pre_delete.disconnect(decorated_handler_with_sender_arg, sender=Car) - 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) + def test_save_and_delete_signals_with_m2m(self): + data = [] - # 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 pre_save_handler(signal, sender, instance, **kwargs): + data.append('pre_save signal, %s' % instance) + if kwargs.get('raw'): + data.append('Is raw') + + def post_save_handler(signal, sender, instance, **kwargs): + data.append('post_save signal, %s' % instance) + if 'created' in kwargs: + if kwargs['created']: + data.append('Is created') + else: + data.append('Is updated') + if kwargs.get('raw'): + data.append('Is raw') + + def pre_delete_handler(signal, sender, instance, **kwargs): + data.append('pre_save signal, %s' % instance) + data.append('instance.id is not None: %s' % (instance.id is not None)) + + def post_delete_handler(signal, sender, instance, **kwargs): + data.append('post_delete signal, %s' % instance) + data.append('instance.id is not None: %s' % (instance.id is not None)) + + signals.pre_save.connect(pre_save_handler) + signals.post_save.connect(post_save_handler) + signals.pre_delete.connect(pre_delete_handler) + signals.post_delete.connect(post_delete_handler) + try: + a1 = Author.objects.create(name='Neal Stephenson') + self.assertEqual(data, [ + "pre_save signal, Neal Stephenson", + "post_save signal, Neal Stephenson", + "Is created" + ]) + data[:] = [] + + b1 = Book.objects.create(name='Snow Crash') + self.assertEqual(data, [ + "pre_save signal, Snow Crash", + "post_save signal, Snow Crash", + "Is created" + ]) + data[:] = [] + + # Assigning and removing to/from m2m shouldn't generate an m2m signal. + b1.authors = [a1] + self.assertEqual(data, []) + b1.authors = [] + self.assertEqual(data, []) + finally: + signals.post_delete.disconnect(pre_save_handler) + signals.pre_delete.disconnect(post_save_handler) + signals.post_save.disconnect(pre_delete_handler) + signals.pre_save.disconnect(post_delete_handler) def test_disconnect_in_dispatch(self): """ Test that signals that disconnect when being called don't mess future dispatching. """ - a, b = MyReceiver(1), MyReceiver(2) + + class Handler(object): + def __init__(self, param): + self.param = param + self._run = False + + def __call__(self, signal, sender, **kwargs): + self._run = True + signal.disconnect(receiver=self, sender=sender) + + a, b = Handler(1), Handler(2) signals.post_save.connect(sender=Person, receiver=a) signals.post_save.connect(sender=Person, receiver=b) Person.objects.create(first_name='John', last_name='Smith') |