From 17c097b166ea3d16d385eed5c29ae7e2844a2f09 Mon Sep 17 00:00:00 2001
From: Russell Keith-Magee <russell@keith-magee.com>
Date: Mon, 13 Sep 2010 05:29:21 +0000
Subject: [PATCH] Migrated proxy_models doctests. Thanks to Eric Florenzano.

git-svn-id: http://code.djangoproject.com/svn/django/trunk@13831 bcc190cf-cafb-0310-a4f2-bffc1f526a37
---
 tests/modeltests/proxy_models/models.py | 230 +----------------
 tests/modeltests/proxy_models/tests.py  | 314 ++++++++++++++++++++++++
 2 files changed, 315 insertions(+), 229 deletions(-)
 create mode 100644 tests/modeltests/proxy_models/tests.py

diff --git a/tests/modeltests/proxy_models/models.py b/tests/modeltests/proxy_models/models.py
index 28446b96c1..90d54d94dd 100644
--- a/tests/modeltests/proxy_models/models.py
+++ b/tests/modeltests/proxy_models/models.py
@@ -161,232 +161,4 @@ class Improvement(Issue):
 
 class ProxyImprovement(Improvement):
     class Meta:
-        proxy = True
-
-__test__ = {'API_TESTS' : """
-# The MyPerson model should be generating the same database queries as the
-# Person model (when the same manager is used in each case).
->>> from django.db import DEFAULT_DB_ALIAS
->>> MyPerson.other.all().query.get_compiler(DEFAULT_DB_ALIAS).as_sql() == Person.objects.order_by("name").query.get_compiler(DEFAULT_DB_ALIAS).as_sql()
-True
-
-# The StatusPerson models should have its own table (it's using ORM-level
-# inheritance).
->>> StatusPerson.objects.all().query.get_compiler(DEFAULT_DB_ALIAS).as_sql() == Person.objects.all().query.get_compiler(DEFAULT_DB_ALIAS).as_sql()
-False
-
-# Creating a Person makes them accessible through the MyPerson proxy.
->>> _ = Person.objects.create(name="Foo McBar")
->>> len(Person.objects.all())
-1
->>> len(MyPerson.objects.all())
-1
->>> MyPerson.objects.get(name="Foo McBar").id
-1
->>> MyPerson.objects.get(id=1).has_special_name()
-False
-
-# Person is not proxied by StatusPerson subclass, however.
->>> StatusPerson.objects.all()
-[]
-
-# A new MyPerson also shows up as a standard Person
->>> _ = MyPerson.objects.create(name="Bazza del Frob")
->>> len(MyPerson.objects.all())
-2
->>> len(Person.objects.all())
-2
-
->>> _ = LowerStatusPerson.objects.create(status="low", name="homer")
->>> LowerStatusPerson.objects.all()
-[<LowerStatusPerson: homer>]
-
-# Correct type when querying a proxy of proxy
-
->>> MyPersonProxy.objects.all()
-[<MyPersonProxy: Bazza del Frob>, <MyPersonProxy: Foo McBar>, <MyPersonProxy: homer>]
-
-# Proxy models are included in the ancestors for a model's DoesNotExist and MultipleObjectsReturned
->>> try:
-...     MyPersonProxy.objects.get(name='Zathras')
-... except Person.DoesNotExist:
-...     pass
->>> try:
-...     MyPersonProxy.objects.get(id__lt=10)
-... except Person.MultipleObjectsReturned:
-...     pass
->>> try:
-...     StatusPerson.objects.get(name='Zathras')
-... except Person.DoesNotExist:
-...     pass
->>> sp1 = StatusPerson.objects.create(name='Bazza Jr.')
->>> sp2 = StatusPerson.objects.create(name='Foo Jr.')
->>> try:
-...     StatusPerson.objects.get(id__lt=10)
-... except Person.MultipleObjectsReturned:
-...     pass
-
-# And now for some things that shouldn't work...
-#
-# All base classes must be non-abstract
->>> class NoAbstract(Abstract):
-...     class Meta:
-...         proxy = True
-Traceback (most recent call last):
-    ....
-TypeError: Abstract base class containing model fields not permitted for proxy model 'NoAbstract'.
-
-# The proxy must actually have one concrete base class
->>> class TooManyBases(Person, Abstract):
-...     class Meta:
-...         proxy = True
-Traceback (most recent call last):
-    ....
-TypeError: Abstract base class containing model fields not permitted for proxy model 'TooManyBases'.
-
->>> class NoBaseClasses(models.Model):
-...     class Meta:
-...         proxy = True
-Traceback (most recent call last):
-    ....
-TypeError: Proxy model 'NoBaseClasses' has no non-abstract model base class.
-
-
-# A proxy cannot introduce any new fields
->>> class NoNewFields(Person):
-...     newfield = models.BooleanField()
-...     class Meta:
-...         proxy = True
-Traceback (most recent call last):
-    ....
-FieldError: Proxy model 'NoNewFields' contains model fields.
-
-# Manager tests.
-
->>> Person.objects.all().delete()
->>> _ = Person.objects.create(name="fred")
->>> _ = Person.objects.create(name="wilma")
->>> _ = Person.objects.create(name="barney")
-
->>> MyPerson.objects.all()
-[<MyPerson: barney>, <MyPerson: fred>]
->>> MyPerson._default_manager.all()
-[<MyPerson: barney>, <MyPerson: fred>]
-
->>> OtherPerson.objects.all()
-[<OtherPerson: barney>, <OtherPerson: wilma>]
->>> OtherPerson.excluder.all()
-[<OtherPerson: barney>, <OtherPerson: fred>]
->>> OtherPerson._default_manager.all()
-[<OtherPerson: barney>, <OtherPerson: wilma>]
-
-# Test save signals for proxy models
->>> from django.db.models import signals
->>> def make_handler(model, event):
-...     def _handler(*args, **kwargs):
-...         print u"%s %s save" % (model, event)
-...     return _handler
->>> h1 = make_handler('MyPerson', 'pre')
->>> h2 = make_handler('MyPerson', 'post')
->>> h3 = make_handler('Person', 'pre')
->>> h4 = make_handler('Person', 'post')
->>> signals.pre_save.connect(h1, sender=MyPerson)
->>> signals.post_save.connect(h2, sender=MyPerson)
->>> signals.pre_save.connect(h3, sender=Person)
->>> signals.post_save.connect(h4, sender=Person)
->>> dino = MyPerson.objects.create(name=u"dino")
-MyPerson pre save
-MyPerson post save
-
-# Test save signals for proxy proxy models
->>> h5 = make_handler('MyPersonProxy', 'pre')
->>> h6 = make_handler('MyPersonProxy', 'post')
->>> signals.pre_save.connect(h5, sender=MyPersonProxy)
->>> signals.post_save.connect(h6, sender=MyPersonProxy)
->>> dino = MyPersonProxy.objects.create(name=u"pebbles")
-MyPersonProxy pre save
-MyPersonProxy post save
-
->>> signals.pre_save.disconnect(h1, sender=MyPerson)
->>> signals.post_save.disconnect(h2, sender=MyPerson)
->>> signals.pre_save.disconnect(h3, sender=Person)
->>> signals.post_save.disconnect(h4, sender=Person)
->>> signals.pre_save.disconnect(h5, sender=MyPersonProxy)
->>> signals.post_save.disconnect(h6, sender=MyPersonProxy)
-
-# A proxy has the same content type as the model it is proxying for (at the
-# storage level, it is meant to be essentially indistinguishable).
->>> ctype = ContentType.objects.get_for_model
->>> ctype(Person) is ctype(OtherPerson)
-True
-
->>> MyPersonProxy.objects.all()
-[<MyPersonProxy: barney>, <MyPersonProxy: dino>, <MyPersonProxy: fred>, <MyPersonProxy: pebbles>]
-
->>> u = User.objects.create(name='Bruce')
->>> User.objects.all()
-[<User: Bruce>]
->>> UserProxy.objects.all()
-[<UserProxy: Bruce>]
->>> UserProxyProxy.objects.all()
-[<UserProxyProxy: Bruce>]
-
-# Proxy objects can be deleted
->>> u2 = UserProxy.objects.create(name='George')
->>> UserProxy.objects.all()
-[<UserProxy: Bruce>, <UserProxy: George>]
->>> u2.delete()
->>> UserProxy.objects.all()
-[<UserProxy: Bruce>]
-
-
-# We can still use `select_related()` to include related models in our querysets.
->>> country = Country.objects.create(name='Australia')
->>> state = State.objects.create(name='New South Wales', country=country)
-
->>> State.objects.select_related()
-[<State: New South Wales>]
->>> StateProxy.objects.select_related()
-[<StateProxy: New South Wales>]
->>> StateProxy.objects.get(name='New South Wales')
-<StateProxy: New South Wales>
->>> StateProxy.objects.select_related().get(name='New South Wales')
-<StateProxy: New South Wales>
-
->>> contributor = TrackerUser.objects.create(name='Contributor',status='contrib')
->>> someone = BaseUser.objects.create(name='Someone')
->>> _ = Bug.objects.create(summary='fix this', version='1.1beta',
-...                        assignee=contributor, reporter=someone)
->>> pcontributor = ProxyTrackerUser.objects.create(name='OtherContributor',
-...                                                status='proxy')
->>> _ = Improvement.objects.create(summary='improve that', version='1.1beta',
-...                                assignee=contributor, reporter=pcontributor,
-...                                associated_bug=ProxyProxyBug.objects.all()[0])
-
-# Related field filter on proxy
->>> ProxyBug.objects.get(version__icontains='beta')
-<ProxyBug: ProxyBug:fix this>
-
-# Select related + filter on proxy
->>> ProxyBug.objects.select_related().get(version__icontains='beta')
-<ProxyBug: ProxyBug:fix this>
-
-# Proxy of proxy, select_related + filter
->>> ProxyProxyBug.objects.select_related().get(version__icontains='beta')
-<ProxyProxyBug: ProxyProxyBug:fix this>
-
-# Select related + filter on a related proxy field
->>> ProxyImprovement.objects.select_related().get(reporter__name__icontains='butor')
-<ProxyImprovement: ProxyImprovement:improve that>
-
-# Select related + filter on a related proxy of proxy field
->>> ProxyImprovement.objects.select_related().get(associated_bug__summary__icontains='fix')
-<ProxyImprovement: ProxyImprovement:improve that>
-
-Proxy models can be loaded from fixtures (Regression for #11194)
->>> from django.core import management
->>> management.call_command('loaddata', 'mypeople.json', verbosity=0)
->>> MyPerson.objects.get(pk=100)
-<MyPerson: Elvis Presley>
-
-"""}
+        proxy = True
\ No newline at end of file
diff --git a/tests/modeltests/proxy_models/tests.py b/tests/modeltests/proxy_models/tests.py
new file mode 100644
index 0000000000..346a2a3296
--- /dev/null
+++ b/tests/modeltests/proxy_models/tests.py
@@ -0,0 +1,314 @@
+from django.test import TestCase
+from django.db import models, DEFAULT_DB_ALIAS
+from django.db.models import signals
+from django.core import management
+from django.core.exceptions import FieldError
+
+from django.contrib.contenttypes.models import ContentType
+
+from models import MyPerson, Person, StatusPerson, LowerStatusPerson
+from models import MyPersonProxy, Abstract, OtherPerson, User, UserProxy
+from models import UserProxyProxy, Country, State, StateProxy, TrackerUser
+from models import BaseUser, Bug, ProxyTrackerUser, Improvement, ProxyProxyBug
+from models import ProxyBug, ProxyImprovement
+
+class ProxyModelTests(TestCase):
+    def test_same_manager_queries(self):
+        """
+        The MyPerson model should be generating the same database queries as
+        the Person model (when the same manager is used in each case).
+        """
+        my_person_sql = MyPerson.other.all().query.get_compiler(
+            DEFAULT_DB_ALIAS).as_sql()
+        person_sql = Person.objects.order_by("name").query.get_compiler(
+            DEFAULT_DB_ALIAS).as_sql()
+        self.assertEqual(my_person_sql, person_sql)
+
+    def test_inheretance_new_table(self):
+        """
+        The StatusPerson models should have its own table (it's using ORM-level
+        inheritance).
+        """
+        sp_sql = StatusPerson.objects.all().query.get_compiler(
+            DEFAULT_DB_ALIAS).as_sql()
+        p_sql = Person.objects.all().query.get_compiler(
+            DEFAULT_DB_ALIAS).as_sql()
+        self.assertNotEqual(sp_sql, p_sql)
+
+    def test_basic_proxy(self):
+        """
+        Creating a Person makes them accessible through the MyPerson proxy.
+        """
+        Person.objects.create(name="Foo McBar")
+        self.assertEqual(len(Person.objects.all()), 1)
+        self.assertEqual(len(MyPerson.objects.all()), 1)
+        self.assertEqual(MyPerson.objects.get(name="Foo McBar").id, 1)
+        self.assertFalse(MyPerson.objects.get(id=1).has_special_name())
+
+    def test_no_proxy(self):
+        """
+        Person is not proxied by StatusPerson subclass.
+        """
+        Person.objects.create(name="Foo McBar")
+        self.assertEqual(list(StatusPerson.objects.all()), [])
+
+    def test_basic_proxy_reverse(self):
+        """
+        A new MyPerson also shows up as a standard Person.
+        """
+        MyPerson.objects.create(name="Bazza del Frob")
+        self.assertEqual(len(MyPerson.objects.all()), 1)
+        self.assertEqual(len(Person.objects.all()), 1)
+
+        LowerStatusPerson.objects.create(status="low", name="homer")
+        lsps = [lsp.name for lsp in LowerStatusPerson.objects.all()]
+        self.assertEqual(lsps, ["homer"])
+
+    def test_correct_type_proxy_of_proxy(self):
+        """
+        Correct type when querying a proxy of proxy
+        """
+        Person.objects.create(name="Foo McBar")
+        MyPerson.objects.create(name="Bazza del Frob")
+        LowerStatusPerson.objects.create(status="low", name="homer")
+        pp = sorted([mpp.name for mpp in MyPersonProxy.objects.all()])
+        self.assertEqual(pp, ['Bazza del Frob', 'Foo McBar', 'homer'])
+
+    def test_proxy_included_in_ancestors(self):
+        """
+        Proxy models are included in the ancestors for a model's DoesNotExist
+        and MultipleObjectsReturned
+        """
+        Person.objects.create(name="Foo McBar")
+        MyPerson.objects.create(name="Bazza del Frob")
+        LowerStatusPerson.objects.create(status="low", name="homer")
+        max_id = Person.objects.aggregate(max_id=models.Max('id'))['max_id']
+
+        self.assertRaises(Person.DoesNotExist,
+            MyPersonProxy.objects.get,
+            name='Zathras'
+        )
+        self.assertRaises(Person.MultipleObjectsReturned,
+            MyPersonProxy.objects.get,
+            id__lt=max_id+1
+        )
+        self.assertRaises(Person.DoesNotExist,
+            StatusPerson.objects.get,
+            name='Zathras'
+        )
+
+        sp1 = StatusPerson.objects.create(name='Bazza Jr.')
+        sp2 = StatusPerson.objects.create(name='Foo Jr.')
+        max_id = Person.objects.aggregate(max_id=models.Max('id'))['max_id']
+
+        self.assertRaises(Person.MultipleObjectsReturned,
+            StatusPerson.objects.get,
+            id__lt=max_id+1
+        )
+
+    def test_abc(self):
+        """
+        All base classes must be non-abstract
+        """
+        def build_abc():
+            class NoAbstract(Abstract):
+                class Meta:
+                    proxy = True
+        self.assertRaises(TypeError, build_abc)
+
+    def test_no_cbc(self):
+        """
+        The proxy must actually have one concrete base class
+        """
+        def build_no_cbc():
+            class TooManyBases(Person, Abstract):
+                class Meta:
+                    proxy = True
+        self.assertRaises(TypeError, build_no_cbc)
+
+    def test_no_base_classes(self):
+        def build_no_base_classes():
+            class NoBaseClasses(models.Model):
+                class Meta:
+                    proxy = True
+        self.assertRaises(TypeError, build_no_base_classes)
+
+    def test_new_fields(self):
+        def build_new_fields():
+            class NoNewFields(Person):
+                newfield = models.BooleanField()
+                class Meta:
+                    proxy = True
+        self.assertRaises(FieldError, build_new_fields)
+
+    def test_myperson_manager(self):
+        Person.objects.create(name="fred")
+        Person.objects.create(name="wilma")
+        Person.objects.create(name="barney")
+
+        resp = [p.name for p in MyPerson.objects.all()]
+        self.assertEqual(resp, ['barney', 'fred'])
+
+        resp = [p.name for p in MyPerson._default_manager.all()]
+        self.assertEqual(resp, ['barney', 'fred'])
+
+    def test_otherperson_manager(self):
+        Person.objects.create(name="fred")
+        Person.objects.create(name="wilma")
+        Person.objects.create(name="barney")
+
+        resp = [p.name for p in OtherPerson.objects.all()]
+        self.assertEqual(resp, ['barney', 'wilma'])
+
+        resp = [p.name for p in OtherPerson.excluder.all()]
+        self.assertEqual(resp, ['barney', 'fred'])
+
+        resp = [p.name for p in OtherPerson._default_manager.all()]
+        self.assertEqual(resp, ['barney', 'wilma'])
+
+    def test_proxy_model_signals(self):
+        """
+        Test save signals for proxy models
+        """
+        output = []
+
+        def make_handler(model, event):
+            def _handler(*args, **kwargs):
+                output.append('%s %s save' % (model, event))
+            return _handler
+
+        h1 = make_handler('MyPerson', 'pre')
+        h2 = make_handler('MyPerson', 'post')
+        h3 = make_handler('Person', 'pre')
+        h4 = make_handler('Person', 'post')
+
+        signals.pre_save.connect(h1, sender=MyPerson)
+        signals.post_save.connect(h2, sender=MyPerson)
+        signals.pre_save.connect(h3, sender=Person)
+        signals.post_save.connect(h4, sender=Person)
+
+        dino = MyPerson.objects.create(name=u"dino")
+        self.assertEqual(output, [
+            'MyPerson pre save',
+            'MyPerson post save'
+        ])
+
+        output = []
+
+        h5 = make_handler('MyPersonProxy', 'pre')
+        h6 = make_handler('MyPersonProxy', 'post')
+
+        signals.pre_save.connect(h5, sender=MyPersonProxy)
+        signals.post_save.connect(h6, sender=MyPersonProxy)
+
+        dino = MyPersonProxy.objects.create(name=u"pebbles")
+
+        self.assertEqual(output, [
+            'MyPersonProxy pre save',
+            'MyPersonProxy post save'
+        ])
+
+        signals.pre_save.disconnect(h1, sender=MyPerson)
+        signals.post_save.disconnect(h2, sender=MyPerson)
+        signals.pre_save.disconnect(h3, sender=Person)
+        signals.post_save.disconnect(h4, sender=Person)
+        signals.pre_save.disconnect(h5, sender=MyPersonProxy)
+        signals.post_save.disconnect(h6, sender=MyPersonProxy)
+
+    def test_content_type(self):
+        ctype = ContentType.objects.get_for_model
+        self.assertTrue(ctype(Person) is ctype(OtherPerson))
+
+    def test_user_userproxy_userproxyproxy(self):
+        User.objects.create(name='Bruce')
+
+        resp = [u.name for u in User.objects.all()]
+        self.assertEqual(resp, ['Bruce'])
+
+        resp = [u.name for u in UserProxy.objects.all()]
+        self.assertEqual(resp, ['Bruce'])
+
+        resp = [u.name for u in UserProxyProxy.objects.all()]
+        self.assertEqual(resp, ['Bruce'])
+
+    def test_proxy_delete(self):
+        """
+        Proxy objects can be deleted
+        """
+        User.objects.create(name='Bruce')
+        u2 = UserProxy.objects.create(name='George')
+
+        resp = [u.name for u in UserProxy.objects.all()]
+        self.assertEqual(resp, ['Bruce', 'George'])
+
+        u2.delete()
+
+        resp = [u.name for u in UserProxy.objects.all()]
+        self.assertEqual(resp, ['Bruce'])
+
+    def test_select_related(self):
+        """
+        We can still use `select_related()` to include related models in our
+        querysets.
+        """
+        country = Country.objects.create(name='Australia')
+        state = State.objects.create(name='New South Wales', country=country)
+
+        resp = [s.name for s in State.objects.select_related()]
+        self.assertEqual(resp, ['New South Wales'])
+
+        resp = [s.name for s in StateProxy.objects.select_related()]
+        self.assertEqual(resp, ['New South Wales'])
+
+        self.assertEqual(StateProxy.objects.get(name='New South Wales').name,
+            'New South Wales')
+
+        resp = StateProxy.objects.select_related().get(name='New South Wales')
+        self.assertEqual(resp.name, 'New South Wales')
+
+    def test_proxy_bug(self):
+        contributor = TrackerUser.objects.create(name='Contributor',
+            status='contrib')
+        someone = BaseUser.objects.create(name='Someone')
+        Bug.objects.create(summary='fix this', version='1.1beta',
+            assignee=contributor, reporter=someone)
+        pcontributor = ProxyTrackerUser.objects.create(name='OtherContributor',
+            status='proxy')
+        Improvement.objects.create(summary='improve that', version='1.1beta',
+            assignee=contributor, reporter=pcontributor,
+            associated_bug=ProxyProxyBug.objects.all()[0])
+
+        # Related field filter on proxy
+        resp = ProxyBug.objects.get(version__icontains='beta')
+        self.assertEqual(repr(resp), '<ProxyBug: ProxyBug:fix this>')
+
+        # Select related + filter on proxy
+        resp = ProxyBug.objects.select_related().get(version__icontains='beta')
+        self.assertEqual(repr(resp), '<ProxyBug: ProxyBug:fix this>')
+
+        # Proxy of proxy, select_related + filter
+        resp = ProxyProxyBug.objects.select_related().get(
+            version__icontains='beta'
+        )
+        self.assertEqual(repr(resp), '<ProxyProxyBug: ProxyProxyBug:fix this>')
+
+        # Select related + filter on a related proxy field
+        resp = ProxyImprovement.objects.select_related().get(
+            reporter__name__icontains='butor'
+        )
+        self.assertEqual(repr(resp),
+            '<ProxyImprovement: ProxyImprovement:improve that>'
+        )
+
+        # Select related + filter on a related proxy of proxy field
+        resp = ProxyImprovement.objects.select_related().get(
+            associated_bug__summary__icontains='fix'
+        )
+        self.assertEqual(repr(resp),
+            '<ProxyImprovement: ProxyImprovement:improve that>'
+        )
+
+    def test_proxy_load_from_fixture(self):
+        management.call_command('loaddata', 'mypeople.json', verbosity=0, commit=False)
+        p = MyPerson.objects.get(pk=100)
+        self.assertEqual(p.name, 'Elvis Presley')