Skip to content
This repository

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse code

Fixed #12060 - equality tests between User and SimpleLazyObject-wrapp…

…ed 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
  • Loading branch information...
commit 162fade2b70d56ee5cbc3a57d1863f3c989775d6 1 parent c6e8e5d
Luke Plant authored October 20, 2009
23  django/utils/functional.py
@@ -316,14 +316,35 @@ def __str__(self):
316 316
         if self._wrapped is None: self._setup()
317 317
         return str(self._wrapped)
318 318
 
  319
+    def __unicode__(self):
  320
+        if self._wrapped is None: self._setup()
  321
+        return unicode(self._wrapped)
  322
+
319 323
     def __deepcopy__(self, memo):
320 324
         if self._wrapped is None:
321  
-            result = self.__class__(self._setupfunc)
  325
+            # We have to use SimpleLazyObject, not self.__class__, because the
  326
+            # latter is proxied.
  327
+            result = SimpleLazyObject(self._setupfunc)
322 328
             memo[id(self)] = result
323 329
             return result
324 330
         else:
325 331
             import copy
326 332
             return copy.deepcopy(self._wrapped, memo)
327 333
 
  334
+    # Need to pretend to be the wrapped class, for the sake of objects that care
  335
+    # about this (especially in equality tests)
  336
+    def __get_class(self):
  337
+        if self._wrapped is None: self._setup()
  338
+        return self._wrapped.__class__
  339
+    __class__ = property(__get_class)
  340
+
  341
+    def __eq__(self, other):
  342
+        if self._wrapped is None: self._setup()
  343
+        return self._wrapped == other
  344
+
  345
+    def __hash__(self):
  346
+        if self._wrapped is None: self._setup()
  347
+        return hash(self._wrapped)
  348
+
328 349
     def _setup(self):
329 350
         self._wrapped = self._setupfunc()
14  tests/regressiontests/context_processors/tests.py
@@ -3,7 +3,7 @@
3 3
 """
4 4
 
5 5
 from django.conf import settings
6  
-from django.contrib.auth.models import Group
  6
+from django.contrib.auth import authenticate
7 7
 from django.db.models import Q
8 8
 from django.test import TestCase
9 9
 from django.template import Template
@@ -74,9 +74,13 @@ def test_message_attrs(self):
74 74
 
75 75
     def test_user_attrs(self):
76 76
         """
77  
-        Test that ContextLazyObject wraps objects properly
  77
+        Test that the lazy objects returned behave just like the wrapped objects.
78 78
         """
  79
+        # These are 'functional' level tests for common use cases.  Direct
  80
+        # testing of the implementation (SimpleLazyObject) is in the 'utils'
  81
+        # tests.
79 82
         self.client.login(username='super', password='secret')
  83
+        user = authenticate(username='super', password='secret')
80 84
         response = self.client.get('/auth_processor_user/')
81 85
         self.assertContains(response, "unicode: super")
82 86
         self.assertContains(response, "id: 100")
@@ -100,3 +104,9 @@ def test_user_attrs(self):
100 104
         #    calling a Python object' in <type 'exceptions.AttributeError'>
101 105
         #    ignored"
102 106
         query = Q(user=response.context['user']) & Q(someflag=True)
  107
+
  108
+        # Tests for user equality.  This is hard because User defines
  109
+        # equality in a non-duck-typing way
  110
+        # See bug #12060
  111
+        self.assertEqual(response.context['user'], user)
  112
+        self.assertEqual(user, response.context['user'])
75  tests/regressiontests/utils/tests.py
@@ -5,6 +5,7 @@
5 5
 from unittest import TestCase
6 6
 
7 7
 from django.utils import html, checksums
  8
+from django.utils.functional import SimpleLazyObject
8 9
 
9 10
 import timesince
10 11
 import datastructures
@@ -161,6 +162,80 @@ def test_luhn(self):
161 162
         for value, output in items:
162 163
             self.check_output(f, value, output)
163 164
 
  165
+class _ComplexObject(object):
  166
+    def __init__(self, name):
  167
+        self.name = name
  168
+
  169
+    def __eq__(self, other):
  170
+        return self.name == other.name
  171
+
  172
+    def __hash__(self):
  173
+        return hash(self.name)
  174
+
  175
+    def __str__(self):
  176
+        return "I am _ComplexObject(%r)" % self.name
  177
+
  178
+    def __unicode__(self):
  179
+        return unicode(self.name)
  180
+
  181
+    def __repr__(self):
  182
+        return "_ComplexObject(%r)" % self.name
  183
+
  184
+complex_object = lambda: _ComplexObject("joe")
  185
+
  186
+class TestUtilsSimpleLazyObject(TestCase):
  187
+    """
  188
+    Tests for SimpleLazyObject
  189
+    """
  190
+    # Note that concrete use cases for SimpleLazyObject are also found in the
  191
+    # auth context processor tests (unless the implementation of that function
  192
+    # is changed).
  193
+
  194
+    def test_equality(self):
  195
+        self.assertEqual(complex_object(), SimpleLazyObject(complex_object))
  196
+        self.assertEqual(SimpleLazyObject(complex_object), complex_object())
  197
+
  198
+    def test_hash(self):
  199
+        # hash() equality would not be true for many objects, but it should be
  200
+        # for _ComplexObject
  201
+        self.assertEqual(hash(complex_object()),
  202
+                         hash(SimpleLazyObject(complex_object)))
  203
+
  204
+    def test_repr(self):
  205
+        # For debugging, it will really confuse things if there is no clue that
  206
+        # SimpleLazyObject is actually a proxy object. So we don't
  207
+        # proxy __repr__
  208
+        self.assert_("SimpleLazyObject" in repr(SimpleLazyObject(complex_object)))
  209
+
  210
+    def test_str(self):
  211
+        self.assertEqual("I am _ComplexObject('joe')", str(SimpleLazyObject(complex_object)))
  212
+
  213
+    def test_unicode(self):
  214
+        self.assertEqual(u"joe", unicode(SimpleLazyObject(complex_object)))
  215
+
  216
+    def test_class(self):
  217
+        # This is important for classes that use __class__ in things like
  218
+        # equality tests.
  219
+        self.assertEqual(_ComplexObject, SimpleLazyObject(complex_object).__class__)
  220
+
  221
+    def test_deepcopy(self):
  222
+        import copy
  223
+        # Check that we *can* do deep copy, and that it returns the right
  224
+        # objects.
  225
+
  226
+        # First, for an unevaluated SimpleLazyObject
  227
+        s = SimpleLazyObject(complex_object)
  228
+        assert s._wrapped is None
  229
+        s2 = copy.deepcopy(s)
  230
+        assert s._wrapped is None # something has gone wrong is s is evaluated
  231
+        self.assertEqual(s2, complex_object())
  232
+
  233
+        # Second, for an evaluated SimpleLazyObject
  234
+        name = s.name # evaluate
  235
+        assert s._wrapped is not None
  236
+        s3 = copy.deepcopy(s)
  237
+        self.assertEqual(s3, complex_object())
  238
+
164 239
 if __name__ == "__main__":
165 240
     import doctest
166 241
     doctest.testmod()

0 notes on commit 162fade

Please sign in to comment.
Something went wrong with that request. Please try again.