diff options
| author | 2020-07-22 23:44:45 -0700 | |
|---|---|---|
| committer | 2020-07-22 23:44:45 -0700 | |
| commit | 2490402c335b11c04c6177342b232079a6d9ac15 (patch) | |
| tree | cdaed299efbc4b4e78d8c79df5a28e7329a7d238 | |
| parent | Merge pull request #957 from ks129/jam-test (diff) | |
| parent | Jam tests: use the MAX_CHANNELS constant more (diff) | |
Merge pull request #1063 from python-discord/bug/util/jams-multi-categories
Support multiple categories for code jam team creation
| -rw-r--r-- | bot/cogs/jams.py | 51 | ||||
| -rw-r--r-- | tests/bot/cogs/test_jams.py | 62 |
2 files changed, 73 insertions, 40 deletions
diff --git a/bot/cogs/jams.py b/bot/cogs/jams.py index a48dbc49a..b3102db2f 100644 --- a/bot/cogs/jams.py +++ b/bot/cogs/jams.py @@ -1,7 +1,7 @@ import logging import typing as t -from discord import CategoryChannel, Guild, Member, PermissionOverwrite, Role, utils +from discord import CategoryChannel, Guild, Member, PermissionOverwrite, Role from discord.ext import commands from more_itertools import unique_everseen @@ -11,6 +11,9 @@ from bot.decorators import with_role log = logging.getLogger(__name__) +MAX_CHANNELS = 50 +CATEGORY_NAME = "Code Jam" + class CodeJams(commands.Cog): """Manages the code-jam related parts of our server.""" @@ -50,30 +53,38 @@ class CodeJams(commands.Cog): f"**Team Members:** {' '.join(member.mention for member in members[1:])}" ) + async def get_category(self, guild: Guild) -> CategoryChannel: + """ + Return a code jam category. + + If all categories are full or none exist, create a new category. + """ + for category in guild.categories: + # Need 2 available spaces: one for the text channel and one for voice. + if category.name == CATEGORY_NAME and MAX_CHANNELS - len(category.channels) >= 2: + return category + + return await self.create_category(guild) + @staticmethod - async def get_category(guild: Guild) -> CategoryChannel: - """Create a Code Jam category if it doesn't exist and return it.""" - code_jam_category = utils.get(guild.categories, name="Code Jam") - - if code_jam_category is None: - log.info("Code Jam category not found, creating it.") - - category_overwrites = { - guild.default_role: PermissionOverwrite(read_messages=False), - guild.me: PermissionOverwrite(read_messages=True) - } - - code_jam_category = await guild.create_category_channel( - "Code Jam", - overwrites=category_overwrites, - reason="It's code jam time!" - ) + async def create_category(guild: Guild) -> CategoryChannel: + """Create a new code jam category and return it.""" + log.info("Creating a new code jam category.") - return code_jam_category + category_overwrites = { + guild.default_role: PermissionOverwrite(read_messages=False), + guild.me: PermissionOverwrite(read_messages=True) + } + + return await guild.create_category_channel( + CATEGORY_NAME, + overwrites=category_overwrites, + reason="It's code jam time!" + ) @staticmethod def get_overwrites(members: t.List[Member], guild: Guild) -> t.Dict[t.Union[Member, Role], PermissionOverwrite]: - """Get Code Jam team channels permission overwrites.""" + """Get code jam team channels permission overwrites.""" # First member is always the team leader team_channel_overwrites = { members[0]: PermissionOverwrite( diff --git a/tests/bot/cogs/test_jams.py b/tests/bot/cogs/test_jams.py index 81fbcb798..b4ad8535f 100644 --- a/tests/bot/cogs/test_jams.py +++ b/tests/bot/cogs/test_jams.py @@ -1,11 +1,22 @@ import unittest -from unittest.mock import AsyncMock, MagicMock, patch +from unittest.mock import AsyncMock, MagicMock, create_autospec -from bot.cogs.jams import CodeJams, setup +from discord import CategoryChannel + +from bot.cogs import jams from bot.constants import Roles from tests.helpers import MockBot, MockContext, MockGuild, MockMember, MockRole, MockTextChannel +def get_mock_category(channel_count: int, name: str) -> CategoryChannel: + """Return a mocked code jam category.""" + category = create_autospec(CategoryChannel, spec_set=True, instance=True) + category.name = name + category.channels = [MockTextChannel() for _ in range(channel_count)] + + return category + + class JamCreateTeamTests(unittest.IsolatedAsyncioTestCase): """Tests for `createteam` command.""" @@ -15,11 +26,7 @@ class JamCreateTeamTests(unittest.IsolatedAsyncioTestCase): self.command_user = MockMember([self.admin_role]) self.guild = MockGuild([self.admin_role]) self.ctx = MockContext(bot=self.bot, author=self.command_user, guild=self.guild) - self.cog = CodeJams(self.bot) - - utils_patcher = patch("bot.cogs.jams.utils") - self.utils_mock = utils_patcher.start() - self.addCleanup(utils_patcher.stop) + 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.""" @@ -29,7 +36,6 @@ class JamCreateTeamTests(unittest.IsolatedAsyncioTestCase): self.cog.add_roles = AsyncMock() self.ctx.reset_mock() - self.utils_mock.reset_mock() members = (MockMember() for _ in range(case)) await self.cog.createteam(self.cog, self.ctx, "foo", members) @@ -61,22 +67,39 @@ class JamCreateTeamTests(unittest.IsolatedAsyncioTestCase): self.cog.add_roles.assert_awaited_once() self.ctx.send.assert_awaited_once() - async def test_category_dont_exist(self): - """Should create code jam category.""" - self.utils_mock.get.return_value = None + 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 - 2, "other")], + ) + + for categories in subtests: + self.guild.reset_mock() + self.guild.categories = categories - await self.cog.get_category(self.guild) + with self.subTest(categories=categories): + actual_category = await self.cog.get_category(self.guild) - self.guild.create_category_channel.assert_awaited_once() - category_overwrites = self.guild.create_category_channel.call_args[1]["overwrites"] + self.guild.create_category_channel.assert_awaited_once() + category_overwrites = self.guild.create_category_channel.call_args[1]["overwrites"] - self.assertFalse(category_overwrites[self.guild.default_role].read_messages) - self.assertTrue(category_overwrites[self.guild.me].read_messages) + self.assertFalse(category_overwrites[self.guild.default_role].read_messages) + self.assertTrue(category_overwrites[self.guild.me].read_messages) + self.assertEqual(self.guild.create_category_channel.return_value, actual_category) async def test_category_channel_exist(self): """Should not try to create category channel.""" - await self.cog.get_category(self.guild) - self.guild.create_category_channel.assert_not_awaited() + expected_category = get_mock_category(jams.MAX_CHANNELS - 2, jams.CATEGORY_NAME) + self.guild.categories = [ + get_mock_category(jams.MAX_CHANNELS - 2, "other"), + expected_category, + get_mock_category(0, jams.CATEGORY_NAME), + ] + + actual_category = await self.cog.get_category(self.guild) + self.assertEqual(expected_category, actual_category) async def test_channel_overwrites(self): """Should have correct permission overwrites for users and roles.""" @@ -103,7 +126,6 @@ class JamCreateTeamTests(unittest.IsolatedAsyncioTestCase): async def test_team_channels_creation(self): """Should create new voice and text channel for team.""" - self.utils_mock.get.return_value = "foo" members = [MockMember() for _ in range(5)] self.cog.get_overwrites = MagicMock() @@ -147,5 +169,5 @@ class CodeJamSetup(unittest.TestCase): def test_setup(self): """Should call `bot.add_cog`.""" bot = MockBot() - setup(bot) + jams.setup(bot) bot.add_cog.assert_called_once() |