aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorGravatar Mark <[email protected]>2020-07-22 12:45:29 -0700
committerGravatar GitHub <[email protected]>2020-07-22 12:45:29 -0700
commit0f6b980a7f9a71c30f044b60f0441f3d9c6a9395 (patch)
tree199ff60aa57ff3c7eb9269621606afabd3193850
parentUse max_units for time since join in user command instead of precision (diff)
parentMerge branch 'master' into jam-test (diff)
Merge pull request #957 from ks129/jam-test
Code Jams unit tests
-rw-r--r--bot/cogs/jams.py59
-rw-r--r--tests/bot/cogs/test_jams.py151
2 files changed, 193 insertions, 17 deletions
diff --git a/bot/cogs/jams.py b/bot/cogs/jams.py
index 1d062b0c2..a48dbc49a 100644
--- a/bot/cogs/jams.py
+++ b/bot/cogs/jams.py
@@ -1,6 +1,7 @@
import logging
+import typing as t
-from discord import Member, PermissionOverwrite, utils
+from discord import CategoryChannel, Guild, Member, PermissionOverwrite, Role, utils
from discord.ext import commands
from more_itertools import unique_everseen
@@ -40,22 +41,39 @@ class CodeJams(commands.Cog):
)
return
- code_jam_category = utils.get(ctx.guild.categories, name="Code Jam")
+ team_channel = await self.create_channels(ctx.guild, team_name, members)
+ await self.add_roles(ctx.guild, members)
+
+ await ctx.send(
+ f":ok_hand: Team created: {team_channel}\n"
+ f"**Team Leader:** {members[0].mention}\n"
+ f"**Team Members:** {' '.join(member.mention for member in members[1:])}"
+ )
+
+ @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 = {
- ctx.guild.default_role: PermissionOverwrite(read_messages=False),
- ctx.guild.me: PermissionOverwrite(read_messages=True)
+ guild.default_role: PermissionOverwrite(read_messages=False),
+ guild.me: PermissionOverwrite(read_messages=True)
}
- code_jam_category = await ctx.guild.create_category_channel(
+ code_jam_category = await guild.create_category_channel(
"Code Jam",
overwrites=category_overwrites,
reason="It's code jam time!"
)
+ return code_jam_category
+
+ @staticmethod
+ def get_overwrites(members: t.List[Member], guild: Guild) -> t.Dict[t.Union[Member, Role], PermissionOverwrite]:
+ """Get Code Jam team channels permission overwrites."""
# First member is always the team leader
team_channel_overwrites = {
members[0]: PermissionOverwrite(
@@ -64,8 +82,8 @@ class CodeJams(commands.Cog):
manage_webhooks=True,
connect=True
),
- ctx.guild.default_role: PermissionOverwrite(read_messages=False, connect=False),
- ctx.guild.get_role(Roles.verified): PermissionOverwrite(
+ guild.default_role: PermissionOverwrite(read_messages=False, connect=False),
+ guild.get_role(Roles.verified): PermissionOverwrite(
read_messages=False,
connect=False
)
@@ -78,8 +96,16 @@ class CodeJams(commands.Cog):
connect=True
)
+ return team_channel_overwrites
+
+ async def create_channels(self, guild: Guild, team_name: str, members: t.List[Member]) -> str:
+ """Create team text and voice channels. Return the mention for the text channel."""
+ # Get permission overwrites and category
+ team_channel_overwrites = self.get_overwrites(members, guild)
+ code_jam_category = await self.get_category(guild)
+
# Create a text channel for the team
- team_channel = await ctx.guild.create_text_channel(
+ team_channel = await guild.create_text_channel(
team_name,
overwrites=team_channel_overwrites,
category=code_jam_category
@@ -88,26 +114,25 @@ class CodeJams(commands.Cog):
# Create a voice channel for the team
team_voice_name = " ".join(team_name.split("-")).title()
- await ctx.guild.create_voice_channel(
+ await guild.create_voice_channel(
team_voice_name,
overwrites=team_channel_overwrites,
category=code_jam_category
)
+ return team_channel.mention
+
+ @staticmethod
+ async def add_roles(guild: Guild, members: t.List[Member]) -> None:
+ """Assign team leader and jammer roles."""
# Assign team leader role
- await members[0].add_roles(ctx.guild.get_role(Roles.team_leaders))
+ await members[0].add_roles(guild.get_role(Roles.team_leaders))
# Assign rest of roles
- jammer_role = ctx.guild.get_role(Roles.jammers)
+ jammer_role = guild.get_role(Roles.jammers)
for member in members:
await member.add_roles(jammer_role)
- await ctx.send(
- f":ok_hand: Team created: {team_channel.mention}\n"
- f"**Team Leader:** {members[0].mention}\n"
- f"**Team Members:** {' '.join(member.mention for member in members[1:])}"
- )
-
def setup(bot: Bot) -> None:
"""Load the CodeJams cog."""
diff --git a/tests/bot/cogs/test_jams.py b/tests/bot/cogs/test_jams.py
new file mode 100644
index 000000000..81fbcb798
--- /dev/null
+++ b/tests/bot/cogs/test_jams.py
@@ -0,0 +1,151 @@
+import unittest
+from unittest.mock import AsyncMock, MagicMock, patch
+
+from bot.cogs.jams import CodeJams, setup
+from bot.constants import Roles
+from tests.helpers import MockBot, MockContext, MockGuild, MockMember, MockRole, MockTextChannel
+
+
+class JamCreateTeamTests(unittest.IsolatedAsyncioTestCase):
+ """Tests for `createteam` command."""
+
+ def setUp(self):
+ self.bot = MockBot()
+ self.admin_role = MockRole(name="Admins", id=Roles.admins)
+ 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)
+
+ 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()
+
+ 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)
+
+ self.ctx.send.assert_awaited_once()
+ self.cog.create_channels.assert_not_awaited()
+ self.cog.add_roles.assert_not_awaited()
+
+ 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.cog.add_roles = AsyncMock()
+
+ member = MockMember()
+ await self.cog.createteam(self.cog, self.ctx, "foo", (member for _ in range(5)))
+
+ 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)
+
+ self.cog.create_channels.assert_awaited_once()
+ 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
+
+ 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.assertFalse(category_overwrites[self.guild.default_role].read_messages)
+ self.assertTrue(category_overwrites[self.guild.me].read_messages)
+
+ 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()
+
+ async def test_channel_overwrites(self):
+ """Should have correct permission overwrites for users and roles."""
+ leader = MockMember()
+ members = [leader] + [MockMember() 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:]:
+ self.assertTrue(overwrites[member].read_messages)
+ self.assertTrue(overwrites[member].connect)
+
+ # Everyone and verified role overwrite
+ self.assertFalse(overwrites[self.guild.default_role].read_messages)
+ self.assertFalse(overwrites[self.guild.default_role].connect)
+ self.assertFalse(overwrites[self.guild.get_role(Roles.verified)].read_messages)
+ self.assertFalse(overwrites[self.guild.get_role(Roles.verified)].connect)
+
+ 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()
+ 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.assertEqual("foobar-channel", actual)
+ 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(
+ "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
+ )
+
+ 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)
+
+ leader.add_roles.assert_any_await(leader_role)
+ for member in members:
+ member.add_roles.assert_any_await(jam_role)
+
+
+class CodeJamSetup(unittest.TestCase):
+ """Test for `setup` function of `CodeJam` cog."""
+
+ def test_setup(self):
+ """Should call `bot.add_cog`."""
+ bot = MockBot()
+ setup(bot)
+ bot.add_cog.assert_called_once()