Merge branch 'master' of github.com:wolever/parameterized
diff --git a/parameterized/parameterized.py b/parameterized/parameterized.py
index 5b0a336..775a1cd 100644
--- a/parameterized/parameterized.py
+++ b/parameterized/parameterized.py
@@ -49,6 +49,27 @@
 def skip_on_empty_helper(*a, **kw):
     raise SkipTest("parameterized input is empty")
 
+def reapply_patches_if_need(func):
+
+    def dummy_wrapper(orgfunc):
+        @wraps(orgfunc)
+        def dummy_func(*args, **kwargs):
+            return orgfunc(*args, **kwargs)
+        return dummy_func
+
+    if hasattr(func, 'patchings'):
+        func = dummy_wrapper(func)
+        tmp_patchings = func.patchings
+        delattr(func, 'patchings')
+        for patch_obj in tmp_patchings:
+            func = patch_obj.decorate_callable(func)
+    return func
+
+def delete_patches_if_need(func):
+    if hasattr(func, 'patchings'):
+        func.patchings[:] = []
+
+
 class param(_param):
     """ Represents a single parameter to a test case.
 
@@ -459,8 +480,16 @@
 
             for num, p in enumerate(paramters):
                 name = name_func(f, num, p)
-                frame_locals[name] = cls.param_as_standalone_func(p, f, name)
+                # If the original function has patches applied by 'mock.patch',
+                # re-construct all patches on the just former decoration layer
+                # of param_as_standalone_func so as not to share
+                # patch objects between new functions
+                nf = reapply_patches_if_need(f)
+                frame_locals[name] = cls.param_as_standalone_func(p, nf, name)
                 frame_locals[name].__doc__ = doc_func(f, num, p)
+            # Delete original patches to prevent new function from evaluating
+            # original patching object as well as re-constructed patches.
+            delete_patches_if_need(f)
 
             f.__test__ = False
         return parameterized_expand_wrapper
diff --git a/parameterized/test.py b/parameterized/test.py
index 2a1f26b..f470127 100644
--- a/parameterized/test.py
+++ b/parameterized/test.py
@@ -1,6 +1,7 @@
 # coding=utf-8
 
 import inspect
+import mock
 from unittest import TestCase
 from nose.tools import assert_equal, assert_raises
 
@@ -100,6 +101,74 @@
     return custom_naming_func
 
 
+@mock.patch("os.getpid")
+class TestParameterizedExpandWithMockPatchForClass(TestCase):
+    expect([
+        "test_one_function_patch_decorator('foo1', 'umask', 'getpid')",
+        "test_one_function_patch_decorator('foo0', 'umask', 'getpid')",
+        "test_one_function_patch_decorator(42, 'umask', 'getpid')",
+    ])
+
+    @parameterized.expand([(42, ), "foo0", param("foo1")])
+    @mock.patch("os.umask")
+    def test_one_function_patch_decorator(self, foo, mock_umask, mock_getpid):
+        missing_tests.remove("test_one_function_patch_decorator(%r, %r, %r)" %
+                             (foo, mock_umask._mock_name,
+                              mock_getpid._mock_name))
+
+    expect([
+        "test_multiple_function_patch_decorator"
+        "(42, 51, 'umask', 'fdopen', 'getpid')",
+        "test_multiple_function_patch_decorator"
+        "('foo0', 'bar0', 'umask', 'fdopen', 'getpid')",
+        "test_multiple_function_patch_decorator"
+        "('foo1', 'bar1', 'umask', 'fdopen', 'getpid')",
+    ])
+
+    @parameterized.expand([(42, 51), ("foo0", "bar0"), param("foo1", "bar1")])
+    @mock.patch("os.fdopen")
+    @mock.patch("os.umask")
+    def test_multiple_function_patch_decorator(self, foo, bar, mock_umask,
+                                               mock_fdopen, mock_getpid):
+        missing_tests.remove("test_multiple_function_patch_decorator"
+                             "(%r, %r, %r, %r, %r)" %
+                             (foo, bar, mock_umask._mock_name,
+                              mock_fdopen._mock_name, mock_getpid._mock_name))
+
+
+class TestParameterizedExpandWithNoMockPatchForClass(TestCase):
+    expect([
+        "test_one_function_patch_decorator('foo1', 'umask')",
+        "test_one_function_patch_decorator('foo0', 'umask')",
+        "test_one_function_patch_decorator(42, 'umask')",
+    ])
+
+    @parameterized.expand([(42, ), "foo0", param("foo1")])
+    @mock.patch("os.umask")
+    def test_one_function_patch_decorator(self, foo, mock_umask):
+        missing_tests.remove("test_one_function_patch_decorator(%r, %r)" %
+                             (foo, mock_umask._mock_name))
+
+    expect([
+        "test_multiple_function_patch_decorator"
+        "(42, 51, 'umask', 'fdopen')",
+        "test_multiple_function_patch_decorator"
+        "('foo0', 'bar0', 'umask', 'fdopen')",
+        "test_multiple_function_patch_decorator"
+        "('foo1', 'bar1', 'umask', 'fdopen')",
+    ])
+
+    @parameterized.expand([(42, 51), ("foo0", "bar0"), param("foo1", "bar1")])
+    @mock.patch("os.fdopen")
+    @mock.patch("os.umask")
+    def test_multiple_function_patch_decorator(self, foo, bar, mock_umask,
+                                               mock_fdopen):
+        missing_tests.remove("test_multiple_function_patch_decorator"
+                             "(%r, %r, %r, %r)" %
+                             (foo, bar, mock_umask._mock_name,
+                              mock_fdopen._mock_name))
+
+
 class TestParamerizedOnTestCase(TestCase):
     expect([
         "test_on_TestCase('foo0', bar=None)",
diff --git a/tox.ini b/tox.ini
index c75a0ab..c58219f 100644
--- a/tox.ini
+++ b/tox.ini
@@ -4,6 +4,7 @@
 [testenv]
 deps=
     nose
+    mock
     nose2: nose2
     pytest: pytest>=2
     unit2: unittest2