derwiki-adroll / mock

Automatically exported from code.google.com/p/mock
BSD 2-Clause "Simplified" License
0 stars 0 forks source link

Sentinels can fail to match, even when they have the same name #114

Closed GoogleCodeExporter closed 9 years ago

GoogleCodeExporter commented 9 years ago
Here is a unit test which replicates the issue, plus a patch to fix it :)

diff -r b36ae42dfbb1 mock.py
--- a/mock.py   Mon Aug 15 23:23:27 2011 +0100
+++ b/mock.py   Wed Aug 17 14:45:46 2011 +1000
@@ -383,6 +383,10 @@
     def __repr__(self):
         return '<SentinelObject "%s">' % self.name

+    def __eq__(self, other):
+        return (other.__class__ == SentinelObject and
+                other.name == self.name)
+

 class Sentinel(object):
     """Access attributes to return a named object, usable as a sentinel."""
diff -r b36ae42dfbb1 tests/testsentinel.py
--- a/tests/testsentinel.py Mon Aug 15 23:23:27 2011 +0100
+++ b/tests/testsentinel.py Wed Aug 17 14:45:46 2011 +1000
@@ -4,7 +4,7 @@

 from tests.support import unittest2

-from mock import sentinel, DEFAULT
+from mock import sentinel, DEFAULT, Sentinel

 class SentinelTest(unittest2.TestCase):
@@ -28,6 +28,18 @@
         # If this doesn't raise an AttributeError then help(mock) is broken
         self.assertRaises(AttributeError, lambda: sentinel.__bases__)

+    def testSameName(self):
+        """Sentinels should match as equal if they have the same name,
+        regardless of how they were created."""
+        self.assertEqual(sentinel.foo, sentinel.foo)
+        self.assertEqual(sentinel.foo, Sentinel().foo)
+
+        bar = sentinel.bar
+        self.assertEqual(bar.name, 'bar')
+        bar.name = 'foo'
+        self.assertEqual(bar.name, 'foo')
+        self.assertEqual(bar, sentinel.foo)
+

 if __name__ == '__main__':
     unittest2.main()

Original issue reported on code.google.com by anthony....@gmail.com on 17 Aug 2011 at 4:48

GoogleCodeExporter commented 9 years ago
The whole point of sentinel is that you create unique objects that can be 
compared on identity - the name is just a convenient way to create them and 
have a useful repr. Under what circumstances are you getting sentinels with the 
same name but a different identity?

Original comment by fuzzyman on 21 Aug 2011 at 1:26

GoogleCodeExporter commented 9 years ago
Well, if you print the sentinel object you don't actually see the identity, 
just the name, so the error that I got was pretty confusing/non-obvious. After 
drilling down I found something like <Sentinel name="foo"> != <Sentinel 
name="foo">. The root issue was that in the custom test handler suite that I 
inherited, the handler setup had a separate call to Sentinel() for some items. 
I'm pretty sure that that's wrong (duh), but the patch above would have saved 
me an hour or two of head scratching.

Alternatively, adding the id to the __str__/__repr__ might be a different way 
to solve the same problem, so that it's obvious that the objects are different 
ones but with the same name. Or else hide/don't export the base Sentinel object 
so that people can't instantiate it themselves.

Original comment by anthony....@gmail.com on 22 Aug 2011 at 1:01

GoogleCodeExporter commented 9 years ago
The Sentinel class is not in __all__ and is not documented, and yes - using it 
like that defeats the purpose of Sentinel! I can rename it to _Sentinel to make 
it clear it is internal though.

Original comment by fuzzyman on 6 Oct 2011 at 10:25

GoogleCodeExporter commented 9 years ago
Committed in Revision c9c03e6c0a.

Original comment by fuzzyman on 6 Oct 2011 at 10:31