diff options
Diffstat (limited to 'tests/unit/compat/mock.py')
| -rw-r--r-- | tests/unit/compat/mock.py | 127 | 
1 files changed, 127 insertions, 0 deletions
| diff --git a/tests/unit/compat/mock.py b/tests/unit/compat/mock.py new file mode 100644 index 00000000..b45d6b5c --- /dev/null +++ b/tests/unit/compat/mock.py @@ -0,0 +1,127 @@ +# (c) 2014, Toshio Kuratomi <tkuratomi@ansible.com> +# +# This file is part of Ansible +# +# Ansible is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# Ansible is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with Ansible.  If not, see <http://www.gnu.org/licenses/>. + +# Make coding more python3-ish +from __future__ import absolute_import, division, print_function + +__metaclass__ = type + +""" +Compat module for Python3.x's unittest.mock module +""" +import sys + +# Python 2.7 + +# Note: Could use the pypi mock library on python3.x as well as python2.x.  It +# is the same as the python3 stdlib mock library + +try: +    # Allow wildcard import because we really do want to import all of mock's +    # symbols into this compat shim +    # pylint: disable=wildcard-import,unused-wildcard-import +    from unittest.mock import * +except ImportError: +    # Python 2 +    # pylint: disable=wildcard-import,unused-wildcard-import +    try: +        from mock import * +    except ImportError: +        print("You need the mock library installed on python2.x to run tests") + + +# Prior to 3.4.4, mock_open cannot handle binary read_data +if sys.version_info >= (3,) and sys.version_info < (3, 4, 4): +    file_spec = None + +    def _iterate_read_data(read_data): +        # Helper for mock_open: +        # Retrieve lines from read_data via a generator so that separate calls to +        # readline, read, and readlines are properly interleaved +        sep = b"\n" if isinstance(read_data, bytes) else "\n" +        data_as_list = [l + sep for l in read_data.split(sep)] + +        if data_as_list[-1] == sep: +            # If the last line ended in a newline, the list comprehension will have an +            # extra entry that's just a newline.  Remove this. +            data_as_list = data_as_list[:-1] +        else: +            # If there wasn't an extra newline by itself, then the file being +            # emulated doesn't have a newline to end the last line  remove the +            # newline that our naive format() added +            data_as_list[-1] = data_as_list[-1][:-1] + +        for line in data_as_list: +            yield line + +    def mock_open(mock=None, read_data=""): +        """ +        A helper function to create a mock to replace the use of `open`. It works +        for `open` called directly or used as a context manager. + +        The `mock` argument is the mock object to configure. If `None` (the +        default) then a `MagicMock` will be created for you, with the API limited +        to methods or attributes available on standard file handles. + +        `read_data` is a string for the `read` methoddline`, and `readlines` of the +        file handle to return.  This is an empty string by default. +        """ + +        def _readlines_side_effect(*args, **kwargs): +            if handle.readlines.return_value is not None: +                return handle.readlines.return_value +            return list(_data) + +        def _read_side_effect(*args, **kwargs): +            if handle.read.return_value is not None: +                return handle.read.return_value +            return type(read_data)().join(_data) + +        def _readline_side_effect(): +            if handle.readline.return_value is not None: +                while True: +                    yield handle.readline.return_value +            for line in _data: +                yield line + +        global file_spec +        if file_spec is None: +            import _io + +            file_spec = list( +                set(dir(_io.TextIOWrapper)).union(set(dir(_io.BytesIO))) +            ) + +        if mock is None: +            mock = MagicMock(name="open", spec=open) + +        handle = MagicMock(spec=file_spec) +        handle.__enter__.return_value = handle + +        _data = _iterate_read_data(read_data) + +        handle.write.return_value = None +        handle.read.return_value = None +        handle.readline.return_value = None +        handle.readlines.return_value = None + +        handle.read.side_effect = _read_side_effect +        handle.readline.side_effect = _readline_side_effect() +        handle.readlines.side_effect = _readlines_side_effect + +        mock.return_value = handle +        return mock | 
