Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse files

[1.1.X] Fixed #12060 - equality tests between User and SimpleLazyObje…

…ct-wrapped User failed.

  
Also added more tests for SimpleLazyObject
  
Thanks to ericholscher for report.

Backport of r11637 from trunk


git-svn-id: http://code.djangoproject.com/svn/django/branches/releases/1.1.X@11638 bcc190cf-cafb-0310-a4f2-bffc1f526a37
  • Loading branch information...
commit aaa9ccfe141f772baa8e08a7815f975e1ab29326 1 parent c1b3808
Luke Plant spookylukey authored
23 django/utils/functional.py
View
@@ -312,14 +312,35 @@ def __str__(self):
if self._wrapped is None: self._setup()
return str(self._wrapped)
+ def __unicode__(self):
+ if self._wrapped is None: self._setup()
+ return unicode(self._wrapped)
+
def __deepcopy__(self, memo):
if self._wrapped is None:
- result = self.__class__(self._setupfunc)
+ # We have to use SimpleLazyObject, not self.__class__, because the
+ # latter is proxied.
+ result = SimpleLazyObject(self._setupfunc)
memo[id(self)] = result
return result
else:
import copy
return copy.deepcopy(self._wrapped, memo)
+ # Need to pretend to be the wrapped class, for the sake of objects that care
+ # about this (especially in equality tests)
+ def __get_class(self):
+ if self._wrapped is None: self._setup()
+ return self._wrapped.__class__
+ __class__ = property(__get_class)
+
+ def __eq__(self, other):
+ if self._wrapped is None: self._setup()
+ return self._wrapped == other
+
+ def __hash__(self):
+ if self._wrapped is None: self._setup()
+ return hash(self._wrapped)
+
def _setup(self):
self._wrapped = self._setupfunc()
14 tests/regressiontests/context_processors/tests.py
View
@@ -3,7 +3,7 @@
"""
from django.conf import settings
-from django.contrib.auth.models import Group
+from django.contrib.auth import authenticate
from django.db.models import Q
from django.test import TestCase
from django.template import Template
@@ -74,9 +74,13 @@ def test_message_attrs(self):
def test_user_attrs(self):
"""
- Test that ContextLazyObject wraps objects properly
+ Test that the lazy objects returned behave just like the wrapped objects.
"""
+ # These are 'functional' level tests for common use cases. Direct
+ # testing of the implementation (SimpleLazyObject) is in the 'utils'
+ # tests.
self.client.login(username='super', password='secret')
+ user = authenticate(username='super', password='secret')
response = self.client.get('/auth_processor_user/')
self.assertContains(response, "unicode: super")
self.assertContains(response, "id: 100")
@@ -100,3 +104,9 @@ def test_user_attrs(self):
# calling a Python object' in <type 'exceptions.AttributeError'>
# ignored"
query = Q(user=response.context['user']) & Q(someflag=True)
+
+ # Tests for user equality. This is hard because User defines
+ # equality in a non-duck-typing way
+ # See bug #12060
+ self.assertEqual(response.context['user'], user)
+ self.assertEqual(user, response.context['user'])
75 tests/regressiontests/utils/tests.py
View
@@ -5,6 +5,7 @@
from unittest import TestCase
from django.utils import html, checksums
+from django.utils.functional import SimpleLazyObject
import timesince
import datastructures
@@ -161,6 +162,80 @@ def test_luhn(self):
for value, output in items:
self.check_output(f, value, output)
+class _ComplexObject(object):
+ def __init__(self, name):
+ self.name = name
+
+ def __eq__(self, other):
+ return self.name == other.name
+
+ def __hash__(self):
+ return hash(self.name)
+
+ def __str__(self):
+ return "I am _ComplexObject(%r)" % self.name
+
+ def __unicode__(self):
+ return unicode(self.name)
+
+ def __repr__(self):
+ return "_ComplexObject(%r)" % self.name
+
+complex_object = lambda: _ComplexObject("joe")
+
+class TestUtilsSimpleLazyObject(TestCase):
+ """
+ Tests for SimpleLazyObject
+ """
+ # Note that concrete use cases for SimpleLazyObject are also found in the
+ # auth context processor tests (unless the implementation of that function
+ # is changed).
+
+ def test_equality(self):
+ self.assertEqual(complex_object(), SimpleLazyObject(complex_object))
+ self.assertEqual(SimpleLazyObject(complex_object), complex_object())
+
+ def test_hash(self):
+ # hash() equality would not be true for many objects, but it should be
+ # for _ComplexObject
+ self.assertEqual(hash(complex_object()),
+ hash(SimpleLazyObject(complex_object)))
+
+ def test_repr(self):
+ # For debugging, it will really confuse things if there is no clue that
+ # SimpleLazyObject is actually a proxy object. So we don't
+ # proxy __repr__
+ self.assert_("SimpleLazyObject" in repr(SimpleLazyObject(complex_object)))
+
+ def test_str(self):
+ self.assertEqual("I am _ComplexObject('joe')", str(SimpleLazyObject(complex_object)))
+
+ def test_unicode(self):
+ self.assertEqual(u"joe", unicode(SimpleLazyObject(complex_object)))
+
+ def test_class(self):
+ # This is important for classes that use __class__ in things like
+ # equality tests.
+ self.assertEqual(_ComplexObject, SimpleLazyObject(complex_object).__class__)
+
+ def test_deepcopy(self):
+ import copy
+ # Check that we *can* do deep copy, and that it returns the right
+ # objects.
+
+ # First, for an unevaluated SimpleLazyObject
+ s = SimpleLazyObject(complex_object)
+ assert s._wrapped is None
+ s2 = copy.deepcopy(s)
+ assert s._wrapped is None # something has gone wrong is s is evaluated
+ self.assertEqual(s2, complex_object())
+
+ # Second, for an evaluated SimpleLazyObject
+ name = s.name # evaluate
+ assert s._wrapped is not None
+ s3 = copy.deepcopy(s)
+ self.assertEqual(s3, complex_object())
+
if __name__ == "__main__":
import doctest
doctest.testmod()
Please sign in to comment.
Something went wrong with that request. Please try again.