diff options
Diffstat (limited to '')
| -rw-r--r-- | tests/cogs/test_information.py | 163 | ||||
| -rw-r--r-- | tests/conftest.py | 32 | 
2 files changed, 195 insertions, 0 deletions
| diff --git a/tests/cogs/test_information.py b/tests/cogs/test_information.py new file mode 100644 index 000000000..85b2d092e --- /dev/null +++ b/tests/cogs/test_information.py @@ -0,0 +1,163 @@ +import asyncio +import logging +import textwrap +from datetime import datetime +from unittest.mock import MagicMock, patch + +import pytest +from discord import ( +    CategoryChannel, +    Colour, +    TextChannel, +    VoiceChannel, +) + +from bot.cogs import information +from bot.constants import Emojis +from bot.decorators import InChannelCheckFailure +from tests.helpers import AsyncMock + + +def cog(simple_bot): +    return information.Information(simple_bot) + + +def role(name: str, id_: int): +    r = MagicMock() +    r.name = name +    r.id = id_ +    r.mention = f'&{name}' +    return r + + +def member(status: str): +    m = MagicMock() +    m.status = status +    return m + + +def ctx(moderator_role, simple_ctx): +    simple_ctx.author.roles = [moderator_role] +    simple_ctx.guild.created_at = datetime(2001, 1, 1) +    simple_ctx.send = AsyncMock() +    return simple_ctx + + +def test_roles_info_command(cog, ctx): +    everyone_role = MagicMock() +    everyone_role.name = '@everyone'  # should be excluded in the output +    ctx.author.roles.append(everyone_role) +    ctx.guild.roles = ctx.author.roles + +    cog.roles_info.can_run = AsyncMock() +    cog.roles_info.can_run.return_value = True + +    coroutine = cog.roles_info.callback(cog, ctx) + +    assert asyncio.run(coroutine) is None  # no rval +    ctx.send.assert_called_once() +    _, kwargs = ctx.send.call_args +    embed = kwargs.pop('embed') +    assert embed.title == "Role information" +    assert embed.colour == Colour.blurple() +    assert embed.description == f"`{ctx.guild.roles[0].id}` - {ctx.guild.roles[0].mention}\n" +    assert embed.footer.text == "Total roles: 1" + + +# There is no argument passed in here that we can use to test, +# so the return value would change constantly. +@patch('bot.cogs.information.time_since') +def test_server_info_command(time_since_patch, cog, ctx, moderator_role): +    time_since_patch.return_value = '2 days ago' + +    ctx.guild.created_at = datetime(2001, 1, 1) +    ctx.guild.features = ('lemons', 'apples') +    ctx.guild.region = 'The Moon' +    ctx.guild.roles = [moderator_role] +    ctx.guild.channels = [ +        TextChannel( +            state={}, +            guild=ctx.guild, +            data={'id': 42, 'name': 'lemons-offering', 'position': 22, 'type': 'text'} +        ), +        CategoryChannel( +            state={}, +            guild=ctx.guild, +            data={'id': 5125, 'name': 'the-lemon-collection', 'position': 22, 'type': 'category'} +        ), +        VoiceChannel( +            state={}, +            guild=ctx.guild, +            data={'id': 15290, 'name': 'listen-to-lemon', 'position': 22, 'type': 'voice'} +        ) +    ] +    ctx.guild.members = [ +        member('online'), member('online'), +        member('idle'), +        member('dnd'), member('dnd'), member('dnd'), member('dnd'), +        member('offline'), member('offline'), member('offline') +    ] +    ctx.guild.member_count = 1_234 +    ctx.guild.icon_url = 'a-lemon.png' + +    coroutine = cog.server_info.callback(cog, ctx) +    assert asyncio.run(coroutine) is None  # no rval + +    time_since_patch.assert_called_once_with(ctx.guild.created_at, precision='days') +    _, kwargs = ctx.send.call_args +    embed = kwargs.pop('embed') +    assert embed.colour == Colour.blurple() +    assert embed.description == textwrap.dedent(f""" +        **Server information** +        Created: {time_since_patch.return_value} +        Voice region: {ctx.guild.region} +        Features: {', '.join(ctx.guild.features)} + +        **Counts** +        Members: {ctx.guild.member_count:,} +        Roles: {len(ctx.guild.roles)} +        Text: 1 +        Voice: 1 +        Channel categories: 1 + +        **Members** +        {Emojis.status_online} 2 +        {Emojis.status_idle} 1 +        {Emojis.status_dnd} 4 +        {Emojis.status_offline} 3 +        """) +    assert embed.thumbnail.url == 'a-lemon.png' + + +def test_user_info_on_other_users_from_non_moderator(ctx, cog): +    ctx.author = MagicMock() +    ctx.author.__eq__.return_value = False +    ctx.author.roles = [] +    coroutine = cog.user_info.callback(cog, ctx, user='scragly')  # skip checks, pass args + +    assert asyncio.run(coroutine) is None  # no rval +    ctx.send.assert_called_once_with( +        "You may not use this command on users other than yourself." +    ) + + +def test_user_info_in_wrong_channel_from_non_moderator(ctx, cog): +    ctx.author = MagicMock() +    ctx.author.__eq__.return_value = False +    ctx.author.roles = [] + +    coroutine = cog.user_info.callback(cog, ctx) +    message = 'Sorry, but you may only use this command within <#267659945086812160>.' +    with pytest.raises(InChannelCheckFailure, match=message): +        assert asyncio.run(coroutine) is None  # no rval + + +def test_setup(simple_bot, caplog): +    information.setup(simple_bot) +    simple_bot.add_cog.assert_called_once() +    [record] = caplog.records + +    assert record.message == "Cog loaded: Information" +    assert record.levelno == logging.INFO diff --git a/tests/conftest.py b/tests/conftest.py new file mode 100644 index 000000000..d3de4484d --- /dev/null +++ b/tests/conftest.py @@ -0,0 +1,32 @@ +from unittest.mock import MagicMock + +import pytest + +from bot.constants import Roles +from tests.helpers import AsyncMock + + +def moderator_role(): +    mock = MagicMock() +    mock.id = Roles.moderator +    mock.name = 'Moderator' +    mock.mention = f'&{mock.name}' +    return mock + + +def simple_bot(): +    mock = MagicMock() +    mock._before_invoke = AsyncMock() +    mock._after_invoke = AsyncMock() +    mock.can_run = AsyncMock() +    mock.can_run.return_value = True +    return mock + + +def simple_ctx(simple_bot): +    mock = MagicMock() +    mock.bot = simple_bot +    return mock | 
