diff --git a/redbot/pytest/__init__.py b/redbot/pytest/__init__.py new file mode 100644 index 000000000..bb67a43fa --- /dev/null +++ b/redbot/pytest/__init__.py @@ -0,0 +1 @@ +from .core import * diff --git a/redbot/pytest/admin.py b/redbot/pytest/admin.py new file mode 100644 index 000000000..25982b532 --- /dev/null +++ b/redbot/pytest/admin.py @@ -0,0 +1,20 @@ +from unittest.mock import MagicMock + +import pytest + +from redbot.cogs.admin import Admin +from redbot.cogs.admin.announcer import Announcer + +__all__ = ["admin", "announcer"] + + +@pytest.fixture() +def admin(config): + return Admin(config) + + +@pytest.fixture() +def announcer(admin): + a = Announcer(MagicMock(), "Some message", admin.conf) + yield a + a.cancel() diff --git a/redbot/pytest/alias.py b/redbot/pytest/alias.py new file mode 100644 index 000000000..cff129ba5 --- /dev/null +++ b/redbot/pytest/alias.py @@ -0,0 +1,13 @@ +import pytest + +from redbot.cogs.alias import Alias +from redbot.core import Config + +__all__ = ["alias"] + + +@pytest.fixture() +def alias(config, monkeypatch): + with monkeypatch.context() as m: + m.setattr(Config, "get_conf", lambda *args, **kwargs: config) + return Alias(None) diff --git a/redbot/pytest/cog_manager.py b/redbot/pytest/cog_manager.py new file mode 100644 index 000000000..edd6499d0 --- /dev/null +++ b/redbot/pytest/cog_manager.py @@ -0,0 +1,13 @@ +import pytest + +__all__ = ["cog_mgr", "default_dir"] + + +@pytest.fixture() +def cog_mgr(red): + return red.cog_mgr + + +@pytest.fixture() +def default_dir(red): + return red.main_dir diff --git a/tests/conftest.py b/redbot/pytest/core.py similarity index 91% rename from tests/conftest.py rename to redbot/pytest/core.py index fb715820a..838e1731f 100644 --- a/tests/conftest.py +++ b/redbot/pytest/core.py @@ -9,6 +9,26 @@ from redbot.core.bot import Red from redbot.core.drivers import red_json +__all__ = [ + "monkeysession", + "override_data_path", + "coroutine", + "json_driver", + "config", + "config_fr", + "red", + "guild_factory", + "empty_guild", + "empty_channel", + "empty_member", + "empty_message", + "empty_role", + "empty_user", + "member_factory", + "user_factory", + "ctx", +] + @pytest.fixture(scope="session") def monkeysession(request): diff --git a/redbot/pytest/data_manager.py b/redbot/pytest/data_manager.py new file mode 100644 index 000000000..d1a68c06b --- /dev/null +++ b/redbot/pytest/data_manager.py @@ -0,0 +1,24 @@ +import pytest + +from redbot.core import data_manager + +__all__ = ["cleanup_datamanager", "data_mgr_config", "cog_instance"] + + +@pytest.fixture(autouse=True) +def cleanup_datamanager(): + data_manager.basic_config = None + data_manager.jsonio = None + + +@pytest.fixture() +def data_mgr_config(tmpdir): + default = data_manager.basic_config_default.copy() + default["BASE_DIR"] = str(tmpdir) + return default + + +@pytest.fixture() +def cog_instance(): + thing = type("CogTest", (object,), {}) + return thing() diff --git a/redbot/pytest/dataconverter.py b/redbot/pytest/dataconverter.py new file mode 100644 index 000000000..f608cf721 --- /dev/null +++ b/redbot/pytest/dataconverter.py @@ -0,0 +1,12 @@ +from pathlib import Path + +from redbot.cogs.dataconverter import core_specs + +__all__ = ["get_specresolver"] + + +def get_specresolver(path): + here = Path(path) + + resolver = core_specs.SpecResolver(here.parent) + return resolver diff --git a/redbot/pytest/downloader.py b/redbot/pytest/downloader.py new file mode 100644 index 000000000..8260d17ff --- /dev/null +++ b/redbot/pytest/downloader.py @@ -0,0 +1,103 @@ +from collections import namedtuple +from pathlib import Path +import json + +import pytest + +from redbot.cogs.downloader.repo_manager import RepoManager, Repo +from redbot.cogs.downloader.installable import Installable + +__all__ = [ + "patch_relative_to", + "repo_manager", + "repo", + "repo_norun", + "bot_repo", + "INFO_JSON", + "installable", + "fake_run_noprint", +] + + +async def fake_run(*args, **kwargs): + fake_result_tuple = namedtuple("fake_result", "returncode result") + res = fake_result_tuple(0, (args, kwargs)) + print(args[0]) + return res + + +async def fake_run_noprint(*args, **kwargs): + fake_result_tuple = namedtuple("fake_result", "returncode result") + res = fake_result_tuple(0, (args, kwargs)) + return res + + +@pytest.fixture(scope="module", autouse=True) +def patch_relative_to(monkeysession): + def fake_relative_to(self, some_path: Path): + return self + + monkeysession.setattr("pathlib.Path.relative_to", fake_relative_to) + + +@pytest.fixture +def repo_manager(tmpdir_factory): + rm = RepoManager() + # rm.repos_folder = Path(str(tmpdir_factory.getbasetemp())) / 'repos' + return rm + + +@pytest.fixture +def repo(tmpdir): + repo_folder = Path(str(tmpdir)) / "repos" / "squid" + repo_folder.mkdir(parents=True, exist_ok=True) + + return Repo( + url="https://github.com/tekulvw/Squid-Plugins", + name="squid", + branch="rewrite_cogs", + folder_path=repo_folder, + ) + + +@pytest.fixture +def repo_norun(repo): + repo._run = fake_run + return repo + + +@pytest.fixture +def bot_repo(event_loop): + cwd = Path.cwd() + return Repo( + name="Red-DiscordBot", + branch="WRONG", + url="https://empty.com/something.git", + folder_path=cwd, + loop=event_loop, + ) + + +# Installable +INFO_JSON = { + "author": ("tekulvw",), + "bot_version": (3, 0, 0), + "description": "A long description", + "hidden": False, + "install_msg": "A post-installation message", + "required_cogs": {}, + "requirements": ("tabulate"), + "short": "A short description", + "tags": ("tag1", "tag2"), + "type": "COG", +} + + +@pytest.fixture +def installable(tmpdir): + cog_path = tmpdir.mkdir("test_repo").mkdir("test_cog") + info_path = cog_path.join("info.json") + info_path.write_text(json.dumps(INFO_JSON), "utf-8") + + cog_info = Installable(Path(str(cog_path))) + return cog_info diff --git a/redbot/pytest/economy.py b/redbot/pytest/economy.py new file mode 100644 index 000000000..6281184cc --- /dev/null +++ b/redbot/pytest/economy.py @@ -0,0 +1,15 @@ +import pytest + +__all__ = ["bank"] + + +@pytest.fixture() +def bank(config, monkeypatch): + from redbot.core import Config + + with monkeypatch.context() as m: + m.setattr(Config, "get_conf", lambda *args, **kwargs: config) + from redbot.core import bank + + bank._register_defaults() + return bank diff --git a/redbot/pytest/mod.py b/redbot/pytest/mod.py new file mode 100644 index 000000000..92e5de9c0 --- /dev/null +++ b/redbot/pytest/mod.py @@ -0,0 +1,15 @@ +import pytest + +__all__ = ["mod"] + + +@pytest.fixture +def mod(config, monkeypatch): + from redbot.core import Config + + with monkeypatch.context() as m: + m.setattr(Config, "get_conf", lambda *args, **kwargs: config) + from redbot.core import modlog + + modlog._register_defaults() + return modlog diff --git a/redbot/pytest/rpc.py b/redbot/pytest/rpc.py new file mode 100644 index 000000000..5ad7900da --- /dev/null +++ b/redbot/pytest/rpc.py @@ -0,0 +1,51 @@ +import pytest +from redbot.core.rpc import RPC, RPCMixin + +from unittest.mock import MagicMock + +__all__ = ["rpc", "rpcmixin", "cog", "existing_func", "existing_multi_func"] + + +@pytest.fixture() +def rpc(): + return RPC() + + +@pytest.fixture() +def rpcmixin(): + r = RPCMixin() + r.rpc = MagicMock(spec=RPC) + return r + + +@pytest.fixture() +def cog(): + class Cog: + async def cofunc(*args, **kwargs): + pass + + async def cofunc2(*args, **kwargs): + pass + + async def cofunc3(*args, **kwargs): + pass + + def func(*args, **kwargs): + pass + + return Cog() + + +@pytest.fixture() +def existing_func(rpc, cog): + rpc.add_method(cog.cofunc) + + return cog.cofunc + + +@pytest.fixture() +def existing_multi_func(rpc, cog): + funcs = [cog.cofunc, cog.cofunc2, cog.cofunc3] + rpc.add_multi_method(*funcs) + + return funcs diff --git a/setup.py b/setup.py index a3939e3ad..b19c1716d 100644 --- a/setup.py +++ b/setup.py @@ -111,10 +111,10 @@ setup( classifiers=[ "Development Status :: 4 - Beta", "Framework :: AsyncIO", + "Framework :: Pytest", "Intended Audience :: Developers", "License :: OSI Approved :: GNU General Public License v3 or later (GPLv3+)", "Operating System :: OS Independent", - "Programming Language :: Python :: 3.5", "Programming Language :: Python :: 3.6", "Topic :: Communications :: Chat", "Topic :: Documentation :: Sphinx", @@ -124,7 +124,8 @@ setup( "redbot=redbot.__main__:main", "redbot-setup=redbot.setup:main", "redbot-launcher=redbot.launcher:main", - ] + ], + "pytest11": ["red-discordbot = redbot.pytest"], }, python_requires=">=3.6,<3.7", setup_requires=get_requirements(), diff --git a/tests/cogs/admin/test_admin.py b/tests/cogs/admin/test_admin.py index e1f5ed2e8..3059e8a11 100644 --- a/tests/cogs/admin/test_admin.py +++ b/tests/cogs/admin/test_admin.py @@ -2,20 +2,7 @@ from unittest.mock import MagicMock import pytest -from redbot.cogs.admin import Admin -from redbot.cogs.admin.announcer import Announcer - - -@pytest.fixture() -def admin(config): - return Admin(config) - - -@pytest.fixture() -def announcer(admin): - a = Announcer(MagicMock(), "Some message", admin.conf) - yield a - a.cancel() +from redbot.pytest.admin import * @pytest.mark.asyncio diff --git a/tests/cogs/dataconverter/test_dataconverter.py b/tests/cogs/dataconverter/test_dataconverter.py index 59f04068a..5c8d9a3e2 100644 --- a/tests/cogs/dataconverter/test_dataconverter.py +++ b/tests/cogs/dataconverter/test_dataconverter.py @@ -1,8 +1,7 @@ import pytest -from pathlib import Path from collections import namedtuple -from redbot.cogs.dataconverter import core_specs +from redbot.pytest.dataconverter import * from redbot.core.utils.data_converter import DataConverter @@ -14,16 +13,9 @@ def mock_dpy_member(guildid, userid): return namedtuple("Member", "id guild")(int(userid), mock_dpy_object(guildid)) -@pytest.fixture() -def specresolver(): - here = Path(__file__) - - resolver = core_specs.SpecResolver(here.parent) - return resolver - - @pytest.mark.asyncio -async def test_mod_nicknames(red, specresolver: core_specs.SpecResolver): +async def test_mod_nicknames(red): + specresolver = get_specresolver(__file__) filepath, converter, cogname, attr, _id = specresolver.get_conversion_info("Past Nicknames") conf = specresolver.get_config_object(red, cogname, attr, _id) diff --git a/tests/cogs/downloader/test_downloader.py b/tests/cogs/downloader/test_downloader.py index 9b3eab07d..7b5790630 100644 --- a/tests/cogs/downloader/test_downloader.py +++ b/tests/cogs/downloader/test_downloader.py @@ -6,69 +6,12 @@ import pytest from unittest.mock import MagicMock from raven.versioning import fetch_git_sha +from redbot.pytest.downloader import * + from redbot.cogs.downloader.repo_manager import RepoManager, Repo from redbot.cogs.downloader.errors import ExistingGitRepo -async def fake_run(*args, **kwargs): - fake_result_tuple = namedtuple("fake_result", "returncode result") - res = fake_result_tuple(0, (args, kwargs)) - print(args[0]) - return res - - -async def fake_run_noprint(*args, **kwargs): - fake_result_tuple = namedtuple("fake_result", "returncode result") - res = fake_result_tuple(0, (args, kwargs)) - return res - - -@pytest.fixture(scope="module", autouse=True) -def patch_relative_to(monkeysession): - def fake_relative_to(self, some_path: Path): - return self - - monkeysession.setattr("pathlib.Path.relative_to", fake_relative_to) - - -@pytest.fixture -def repo_manager(tmpdir_factory): - rm = RepoManager() - # rm.repos_folder = Path(str(tmpdir_factory.getbasetemp())) / 'repos' - return rm - - -@pytest.fixture -def repo(tmpdir): - repo_folder = Path(str(tmpdir)) / "repos" / "squid" - repo_folder.mkdir(parents=True, exist_ok=True) - - return Repo( - url="https://github.com/tekulvw/Squid-Plugins", - name="squid", - branch="rewrite_cogs", - folder_path=repo_folder, - ) - - -@pytest.fixture -def repo_norun(repo): - repo._run = fake_run - return repo - - -@pytest.fixture -def bot_repo(event_loop): - cwd = Path.cwd() - return Repo( - name="Red-DiscordBot", - branch="WRONG", - url="https://empty.com/something.git", - folder_path=cwd, - loop=event_loop, - ) - - def test_existing_git_repo(tmpdir): repo_folder = Path(str(tmpdir)) / "repos" / "squid" / ".git" repo_folder.mkdir(parents=True, exist_ok=True) diff --git a/tests/cogs/downloader/test_installable.py b/tests/cogs/downloader/test_installable.py index 5dd50de96..3d1765a34 100644 --- a/tests/cogs/downloader/test_installable.py +++ b/tests/cogs/downloader/test_installable.py @@ -3,31 +3,9 @@ from pathlib import Path import pytest +from redbot.pytest.downloader import * from redbot.cogs.downloader.installable import Installable, InstallableType -INFO_JSON = { - "author": ("tekulvw",), - "bot_version": (3, 0, 0), - "description": "A long description", - "hidden": False, - "install_msg": "A post-installation message", - "required_cogs": {}, - "requirements": ("tabulate"), - "short": "A short description", - "tags": ("tag1", "tag2"), - "type": "COG", -} - - -@pytest.fixture -def installable(tmpdir): - cog_path = tmpdir.mkdir("test_repo").mkdir("test_cog") - info_path = cog_path.join("info.json") - info_path.write_text(json.dumps(INFO_JSON), "utf-8") - - cog_info = Installable(Path(str(cog_path))) - return cog_info - def test_process_info_file(installable): for k, v in INFO_JSON.items(): diff --git a/tests/cogs/test_alias.py b/tests/cogs/test_alias.py index 92f55bfbf..73f51b4c0 100644 --- a/tests/cogs/test_alias.py +++ b/tests/cogs/test_alias.py @@ -1,14 +1,5 @@ import pytest - -from redbot.cogs.alias import Alias -from redbot.core import Config - - -@pytest.fixture() -def alias(config, monkeypatch): - with monkeypatch.context() as m: - m.setattr(Config, "get_conf", lambda *args, **kwargs: config) - return Alias(None) +from redbot.pytest.alias import * def test_is_valid_alias_name(alias): diff --git a/tests/cogs/test_economy.py b/tests/cogs/test_economy.py index d502ae617..4bd0e4ec1 100644 --- a/tests/cogs/test_economy.py +++ b/tests/cogs/test_economy.py @@ -1,16 +1,5 @@ import pytest - - -@pytest.fixture() -def bank(config, monkeypatch): - from redbot.core import Config - - with monkeypatch.context() as m: - m.setattr(Config, "get_conf", lambda *args, **kwargs: config) - from redbot.core import bank - - bank._register_defaults() - return bank +from redbot.pytest.economy import * @pytest.mark.asyncio diff --git a/tests/cogs/test_mod.py b/tests/cogs/test_mod.py index 7409b9916..d7ced7c79 100644 --- a/tests/cogs/test_mod.py +++ b/tests/cogs/test_mod.py @@ -1,16 +1,6 @@ import pytest - -@pytest.fixture -def mod(config, monkeypatch): - from redbot.core import Config - - with monkeypatch.context() as m: - m.setattr(Config, "get_conf", lambda *args, **kwargs: config) - from redbot.core import modlog - - modlog._register_defaults() - return modlog +from redbot.pytest.mod import * @pytest.mark.asyncio diff --git a/tests/core/test_cog_manager.py b/tests/core/test_cog_manager.py index b762ed6aa..cc34d6f01 100644 --- a/tests/core/test_cog_manager.py +++ b/tests/core/test_cog_manager.py @@ -2,19 +2,10 @@ from pathlib import Path import pytest +from redbot.pytest.cog_manager import * from redbot.core import cog_manager -@pytest.fixture() -def cog_mgr(red): - return red.cog_mgr - - -@pytest.fixture() -def default_dir(red): - return red.main_dir - - @pytest.mark.skip @pytest.mark.asyncio async def test_ensure_cogs_in_paths(cog_mgr, default_dir): diff --git a/tests/core/test_data_manager.py b/tests/core/test_data_manager.py index e817e84f3..4af979d80 100644 --- a/tests/core/test_data_manager.py +++ b/tests/core/test_data_manager.py @@ -3,28 +3,10 @@ from pathlib import Path import pytest +from redbot.pytest.data_manager import * from redbot.core import data_manager -@pytest.fixture(autouse=True) -def cleanup_datamanager(): - data_manager.basic_config = None - data_manager.jsonio = None - - -@pytest.fixture() -def data_mgr_config(tmpdir): - default = data_manager.basic_config_default.copy() - default["BASE_DIR"] = str(tmpdir) - return default - - -@pytest.fixture() -def cog_instance(): - thing = type("CogTest", (object,), {}) - return thing() - - def test_no_basic(cog_instance): with pytest.raises(RuntimeError): data_manager.core_data_path() diff --git a/tests/core/test_rpc.py b/tests/core/test_rpc.py index 7fa1f6564..6565956b9 100644 --- a/tests/core/test_rpc.py +++ b/tests/core/test_rpc.py @@ -1,52 +1,7 @@ import pytest -from redbot.core.rpc import RPC, RPCMixin, get_name -from unittest.mock import MagicMock - - -@pytest.fixture() -def rpc(): - return RPC() - - -@pytest.fixture() -def rpcmixin(): - r = RPCMixin() - r.rpc = MagicMock(spec=RPC) - return r - - -@pytest.fixture() -def cog(): - class Cog: - async def cofunc(*args, **kwargs): - pass - - async def cofunc2(*args, **kwargs): - pass - - async def cofunc3(*args, **kwargs): - pass - - def func(*args, **kwargs): - pass - - return Cog() - - -@pytest.fixture() -def existing_func(rpc, cog): - rpc.add_method(cog.cofunc) - - return cog.cofunc - - -@pytest.fixture() -def existing_multi_func(rpc, cog): - funcs = [cog.cofunc, cog.cofunc2, cog.cofunc3] - rpc.add_multi_method(*funcs) - - return funcs +from redbot.pytest.rpc import * +from redbot.core.rpc import get_name def test_get_name(cog):