From d4253e106771f90a983717a994349d52337b2de9 Mon Sep 17 00:00:00 2001 From: Numerlor <25886452+Numerlor@users.noreply.github.com> Date: Sun, 8 Mar 2020 19:40:34 +0100 Subject: Add tests for FirstHash class. --- tests/bot/cogs/moderation/__init__.py | 0 tests/bot/cogs/moderation/test_silence.py | 25 +++++++++++++++++++++++++ 2 files changed, 25 insertions(+) create mode 100644 tests/bot/cogs/moderation/__init__.py create mode 100644 tests/bot/cogs/moderation/test_silence.py (limited to 'tests') diff --git a/tests/bot/cogs/moderation/__init__.py b/tests/bot/cogs/moderation/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/tests/bot/cogs/moderation/test_silence.py b/tests/bot/cogs/moderation/test_silence.py new file mode 100644 index 000000000..2a06f5944 --- /dev/null +++ b/tests/bot/cogs/moderation/test_silence.py @@ -0,0 +1,25 @@ +import unittest + +from bot.cogs.moderation.silence import FirstHash + + +class FirstHashTests(unittest.TestCase): + def setUp(self) -> None: + self.test_cases = ( + (FirstHash(0, 4), FirstHash(0, 5)), + (FirstHash("string", None), FirstHash("string", True)) + ) + + def test_hashes_equal(self): + """Check hashes equal with same first item.""" + + for tuple1, tuple2 in self.test_cases: + with self.subTest(tuple1=tuple1, tuple2=tuple2): + self.assertEqual(hash(tuple1), hash(tuple2)) + + def test_eq(self): + """Check objects are equal with same first item.""" + + for tuple1, tuple2 in self.test_cases: + with self.subTest(tuple1=tuple1, tuple2=tuple2): + self.assertTrue(tuple1 == tuple2) -- cgit v1.2.3 From e872176b452ceca1b639ef42d640e18656c7c0c9 Mon Sep 17 00:00:00 2001 From: Numerlor <25886452+Numerlor@users.noreply.github.com> Date: Sun, 8 Mar 2020 19:42:18 +0100 Subject: Add test case for Silence cog. --- tests/bot/cogs/moderation/test_silence.py | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) (limited to 'tests') diff --git a/tests/bot/cogs/moderation/test_silence.py b/tests/bot/cogs/moderation/test_silence.py index 2a06f5944..1db2b6eec 100644 --- a/tests/bot/cogs/moderation/test_silence.py +++ b/tests/bot/cogs/moderation/test_silence.py @@ -1,6 +1,7 @@ import unittest -from bot.cogs.moderation.silence import FirstHash +from bot.cogs.moderation.silence import FirstHash, Silence +from tests.helpers import MockBot, MockContext class FirstHashTests(unittest.TestCase): @@ -23,3 +24,11 @@ class FirstHashTests(unittest.TestCase): for tuple1, tuple2 in self.test_cases: with self.subTest(tuple1=tuple1, tuple2=tuple2): self.assertTrue(tuple1 == tuple2) + + +class SilenceTests(unittest.TestCase): + def setUp(self) -> None: + + self.bot = MockBot() + self.cog = Silence(self.bot) + self.ctx = MockContext() -- cgit v1.2.3 From 1d83a5752aae483224129ee798e529f3d7d8e132 Mon Sep 17 00:00:00 2001 From: Numerlor <25886452+Numerlor@users.noreply.github.com> Date: Sun, 8 Mar 2020 19:42:51 +0100 Subject: Add test for `silence` discord output. --- tests/bot/cogs/moderation/test_silence.py | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) (limited to 'tests') diff --git a/tests/bot/cogs/moderation/test_silence.py b/tests/bot/cogs/moderation/test_silence.py index 1db2b6eec..088410bee 100644 --- a/tests/bot/cogs/moderation/test_silence.py +++ b/tests/bot/cogs/moderation/test_silence.py @@ -1,6 +1,10 @@ +import asyncio import unittest +from functools import partial +from unittest import mock from bot.cogs.moderation.silence import FirstHash, Silence +from bot.constants import Emojis from tests.helpers import MockBot, MockContext @@ -32,3 +36,23 @@ class SilenceTests(unittest.TestCase): self.bot = MockBot() self.cog = Silence(self.bot) self.ctx = MockContext() + + def test_silence_sent_correct_discord_message(self): + """Check if proper message was sent when called with duration in channel with previous state.""" + test_cases = ( + ((self.cog, self.ctx, 0.0001), f"{Emojis.check_mark} #channel silenced for 0.0001 minute(s).", True,), + ((self.cog, self.ctx, None), f"{Emojis.check_mark} #channel silenced indefinitely.", True,), + ((self.cog, self.ctx, 5), f"{Emojis.cross_mark} #channel is already silenced.", False,), + ) + for silence_call_args, result_message, _silence_patch_return in test_cases: + with self.subTest( + silence_duration=silence_call_args[-1], + result_message=result_message, + starting_unsilenced_state=_silence_patch_return + ): + with mock.patch( + "bot.cogs.moderation.silence.Silence._silence", + new_callable=partial(mock.AsyncMock, return_value=_silence_patch_return) + ): + asyncio.run(self.cog.silence.callback(*silence_call_args)) + self.ctx.send.call_args.assert_called_once_with(result_message) -- cgit v1.2.3 From cfbe3b9742b5531bdced1d5b099739f01033a6bb Mon Sep 17 00:00:00 2001 From: Numerlor <25886452+Numerlor@users.noreply.github.com> Date: Sun, 8 Mar 2020 22:20:00 +0100 Subject: Add test for `unsilence` discord output. --- tests/bot/cogs/moderation/test_silence.py | 9 +++++++++ 1 file changed, 9 insertions(+) (limited to 'tests') diff --git a/tests/bot/cogs/moderation/test_silence.py b/tests/bot/cogs/moderation/test_silence.py index 088410bee..17420ce7d 100644 --- a/tests/bot/cogs/moderation/test_silence.py +++ b/tests/bot/cogs/moderation/test_silence.py @@ -56,3 +56,12 @@ class SilenceTests(unittest.TestCase): ): asyncio.run(self.cog.silence.callback(*silence_call_args)) self.ctx.send.call_args.assert_called_once_with(result_message) + + def test_unsilence_sent_correct_discord_message(self): + """Check if proper message was sent to `alert_chanel`.""" + with mock.patch( + "bot.cogs.moderation.silence.Silence._unsilence", + new_callable=partial(mock.AsyncMock, return_value=True) + ): + asyncio.run(self.cog.unsilence.callback(self.cog, self.ctx)) + self.ctx.channel.send.call_args.assert_called_once_with(f"{Emojis.check_mark} Unsilenced #channel.") -- cgit v1.2.3 From ee94c38063981ee6770c1d263eab9c0d2e178380 Mon Sep 17 00:00:00 2001 From: Numerlor <25886452+Numerlor@users.noreply.github.com> Date: Mon, 9 Mar 2020 20:41:55 +0100 Subject: Use `patch.object` instead of patch with direct `return_value`. --- tests/bot/cogs/moderation/test_silence.py | 11 ++--------- 1 file changed, 2 insertions(+), 9 deletions(-) (limited to 'tests') diff --git a/tests/bot/cogs/moderation/test_silence.py b/tests/bot/cogs/moderation/test_silence.py index 17420ce7d..53b3fd388 100644 --- a/tests/bot/cogs/moderation/test_silence.py +++ b/tests/bot/cogs/moderation/test_silence.py @@ -1,6 +1,5 @@ import asyncio import unittest -from functools import partial from unittest import mock from bot.cogs.moderation.silence import FirstHash, Silence @@ -50,18 +49,12 @@ class SilenceTests(unittest.TestCase): result_message=result_message, starting_unsilenced_state=_silence_patch_return ): - with mock.patch( - "bot.cogs.moderation.silence.Silence._silence", - new_callable=partial(mock.AsyncMock, return_value=_silence_patch_return) - ): + with mock.patch.object(self.cog, "_silence", return_value=_silence_patch_return): asyncio.run(self.cog.silence.callback(*silence_call_args)) self.ctx.send.call_args.assert_called_once_with(result_message) def test_unsilence_sent_correct_discord_message(self): """Check if proper message was sent to `alert_chanel`.""" - with mock.patch( - "bot.cogs.moderation.silence.Silence._unsilence", - new_callable=partial(mock.AsyncMock, return_value=True) - ): + with mock.patch.object(self.cog, "_unsilence", return_value=True): asyncio.run(self.cog.unsilence.callback(self.cog, self.ctx)) self.ctx.channel.send.call_args.assert_called_once_with(f"{Emojis.check_mark} Unsilenced #channel.") -- cgit v1.2.3 From 85c439fbf78f59ff314f4f9daef1467d486709c3 Mon Sep 17 00:00:00 2001 From: Numerlor <25886452+Numerlor@users.noreply.github.com> Date: Wed, 11 Mar 2020 00:01:58 +0100 Subject: Remove unnecessary args from test cases. Needless call args which were constant were kept in the test cases, resulting in redundant code, the args were moved directly into the function call. --- tests/bot/cogs/moderation/test_silence.py | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) (limited to 'tests') diff --git a/tests/bot/cogs/moderation/test_silence.py b/tests/bot/cogs/moderation/test_silence.py index 53b3fd388..1341911d5 100644 --- a/tests/bot/cogs/moderation/test_silence.py +++ b/tests/bot/cogs/moderation/test_silence.py @@ -39,18 +39,18 @@ class SilenceTests(unittest.TestCase): def test_silence_sent_correct_discord_message(self): """Check if proper message was sent when called with duration in channel with previous state.""" test_cases = ( - ((self.cog, self.ctx, 0.0001), f"{Emojis.check_mark} #channel silenced for 0.0001 minute(s).", True,), - ((self.cog, self.ctx, None), f"{Emojis.check_mark} #channel silenced indefinitely.", True,), - ((self.cog, self.ctx, 5), f"{Emojis.cross_mark} #channel is already silenced.", False,), + (0.0001, f"{Emojis.check_mark} #channel silenced for 0.0001 minute(s).", True,), + (None, f"{Emojis.check_mark} #channel silenced indefinitely.", True,), + (5, f"{Emojis.cross_mark} #channel is already silenced.", False,), ) - for silence_call_args, result_message, _silence_patch_return in test_cases: + for duration, result_message, _silence_patch_return in test_cases: with self.subTest( - silence_duration=silence_call_args[-1], + silence_duration=duration, result_message=result_message, starting_unsilenced_state=_silence_patch_return ): with mock.patch.object(self.cog, "_silence", return_value=_silence_patch_return): - asyncio.run(self.cog.silence.callback(*silence_call_args)) + asyncio.run(self.cog.silence.callback(self.cog, self.ctx, duration)) self.ctx.send.call_args.assert_called_once_with(result_message) def test_unsilence_sent_correct_discord_message(self): -- cgit v1.2.3 From adaf456607ba2f2724c6fd34308cd170c81aa651 Mon Sep 17 00:00:00 2001 From: Numerlor <25886452+Numerlor@users.noreply.github.com> Date: Wed, 11 Mar 2020 00:56:31 +0100 Subject: Remove channel mentions from output discord messages. With the removal of the channel args, it's no longer necessary to mention the channel in the command output. Tests adjusted accordingly --- bot/cogs/moderation/silence.py | 8 ++++---- tests/bot/cogs/moderation/test_silence.py | 8 ++++---- 2 files changed, 8 insertions(+), 8 deletions(-) (limited to 'tests') diff --git a/bot/cogs/moderation/silence.py b/bot/cogs/moderation/silence.py index 76c5a171d..68cad4062 100644 --- a/bot/cogs/moderation/silence.py +++ b/bot/cogs/moderation/silence.py @@ -92,13 +92,13 @@ class Silence(commands.Cog): If duration is forever, start a notifier loop that triggers every 15 minutes. """ if not await self._silence(ctx.channel, persistent=(duration is None), duration=duration): - await ctx.send(f"{Emojis.cross_mark} {ctx.channel.mention} is already silenced.") + await ctx.send(f"{Emojis.cross_mark} current channel is already silenced.") return if duration is None: - await ctx.send(f"{Emojis.check_mark} {ctx.channel.mention} silenced indefinitely.") + await ctx.send(f"{Emojis.check_mark} silenced current channel indefinitely.") return - await ctx.send(f"{Emojis.check_mark} {ctx.channel.mention} silenced for {duration} minute(s).") + await ctx.send(f"{Emojis.check_mark} silenced current channel for {duration} minute(s).") await asyncio.sleep(duration*60) await ctx.invoke(self.unsilence) @@ -110,7 +110,7 @@ class Silence(commands.Cog): Unsilence a previously silenced `channel` and remove it from indefinitely muted channels notice if applicable. """ if await self._unsilence(ctx.channel): - await ctx.send(f"{Emojis.check_mark} Unsilenced {ctx.channel.mention}.") + await ctx.send(f"{Emojis.check_mark} unsilenced current channel.") async def _silence(self, channel: TextChannel, persistent: bool, duration: Optional[int]) -> bool: """ diff --git a/tests/bot/cogs/moderation/test_silence.py b/tests/bot/cogs/moderation/test_silence.py index 1341911d5..6da374a8f 100644 --- a/tests/bot/cogs/moderation/test_silence.py +++ b/tests/bot/cogs/moderation/test_silence.py @@ -39,9 +39,9 @@ class SilenceTests(unittest.TestCase): def test_silence_sent_correct_discord_message(self): """Check if proper message was sent when called with duration in channel with previous state.""" test_cases = ( - (0.0001, f"{Emojis.check_mark} #channel silenced for 0.0001 minute(s).", True,), - (None, f"{Emojis.check_mark} #channel silenced indefinitely.", True,), - (5, f"{Emojis.cross_mark} #channel is already silenced.", False,), + (0.0001, f"{Emojis.check_mark} silenced current channel for 0.0001 minute(s).", True,), + (None, f"{Emojis.check_mark} silenced current channel indefinitely.", True,), + (5, f"{Emojis.cross_mark} current channel is already silenced.", False,), ) for duration, result_message, _silence_patch_return in test_cases: with self.subTest( @@ -57,4 +57,4 @@ class SilenceTests(unittest.TestCase): """Check if proper message was sent to `alert_chanel`.""" with mock.patch.object(self.cog, "_unsilence", return_value=True): asyncio.run(self.cog.unsilence.callback(self.cog, self.ctx)) - self.ctx.channel.send.call_args.assert_called_once_with(f"{Emojis.check_mark} Unsilenced #channel.") + self.ctx.send.call_args.assert_called_once_with(f"{Emojis.check_mark} unsilenced current channel.") -- cgit v1.2.3 From 68d43946d1dc6393a4f7b8b4812b5c4787842c12 Mon Sep 17 00:00:00 2001 From: Numerlor <25886452+Numerlor@users.noreply.github.com> Date: Wed, 11 Mar 2020 01:28:26 +0100 Subject: Add test for `_silence` method. --- tests/bot/cogs/moderation/test_silence.py | 35 ++++++++++++++++++++++++++++++- 1 file changed, 34 insertions(+), 1 deletion(-) (limited to 'tests') diff --git a/tests/bot/cogs/moderation/test_silence.py b/tests/bot/cogs/moderation/test_silence.py index 6da374a8f..6a75db2a0 100644 --- a/tests/bot/cogs/moderation/test_silence.py +++ b/tests/bot/cogs/moderation/test_silence.py @@ -1,10 +1,11 @@ import asyncio import unittest from unittest import mock +from unittest.mock import Mock from bot.cogs.moderation.silence import FirstHash, Silence from bot.constants import Emojis -from tests.helpers import MockBot, MockContext +from tests.helpers import MockBot, MockContext, MockTextChannel class FirstHashTests(unittest.TestCase): @@ -35,6 +36,7 @@ class SilenceTests(unittest.TestCase): self.bot = MockBot() self.cog = Silence(self.bot) self.ctx = MockContext() + self.cog._verified_role = None def test_silence_sent_correct_discord_message(self): """Check if proper message was sent when called with duration in channel with previous state.""" @@ -58,3 +60,34 @@ class SilenceTests(unittest.TestCase): with mock.patch.object(self.cog, "_unsilence", return_value=True): asyncio.run(self.cog.unsilence.callback(self.cog, self.ctx)) self.ctx.send.call_args.assert_called_once_with(f"{Emojis.check_mark} unsilenced current channel.") + + def test_silence_private_for_false(self): + """Permissions are not set and `False` is returned in an already silenced channel.""" + perm_overwrite = Mock(send_messages=False) + channel = Mock(overwrites_for=Mock(return_value=perm_overwrite)) + + self.assertFalse(asyncio.run(self.cog._silence(channel, True, None))) + channel.set_permissions.assert_not_called() + + def test_silence_private_silenced_channel(self): + """Channel had `send_message` permissions revoked and was added to `muted_channels`.""" + channel = MockTextChannel() + muted_channels = Mock() + with mock.patch.object(self.cog, "muted_channels", new=muted_channels, create=True): + self.assertTrue(asyncio.run(self.cog._silence(channel, False, None))) + channel.set_permissions.assert_called_once() + self.assertFalse(channel.set_permissions.call_args.kwargs['overwrite'].send_messages) + muted_channels.add.call_args.assert_called_once_with(channel) + + def test_silence_private_notifier(self): + """Channel should be added to notifier with `persistent` set to `True`, and the other way around.""" + channel = MockTextChannel() + with mock.patch.object(self.cog, "notifier", create=True): + with self.subTest(persistent=True): + asyncio.run(self.cog._silence(channel, True, None)) + self.cog.notifier.add_channel.assert_called_once() + + with mock.patch.object(self.cog, "notifier", create=True): + with self.subTest(persistent=False): + asyncio.run(self.cog._silence(channel, False, None)) + self.cog.notifier.add_channel.assert_not_called() -- cgit v1.2.3 From fef8c8e8504d8431ae7cad23128733d0b9039c7a Mon Sep 17 00:00:00 2001 From: Numerlor <25886452+Numerlor@users.noreply.github.com> Date: Wed, 11 Mar 2020 02:31:36 +0100 Subject: Use async test case. This allows us to use coroutines with await directly instead of asyncio.run --- tests/bot/cogs/moderation/test_silence.py | 26 ++++++++++++-------------- 1 file changed, 12 insertions(+), 14 deletions(-) (limited to 'tests') diff --git a/tests/bot/cogs/moderation/test_silence.py b/tests/bot/cogs/moderation/test_silence.py index 6a75db2a0..33ff78ca6 100644 --- a/tests/bot/cogs/moderation/test_silence.py +++ b/tests/bot/cogs/moderation/test_silence.py @@ -1,4 +1,3 @@ -import asyncio import unittest from unittest import mock from unittest.mock import Mock @@ -30,15 +29,14 @@ class FirstHashTests(unittest.TestCase): self.assertTrue(tuple1 == tuple2) -class SilenceTests(unittest.TestCase): +class SilenceTests(unittest.IsolatedAsyncioTestCase): def setUp(self) -> None: - self.bot = MockBot() self.cog = Silence(self.bot) self.ctx = MockContext() self.cog._verified_role = None - def test_silence_sent_correct_discord_message(self): + async def test_silence_sent_correct_discord_message(self): """Check if proper message was sent when called with duration in channel with previous state.""" test_cases = ( (0.0001, f"{Emojis.check_mark} silenced current channel for 0.0001 minute(s).", True,), @@ -52,42 +50,42 @@ class SilenceTests(unittest.TestCase): starting_unsilenced_state=_silence_patch_return ): with mock.patch.object(self.cog, "_silence", return_value=_silence_patch_return): - asyncio.run(self.cog.silence.callback(self.cog, self.ctx, duration)) + await self.cog.silence.callback(self.cog, self.ctx, duration) self.ctx.send.call_args.assert_called_once_with(result_message) - def test_unsilence_sent_correct_discord_message(self): + async def test_unsilence_sent_correct_discord_message(self): """Check if proper message was sent to `alert_chanel`.""" with mock.patch.object(self.cog, "_unsilence", return_value=True): - asyncio.run(self.cog.unsilence.callback(self.cog, self.ctx)) + await self.cog.unsilence.callback(self.cog, self.ctx) self.ctx.send.call_args.assert_called_once_with(f"{Emojis.check_mark} unsilenced current channel.") - def test_silence_private_for_false(self): + async def test_silence_private_for_false(self): """Permissions are not set and `False` is returned in an already silenced channel.""" perm_overwrite = Mock(send_messages=False) channel = Mock(overwrites_for=Mock(return_value=perm_overwrite)) - self.assertFalse(asyncio.run(self.cog._silence(channel, True, None))) + self.assertFalse(await self.cog._silence(channel, True, None)) channel.set_permissions.assert_not_called() - def test_silence_private_silenced_channel(self): + async def test_silence_private_silenced_channel(self): """Channel had `send_message` permissions revoked and was added to `muted_channels`.""" channel = MockTextChannel() muted_channels = Mock() with mock.patch.object(self.cog, "muted_channels", new=muted_channels, create=True): - self.assertTrue(asyncio.run(self.cog._silence(channel, False, None))) + self.assertTrue(await self.cog._silence(channel, False, None)) channel.set_permissions.assert_called_once() self.assertFalse(channel.set_permissions.call_args.kwargs['overwrite'].send_messages) muted_channels.add.call_args.assert_called_once_with(channel) - def test_silence_private_notifier(self): + async def test_silence_private_notifier(self): """Channel should be added to notifier with `persistent` set to `True`, and the other way around.""" channel = MockTextChannel() with mock.patch.object(self.cog, "notifier", create=True): with self.subTest(persistent=True): - asyncio.run(self.cog._silence(channel, True, None)) + await self.cog._silence(channel, True, None) self.cog.notifier.add_channel.assert_called_once() with mock.patch.object(self.cog, "notifier", create=True): with self.subTest(persistent=False): - asyncio.run(self.cog._silence(channel, False, None)) + await self.cog._silence(channel, False, None) self.cog.notifier.add_channel.assert_not_called() -- cgit v1.2.3 From c575beccdbe5e4e715a4b11b378dd969a0327191 Mon Sep 17 00:00:00 2001 From: Numerlor <25886452+Numerlor@users.noreply.github.com> Date: Wed, 11 Mar 2020 02:47:07 +0100 Subject: Add tests for `_unsilence` --- tests/bot/cogs/moderation/test_silence.py | 34 ++++++++++++++++++++++++++++++- 1 file changed, 33 insertions(+), 1 deletion(-) (limited to 'tests') diff --git a/tests/bot/cogs/moderation/test_silence.py b/tests/bot/cogs/moderation/test_silence.py index 33ff78ca6..acfa3ffb8 100644 --- a/tests/bot/cogs/moderation/test_silence.py +++ b/tests/bot/cogs/moderation/test_silence.py @@ -1,6 +1,6 @@ import unittest from unittest import mock -from unittest.mock import Mock +from unittest.mock import MagicMock, Mock from bot.cogs.moderation.silence import FirstHash, Silence from bot.constants import Emojis @@ -89,3 +89,35 @@ class SilenceTests(unittest.IsolatedAsyncioTestCase): with self.subTest(persistent=False): await self.cog._silence(channel, False, None) self.cog.notifier.add_channel.assert_not_called() + + async def test_unsilence_private_for_false(self): + """Permissions are not set and `False` is returned in an unsilenced channel.""" + channel = Mock() + self.assertFalse(await self.cog._unsilence(channel)) + channel.set_permissions.assert_not_called() + + async def test_unsilence_private_unsilenced_channel(self): + """Channel had `send_message` permissions restored""" + perm_overwrite = MagicMock(send_messages=False) + channel = MockTextChannel(overwrites_for=Mock(return_value=perm_overwrite)) + with mock.patch.object(self.cog, "notifier", create=True): + self.assertTrue(await self.cog._unsilence(channel)) + channel.set_permissions.assert_called_once() + self.assertTrue(channel.set_permissions.call_args.kwargs['overwrite'].send_messages) + + async def test_unsilence_private_removed_notifier(self): + """Channel was removed from `notifier` on unsilence.""" + perm_overwrite = MagicMock(send_messages=False) + channel = MockTextChannel(overwrites_for=Mock(return_value=perm_overwrite)) + with mock.patch.object(self.cog, "notifier", create=True): + await self.cog._unsilence(channel) + self.cog.notifier.remove_channel.call_args.assert_called_once_with(channel) + + async def test_unsilence_private_removed_muted_channel(self): + """Channel was removed from `muted_channels` on unsilence.""" + perm_overwrite = MagicMock(send_messages=False) + channel = MockTextChannel(overwrites_for=Mock(return_value=perm_overwrite)) + with mock.patch.object(self.cog, "muted_channels", create=True),\ + mock.patch.object(self.cog, "notifier", create=True): # noqa E127 + await self.cog._unsilence(channel) + self.cog.muted_channels.remove.call_args.assert_called_once_with(channel) -- cgit v1.2.3 From a3f07589b215317d6a0fc16d982c3b645fe96151 Mon Sep 17 00:00:00 2001 From: Numerlor <25886452+Numerlor@users.noreply.github.com> Date: Wed, 11 Mar 2020 02:54:35 +0100 Subject: Separate tests for permissions and `muted_channels.add` on `_silence`. --- tests/bot/cogs/moderation/test_silence.py | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) (limited to 'tests') diff --git a/tests/bot/cogs/moderation/test_silence.py b/tests/bot/cogs/moderation/test_silence.py index acfa3ffb8..3a513f3a7 100644 --- a/tests/bot/cogs/moderation/test_silence.py +++ b/tests/bot/cogs/moderation/test_silence.py @@ -68,14 +68,11 @@ class SilenceTests(unittest.IsolatedAsyncioTestCase): channel.set_permissions.assert_not_called() async def test_silence_private_silenced_channel(self): - """Channel had `send_message` permissions revoked and was added to `muted_channels`.""" + """Channel had `send_message` permissions revoked.""" channel = MockTextChannel() - muted_channels = Mock() - with mock.patch.object(self.cog, "muted_channels", new=muted_channels, create=True): - self.assertTrue(await self.cog._silence(channel, False, None)) + self.assertTrue(await self.cog._silence(channel, False, None)) channel.set_permissions.assert_called_once() self.assertFalse(channel.set_permissions.call_args.kwargs['overwrite'].send_messages) - muted_channels.add.call_args.assert_called_once_with(channel) async def test_silence_private_notifier(self): """Channel should be added to notifier with `persistent` set to `True`, and the other way around.""" @@ -90,6 +87,12 @@ class SilenceTests(unittest.IsolatedAsyncioTestCase): await self.cog._silence(channel, False, None) self.cog.notifier.add_channel.assert_not_called() + async def test_silence_private_removed_muted_channel(self): + channel = MockTextChannel() + with mock.patch.object(self.cog, "muted_channels") as muted_channels: + await self.cog._silence(MockTextChannel(), False, None) + muted_channels.add.call_args.assert_called_once_with(channel) + async def test_unsilence_private_for_false(self): """Permissions are not set and `False` is returned in an unsilenced channel.""" channel = Mock() -- cgit v1.2.3 From c72d31f717ac5e755fe3848c99ebf426fcdf6d8b Mon Sep 17 00:00:00 2001 From: Numerlor <25886452+Numerlor@users.noreply.github.com> Date: Wed, 11 Mar 2020 02:58:09 +0100 Subject: Use patch decorators and assign names from `with` patches. --- tests/bot/cogs/moderation/test_silence.py | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) (limited to 'tests') diff --git a/tests/bot/cogs/moderation/test_silence.py b/tests/bot/cogs/moderation/test_silence.py index 3a513f3a7..027508661 100644 --- a/tests/bot/cogs/moderation/test_silence.py +++ b/tests/bot/cogs/moderation/test_silence.py @@ -99,28 +99,28 @@ class SilenceTests(unittest.IsolatedAsyncioTestCase): self.assertFalse(await self.cog._unsilence(channel)) channel.set_permissions.assert_not_called() - async def test_unsilence_private_unsilenced_channel(self): + @mock.patch.object(Silence, "notifier", create=True) + async def test_unsilence_private_unsilenced_channel(self, _): """Channel had `send_message` permissions restored""" perm_overwrite = MagicMock(send_messages=False) channel = MockTextChannel(overwrites_for=Mock(return_value=perm_overwrite)) - with mock.patch.object(self.cog, "notifier", create=True): - self.assertTrue(await self.cog._unsilence(channel)) + self.assertTrue(await self.cog._unsilence(channel)) channel.set_permissions.assert_called_once() self.assertTrue(channel.set_permissions.call_args.kwargs['overwrite'].send_messages) - async def test_unsilence_private_removed_notifier(self): + @mock.patch.object(Silence, "notifier", create=True) + async def test_unsilence_private_removed_notifier(self, notifier): """Channel was removed from `notifier` on unsilence.""" perm_overwrite = MagicMock(send_messages=False) channel = MockTextChannel(overwrites_for=Mock(return_value=perm_overwrite)) - with mock.patch.object(self.cog, "notifier", create=True): - await self.cog._unsilence(channel) - self.cog.notifier.remove_channel.call_args.assert_called_once_with(channel) + await self.cog._unsilence(channel) + notifier.remove_channel.call_args.assert_called_once_with(channel) - async def test_unsilence_private_removed_muted_channel(self): + @mock.patch.object(Silence, "notifier", create=True) + async def test_unsilence_private_removed_muted_channel(self, _): """Channel was removed from `muted_channels` on unsilence.""" perm_overwrite = MagicMock(send_messages=False) channel = MockTextChannel(overwrites_for=Mock(return_value=perm_overwrite)) - with mock.patch.object(self.cog, "muted_channels", create=True),\ - mock.patch.object(self.cog, "notifier", create=True): # noqa E127 + with mock.patch.object(self.cog, "muted_channels") as muted_channels: await self.cog._unsilence(channel) - self.cog.muted_channels.remove.call_args.assert_called_once_with(channel) + muted_channels.remove.call_args.assert_called_once_with(channel) -- cgit v1.2.3 From 44967038f39f4ecd1375fb9edff2b972becb5661 Mon Sep 17 00:00:00 2001 From: Numerlor <25886452+Numerlor@users.noreply.github.com> Date: Wed, 11 Mar 2020 14:51:15 +0100 Subject: Add test for `cog_unload`. --- tests/bot/cogs/moderation/test_silence.py | 18 +++++++++++++++++- 1 file changed, 17 insertions(+), 1 deletion(-) (limited to 'tests') diff --git a/tests/bot/cogs/moderation/test_silence.py b/tests/bot/cogs/moderation/test_silence.py index 027508661..fc2600f5c 100644 --- a/tests/bot/cogs/moderation/test_silence.py +++ b/tests/bot/cogs/moderation/test_silence.py @@ -3,7 +3,7 @@ from unittest import mock from unittest.mock import MagicMock, Mock from bot.cogs.moderation.silence import FirstHash, Silence -from bot.constants import Emojis +from bot.constants import Emojis, Roles from tests.helpers import MockBot, MockContext, MockTextChannel @@ -124,3 +124,19 @@ class SilenceTests(unittest.IsolatedAsyncioTestCase): with mock.patch.object(self.cog, "muted_channels") as muted_channels: await self.cog._unsilence(channel) muted_channels.remove.call_args.assert_called_once_with(channel) + + @mock.patch("bot.cogs.moderation.silence.asyncio") + @mock.patch.object(Silence, "_mod_alerts_channel", create=True) + def test_cog_unload(self, alert_channel, asyncio_mock): + """Task for sending an alert was created with present `muted_channels`.""" + with mock.patch.object(self.cog, "muted_channels"): + self.cog.cog_unload() + asyncio_mock.create_task.call_args.assert_called_once_with( + alert_channel.send(f"<@&{Roles.moderators}> channels left silenced on cog unload: ") + ) + + @mock.patch("bot.cogs.moderation.silence.asyncio") + def test_cog_unload1(self, asyncio_mock): + """No task created with no channels.""" + self.cog.cog_unload() + asyncio_mock.create_task.assert_not_called() -- cgit v1.2.3 From cb9397ba9ef311917629c8904087c1b3c38cc2d3 Mon Sep 17 00:00:00 2001 From: Numerlor <25886452+Numerlor@users.noreply.github.com> Date: Wed, 11 Mar 2020 15:26:03 +0100 Subject: Add test for `cog_check`. --- tests/bot/cogs/moderation/test_silence.py | 7 +++++++ 1 file changed, 7 insertions(+) (limited to 'tests') diff --git a/tests/bot/cogs/moderation/test_silence.py b/tests/bot/cogs/moderation/test_silence.py index fc2600f5c..eaf897d1d 100644 --- a/tests/bot/cogs/moderation/test_silence.py +++ b/tests/bot/cogs/moderation/test_silence.py @@ -140,3 +140,10 @@ class SilenceTests(unittest.IsolatedAsyncioTestCase): """No task created with no channels.""" self.cog.cog_unload() asyncio_mock.create_task.assert_not_called() + + @mock.patch("bot.cogs.moderation.silence.with_role_check") + @mock.patch("bot.cogs.moderation.silence.MODERATION_ROLES", new=(1, 2, 3)) + def test_cog_check(self, role_check): + """Role check is called with `MODERATION_ROLES`""" + self.cog.cog_check(self.ctx) + role_check.assert_called_once_with(self.ctx, *(1, 2, 3)) -- cgit v1.2.3 From fbee48ee04dc6b44f97f229549c62cbfd5cef615 Mon Sep 17 00:00:00 2001 From: Numerlor <25886452+Numerlor@users.noreply.github.com> Date: Wed, 11 Mar 2020 15:32:06 +0100 Subject: Fix erroneous `assert_called_once_with` calls. `assert_called_once_with` was being tested on call_args which always reported success.st. --- tests/bot/cogs/moderation/test_silence.py | 15 +++++++-------- 1 file changed, 7 insertions(+), 8 deletions(-) (limited to 'tests') diff --git a/tests/bot/cogs/moderation/test_silence.py b/tests/bot/cogs/moderation/test_silence.py index eaf897d1d..4163a9af7 100644 --- a/tests/bot/cogs/moderation/test_silence.py +++ b/tests/bot/cogs/moderation/test_silence.py @@ -51,13 +51,13 @@ class SilenceTests(unittest.IsolatedAsyncioTestCase): ): with mock.patch.object(self.cog, "_silence", return_value=_silence_patch_return): await self.cog.silence.callback(self.cog, self.ctx, duration) - self.ctx.send.call_args.assert_called_once_with(result_message) + self.ctx.send.assert_called_once_with(result_message) async def test_unsilence_sent_correct_discord_message(self): """Check if proper message was sent to `alert_chanel`.""" with mock.patch.object(self.cog, "_unsilence", return_value=True): await self.cog.unsilence.callback(self.cog, self.ctx) - self.ctx.send.call_args.assert_called_once_with(f"{Emojis.check_mark} unsilenced current channel.") + self.ctx.send.assert_called_once_with(f"{Emojis.check_mark} unsilenced current channel.") async def test_silence_private_for_false(self): """Permissions are not set and `False` is returned in an already silenced channel.""" @@ -91,7 +91,7 @@ class SilenceTests(unittest.IsolatedAsyncioTestCase): channel = MockTextChannel() with mock.patch.object(self.cog, "muted_channels") as muted_channels: await self.cog._silence(MockTextChannel(), False, None) - muted_channels.add.call_args.assert_called_once_with(channel) + muted_channels.add.assert_called_once_with(channel) async def test_unsilence_private_for_false(self): """Permissions are not set and `False` is returned in an unsilenced channel.""" @@ -114,7 +114,7 @@ class SilenceTests(unittest.IsolatedAsyncioTestCase): perm_overwrite = MagicMock(send_messages=False) channel = MockTextChannel(overwrites_for=Mock(return_value=perm_overwrite)) await self.cog._unsilence(channel) - notifier.remove_channel.call_args.assert_called_once_with(channel) + notifier.remove_channel.assert_called_once_with(channel) @mock.patch.object(Silence, "notifier", create=True) async def test_unsilence_private_removed_muted_channel(self, _): @@ -123,7 +123,7 @@ class SilenceTests(unittest.IsolatedAsyncioTestCase): channel = MockTextChannel(overwrites_for=Mock(return_value=perm_overwrite)) with mock.patch.object(self.cog, "muted_channels") as muted_channels: await self.cog._unsilence(channel) - muted_channels.remove.call_args.assert_called_once_with(channel) + muted_channels.remove.assert_called_once_with(channel) @mock.patch("bot.cogs.moderation.silence.asyncio") @mock.patch.object(Silence, "_mod_alerts_channel", create=True) @@ -131,9 +131,8 @@ class SilenceTests(unittest.IsolatedAsyncioTestCase): """Task for sending an alert was created with present `muted_channels`.""" with mock.patch.object(self.cog, "muted_channels"): self.cog.cog_unload() - asyncio_mock.create_task.call_args.assert_called_once_with( - alert_channel.send(f"<@&{Roles.moderators}> channels left silenced on cog unload: ") - ) + asyncio_mock.create_task.assert_called_once_with(alert_channel.send()) + alert_channel.send.called_once_with(f"<@&{Roles.moderators}> chandnels left silenced on cog unload: ") @mock.patch("bot.cogs.moderation.silence.asyncio") def test_cog_unload1(self, asyncio_mock): -- cgit v1.2.3 From 64b27e557acf268a19246b2eb80ad6a743df95f4 Mon Sep 17 00:00:00 2001 From: Numerlor <25886452+Numerlor@users.noreply.github.com> Date: Wed, 11 Mar 2020 15:32:24 +0100 Subject: Reset `self.ctx` call history after every subtest. --- tests/bot/cogs/moderation/test_silence.py | 1 + 1 file changed, 1 insertion(+) (limited to 'tests') diff --git a/tests/bot/cogs/moderation/test_silence.py b/tests/bot/cogs/moderation/test_silence.py index 4163a9af7..ab2f091ec 100644 --- a/tests/bot/cogs/moderation/test_silence.py +++ b/tests/bot/cogs/moderation/test_silence.py @@ -52,6 +52,7 @@ class SilenceTests(unittest.IsolatedAsyncioTestCase): with mock.patch.object(self.cog, "_silence", return_value=_silence_patch_return): await self.cog.silence.callback(self.cog, self.ctx, duration) self.ctx.send.assert_called_once_with(result_message) + self.ctx.reset_mock() async def test_unsilence_sent_correct_discord_message(self): """Check if proper message was sent to `alert_chanel`.""" -- cgit v1.2.3 From 10428d9a456c7bce533cda53100e4c35930211d6 Mon Sep 17 00:00:00 2001 From: Numerlor <25886452+Numerlor@users.noreply.github.com> Date: Wed, 11 Mar 2020 15:33:05 +0100 Subject: Pass created channel instead of new object. Creating a new object caused the assert to fail because different objects were used. --- tests/bot/cogs/moderation/test_silence.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'tests') diff --git a/tests/bot/cogs/moderation/test_silence.py b/tests/bot/cogs/moderation/test_silence.py index ab2f091ec..23f8a84ab 100644 --- a/tests/bot/cogs/moderation/test_silence.py +++ b/tests/bot/cogs/moderation/test_silence.py @@ -91,7 +91,7 @@ class SilenceTests(unittest.IsolatedAsyncioTestCase): async def test_silence_private_removed_muted_channel(self): channel = MockTextChannel() with mock.patch.object(self.cog, "muted_channels") as muted_channels: - await self.cog._silence(MockTextChannel(), False, None) + await self.cog._silence(channel, False, None) muted_channels.add.assert_called_once_with(channel) async def test_unsilence_private_for_false(self): -- cgit v1.2.3 From b2aa9af7f9f1485aa3ae8ed4d029fd2d72ea17ad Mon Sep 17 00:00:00 2001 From: Numerlor <25886452+Numerlor@users.noreply.github.com> Date: Wed, 11 Mar 2020 16:02:35 +0100 Subject: Add tests for `_get_instance_vars`. --- tests/bot/cogs/moderation/test_silence.py | 29 ++++++++++++++++++++++++++++- 1 file changed, 28 insertions(+), 1 deletion(-) (limited to 'tests') diff --git a/tests/bot/cogs/moderation/test_silence.py b/tests/bot/cogs/moderation/test_silence.py index 23f8a84ab..c9aa7d84f 100644 --- a/tests/bot/cogs/moderation/test_silence.py +++ b/tests/bot/cogs/moderation/test_silence.py @@ -3,7 +3,7 @@ from unittest import mock from unittest.mock import MagicMock, Mock from bot.cogs.moderation.silence import FirstHash, Silence -from bot.constants import Emojis, Roles +from bot.constants import Channels, Emojis, Guild, Roles from tests.helpers import MockBot, MockContext, MockTextChannel @@ -36,6 +36,33 @@ class SilenceTests(unittest.IsolatedAsyncioTestCase): self.ctx = MockContext() self.cog._verified_role = None + async def test_instance_vars_got_guild(self): + """Bot got guild after it became available.""" + await self.cog._get_instance_vars() + self.bot.wait_until_guild_available.assert_called_once() + self.bot.get_guild.assert_called_once_with(Guild.id) + + async def test_instance_vars_got_role(self): + """Got `Roles.verified` role from guild.""" + await self.cog._get_instance_vars() + guild = self.bot.get_guild() + guild.get_role.assert_called_once_with(Roles.verified) + + async def test_instance_vars_got_channels(self): + """Got channels from bot.""" + await self.cog._get_instance_vars() + self.bot.get_channel.called_once_with(Channels.mod_alerts) + self.bot.get_channel.called_once_with(Channels.mod_log) + + @mock.patch("bot.cogs.moderation.silence.SilenceNotifier") + async def test_instance_vars_got_notifier(self, notifier): + """Notifier was started with channel.""" + mod_log = MockTextChannel() + self.bot.get_channel.side_effect = (None, mod_log) + await self.cog._get_instance_vars() + notifier.assert_called_once_with(mod_log) + self.bot.get_channel.side_effect = None + async def test_silence_sent_correct_discord_message(self): """Check if proper message was sent when called with duration in channel with previous state.""" test_cases = ( -- cgit v1.2.3 From 8ee70ffe645621a6b97172176afe1ac63261df31 Mon Sep 17 00:00:00 2001 From: Numerlor <25886452+Numerlor@users.noreply.github.com> Date: Wed, 11 Mar 2020 16:10:38 +0100 Subject: Create test case for `SilenceNotifier` --- tests/bot/cogs/moderation/test_silence.py | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) (limited to 'tests') diff --git a/tests/bot/cogs/moderation/test_silence.py b/tests/bot/cogs/moderation/test_silence.py index c9aa7d84f..fc7734d45 100644 --- a/tests/bot/cogs/moderation/test_silence.py +++ b/tests/bot/cogs/moderation/test_silence.py @@ -2,7 +2,7 @@ import unittest from unittest import mock from unittest.mock import MagicMock, Mock -from bot.cogs.moderation.silence import FirstHash, Silence +from bot.cogs.moderation.silence import FirstHash, Silence, SilenceNotifier from bot.constants import Channels, Emojis, Guild, Roles from tests.helpers import MockBot, MockContext, MockTextChannel @@ -29,6 +29,12 @@ class FirstHashTests(unittest.TestCase): self.assertTrue(tuple1 == tuple2) +class SilenceNotifierTests(unittest.IsolatedAsyncioTestCase): + def setUp(self) -> None: + self.alert_channel = MockTextChannel() + self.notifier = SilenceNotifier(self.alert_channel) + + class SilenceTests(unittest.IsolatedAsyncioTestCase): def setUp(self) -> None: self.bot = MockBot() -- cgit v1.2.3 From fd75f10f3c8a588bd1763873baad08b8f90d58a3 Mon Sep 17 00:00:00 2001 From: Numerlor <25886452+Numerlor@users.noreply.github.com> Date: Wed, 11 Mar 2020 17:09:40 +0100 Subject: Add tests for `add_channel`. --- tests/bot/cogs/moderation/test_silence.py | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) (limited to 'tests') diff --git a/tests/bot/cogs/moderation/test_silence.py b/tests/bot/cogs/moderation/test_silence.py index fc7734d45..be5b8e550 100644 --- a/tests/bot/cogs/moderation/test_silence.py +++ b/tests/bot/cogs/moderation/test_silence.py @@ -33,6 +33,27 @@ class SilenceNotifierTests(unittest.IsolatedAsyncioTestCase): def setUp(self) -> None: self.alert_channel = MockTextChannel() self.notifier = SilenceNotifier(self.alert_channel) + self.notifier.stop = self.notifier_stop_mock = Mock() + self.notifier.start = self.notifier_start_mock = Mock() + self.notifier._current_loop = self.current_loop_mock = Mock() + + def test_add_channel_adds_channel(self): + """Channel in FirstHash with current loop is added to internal set.""" + channel = Mock() + with mock.patch.object(self.notifier, "_silenced_channels") as silenced_channels: + self.notifier.add_channel(channel) + silenced_channels.add.assert_called_with(FirstHash(channel, self.current_loop_mock)) + + def test_add_channel_starts_loop(self): + """Loop is started if `_silenced_channels` was empty.""" + self.notifier.add_channel(Mock()) + self.notifier_start_mock.assert_called_once() + + def test_add_channel_skips_start_with_channels(self): + """Loop start is not called when `_silenced_channels` is not empty.""" + with mock.patch.object(self.notifier, "_silenced_channels"): + self.notifier.add_channel(Mock()) + self.notifier_start_mock.assert_not_called() class SilenceTests(unittest.IsolatedAsyncioTestCase): -- cgit v1.2.3 From d9c904164a9e54750ce8ee36535bceacfc4800f5 Mon Sep 17 00:00:00 2001 From: Numerlor <25886452+Numerlor@users.noreply.github.com> Date: Wed, 11 Mar 2020 18:06:53 +0100 Subject: Remove `_current_loop` from setup. --- tests/bot/cogs/moderation/test_silence.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) (limited to 'tests') diff --git a/tests/bot/cogs/moderation/test_silence.py b/tests/bot/cogs/moderation/test_silence.py index be5b8e550..2e04dc407 100644 --- a/tests/bot/cogs/moderation/test_silence.py +++ b/tests/bot/cogs/moderation/test_silence.py @@ -35,14 +35,13 @@ class SilenceNotifierTests(unittest.IsolatedAsyncioTestCase): self.notifier = SilenceNotifier(self.alert_channel) self.notifier.stop = self.notifier_stop_mock = Mock() self.notifier.start = self.notifier_start_mock = Mock() - self.notifier._current_loop = self.current_loop_mock = Mock() def test_add_channel_adds_channel(self): """Channel in FirstHash with current loop is added to internal set.""" channel = Mock() with mock.patch.object(self.notifier, "_silenced_channels") as silenced_channels: self.notifier.add_channel(channel) - silenced_channels.add.assert_called_with(FirstHash(channel, self.current_loop_mock)) + silenced_channels.add.assert_called_with(FirstHash(channel, self.notifier._current_loop)) def test_add_channel_starts_loop(self): """Loop is started if `_silenced_channels` was empty.""" -- cgit v1.2.3 From 4740c0fcdc6da6f164963fb34715e78c5d586cec Mon Sep 17 00:00:00 2001 From: Numerlor <25886452+Numerlor@users.noreply.github.com> Date: Wed, 11 Mar 2020 18:07:14 +0100 Subject: Add tests for `remove_channel`. --- tests/bot/cogs/moderation/test_silence.py | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) (limited to 'tests') diff --git a/tests/bot/cogs/moderation/test_silence.py b/tests/bot/cogs/moderation/test_silence.py index 2e04dc407..c52ca2a2a 100644 --- a/tests/bot/cogs/moderation/test_silence.py +++ b/tests/bot/cogs/moderation/test_silence.py @@ -54,6 +54,24 @@ class SilenceNotifierTests(unittest.IsolatedAsyncioTestCase): self.notifier.add_channel(Mock()) self.notifier_start_mock.assert_not_called() + def test_remove_channel_removes_channel(self): + """Channel in FirstHash is removed from `_silenced_channels`.""" + channel = Mock() + with mock.patch.object(self.notifier, "_silenced_channels") as silenced_channels: + self.notifier.remove_channel(channel) + silenced_channels.remove.assert_called_with(FirstHash(channel)) + + def test_remove_channel_stops_loop(self): + """Notifier loop is stopped if `_silenced_channels` is empty after remove.""" + with mock.patch.object(self.notifier, "_silenced_channels", __bool__=lambda _: False): + self.notifier.remove_channel(Mock()) + self.notifier_stop_mock.assert_called_once() + + def test_remove_channel_skips_stop_with_channels(self): + """Notifier loop is not stopped if `_silenced_channels` is not empty after remove.""" + self.notifier.remove_channel(Mock()) + self.notifier_stop_mock.assert_not_called() + class SilenceTests(unittest.IsolatedAsyncioTestCase): def setUp(self) -> None: -- cgit v1.2.3 From 28cf22bcd98d94fa27e80dde4c86c9054b33c538 Mon Sep 17 00:00:00 2001 From: Numerlor <25886452+Numerlor@users.noreply.github.com> Date: Wed, 11 Mar 2020 21:55:09 +0100 Subject: Add tests for `_notifier`. --- tests/bot/cogs/moderation/test_silence.py | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) (limited to 'tests') diff --git a/tests/bot/cogs/moderation/test_silence.py b/tests/bot/cogs/moderation/test_silence.py index c52ca2a2a..d4719159e 100644 --- a/tests/bot/cogs/moderation/test_silence.py +++ b/tests/bot/cogs/moderation/test_silence.py @@ -72,6 +72,25 @@ class SilenceNotifierTests(unittest.IsolatedAsyncioTestCase): self.notifier.remove_channel(Mock()) self.notifier_stop_mock.assert_not_called() + async def test_notifier_private_sends_alert(self): + """Alert is sent on 15 min intervals.""" + test_cases = (900, 1800, 2700) + for current_loop in test_cases: + with self.subTest(current_loop=current_loop): + with mock.patch.object(self.notifier, "_current_loop", new=current_loop): + await self.notifier._notifier() + self.alert_channel.send.assert_called_once_with(f"<@&{Roles.moderators}> currently silenced channels: ") + self.alert_channel.send.reset_mock() + + async def test_notifier_skips_alert(self): + """Alert is skipped on first loop or not an increment of 900.""" + test_cases = (0, 15, 5000) + for current_loop in test_cases: + with self.subTest(current_loop=current_loop): + with mock.patch.object(self.notifier, "_current_loop", new=current_loop): + await self.notifier._notifier() + self.alert_channel.send.assert_not_called() + class SilenceTests(unittest.IsolatedAsyncioTestCase): def setUp(self) -> None: -- cgit v1.2.3 From 252b385e46ef542203e69f4f6d147dadbcec8f0f Mon Sep 17 00:00:00 2001 From: Numerlor <25886452+Numerlor@users.noreply.github.com> Date: Sun, 15 Mar 2020 16:11:35 +0100 Subject: Use dict instead of a set and custom class. The FirstHash class is no longer necessary with only channels and the current loop in tuples. FirstHash was removed, along with its tests and tests were adjusted for new dict behaviour. --- bot/cogs/moderation/silence.py | 24 +++++------------------- tests/bot/cogs/moderation/test_silence.py | 28 +++------------------------- 2 files changed, 8 insertions(+), 44 deletions(-) (limited to 'tests') diff --git a/bot/cogs/moderation/silence.py b/bot/cogs/moderation/silence.py index 8ed1cb28b..5df1fbbc0 100644 --- a/bot/cogs/moderation/silence.py +++ b/bot/cogs/moderation/silence.py @@ -15,26 +15,12 @@ from bot.utils.checks import with_role_check log = logging.getLogger(__name__) -class FirstHash(tuple): - """Tuple with only first item used for hash and eq.""" - - def __new__(cls, *args): - """Construct tuple from `args`.""" - return super().__new__(cls, args) - - def __hash__(self): - return hash((self[0],)) - - def __eq__(self, other: "FirstHash"): - return self[0] == other[0] - - class SilenceNotifier(tasks.Loop): """Loop notifier for posting notices to `alert_channel` containing added channels.""" def __init__(self, alert_channel: TextChannel): super().__init__(self._notifier, seconds=1, minutes=0, hours=0, count=None, reconnect=True, loop=None) - self._silenced_channels = set() + self._silenced_channels = {} self._alert_channel = alert_channel def add_channel(self, channel: TextChannel) -> None: @@ -42,12 +28,12 @@ class SilenceNotifier(tasks.Loop): if not self._silenced_channels: self.start() log.info("Starting notifier loop.") - self._silenced_channels.add(FirstHash(channel, self._current_loop)) + self._silenced_channels[channel] = self._current_loop def remove_channel(self, channel: TextChannel) -> None: """Remove channel from `_silenced_channels` and stop loop if no channels remain.""" with suppress(KeyError): - self._silenced_channels.remove(FirstHash(channel)) + del self._silenced_channels[channel] if not self._silenced_channels: self.stop() log.info("Stopping notifier loop.") @@ -58,11 +44,11 @@ class SilenceNotifier(tasks.Loop): if self._current_loop and not self._current_loop/60 % 15: log.debug( f"Sending notice with channels: " - f"{', '.join(f'#{channel} ({channel.id})' for channel, _ in self._silenced_channels)}." + f"{', '.join(f'#{channel} ({channel.id})' for channel in self._silenced_channels)}." ) channels_text = ', '.join( f"{channel.mention} for {(self._current_loop-start)//60} min" - for channel, start in self._silenced_channels + for channel, start in self._silenced_channels.items() ) await self._alert_channel.send(f"<@&{Roles.moderators}> currently silenced channels: {channels_text}") diff --git a/tests/bot/cogs/moderation/test_silence.py b/tests/bot/cogs/moderation/test_silence.py index d4719159e..6114fee21 100644 --- a/tests/bot/cogs/moderation/test_silence.py +++ b/tests/bot/cogs/moderation/test_silence.py @@ -2,33 +2,11 @@ import unittest from unittest import mock from unittest.mock import MagicMock, Mock -from bot.cogs.moderation.silence import FirstHash, Silence, SilenceNotifier +from bot.cogs.moderation.silence import Silence, SilenceNotifier from bot.constants import Channels, Emojis, Guild, Roles from tests.helpers import MockBot, MockContext, MockTextChannel -class FirstHashTests(unittest.TestCase): - def setUp(self) -> None: - self.test_cases = ( - (FirstHash(0, 4), FirstHash(0, 5)), - (FirstHash("string", None), FirstHash("string", True)) - ) - - def test_hashes_equal(self): - """Check hashes equal with same first item.""" - - for tuple1, tuple2 in self.test_cases: - with self.subTest(tuple1=tuple1, tuple2=tuple2): - self.assertEqual(hash(tuple1), hash(tuple2)) - - def test_eq(self): - """Check objects are equal with same first item.""" - - for tuple1, tuple2 in self.test_cases: - with self.subTest(tuple1=tuple1, tuple2=tuple2): - self.assertTrue(tuple1 == tuple2) - - class SilenceNotifierTests(unittest.IsolatedAsyncioTestCase): def setUp(self) -> None: self.alert_channel = MockTextChannel() @@ -41,7 +19,7 @@ class SilenceNotifierTests(unittest.IsolatedAsyncioTestCase): channel = Mock() with mock.patch.object(self.notifier, "_silenced_channels") as silenced_channels: self.notifier.add_channel(channel) - silenced_channels.add.assert_called_with(FirstHash(channel, self.notifier._current_loop)) + silenced_channels.__setitem__.assert_called_with(channel, self.notifier._current_loop) def test_add_channel_starts_loop(self): """Loop is started if `_silenced_channels` was empty.""" @@ -59,7 +37,7 @@ class SilenceNotifierTests(unittest.IsolatedAsyncioTestCase): channel = Mock() with mock.patch.object(self.notifier, "_silenced_channels") as silenced_channels: self.notifier.remove_channel(channel) - silenced_channels.remove.assert_called_with(FirstHash(channel)) + silenced_channels.__delitem__.assert_called_with(channel) def test_remove_channel_stops_loop(self): """Notifier loop is stopped if `_silenced_channels` is empty after remove.""" -- cgit v1.2.3 From 36c57c6f89a070fbb77a641182e37c788b6de7a0 Mon Sep 17 00:00:00 2001 From: Numerlor <25886452+Numerlor@users.noreply.github.com> Date: Sun, 15 Mar 2020 18:21:49 +0100 Subject: Adjust tests for new calling behaviour. `.set_permissions` calls were changed to use kwargs directly instead of an overwrite, this reflects the changes in tests. --- tests/bot/cogs/moderation/test_silence.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'tests') diff --git a/tests/bot/cogs/moderation/test_silence.py b/tests/bot/cogs/moderation/test_silence.py index 6114fee21..b09426fde 100644 --- a/tests/bot/cogs/moderation/test_silence.py +++ b/tests/bot/cogs/moderation/test_silence.py @@ -141,7 +141,7 @@ class SilenceTests(unittest.IsolatedAsyncioTestCase): channel = MockTextChannel() self.assertTrue(await self.cog._silence(channel, False, None)) channel.set_permissions.assert_called_once() - self.assertFalse(channel.set_permissions.call_args.kwargs['overwrite'].send_messages) + self.assertFalse(channel.set_permissions.call_args.kwargs['send_messages']) async def test_silence_private_notifier(self): """Channel should be added to notifier with `persistent` set to `True`, and the other way around.""" @@ -175,7 +175,7 @@ class SilenceTests(unittest.IsolatedAsyncioTestCase): channel = MockTextChannel(overwrites_for=Mock(return_value=perm_overwrite)) self.assertTrue(await self.cog._unsilence(channel)) channel.set_permissions.assert_called_once() - self.assertTrue(channel.set_permissions.call_args.kwargs['overwrite'].send_messages) + self.assertTrue(channel.set_permissions.call_args.kwargs['send_messages']) @mock.patch.object(Silence, "notifier", create=True) async def test_unsilence_private_removed_notifier(self, notifier): -- cgit v1.2.3 From 0a2774fadddd18a86822a47599ebc4b76f1e5a7e Mon Sep 17 00:00:00 2001 From: Numerlor <25886452+Numerlor@users.noreply.github.com> Date: Sun, 15 Mar 2020 18:23:11 +0100 Subject: Set `_get_instance_vars_event` in test's `setUp`. --- tests/bot/cogs/moderation/test_silence.py | 2 ++ 1 file changed, 2 insertions(+) (limited to 'tests') diff --git a/tests/bot/cogs/moderation/test_silence.py b/tests/bot/cogs/moderation/test_silence.py index b09426fde..c6f1fc1da 100644 --- a/tests/bot/cogs/moderation/test_silence.py +++ b/tests/bot/cogs/moderation/test_silence.py @@ -76,6 +76,8 @@ class SilenceTests(unittest.IsolatedAsyncioTestCase): self.cog = Silence(self.bot) self.ctx = MockContext() self.cog._verified_role = None + # Set event so command callbacks can continue. + self.cog._get_instance_vars_event.set() async def test_instance_vars_got_guild(self): """Bot got guild after it became available.""" -- cgit v1.2.3 From 039a04462be58e9d345e32efcae13c8c999776db Mon Sep 17 00:00:00 2001 From: Numerlor <25886452+Numerlor@users.noreply.github.com> Date: Tue, 17 Mar 2020 13:23:44 +0100 Subject: Fix `test_cog_unload` passing tests with invalid values. The first assert - `asyncio_mock.create_task.assert_called_once_with` called `alert_channel`'s send resulting in an extra call. `send` on `alert_channel` was not tested properly because of a typo and a missing assert in the method call. --- tests/bot/cogs/moderation/test_silence.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'tests') diff --git a/tests/bot/cogs/moderation/test_silence.py b/tests/bot/cogs/moderation/test_silence.py index c6f1fc1da..febfd584b 100644 --- a/tests/bot/cogs/moderation/test_silence.py +++ b/tests/bot/cogs/moderation/test_silence.py @@ -202,8 +202,8 @@ class SilenceTests(unittest.IsolatedAsyncioTestCase): """Task for sending an alert was created with present `muted_channels`.""" with mock.patch.object(self.cog, "muted_channels"): self.cog.cog_unload() + alert_channel.send.assert_called_once_with(f"<@&{Roles.moderators}> channels left silenced on cog unload: ") asyncio_mock.create_task.assert_called_once_with(alert_channel.send()) - alert_channel.send.called_once_with(f"<@&{Roles.moderators}> chandnels left silenced on cog unload: ") @mock.patch("bot.cogs.moderation.silence.asyncio") def test_cog_unload1(self, asyncio_mock): -- cgit v1.2.3 From 2803c13c477634ceefe3501ad9cb7c76cfecf450 Mon Sep 17 00:00:00 2001 From: Numerlor <25886452+Numerlor@users.noreply.github.com> Date: Tue, 17 Mar 2020 17:10:16 +0100 Subject: Rename `cog_unload` tests. Previous names were undescriptive from testing phases. --- tests/bot/cogs/moderation/test_silence.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'tests') diff --git a/tests/bot/cogs/moderation/test_silence.py b/tests/bot/cogs/moderation/test_silence.py index febfd584b..07a70e7dc 100644 --- a/tests/bot/cogs/moderation/test_silence.py +++ b/tests/bot/cogs/moderation/test_silence.py @@ -198,7 +198,7 @@ class SilenceTests(unittest.IsolatedAsyncioTestCase): @mock.patch("bot.cogs.moderation.silence.asyncio") @mock.patch.object(Silence, "_mod_alerts_channel", create=True) - def test_cog_unload(self, alert_channel, asyncio_mock): + def test_cog_unload_starts_task(self, alert_channel, asyncio_mock): """Task for sending an alert was created with present `muted_channels`.""" with mock.patch.object(self.cog, "muted_channels"): self.cog.cog_unload() @@ -206,7 +206,7 @@ class SilenceTests(unittest.IsolatedAsyncioTestCase): asyncio_mock.create_task.assert_called_once_with(alert_channel.send()) @mock.patch("bot.cogs.moderation.silence.asyncio") - def test_cog_unload1(self, asyncio_mock): + def test_cog_unload_skips_task_start(self, asyncio_mock): """No task created with no channels.""" self.cog.cog_unload() asyncio_mock.create_task.assert_not_called() -- cgit v1.2.3 From 20c41f2c5af6fd716c3e7f15de412f7f16f5ff1e Mon Sep 17 00:00:00 2001 From: Numerlor <25886452+Numerlor@users.noreply.github.com> Date: Tue, 17 Mar 2020 17:15:10 +0100 Subject: Remove one indentation level. Co-authored-by: MarkKoz --- tests/bot/cogs/moderation/test_silence.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'tests') diff --git a/tests/bot/cogs/moderation/test_silence.py b/tests/bot/cogs/moderation/test_silence.py index 07a70e7dc..8b9e30cfe 100644 --- a/tests/bot/cogs/moderation/test_silence.py +++ b/tests/bot/cogs/moderation/test_silence.py @@ -115,9 +115,9 @@ class SilenceTests(unittest.IsolatedAsyncioTestCase): ) for duration, result_message, _silence_patch_return in test_cases: with self.subTest( - silence_duration=duration, - result_message=result_message, - starting_unsilenced_state=_silence_patch_return + silence_duration=duration, + result_message=result_message, + starting_unsilenced_state=_silence_patch_return ): with mock.patch.object(self.cog, "_silence", return_value=_silence_patch_return): await self.cog.silence.callback(self.cog, self.ctx, duration) -- cgit v1.2.3 From d456e40ac97a38ee99561546bcafb6aa94117cb7 Mon Sep 17 00:00:00 2001 From: Numerlor <25886452+Numerlor@users.noreply.github.com> Date: Tue, 17 Mar 2020 17:16:31 +0100 Subject: Remove `alert_channel` mention from docstring. After removing the optional channel arg and changing output message channels we're only testing `ctx`'s `send`. --- tests/bot/cogs/moderation/test_silence.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'tests') diff --git a/tests/bot/cogs/moderation/test_silence.py b/tests/bot/cogs/moderation/test_silence.py index 8b9e30cfe..b4a34bbc7 100644 --- a/tests/bot/cogs/moderation/test_silence.py +++ b/tests/bot/cogs/moderation/test_silence.py @@ -125,7 +125,7 @@ class SilenceTests(unittest.IsolatedAsyncioTestCase): self.ctx.reset_mock() async def test_unsilence_sent_correct_discord_message(self): - """Check if proper message was sent to `alert_chanel`.""" + """Proper reply after a successful unsilence.""" with mock.patch.object(self.cog, "_unsilence", return_value=True): await self.cog.unsilence.callback(self.cog, self.ctx) self.ctx.send.assert_called_once_with(f"{Emojis.check_mark} unsilenced current channel.") -- cgit v1.2.3 From 386c93a6f18adbf84691f17b13f5113800a353ae Mon Sep 17 00:00:00 2001 From: Numerlor <25886452+Numerlor@users.noreply.github.com> Date: Tue, 17 Mar 2020 19:40:27 +0100 Subject: Fix test name. `removed` was describing the opposite behaviour. --- tests/bot/cogs/moderation/test_silence.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'tests') diff --git a/tests/bot/cogs/moderation/test_silence.py b/tests/bot/cogs/moderation/test_silence.py index b4a34bbc7..55193e2f8 100644 --- a/tests/bot/cogs/moderation/test_silence.py +++ b/tests/bot/cogs/moderation/test_silence.py @@ -158,7 +158,7 @@ class SilenceTests(unittest.IsolatedAsyncioTestCase): await self.cog._silence(channel, False, None) self.cog.notifier.add_channel.assert_not_called() - async def test_silence_private_removed_muted_channel(self): + async def test_silence_private_added_muted_channel(self): channel = MockTextChannel() with mock.patch.object(self.cog, "muted_channels") as muted_channels: await self.cog._silence(channel, False, None) -- cgit v1.2.3 From dced6fdf5f571b82bc975dd3159af57c6f9a12b3 Mon Sep 17 00:00:00 2001 From: Numerlor <25886452+Numerlor@users.noreply.github.com> Date: Tue, 17 Mar 2020 19:41:13 +0100 Subject: Add docstring to test. --- tests/bot/cogs/moderation/test_silence.py | 1 + 1 file changed, 1 insertion(+) (limited to 'tests') diff --git a/tests/bot/cogs/moderation/test_silence.py b/tests/bot/cogs/moderation/test_silence.py index 55193e2f8..71541086d 100644 --- a/tests/bot/cogs/moderation/test_silence.py +++ b/tests/bot/cogs/moderation/test_silence.py @@ -159,6 +159,7 @@ class SilenceTests(unittest.IsolatedAsyncioTestCase): self.cog.notifier.add_channel.assert_not_called() async def test_silence_private_added_muted_channel(self): + """Channel was added to `muted_channels` on silence.""" channel = MockTextChannel() with mock.patch.object(self.cog, "muted_channels") as muted_channels: await self.cog._silence(channel, False, None) -- cgit v1.2.3 From c68b943708eaca110ddfa6121872513a422bbef4 Mon Sep 17 00:00:00 2001 From: Numerlor <25886452+Numerlor@users.noreply.github.com> Date: Tue, 17 Mar 2020 20:10:50 +0100 Subject: Use set `discard` instead of `remove`. Discard ignores non present values, allowing us to skip the KeyError suppress. --- bot/cogs/moderation/silence.py | 3 +-- tests/bot/cogs/moderation/test_silence.py | 2 +- 2 files changed, 2 insertions(+), 3 deletions(-) (limited to 'tests') diff --git a/bot/cogs/moderation/silence.py b/bot/cogs/moderation/silence.py index 1523baf11..a1446089e 100644 --- a/bot/cogs/moderation/silence.py +++ b/bot/cogs/moderation/silence.py @@ -141,8 +141,7 @@ class Silence(commands.Cog): await channel.set_permissions(self._verified_role, **dict(current_overwrite, send_messages=True)) log.info(f"Unsilenced channel #{channel} ({channel.id}).") self.notifier.remove_channel(channel) - with suppress(KeyError): - self.muted_channels.remove(channel) + self.muted_channels.discard(channel) return True log.info(f"Tried to unsilence channel #{channel} ({channel.id}) but the channel was not silenced.") return False diff --git a/tests/bot/cogs/moderation/test_silence.py b/tests/bot/cogs/moderation/test_silence.py index 71541086d..eee020455 100644 --- a/tests/bot/cogs/moderation/test_silence.py +++ b/tests/bot/cogs/moderation/test_silence.py @@ -195,7 +195,7 @@ class SilenceTests(unittest.IsolatedAsyncioTestCase): channel = MockTextChannel(overwrites_for=Mock(return_value=perm_overwrite)) with mock.patch.object(self.cog, "muted_channels") as muted_channels: await self.cog._unsilence(channel) - muted_channels.remove.assert_called_once_with(channel) + muted_channels.discard.assert_called_once_with(channel) @mock.patch("bot.cogs.moderation.silence.asyncio") @mock.patch.object(Silence, "_mod_alerts_channel", create=True) -- cgit v1.2.3 From cd429230fcb18c7101afd931317d37ad142bfe4b Mon Sep 17 00:00:00 2001 From: Numerlor <25886452+Numerlor@users.noreply.github.com> Date: Tue, 17 Mar 2020 20:11:44 +0100 Subject: Add tests ensuring permissions get preserved. --- tests/bot/cogs/moderation/test_silence.py | 31 +++++++++++++++++++++++++++++++ 1 file changed, 31 insertions(+) (limited to 'tests') diff --git a/tests/bot/cogs/moderation/test_silence.py b/tests/bot/cogs/moderation/test_silence.py index eee020455..44682a1bd 100644 --- a/tests/bot/cogs/moderation/test_silence.py +++ b/tests/bot/cogs/moderation/test_silence.py @@ -2,6 +2,8 @@ import unittest from unittest import mock from unittest.mock import MagicMock, Mock +from discord import PermissionOverwrite + from bot.cogs.moderation.silence import Silence, SilenceNotifier from bot.constants import Channels, Emojis, Guild, Roles from tests.helpers import MockBot, MockContext, MockTextChannel @@ -145,6 +147,20 @@ class SilenceTests(unittest.IsolatedAsyncioTestCase): channel.set_permissions.assert_called_once() self.assertFalse(channel.set_permissions.call_args.kwargs['send_messages']) + async def test_silence_private_preserves_permissions(self): + """Previous permissions were preserved when channel was silenced.""" + channel = MockTextChannel() + # Set up mock channel permission state. + mock_permissions = PermissionOverwrite() + mock_permissions_dict = dict(mock_permissions) + channel.overwrites_for.return_value = mock_permissions + await self.cog._silence(channel, False, None) + new_permissions = channel.set_permissions.call_args.kwargs + # Remove 'send_messages' key because it got changed in the method. + del new_permissions['send_messages'] + del mock_permissions_dict['send_messages'] + self.assertDictEqual(mock_permissions_dict, new_permissions) + async def test_silence_private_notifier(self): """Channel should be added to notifier with `persistent` set to `True`, and the other way around.""" channel = MockTextChannel() @@ -197,6 +213,21 @@ class SilenceTests(unittest.IsolatedAsyncioTestCase): await self.cog._unsilence(channel) muted_channels.discard.assert_called_once_with(channel) + @mock.patch.object(Silence, "notifier", create=True) + async def test_unsilence_private_preserves_permissions(self, _): + """Previous permissions were preserved when channel was unsilenced.""" + channel = MockTextChannel() + # Set up mock channel permission state. + mock_permissions = PermissionOverwrite(send_messages=False) + mock_permissions_dict = dict(mock_permissions) + channel.overwrites_for.return_value = mock_permissions + await self.cog._unsilence(channel) + new_permissions = channel.set_permissions.call_args.kwargs + # Remove 'send_messages' key because it got changed in the method. + del new_permissions['send_messages'] + del mock_permissions_dict['send_messages'] + self.assertDictEqual(mock_permissions_dict, new_permissions) + @mock.patch("bot.cogs.moderation.silence.asyncio") @mock.patch.object(Silence, "_mod_alerts_channel", create=True) def test_cog_unload_starts_task(self, alert_channel, asyncio_mock): -- cgit v1.2.3 From cefcc575b6faa94fb18f1985f039125d023b2580 Mon Sep 17 00:00:00 2001 From: Numerlor <25886452+Numerlor@users.noreply.github.com> Date: Tue, 17 Mar 2020 22:18:58 +0100 Subject: Add tests for `HushDurationConverter`. --- tests/bot/test_converters.py | 30 ++++++++++++++++++++++++++++++ 1 file changed, 30 insertions(+) (limited to 'tests') diff --git a/tests/bot/test_converters.py b/tests/bot/test_converters.py index 1e5ca62ae..ca8cb6825 100644 --- a/tests/bot/test_converters.py +++ b/tests/bot/test_converters.py @@ -8,6 +8,7 @@ from discord.ext.commands import BadArgument from bot.converters import ( Duration, + HushDurationConverter, ISODateTime, TagContentConverter, TagNameConverter, @@ -271,3 +272,32 @@ class ConverterTests(unittest.TestCase): exception_message = f"`{datetime_string}` is not a valid ISO-8601 datetime string" with self.assertRaises(BadArgument, msg=exception_message): asyncio.run(converter.convert(self.context, datetime_string)) + + def test_hush_duration_converter_for_valid(self): + """HushDurationConverter returns correct value for minutes duration or `"forever"` strings.""" + test_values = ( + ("0", 0), + ("15", 15), + ("10", 10), + ("5m", 5), + ("5M", 5), + ("forever", None), + ) + converter = HushDurationConverter() + for minutes_string, expected_minutes in test_values: + with self.subTest(minutes_string=minutes_string, expected_minutes=expected_minutes): + converted = asyncio.run(converter.convert(self.context, minutes_string)) + self.assertEqual(expected_minutes, converted) + + def test_hush_duration_converter_for_invalid(self): + """HushDurationConverter raises correct exception for invalid minutes duration strings.""" + test_values = ( + ("16", "Duration must be at most 15 minutes."), + ("10d", "10d is not a valid minutes duration."), + ("-1", "-1 is not a valid minutes duration."), + ) + converter = HushDurationConverter() + for invalid_minutes_string, exception_message in test_values: + with self.subTest(invalid_minutes_string=invalid_minutes_string, exception_message=exception_message): + with self.assertRaisesRegex(BadArgument, exception_message): + asyncio.run(converter.convert(self.context, invalid_minutes_string)) -- cgit v1.2.3 From 430c616ec4ec60a5ddb1e66d3aacc622c9a78ae6 Mon Sep 17 00:00:00 2001 From: MarkKoz Date: Wed, 25 Mar 2020 12:21:57 -0700 Subject: Snekbox tests: test `get_code` Should return 1st arg (or None) if eval cmd in message, otherwise return full content. --- tests/bot/cogs/test_snekbox.py | 36 ++++++++++++++++++++++++++++++++---- 1 file changed, 32 insertions(+), 4 deletions(-) (limited to 'tests') diff --git a/tests/bot/cogs/test_snekbox.py b/tests/bot/cogs/test_snekbox.py index fd9468829..1fad6904b 100644 --- a/tests/bot/cogs/test_snekbox.py +++ b/tests/bot/cogs/test_snekbox.py @@ -3,9 +3,11 @@ import logging import unittest from unittest.mock import AsyncMock, MagicMock, Mock, call, patch +from discord.ext import commands + +from bot import constants from bot.cogs import snekbox from bot.cogs.snekbox import Snekbox -from bot.constants import URLs from tests.helpers import MockBot, MockContext, MockMessage, MockReaction, MockUser @@ -23,7 +25,7 @@ class SnekboxTests(unittest.IsolatedAsyncioTestCase): self.assertEqual(await self.cog.post_eval("import random"), "return") self.bot.http_session.post.assert_called_with( - URLs.snekbox_eval_api, + constants.URLs.snekbox_eval_api, json={"input": "import random"}, raise_for_status=True ) @@ -43,10 +45,10 @@ class SnekboxTests(unittest.IsolatedAsyncioTestCase): self.assertEqual( await self.cog.upload_output("My awesome output"), - URLs.paste_service.format(key=key) + constants.URLs.paste_service.format(key=key) ) self.bot.http_session.post.assert_called_with( - URLs.paste_service.format(key="documents"), + constants.URLs.paste_service.format(key="documents"), data="My awesome output", raise_for_status=True ) @@ -302,6 +304,32 @@ class SnekboxTests(unittest.IsolatedAsyncioTestCase): self.assertEqual(actual, None) ctx.message.clear_reactions.assert_called_once() + async def test_get_code(self): + """Should return 1st arg (or None) if eval cmd in message, otherwise return full content.""" + prefix = constants.Bot.prefix + subtests = ( + (self.cog.eval_command, f"{prefix}{self.cog.eval_command.name} print(1)", "print(1)"), + (self.cog.eval_command, f"{prefix}{self.cog.eval_command.name}", None), + (MagicMock(spec=commands.Command), f"{prefix}tags get foo"), + (None, "print(123)") + ) + + for command, content, *expected_code in subtests: + if not expected_code: + expected_code = content + else: + [expected_code] = expected_code + + with self.subTest(content=content, expected_code=expected_code): + self.bot.get_context.reset_mock() + self.bot.get_context.return_value = MockContext(command=command) + message = MockMessage(content=content) + + actual_code = await self.cog.get_code(message) + + self.bot.get_context.assert_awaited_once_with(message) + self.assertEqual(actual_code, expected_code) + def test_predicate_eval_message_edit(self): """Test the predicate_eval_message_edit function.""" msg0 = MockMessage(id=1, content='abc') -- cgit v1.2.3 From c3e9a290a93c978a4dfec3ab121a0e45147855c8 Mon Sep 17 00:00:00 2001 From: MarkKoz Date: Wed, 25 Mar 2020 14:08:34 -0700 Subject: Snekbox tests: use `get_code` in `test_continue_eval_does_continue` --- tests/bot/cogs/test_snekbox.py | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) (limited to 'tests') diff --git a/tests/bot/cogs/test_snekbox.py b/tests/bot/cogs/test_snekbox.py index 1fad6904b..1dec0ccaf 100644 --- a/tests/bot/cogs/test_snekbox.py +++ b/tests/bot/cogs/test_snekbox.py @@ -1,7 +1,7 @@ import asyncio import logging import unittest -from unittest.mock import AsyncMock, MagicMock, Mock, call, patch +from unittest.mock import AsyncMock, MagicMock, Mock, call, create_autospec, patch from discord.ext import commands @@ -281,11 +281,14 @@ class SnekboxTests(unittest.IsolatedAsyncioTestCase): """Test that the continue_eval function does continue if required conditions are met.""" ctx = MockContext(message=MockMessage(add_reaction=AsyncMock(), clear_reactions=AsyncMock())) response = MockMessage(delete=AsyncMock()) - new_msg = MockMessage(content='!e NewCode') + new_msg = MockMessage() self.bot.wait_for.side_effect = ((None, new_msg), None) + expected = "NewCode" + self.cog.get_code = create_autospec(self.cog.get_code, spec_set=True, return_value=expected) actual = await self.cog.continue_eval(ctx, response) - self.assertEqual(actual, 'NewCode') + self.cog.get_code.assert_awaited_once_with(new_msg) + self.assertEqual(actual, expected) self.bot.wait_for.assert_has_awaits( ( call('message_edit', check=partial_mock(snekbox.predicate_eval_message_edit, ctx), timeout=10), -- cgit v1.2.3 From 582ddbb1ca8bab2cb883781911f5f35962330995 Mon Sep 17 00:00:00 2001 From: Sebastiaan Zeeff <33516116+SebastiaanZ@users.noreply.github.com> Date: Mon, 30 Mar 2020 13:36:34 +0200 Subject: Set unsilence permissions to inherit instead of true The "unsilence" action of the silence/hush command used `send_messages=True` when unsilencing a hushed channel. This had the side effect of also enabling send messages permissions for those with the Muted rule, as an explicit True permission apparently overwrites an explicit False permission, even if the latter was set for a higher top-role. The solution is to revert back to the `Inherit` permission by assigning `None`. This is what we normally use when Developers are allowed to send messages to a channel. --- bot/cogs/moderation/silence.py | 2 +- tests/bot/cogs/moderation/test_silence.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) (limited to 'tests') diff --git a/bot/cogs/moderation/silence.py b/bot/cogs/moderation/silence.py index a1446089e..1ef3967a9 100644 --- a/bot/cogs/moderation/silence.py +++ b/bot/cogs/moderation/silence.py @@ -138,7 +138,7 @@ class Silence(commands.Cog): """ current_overwrite = channel.overwrites_for(self._verified_role) if current_overwrite.send_messages is False: - await channel.set_permissions(self._verified_role, **dict(current_overwrite, send_messages=True)) + await channel.set_permissions(self._verified_role, **dict(current_overwrite, send_messages=None)) log.info(f"Unsilenced channel #{channel} ({channel.id}).") self.notifier.remove_channel(channel) self.muted_channels.discard(channel) diff --git a/tests/bot/cogs/moderation/test_silence.py b/tests/bot/cogs/moderation/test_silence.py index 44682a1bd..3fd149f04 100644 --- a/tests/bot/cogs/moderation/test_silence.py +++ b/tests/bot/cogs/moderation/test_silence.py @@ -194,7 +194,7 @@ class SilenceTests(unittest.IsolatedAsyncioTestCase): channel = MockTextChannel(overwrites_for=Mock(return_value=perm_overwrite)) self.assertTrue(await self.cog._unsilence(channel)) channel.set_permissions.assert_called_once() - self.assertTrue(channel.set_permissions.call_args.kwargs['send_messages']) + self.assertIsNone(channel.set_permissions.call_args.kwargs['send_messages']) @mock.patch.object(Silence, "notifier", create=True) async def test_unsilence_private_removed_notifier(self, notifier): -- cgit v1.2.3