Fixed #12060 - equality tests between User and SimpleLazyObject-wrapped User failed.
Also added more tests for SimpleLazyObject Thanks to ericholscher for report. git-svn-id: http://code.djangoproject.com/svn/django/trunk@11637 bcc190cf-cafb-0310-a4f2-bffc1f526a37
This commit is contained in:
parent
c6e8e5d9f0
commit
162fade2b7
|
@ -316,14 +316,35 @@ class SimpleLazyObject(LazyObject):
|
||||||
if self._wrapped is None: self._setup()
|
if self._wrapped is None: self._setup()
|
||||||
return str(self._wrapped)
|
return str(self._wrapped)
|
||||||
|
|
||||||
|
def __unicode__(self):
|
||||||
|
if self._wrapped is None: self._setup()
|
||||||
|
return unicode(self._wrapped)
|
||||||
|
|
||||||
def __deepcopy__(self, memo):
|
def __deepcopy__(self, memo):
|
||||||
if self._wrapped is None:
|
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
|
memo[id(self)] = result
|
||||||
return result
|
return result
|
||||||
else:
|
else:
|
||||||
import copy
|
import copy
|
||||||
return copy.deepcopy(self._wrapped, memo)
|
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):
|
def _setup(self):
|
||||||
self._wrapped = self._setupfunc()
|
self._wrapped = self._setupfunc()
|
||||||
|
|
|
@ -3,7 +3,7 @@ Tests for Django's bundled context processors.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
from django.conf import settings
|
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.db.models import Q
|
||||||
from django.test import TestCase
|
from django.test import TestCase
|
||||||
from django.template import Template
|
from django.template import Template
|
||||||
|
@ -74,9 +74,13 @@ class AuthContextProcessorTests(TestCase):
|
||||||
|
|
||||||
def test_user_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')
|
self.client.login(username='super', password='secret')
|
||||||
|
user = authenticate(username='super', password='secret')
|
||||||
response = self.client.get('/auth_processor_user/')
|
response = self.client.get('/auth_processor_user/')
|
||||||
self.assertContains(response, "unicode: super")
|
self.assertContains(response, "unicode: super")
|
||||||
self.assertContains(response, "id: 100")
|
self.assertContains(response, "id: 100")
|
||||||
|
@ -100,3 +104,9 @@ class AuthContextProcessorTests(TestCase):
|
||||||
# calling a Python object' in <type 'exceptions.AttributeError'>
|
# calling a Python object' in <type 'exceptions.AttributeError'>
|
||||||
# ignored"
|
# ignored"
|
||||||
query = Q(user=response.context['user']) & Q(someflag=True)
|
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'])
|
||||||
|
|
|
@ -5,6 +5,7 @@ Tests for django.utils.
|
||||||
from unittest import TestCase
|
from unittest import TestCase
|
||||||
|
|
||||||
from django.utils import html, checksums
|
from django.utils import html, checksums
|
||||||
|
from django.utils.functional import SimpleLazyObject
|
||||||
|
|
||||||
import timesince
|
import timesince
|
||||||
import datastructures
|
import datastructures
|
||||||
|
@ -161,6 +162,80 @@ class TestUtilsChecksums(TestCase):
|
||||||
for value, output in items:
|
for value, output in items:
|
||||||
self.check_output(f, value, output)
|
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__":
|
if __name__ == "__main__":
|
||||||
import doctest
|
import doctest
|
||||||
doctest.testmod()
|
doctest.testmod()
|
||||||
|
|
Loading…
Reference in New Issue