async def test_confirmation_result_large_diff(self): """Should return True if confirmed and False if _send_prompt fails or aborted.""" author = helpers.MockMember() mock_message = helpers.MockMessage() subtests = ( (True, mock_message, True, "confirmed"), (False, None, False, "_send_prompt failed"), (False, mock_message, False, "aborted"), ) for expected_result, expected_message, confirmed, msg in subtests: with self.subTest(msg=msg): self.syncer._send_prompt = helpers.AsyncMock( return_value=expected_message) self.syncer._wait_for_confirmation = helpers.AsyncMock( return_value=confirmed) coro = self.syncer._get_confirmation_result(4, author) actual_result, actual_message = await coro self.syncer._send_prompt.assert_called_once_with( None) # message defaults to None self.assertIs(actual_result, expected_result) self.assertEqual(actual_message, expected_message) if expected_message: self.syncer._wait_for_confirmation.assert_called_once_with( author, expected_message)
async def test_sync_respects_confirmation_result(self): """The sync should abort if confirmation fails and continue if confirmed.""" mock_message = helpers.MockMessage() subtests = ( (True, mock_message), (False, None), ) for confirmed, message in subtests: with self.subTest(confirmed=confirmed): self.syncer._sync.reset_mock() self.syncer._get_diff.reset_mock() diff = _Diff({1, 2, 3}, {4, 5}, None) self.syncer._get_diff.return_value = diff self.syncer._get_confirmation_result = helpers.AsyncMock( return_value=(confirmed, message)) guild = helpers.MockGuild() await self.syncer.sync(guild) self.syncer._get_diff.assert_called_once_with(guild) self.syncer._get_confirmation_result.assert_called_once() if confirmed: self.syncer._sync.assert_called_once_with(diff) else: self.syncer._sync.assert_not_called()
async def test_sync_confirmation_context_redirect(self): """If ctx is given, a new message should be sent and author should be ctx's author.""" mock_member = helpers.MockMember() subtests = ( (None, self.bot.user, None), (helpers.MockContext(author=mock_member), mock_member, helpers.MockMessage()), ) for ctx, author, message in subtests: with self.subTest(ctx=ctx, author=author, message=message): if ctx is not None: ctx.send.return_value = message self.syncer._get_confirmation_result = helpers.AsyncMock( return_value=(False, None)) guild = helpers.MockGuild() await self.syncer.sync(guild, ctx) if ctx is not None: ctx.send.assert_called_once() self.syncer._get_confirmation_result.assert_called_once() self.assertEqual( self.syncer._get_confirmation_result.call_args[0][1], author) self.assertEqual( self.syncer._get_confirmation_result.call_args[0][2], message)
def test_async_mock_provides_coroutine_for_dunder_call(self): """Test if AsyncMock objects have a coroutine for their __call__ method.""" async_mock = helpers.AsyncMock() self.assertTrue(inspect.iscoroutinefunction(async_mock.__call__)) coroutine = async_mock() self.assertTrue(inspect.iscoroutine(coroutine)) self.assertIsNotNone(asyncio.run(coroutine))
async def test_confirmation_result_small_diff(self): """Should always return True and the given message if the diff size is too small.""" author = helpers.MockMember() expected_message = helpers.MockMessage() for size in (3, 2): with self.subTest(size=size): self.syncer._send_prompt = helpers.AsyncMock() self.syncer._wait_for_confirmation = helpers.AsyncMock() coro = self.syncer._get_confirmation_result( size, author, expected_message) result, actual_message = await coro self.assertTrue(result) self.assertEqual(actual_message, expected_message) self.syncer._send_prompt.assert_not_called() self.syncer._wait_for_confirmation.assert_not_called()
def test_role_info_command(self): """Tests the `role info` command.""" dummy_role = helpers.MockRole(name="Dummy", role_id=112233445566778899, colour=discord.Colour.blurple(), position=10, members=[self.ctx.author], permissions=discord.Permissions(0)) admin_role = helpers.MockRole( name="Admins", role_id=998877665544332211, colour=discord.Colour.red(), position=3, members=[self.ctx.author], permissions=discord.Permissions(0), ) self.ctx.guild.roles.append([dummy_role, admin_role]) self.cog.role_info.can_run = helpers.AsyncMock() self.cog.role_info.can_run.return_value = True coroutine = self.cog.role_info.callback(self.cog, self.ctx, dummy_role, admin_role) self.assertIsNone(asyncio.run(coroutine)) self.assertEqual(self.ctx.send.call_count, 2) (_, dummy_kwargs), (_, admin_kwargs) = self.ctx.send.call_args_list dummy_embed = dummy_kwargs["embed"] admin_embed = admin_kwargs["embed"] self.assertEqual(dummy_embed.title, "Dummy info") self.assertEqual(dummy_embed.colour, discord.Colour.blurple()) self.assertEqual(dummy_embed.fields[0].value, str(dummy_role.id)) self.assertEqual(dummy_embed.fields[1].value, f"#{dummy_role.colour.value:0>6x}") self.assertEqual(dummy_embed.fields[2].value, "0.63 0.48 218") self.assertEqual(dummy_embed.fields[3].value, "1") self.assertEqual(dummy_embed.fields[4].value, "10") self.assertEqual(dummy_embed.fields[5].value, "0") self.assertEqual(admin_embed.title, "Admins info") self.assertEqual(admin_embed.colour, discord.Colour.red())
def test_roles_command_command(self): """Test if the `role_info` command correctly returns the `moderator_role`.""" self.ctx.guild.roles.append(self.moderator_role) self.cog.roles_info.can_run = helpers.AsyncMock() self.cog.roles_info.can_run.return_value = True coroutine = self.cog.roles_info.callback(self.cog, self.ctx) self.assertIsNone(asyncio.run(coroutine)) self.ctx.send.assert_called_once() _, kwargs = self.ctx.send.call_args embed = kwargs.pop('embed') self.assertEqual(embed.title, "Role information") self.assertEqual(embed.colour, discord.Colour.blurple()) self.assertEqual(embed.description, f"`{self.moderator_role.id}` - {self.moderator_role.mention}\n") self.assertEqual(embed.footer.text, "Total roles: 1")
async def test_sync_message_edited(self): """The message should be edited if one was sent, even if the sync has an API error.""" subtests = ( (None, None, False), (helpers.MockMessage(), None, True), (helpers.MockMessage(), ResponseCodeError(mock.MagicMock()), True), ) for message, side_effect, should_edit in subtests: with self.subTest(message=message, side_effect=side_effect, should_edit=should_edit): self.syncer._sync.side_effect = side_effect self.syncer._get_confirmation_result = helpers.AsyncMock( return_value=(True, message)) guild = helpers.MockGuild() await self.syncer.sync(guild) if should_edit: message.edit.assert_called_once() self.assertIn("content", message.edit.call_args[1])
async def test_sync_diff_size(self): """The diff size should be correctly calculated.""" subtests = ( (6, _Diff({1, 2}, {3, 4}, {5, 6})), (5, _Diff({1, 2, 3}, None, {4, 5})), (0, _Diff(None, None, None)), (0, _Diff(set(), set(), set())), ) for size, diff in subtests: with self.subTest(size=size, diff=diff): self.syncer._get_diff.reset_mock() self.syncer._get_diff.return_value = diff self.syncer._get_confirmation_result = helpers.AsyncMock( return_value=(False, None)) guild = helpers.MockGuild() await self.syncer.sync(guild) self.syncer._get_diff.assert_called_once_with(guild) self.syncer._get_confirmation_result.assert_called_once() self.assertEqual( self.syncer._get_confirmation_result.call_args[0][0], size)
def __init__(self, **kwargs): super().__init__(spec=helpers.bot_instance, **kwargs) # Fake attribute self.release_the_walrus = helpers.AsyncMock()
def setUp(self): """Common set-up steps done before for each test.""" self.bot = helpers.MockBot() self.bot.api_client.get = helpers.AsyncMock() self.cog = information.Information(self.bot)
class UserEmbedTests(unittest.TestCase): """Tests for the creation of the `!user` embed.""" def setUp(self): """Common set-up steps done before for each test.""" self.bot = helpers.MockBot() self.bot.api_client.get = helpers.AsyncMock() self.cog = information.Information(self.bot) @unittest.mock.patch(f"{COG_PATH}.basic_user_infraction_counts", new=helpers.AsyncMock(return_value="")) def test_create_user_embed_uses_string_representation_of_user_in_title_if_nick_is_not_available( self): """The embed should use the string representation of the user if they don't have a nick.""" ctx = helpers.MockContext(channel=helpers.MockTextChannel( channel_id=1)) user = helpers.MockMember() user.nick = None user.__str__ = unittest.mock.Mock(return_value="Mr. Hemlock") embed = asyncio.run(self.cog.create_user_embed(ctx, user)) self.assertEqual(embed.title, "Mr. Hemlock") @unittest.mock.patch(f"{COG_PATH}.basic_user_infraction_counts", new=helpers.AsyncMock(return_value="")) def test_create_user_embed_uses_nick_in_title_if_available(self): """The embed should use the nick if it's available.""" ctx = helpers.MockContext(channel=helpers.MockTextChannel( channel_id=1)) user = helpers.MockMember() user.nick = "Cat lover" user.__str__ = unittest.mock.Mock(return_value="Mr. Hemlock") embed = asyncio.run(self.cog.create_user_embed(ctx, user)) self.assertEqual(embed.title, "Cat lover (Mr. Hemlock)") @unittest.mock.patch(f"{COG_PATH}.basic_user_infraction_counts", new=helpers.AsyncMock(return_value="")) def test_create_user_embed_ignores_everyone_role(self): """Created `!user` embeds should not contain mention of the @everyone-role.""" ctx = helpers.MockContext(channel=helpers.MockTextChannel( channel_id=1)) admins_role = helpers.MockRole('Admins') admins_role.colour = 100 # A `MockMember` has the @Everyone role by default; we add the Admins to that. user = helpers.MockMember(roles=[admins_role], top_role=admins_role) embed = asyncio.run(self.cog.create_user_embed(ctx, user)) self.assertIn("&Admins", embed.description) self.assertNotIn("&Everyone", embed.description) @unittest.mock.patch(f"{COG_PATH}.expanded_user_infraction_counts", new_callable=helpers.AsyncMock) @unittest.mock.patch(f"{COG_PATH}.user_nomination_counts", new_callable=helpers.AsyncMock) def test_create_user_embed_expanded_information_in_moderation_channels( self, nomination_counts, infraction_counts): """The embed should contain expanded infractions and nomination info in mod channels.""" ctx = helpers.MockContext(channel=helpers.MockTextChannel( channel_id=50)) moderators_role = helpers.MockRole('Moderators') moderators_role.colour = 100 infraction_counts.return_value = "expanded infractions info" nomination_counts.return_value = "nomination info" user = helpers.MockMember(user_id=314, roles=[moderators_role], top_role=moderators_role) embed = asyncio.run(self.cog.create_user_embed(ctx, user)) infraction_counts.assert_called_once_with(user) nomination_counts.assert_called_once_with(user) self.assertEqual( textwrap.dedent(f""" **User Information** Created: {"1 year ago"} Profile: {user.mention} ID: {user.id} **Member Information** Joined: {"1 year ago"} Roles: &Moderators expanded infractions info nomination info """).strip(), embed.description) @unittest.mock.patch(f"{COG_PATH}.basic_user_infraction_counts", new_callable=helpers.AsyncMock) def test_create_user_embed_basic_information_outside_of_moderation_channels( self, infraction_counts): """The embed should contain only basic infraction data outside of mod channels.""" ctx = helpers.MockContext(channel=helpers.MockTextChannel( channel_id=100)) moderators_role = helpers.MockRole('Moderators') moderators_role.colour = 100 infraction_counts.return_value = "basic infractions info" user = helpers.MockMember(user_id=314, roles=[moderators_role], top_role=moderators_role) embed = asyncio.run(self.cog.create_user_embed(ctx, user)) infraction_counts.assert_called_once_with(user) self.assertEqual( textwrap.dedent(f""" **User Information** Created: {"1 year ago"} Profile: {user.mention} ID: {user.id} **Member Information** Joined: {"1 year ago"} Roles: &Moderators basic infractions info """).strip(), embed.description) @unittest.mock.patch(f"{COG_PATH}.basic_user_infraction_counts", new=helpers.AsyncMock(return_value="")) def test_create_user_embed_uses_top_role_colour_when_user_has_roles(self): """The embed should be created with the colour of the top role, if a top role is available.""" ctx = helpers.MockContext() moderators_role = helpers.MockRole('Moderators') moderators_role.colour = 100 user = helpers.MockMember(user_id=314, roles=[moderators_role], top_role=moderators_role) embed = asyncio.run(self.cog.create_user_embed(ctx, user)) self.assertEqual(embed.colour, discord.Colour(moderators_role.colour)) @unittest.mock.patch(f"{COG_PATH}.basic_user_infraction_counts", new=helpers.AsyncMock(return_value="")) def test_create_user_embed_uses_blurple_colour_when_user_has_no_roles( self): """The embed should be created with a blurple colour if the user has no assigned roles.""" ctx = helpers.MockContext() user = helpers.MockMember(user_id=217) embed = asyncio.run(self.cog.create_user_embed(ctx, user)) self.assertEqual(embed.colour, discord.Colour.blurple()) @unittest.mock.patch(f"{COG_PATH}.basic_user_infraction_counts", new=helpers.AsyncMock(return_value="")) def test_create_user_embed_uses_png_format_of_user_avatar_as_thumbnail( self): """The embed thumbnail should be set to the user's avatar in `png` format.""" ctx = helpers.MockContext() user = helpers.MockMember(user_id=217) user.avatar_url_as.return_value = "avatar url" embed = asyncio.run(self.cog.create_user_embed(ctx, user)) user.avatar_url_as.assert_called_once_with(format="png") self.assertEqual(embed.thumbnail.url, "avatar url")
class TestSyncer(Syncer): """Syncer subclass with mocks for abstract methods for testing purposes.""" name = "test" _get_diff = helpers.AsyncMock() _sync = helpers.AsyncMock()
def setUp(self): super().setUp() self.cog.patch_user = helpers.AsyncMock(spec_set=self.cog.patch_user)