From 16089ba1352cd80b33b23e1bddb4d4ea4ed5c18a Mon Sep 17 00:00:00 2001 From: Alex Gaynor Date: Sat, 9 Oct 2010 21:55:15 +0000 Subject: [PATCH] Converted defer_regress tests from doctests to unittests. We have always been at war with doctests. git-svn-id: http://code.djangoproject.com/svn/django/trunk@14094 bcc190cf-cafb-0310-a4f2-bffc1f526a37 --- tests/regressiontests/defer_regress/models.py | 112 ------------- tests/regressiontests/defer_regress/tests.py | 157 +++++++++++++++++- 2 files changed, 156 insertions(+), 113 deletions(-) diff --git a/tests/regressiontests/defer_regress/models.py b/tests/regressiontests/defer_regress/models.py index 8b42165891..8db8c29960 100644 --- a/tests/regressiontests/defer_regress/models.py +++ b/tests/regressiontests/defer_regress/models.py @@ -34,115 +34,3 @@ class Leaf(models.Model): class ResolveThis(models.Model): num = models.FloatField() name = models.CharField(max_length=16) - -__test__ = {"regression_tests": """ -Deferred fields should really be deferred and not accidentally use the field's -default value just because they aren't passed to __init__. - ->>> settings.DEBUG = True ->>> _ = Item.objects.create(name="first", value=42) ->>> obj = Item.objects.only("name", "other_value").get(name="first") - -# Accessing "name" doesn't trigger a new database query. Accessing "value" or -# "text" should. ->>> num = len(connection.queries) ->>> obj.name -u"first" ->>> obj.other_value -0 ->>> len(connection.queries) == num -True ->>> obj.value -42 ->>> len(connection.queries) == num + 1 # Effect of values lookup. -True ->>> obj.text -u"xyzzy" ->>> len(connection.queries) == num + 2 # Effect of text lookup. -True ->>> obj.text -u"xyzzy" ->>> len(connection.queries) == num + 2 -True - ->>> settings.DEBUG = False - -Regression test for #10695. Make sure different instances don't inadvertently -share data in the deferred descriptor objects. - ->>> i = Item.objects.create(name="no I'm first", value=37) ->>> items = Item.objects.only('value').order_by('-value') ->>> items[0].name -u'first' ->>> items[1].name -u"no I'm first" - ->>> _ = RelatedItem.objects.create(item=i) ->>> r = RelatedItem.objects.defer('item').get() ->>> r.item_id == i.id -True ->>> r.item == i -True - -Some further checks for select_related() and inherited model behaviour -(regression for #10710). - ->>> c1 = Child.objects.create(name="c1", value=42) ->>> c2 = Child.objects.create(name="c2", value=37) ->>> obj = Leaf.objects.create(name="l1", child=c1, second_child=c2) - ->>> obj = Leaf.objects.only("name", "child").select_related()[0] ->>> obj.child.name -u'c1' ->>> Leaf.objects.select_related().only("child__name", "second_child__name") -[] - -Models instances with deferred fields should still return the same content -types as their non-deferred versions (bug #10738). ->>> ctype = ContentType.objects.get_for_model ->>> c1 = ctype(Item.objects.all()[0]) ->>> c2 = ctype(Item.objects.defer("name")[0]) ->>> c3 = ctype(Item.objects.only("name")[0]) ->>> c1 is c2 is c3 -True - -# Regression for #10733 - only() can be used on a model with two foreign keys. ->>> results = Leaf.objects.all().only('name', 'child', 'second_child').select_related() ->>> results[0].child.name -u'c1' ->>> results[0].second_child.name -u'c2' - ->>> results = Leaf.objects.all().only('name', 'child', 'second_child', 'child__name', 'second_child__name').select_related() ->>> results[0].child.name -u'c1' ->>> results[0].second_child.name -u'c2' - -# Test for #12163 - Pickling error saving session with unsaved model instances. ->>> from django.contrib.sessions.backends.db import SessionStore ->>> SESSION_KEY = '2b1189a188b44ad18c35e1baac6ceead' ->>> item = Item() ->>> item._deferred -False ->>> s = SessionStore(SESSION_KEY) ->>> s.clear() ->>> s['item'] = item ->>> s.save() ->>> s = SessionStore(SESSION_KEY) ->>> s.modified = True ->>> s.save() ->>> i2 = s['item'] ->>> i2._deferred # Item must still be non-deferred -False - -# Regression for #11936 - loading.get_models should not return deferred models by default. ->>> from django.db.models.loading import get_models ->>> sorted(get_models(models.get_app('defer_regress')), key=lambda obj: obj._meta.object_name) -[, , , , ] - ->>> sorted(get_models(models.get_app('defer_regress'), include_deferred=True), key=lambda obj: obj._meta.object_name) -[, , , , , , , , , , , , , , , , , ] -""" -} - diff --git a/tests/regressiontests/defer_regress/tests.py b/tests/regressiontests/defer_regress/tests.py index 860c7f8e31..affb0e2405 100644 --- a/tests/regressiontests/defer_regress/tests.py +++ b/tests/regressiontests/defer_regress/tests.py @@ -1,7 +1,162 @@ +from operator import attrgetter + +from django.conf import settings +from django.contrib.contenttypes.models import ContentType +from django.contrib.sessions.backends.db import SessionStore +from django.db import connection +from django.db.models.loading import cache from django.test import TestCase -from models import ResolveThis + +from models import ResolveThis, Item, RelatedItem, Child, Leaf + class DeferRegressionTest(TestCase): + def assert_num_queries(self, n, func, *args, **kwargs): + old_DEBUG = settings.DEBUG + settings.DEBUG = True + starting_queries = len(connection.queries) + try: + func(*args, **kwargs) + finally: + settings.DEBUG = old_DEBUG + self.assertEqual(starting_queries + n, len(connection.queries)) + + + def test_basic(self): + # Deferred fields should really be deferred and not accidentally use + # the field's default value just because they aren't passed to __init__ + + Item.objects.create(name="first", value=42) + obj = Item.objects.only("name", "other_value").get(name="first") + # Accessing "name" doesn't trigger a new database query. Accessing + # "value" or "text" should. + def test(): + self.assertEqual(obj.name, "first") + self.assertEqual(obj.other_value, 0) + self.assert_num_queries(0, test) + + def test(): + self.assertEqual(obj.value, 42) + self.assert_num_queries(1, test) + + def test(): + self.assertEqual(obj.text, "xyzzy") + self.assert_num_queries(1, test) + + def test(): + self.assertEqual(obj.text, "xyzzy") + self.assert_num_queries(0, test) + + # Regression test for #10695. Make sure different instances don't + # inadvertently share data in the deferred descriptor objects. + i = Item.objects.create(name="no I'm first", value=37) + items = Item.objects.only("value").order_by("-value") + self.assertEqual(items[0].name, "first") + self.assertEqual(items[1].name, "no I'm first") + + RelatedItem.objects.create(item=i) + r = RelatedItem.objects.defer("item").get() + self.assertEqual(r.item_id, i.id) + self.assertEqual(r.item, i) + + # Some further checks for select_related() and inherited model + # behaviour (regression for #10710). + c1 = Child.objects.create(name="c1", value=42) + c2 = Child.objects.create(name="c2", value=37) + Leaf.objects.create(name="l1", child=c1, second_child=c2) + + obj = Leaf.objects.only("name", "child").select_related()[0] + self.assertEqual(obj.child.name, "c1") + + self.assertQuerysetEqual( + Leaf.objects.select_related().only("child__name", "second_child__name"), [ + "l1", + ], + attrgetter("name") + ) + + # Models instances with deferred fields should still return the same + # content types as their non-deferred versions (bug #10738). + ctype = ContentType.objects.get_for_model + c1 = ctype(Item.objects.all()[0]) + c2 = ctype(Item.objects.defer("name")[0]) + c3 = ctype(Item.objects.only("name")[0]) + self.assertTrue(c1 is c2 is c3) + + # Regression for #10733 - only() can be used on a model with two + # foreign keys. + results = Leaf.objects.only("name", "child", "second_child").select_related() + self.assertEqual(results[0].child.name, "c1") + self.assertEqual(results[0].second_child.name, "c2") + + results = Leaf.objects.only("name", "child", "second_child", "child__name", "second_child__name").select_related() + self.assertEqual(results[0].child.name, "c1") + self.assertEqual(results[0].second_child.name, "c2") + + # Test for #12163 - Pickling error saving session with unsaved model + # instances. + SESSION_KEY = '2b1189a188b44ad18c35e1baac6ceead' + + item = Item() + item._deferred = False + s = SessionStore(SESSION_KEY) + s.clear() + s["item"] = item + s.save() + + s = SessionStore(SESSION_KEY) + s.modified = True + s.save() + + i2 = s["item"] + self.assertFalse(i2._deferred) + + # Regression for #11936 - loading.get_models should not return deferred + # models by default. + klasses = sorted( + cache.get_models(cache.get_app("defer_regress")), + key=lambda klass: klass.__name__ + ) + self.assertEqual( + klasses, [ + Child, + Item, + Leaf, + RelatedItem, + ResolveThis, + ] + ) + + klasses = sorted( + map( + attrgetter("__name__"), + cache.get_models( + cache.get_app("defer_regress"), include_deferred=True + ), + ) + ) + self.assertEqual( + klasses, [ + "Child", + "Child_Deferred_value", + "Item", + "Item_Deferred_name", + "Item_Deferred_name_other_value_text", + "Item_Deferred_name_other_value_value", + "Item_Deferred_other_value_text_value", + "Item_Deferred_text_value", + "Leaf", + "Leaf_Deferred_child_id_second_child_id_value", + "Leaf_Deferred_name_value", + "Leaf_Deferred_second_child_value", + "Leaf_Deferred_value", + "RelatedItem", + "RelatedItem_Deferred_", + "RelatedItem_Deferred_item_id", + "ResolveThis", + ] + ) + def test_resolve_columns(self): rt = ResolveThis.objects.create(num=5.0, name='Foobar') qs = ResolveThis.objects.defer('num')