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:
Luke Plant 2009-10-20 14:11:08 +00:00
parent c6e8e5d9f0
commit 162fade2b7
3 changed files with 109 additions and 3 deletions

View File

@ -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()

View File

@ -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'])

View File

@ -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()