diff options
Diffstat (limited to 'tests')
| -rw-r--r-- | tests/bot/exts/utils/test_jams.py | 137 | ||||
| -rw-r--r-- | tests/helpers.py | 22 | 
2 files changed, 92 insertions, 67 deletions
| diff --git a/tests/bot/exts/utils/test_jams.py b/tests/bot/exts/utils/test_jams.py index 85d6a1173..368a15476 100644 --- a/tests/bot/exts/utils/test_jams.py +++ b/tests/bot/exts/utils/test_jams.py @@ -2,10 +2,24 @@ import unittest  from unittest.mock import AsyncMock, MagicMock, create_autospec  from discord import CategoryChannel +from discord.ext.commands import BadArgument  from bot.constants import Roles  from bot.exts.utils import jams -from tests.helpers import MockBot, MockContext, MockGuild, MockMember, MockRole, MockTextChannel +from tests.helpers import ( +    MockAttachment, MockBot, MockCategoryChannel, MockContext, +    MockGuild, MockMember, MockRole, MockTextChannel +) + +TEST_CSV = b"""\ +Team Name,Team Member Discord ID,Team Leader +Annoyed Alligators,12345,Y +Annoyed Alligators,54321,N +Oscillating Otters,12358,Y +Oscillating Otters,74832,N +Oscillating Otters,19903,N +Annoyed Alligators,11111,N +"""  def get_mock_category(channel_count: int, name: str) -> CategoryChannel: @@ -17,8 +31,8 @@ def get_mock_category(channel_count: int, name: str) -> CategoryChannel:      return category -class JamCreateTeamTests(unittest.IsolatedAsyncioTestCase): -    """Tests for `createteam` command.""" +class JamCodejamCreateTests(unittest.IsolatedAsyncioTestCase): +    """Tests for `codejam create` command."""      def setUp(self):          self.bot = MockBot() @@ -28,60 +42,64 @@ class JamCreateTeamTests(unittest.IsolatedAsyncioTestCase):          self.ctx = MockContext(bot=self.bot, author=self.command_user, guild=self.guild)          self.cog = jams.CodeJams(self.bot) -    async def test_too_small_amount_of_team_members_passed(self): -        """Should `ctx.send` and exit early when too small amount of members.""" -        for case in (1, 2): -            with self.subTest(amount_of_members=case): -                self.cog.create_channels = AsyncMock() -                self.cog.add_roles = AsyncMock() +    async def test_message_without_attachments(self): +        """If no link or attachments are provided, commands.BadArgument should be raised.""" +        self.ctx.message.attachments = [] -                self.ctx.reset_mock() -                members = (MockMember() for _ in range(case)) -                await self.cog.createteam(self.cog, self.ctx, "foo", members) +        with self.assertRaises(BadArgument): +            await self.cog.create(self.cog, self.ctx, None) -                self.ctx.send.assert_awaited_once() -                self.cog.create_channels.assert_not_awaited() -                self.cog.add_roles.assert_not_awaited() +    async def test_result_sending(self): +        """Should call `ctx.send` when everything goes right.""" +        self.ctx.message.attachments = [MockAttachment()] +        self.ctx.message.attachments[0].read = AsyncMock() +        self.ctx.message.attachments[0].read.return_value = TEST_CSV + +        team_leaders = MockRole() + +        self.guild.get_member.return_value = MockMember() -    async def test_duplicate_members_provided(self): -        """Should `ctx.send` and exit early because duplicate members provided and total there is only 1 member.""" -        self.cog.create_channels = AsyncMock() +        self.ctx.guild.create_role = AsyncMock() +        self.ctx.guild.create_role.return_value = team_leaders +        self.cog.create_team_channel = AsyncMock() +        self.cog.create_team_leader_channel = AsyncMock()          self.cog.add_roles = AsyncMock() -        member = MockMember() -        await self.cog.createteam(self.cog, self.ctx, "foo", (member for _ in range(5))) +        await self.cog.create(self.cog, self.ctx, None) +        self.cog.create_team_channel.assert_awaited() +        self.cog.create_team_leader_channel.assert_awaited_once_with( +            self.ctx.guild, team_leaders +        )          self.ctx.send.assert_awaited_once() -        self.cog.create_channels.assert_not_awaited() -        self.cog.add_roles.assert_not_awaited() - -    async def test_result_sending(self): -        """Should call `ctx.send` when everything goes right.""" -        self.cog.create_channels = AsyncMock() -        self.cog.add_roles = AsyncMock() -        members = [MockMember() for _ in range(5)] -        await self.cog.createteam(self.cog, self.ctx, "foo", members) +    async def test_link_returning_non_200_status(self): +        """When the URL passed returns a non 200 status, it should send a message informing them.""" +        self.bot.http_session.get.return_value = mock = MagicMock() +        mock.status = 404 +        await self.cog.create(self.cog, self.ctx, "https://not-a-real-link.com") -        self.cog.create_channels.assert_awaited_once() -        self.cog.add_roles.assert_awaited_once()          self.ctx.send.assert_awaited_once()      async def test_category_doesnt_exist(self):          """Should create a new code jam category."""          subtests = (              [], -            [get_mock_category(jams.MAX_CHANNELS - 1, jams.CATEGORY_NAME)], +            [get_mock_category(jams.MAX_CHANNELS, jams.CATEGORY_NAME)],              [get_mock_category(jams.MAX_CHANNELS - 2, "other")],          ) +        self.cog.send_status_update = AsyncMock() +          for categories in subtests: +            self.cog.send_status_update.reset_mock()              self.guild.reset_mock()              self.guild.categories = categories              with self.subTest(categories=categories):                  actual_category = await self.cog.get_category(self.guild) +                self.cog.send_status_update.assert_called_once()                  self.guild.create_category_channel.assert_awaited_once()                  category_overwrites = self.guild.create_category_channel.call_args[1]["overwrites"] @@ -103,62 +121,47 @@ class JamCreateTeamTests(unittest.IsolatedAsyncioTestCase):      async def test_channel_overwrites(self):          """Should have correct permission overwrites for users and roles.""" -        leader = MockMember() -        members = [leader] + [MockMember() for _ in range(4)] +        leader = (MockMember(), True) +        members = [leader] + [(MockMember(), False) for _ in range(4)]          overwrites = self.cog.get_overwrites(members, self.guild) -        # Leader permission overwrites -        self.assertTrue(overwrites[leader].manage_messages) -        self.assertTrue(overwrites[leader].read_messages) -        self.assertTrue(overwrites[leader].manage_webhooks) -        self.assertTrue(overwrites[leader].connect) - -        # Other members permission overwrites -        for member in members[1:]: +        for member, _ in members:              self.assertTrue(overwrites[member].read_messages) -            self.assertTrue(overwrites[member].connect) - -        # Everyone role overwrite -        self.assertFalse(overwrites[self.guild.default_role].read_messages) -        self.assertFalse(overwrites[self.guild.default_role].connect)      async def test_team_channels_creation(self): -        """Should create new voice and text channel for team.""" -        members = [MockMember() for _ in range(5)] +        """Should create a text channel for a team.""" +        team_leaders = MockRole() +        members = [(MockMember(), True)] + [(MockMember(), False) for _ in range(5)] +        category = MockCategoryChannel() +        category.create_text_channel = AsyncMock()          self.cog.get_overwrites = MagicMock()          self.cog.get_category = AsyncMock() -        self.ctx.guild.create_text_channel.return_value = MockTextChannel(mention="foobar-channel") -        actual = await self.cog.create_channels(self.guild, "my-team", members) +        self.cog.get_category.return_value = category +        self.cog.add_team_leader_roles = AsyncMock() -        self.assertEqual("foobar-channel", actual) +        await self.cog.create_team_channel(self.guild, "my-team", members, team_leaders) +        self.cog.add_team_leader_roles.assert_awaited_once_with(members, team_leaders)          self.cog.get_overwrites.assert_called_once_with(members, self.guild)          self.cog.get_category.assert_awaited_once_with(self.guild) -        self.guild.create_text_channel.assert_awaited_once_with( +        category.create_text_channel.assert_awaited_once_with(              "my-team", -            overwrites=self.cog.get_overwrites.return_value, -            category=self.cog.get_category.return_value -        ) -        self.guild.create_voice_channel.assert_awaited_once_with( -            "My Team", -            overwrites=self.cog.get_overwrites.return_value, -            category=self.cog.get_category.return_value +            overwrites=self.cog.get_overwrites.return_value          )      async def test_jam_roles_adding(self):          """Should add team leader role to leader and jam role to every team member."""          leader_role = MockRole(name="Team Leader") -        jam_role = MockRole(name="Jammer") -        self.guild.get_role.side_effect = [leader_role, jam_role]          leader = MockMember() -        members = [leader] + [MockMember() for _ in range(4)] -        await self.cog.add_roles(self.guild, members) +        members = [(leader, True)] + [(MockMember(), False) for _ in range(4)] +        await self.cog.add_team_leader_roles(members, leader_role) -        leader.add_roles.assert_any_await(leader_role) -        for member in members: -            member.add_roles.assert_any_await(jam_role) +        leader.add_roles.assert_awaited_once_with(leader_role) +        for member, is_leader in members: +            if not is_leader: +                member.add_roles.assert_not_awaited()  class CodeJamSetup(unittest.TestCase): diff --git a/tests/helpers.py b/tests/helpers.py index e3dc5fe5b..eedd7a601 100644 --- a/tests/helpers.py +++ b/tests/helpers.py @@ -361,6 +361,27 @@ class MockDMChannel(CustomMockMixin, unittest.mock.Mock, HashableMixin):          super().__init__(**collections.ChainMap(kwargs, default_kwargs)) +# Create CategoryChannel instance to get a realistic MagicMock of `discord.CategoryChannel` +category_channel_data = { +    'id': 1, +    'type': discord.ChannelType.category, +    'name': 'category', +    'position': 1, +} + +state = unittest.mock.MagicMock() +guild = unittest.mock.MagicMock() +category_channel_instance = discord.CategoryChannel( +    state=state, guild=guild, data=category_channel_data +) + + +class MockCategoryChannel(CustomMockMixin, unittest.mock.Mock, HashableMixin): +    def __init__(self, **kwargs) -> None: +        default_kwargs = {'id': next(self.discord_id)} +        super().__init__(**collections.ChainMap(default_kwargs, kwargs)) + +  # Create a Message instance to get a realistic MagicMock of `discord.Message`  message_data = {      'id': 1, @@ -403,6 +424,7 @@ class MockContext(CustomMockMixin, unittest.mock.MagicMock):          self.guild = kwargs.get('guild', MockGuild())          self.author = kwargs.get('author', MockMember())          self.channel = kwargs.get('channel', MockTextChannel()) +        self.message = kwargs.get('message', MockMessage())          self.invoked_from_error_handler = kwargs.get('invoked_from_error_handler', False) | 
