1# encoding: utf-8
2
3"""Utility functions wrapping the excellent *mock* library"""
4
5from __future__ import absolute_import, division, print_function, unicode_literals
6
7import sys
8
9if sys.version_info >= (3, 3):
10    from unittest import mock  # noqa
11    from unittest.mock import ANY, call, MagicMock  # noqa
12    from unittest.mock import create_autospec, Mock, mock_open, patch, PropertyMock
13else:
14    import mock  # noqa
15    from mock import ANY, call, MagicMock  # noqa
16    from mock import create_autospec, Mock, patch, PropertyMock
17
18
19def class_mock(request, q_class_name, autospec=True, **kwargs):
20    """Return mock patching class with qualified name *q_class_name*.
21
22    The mock is autospec'ed based on the patched class unless the optional
23    argument *autospec* is set to False. Any other keyword arguments are
24    passed through to Mock(). Patch is reversed after calling test returns.
25    """
26    _patch = patch(q_class_name, autospec=autospec, **kwargs)
27    request.addfinalizer(_patch.stop)
28    return _patch.start()
29
30
31def cls_attr_mock(request, cls, attr_name, name=None, **kwargs):
32    """
33    Return a mock for attribute *attr_name* on *cls* where the patch is
34    reversed after pytest uses it.
35    """
36    name = request.fixturename if name is None else name
37    _patch = patch.object(cls, attr_name, name=name, **kwargs)
38    request.addfinalizer(_patch.stop)
39    return _patch.start()
40
41
42def function_mock(request, q_function_name, autospec=True, **kwargs):
43    """Return mock patching function with qualified name *q_function_name*.
44
45    Patch is reversed after calling test returns.
46    """
47    _patch = patch(q_function_name, autospec=autospec, **kwargs)
48    request.addfinalizer(_patch.stop)
49    return _patch.start()
50
51
52def initializer_mock(request, cls, autospec=True, **kwargs):
53    """Return mock for __init__() method on *cls*.
54
55    The patch is reversed after pytest uses it.
56    """
57    _patch = patch.object(
58        cls, "__init__", autospec=autospec, return_value=None, **kwargs
59    )
60    request.addfinalizer(_patch.stop)
61    return _patch.start()
62
63
64def instance_mock(request, cls, name=None, spec_set=True, **kwargs):
65    """
66    Return a mock for an instance of *cls* that draws its spec from the class
67    and does not allow new attributes to be set on the instance. If *name* is
68    missing or |None|, the name of the returned |Mock| instance is set to
69    *request.fixturename*. Additional keyword arguments are passed through to
70    the Mock() call that creates the mock.
71    """
72    name = name if name is not None else request.fixturename
73    return create_autospec(
74        cls, _name=name, spec_set=spec_set, instance=True, **kwargs
75    )
76
77
78def loose_mock(request, name=None, **kwargs):
79    """
80    Return a "loose" mock, meaning it has no spec to constrain calls on it.
81    Additional keyword arguments are passed through to Mock(). If called
82    without a name, it is assigned the name of the fixture.
83    """
84    if name is None:
85        name = request.fixturename
86    return Mock(name=name, **kwargs)
87
88
89def method_mock(request, cls, method_name, autospec=True, **kwargs):
90    """Return mock for method *method_name* on *cls*.
91
92    The patch is reversed after pytest uses it.
93    """
94    _patch = patch.object(cls, method_name, autospec=autospec, **kwargs)
95    request.addfinalizer(_patch.stop)
96    return _patch.start()
97
98
99def open_mock(request, module_name, **kwargs):
100    """
101    Return a mock for the builtin `open()` method in *module_name*.
102    """
103    target = '%s.open' % module_name
104    _patch = patch(target, mock_open(), create=True, **kwargs)
105    request.addfinalizer(_patch.stop)
106    return _patch.start()
107
108
109def property_mock(request, cls, prop_name, **kwargs):
110    """
111    Return a mock for property *prop_name* on class *cls* where the patch is
112    reversed after pytest uses it.
113    """
114    _patch = patch.object(cls, prop_name, new_callable=PropertyMock, **kwargs)
115    request.addfinalizer(_patch.stop)
116    return _patch.start()
117
118
119def var_mock(request, q_var_name, **kwargs):
120    """
121    Return a mock patching the variable with qualified name *q_var_name*.
122    Patch is reversed after calling test returns.
123    """
124    _patch = patch(q_var_name, **kwargs)
125    request.addfinalizer(_patch.stop)
126    return _patch.start()
127