# Copyright (C) 2015, 2018, 2020 The Meme Factory, Inc.
# http://www.karlpinc.com/

# This file is part of PGWUI_Testing.
#
# This program is free software: you can redistribute it and/or
# modify it under the terms of the GNU Affero General Public License
# as published by the Free Software Foundation, either version 3 of
# the License, or (at your option) any later version.
#
# This program 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
# Affero General Public License for more details.
#
# You should have received a copy of the GNU Affero General Public
# License along with this program.  If not, see
# <http://www.gnu.org/licenses/>.
#

# Karl O. Pinc <kop@karlpinc.com>

from pytest import fixture
from unittest import mock


# Mock support

def make_mock_fixture(module, method, autouse=False, wraps=None):
    '''Returns a pytest fixture that mocks a module's method or a class's
    class method.  "module" is a module or a class, but method is a string.
    '''
    @fixture(autouse=autouse)
    def fix(monkeypatch):
        mocked = mock.Mock(
            spec=getattr(module, method), name=method, wraps=wraps)
        monkeypatch.setattr(module, method, mocked)
        return mocked
    return fix


def make_magicmock_fixture(module, method, autouse=False, autospec=False):
    '''Returns a pytest fixture that magic mocks a module's method or a
    class's class method.  "module" is a module or a class, but method
    is a string.
    '''
    @fixture(autouse=autouse)
    def fix(monkeypatch):
        if autospec:
            mocked = mock.create_autospec(
                getattr(module, method), spec_set=True)
        else:
            mocked = mock.MagicMock(
                spec=getattr(module, method), name=method)
        monkeypatch.setattr(module, method, mocked)
        return mocked
    return fix


def instance_method_mock_fixture(method):
    '''Returns a pytest fixture that mocks an instance method of a class.
    "method" is a string.

    The fixture is called by the test function with the class instance
    that's to be monkeypatched and the mock is returned for the
    test function to configure/etc.
    '''
    @fixture
    def fix(monkeypatch):
        def run(cls):
            mocked = mock.Mock(spec=getattr(cls, method), name=method)
            monkeypatch.setattr(cls, method, mocked)
            return mocked
        return run
    return fix
