From 07d9f08f616a34e4b47656f04eb20b255f7b41e8 Mon Sep 17 00:00:00 2001
From: Michael Foord <michael@voidspace.org.uk>
Date: Tue, 17 May 2011 19:12:06 +0100
Subject: [PATCH] Recursive function references work with _spec_signature

---
 mock.py                   | 18 +++++++++++-------
 tests/testhelpers.py      | 10 ++++++++++
 tests/testmagicmethods.py |  2 ++
 tox.ini                   |  5 ++---
 4 files changed, 25 insertions(+), 10 deletions(-)

diff --git a/mock.py b/mock.py
index 78eec96..f0528c7 100644
--- a/mock.py
+++ b/mock.py
@@ -114,7 +114,7 @@ def _getsignature(func, skipfirst):
 def _copy_func_details(func, funcopy):
     funcopy.__name__ = func.__name__
     funcopy.__doc__ = func.__doc__
-    funcopy.__dict__.update(func.__dict__)
+    #funcopy.__dict__.update(func.__dict__)
     funcopy.__module__ = func.__module__
     if not inPy3k:
         funcopy.func_defaults = func.func_defaults
@@ -1148,9 +1148,12 @@ def _spec_signature(spec, spec_set=False, inherit=False, _parent=None,
             # allow a mock to actually be a function from mocksignature
             continue
 
-        # XXXX need a better way of getting attributes
-        # without triggering code execution (?)
+        # XXXX do we need a better way of getting attributes
+        # without triggering code execution (?) (possibly not)s
         original = getattr(spec, entry)
+        kwargs = {'spec': original}
+        if spec_set:
+            kwargs = {'spec_set': original}
 
         if not isinstance(original, FunctionTypes):
             if type(spec) in (int, float, bool):
@@ -1159,16 +1162,17 @@ def _spec_signature(spec, spec_set=False, inherit=False, _parent=None,
                 #  pypy 1.5.1 which is fixed in trunk.)
                 # Instead we could check for attributes that have the same
                 # type as the parent - this might solve the general problem.
-                kwargs = {'spec': original}
-                if spec_set:
-                    kwargs = {'spec_set': original}
                 new = MagicMock(parent=mock, name=entry, **kwargs)
                 mock._mock_children[entry] = new
             else:
                 new = _spec_signature(original, spec_set, inherit,
                                       mock, entry, _ids)
         else:
-            existing = getattr(mock, entry)
+            if isinstance(spec, FunctionTypes):
+                existing = MagicMock(parent=mock.mock, name=entry, **kwargs)
+                mock._mock_children[entry] = existing
+            else:
+                existing = getattr(mock, entry)
             skipfirst = _must_skip(spec, entry, is_type)
             new = mocksignature(original, existing, skipfirst=skipfirst)
 
diff --git a/tests/testhelpers.py b/tests/testhelpers.py
index bb665da..5b0b94e 100644
--- a/tests/testhelpers.py
+++ b/tests/testhelpers.py
@@ -365,6 +365,16 @@ class SpecSignatureTest(unittest2.TestCase):
 
         mock = _spec_signature(f)
         self.assertRaises(TypeError, mock)
+        mock(1, 2)
+        mock.assert_called_with(1, 2)
+
+        f.f = f
+        mock = _spec_signature(f)
+        self.assertRaises(TypeError, mock.f)
+        mock.f(1, 2)
+        mock.f.assert_called_with(1, 2)
+        # XXX Note that this is *not* recursive, the function is only copied
+        #     for one level deep.
 
 
     def test_none(self):
diff --git a/tests/testmagicmethods.py b/tests/testmagicmethods.py
index 00c24a2..a8cf02c 100644
--- a/tests/testmagicmethods.py
+++ b/tests/testmagicmethods.py
@@ -162,6 +162,8 @@ class TestMockingMagicMethods(unittest2.TestCase):
 
 
     def testComparison(self):
+        # note: this test fails with Jython 2.5.1 due to a Jython bug
+        #       it is fixed in jython 2.5.2
         if not inPy3k:
             # incomparable in Python 3
             self. assertEqual(Mock() < 3, object() < 3)
diff --git a/tox.ini b/tox.ini
index c6b7477..6f4c22b 100644
--- a/tox.ini
+++ b/tox.ini
@@ -32,6 +32,5 @@ commands=
     {envbindir}/python -m unittest discover []
 deps =
 
-[testenv:pypy]
-deps=unittest2
-commands={envbindir}/unit2 discover []
+# note for jython. Execute in tests directory:
+# rm `find . -name '*$py.class'`
\ No newline at end of file
-- 
GitLab