async def test_command(self, parser_mock): """Test that the command passes in the correct arguments for different calls.""" test_cases = ( (), (15, ), (MockTextChannel(),), (MockTextChannel(), 15), ) ctx = MockContext() parser_mock.return_value = (ctx.channel, 10) for case in test_cases: with self.subTest("Test command converters", args=case): await self.cog.silence.callback(self.cog, ctx, *case) try: first_arg = case[0] except IndexError: # Default value when the first argument is not passed first_arg = None try: second_arg = case[1] except IndexError: # Default value when the second argument is not passed second_arg = 10 parser_mock.assert_called_with(ctx, first_arg, second_arg)
async def test_async_init_got_notifier(self, notifier): """Notifier was started with channel.""" self.bot.get_channel.side_effect = lambda id_: MockTextChannel(id=id_) await self.cog._async_init() notifier.assert_called_once_with(MockTextChannel(id=Channels.mod_log)) self.assertEqual(self.cog.notifier, notifier.return_value)
async def test_rescheduled_active(self): """Rescheduled active silences.""" channels = [MockTextChannel(id=123), MockTextChannel(id=456)] self.bot.get_channel.side_effect = channels self.cog.unsilence_timestamps.items.return_value = [(123, 2000), (456, 3000)] silence.datetime.now.return_value = datetime.fromtimestamp( 1000, tz=timezone.utc) self.cog._unsilence_wrapper = mock.MagicMock() unsilence_return = self.cog._unsilence_wrapper.return_value await self.cog._reschedule() # Yuck. calls = [ mock.call(1000, 123, unsilence_return), mock.call(2000, 456, unsilence_return) ] self.cog.scheduler.schedule_later.assert_has_calls(calls) unsilence_calls = [mock.call(channel) for channel in channels] self.cog._unsilence_wrapper.assert_has_calls(unsilence_calls) self.cog.notifier.add_channel.assert_not_called()
async def test_try_silence_silence_arguments(self): """Should run silence with the correct channel, duration, and kick arguments.""" self.bot.get_command.return_value.can_run = AsyncMock( return_value=True) test_cases = ( (MockTextChannel(), None), # None represents the case when no argument is passed (MockTextChannel(), False), (MockTextChannel(), True)) for channel, kick in test_cases: with self.subTest(kick=kick, channel=channel): self.ctx.reset_mock() self.ctx.invoked_with = "shh" self.ctx.message.content = f"!shh {channel.name} {kick if kick is not None else ''}" self.ctx.guild.text_channels = [channel] self.assertTrue(await self.cog.try_silence(self.ctx)) self.ctx.invoke.assert_awaited_once_with( self.bot.get_command.return_value, duration_or_channel=channel, duration=4, kick=(kick if kick is not None else False))
async def test_unsilenced_expired(self): """Unsilenced expired silences.""" channels = [MockTextChannel(id=123), MockTextChannel(id=456)] self.bot.get_channel.side_effect = channels self.cog.unsilence_timestamps.items.return_value = [(123, 100), (456, 200)] await self.cog._reschedule() self.cog._unsilence_wrapper.assert_any_call(channels[0]) self.cog._unsilence_wrapper.assert_any_call(channels[1]) self.cog.notifier.add_channel.assert_not_called() self.cog.scheduler.schedule_later.assert_not_called()
async def test_added_permanent_to_notifier(self): """Permanently silenced channels were added to the notifier.""" channels = [MockTextChannel(id=123), MockTextChannel(id=456)] self.bot.get_channel.side_effect = channels self.cog.unsilence_timestamps.items.return_value = [(123, -1), (456, -1)] await self.cog._reschedule() self.cog.notifier.add_channel.assert_any_call(channels[0]) self.cog.notifier.add_channel.assert_any_call(channels[1]) self.cog._unsilence_wrapper.assert_not_called() self.cog.scheduler.schedule_later.assert_not_called()
async def test_kick_not_called(self, ctx, sync, kick): """Tests that silence command does not call kick on a text channel.""" channel = MockTextChannel() await self.cog.silence.callback(self.cog, ctx, channel, 10, kick=True) sync.assert_not_called() kick.assert_not_called()
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
def get_mock_category(channel_count: int, name: str) -> CategoryChannel: """Return a mocked code jam category.""" category = create_autospec(CategoryChannel, spec_set=True, instance=True) category.name = name category.channels = [MockTextChannel() for _ in range(channel_count)] return category
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)) await self.cog._unsilence(channel) notifier.remove_channel.assert_called_once_with(channel)
async def test_silence_private_silenced_channel(self): """Channel had `send_message` permissions revoked.""" 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['send_messages'])
def setUp(self) -> None: self.bot = MockBot(get_channel=lambda _: MockTextChannel()) self.cog = silence.Silence(self.bot) self.cog._init_task = asyncio.Future() self.cog._init_task.set_result(None) overwrites_cache = mock.create_autospec(self.cog.previous_overwrites, spec_set=True) self.cog.previous_overwrites = overwrites_cache asyncio.run(self.cog._async_init()) # Populate instance attributes. self.cog.scheduler.__contains__.return_value = True overwrites_cache.get.return_value = '{"send_messages": true, "add_reactions": false}' self.channel = MockTextChannel() self.overwrite = PermissionOverwrite(stream=True, send_messages=False, add_reactions=False) self.channel.overwrites_for.return_value = self.overwrite
async def test_set_slowmode_no_channel(self) -> None: """Set slowmode without a given channel.""" test_cases = ( ('helpers', 23, True, f'{Emojis.check_mark} The slowmode delay for #helpers is now 23 seconds.'), ('mods', 76526, False, f'{Emojis.cross_mark} The slowmode delay must be between 0 and 6 hours.'), ('admins', 97, True, f'{Emojis.check_mark} The slowmode delay for #admins is now 1 minute and 37 seconds.') ) for channel_name, seconds, edited, result_msg in test_cases: with self.subTest( channel_mention=channel_name, seconds=seconds, edited=edited, result_msg=result_msg ): self.ctx.channel = MockTextChannel(name=channel_name) await self.cog.set_slowmode(self.cog, self.ctx, None, relativedelta(seconds=seconds)) if edited: self.ctx.channel.edit.assert_awaited_once_with(slowmode_delay=float(seconds)) else: self.ctx.channel.edit.assert_not_called() self.ctx.send.assert_called_once_with(result_msg) self.ctx.reset_mock()
async def test_sent_correct_message(self): """Appropriate failure/success message was sent by the command.""" unsilenced_overwrite = PermissionOverwrite(send_messages=True, add_reactions=True) test_cases = ( (True, silence.MSG_UNSILENCE_SUCCESS, unsilenced_overwrite), (False, silence.MSG_UNSILENCE_FAIL, unsilenced_overwrite), (False, silence.MSG_UNSILENCE_MANUAL, self.text_overwrite), (False, silence.MSG_UNSILENCE_MANUAL, PermissionOverwrite(send_messages=False)), (False, silence.MSG_UNSILENCE_MANUAL, PermissionOverwrite(add_reactions=False)), ) targets = (None, MockTextChannel()) for (was_unsilenced, message, overwrite), target in itertools.product(test_cases, targets): ctx = MockContext() ctx.channel.overwrites_for.return_value = overwrite if target: target.overwrites_for.return_value = overwrite with mock.patch.object(self.cog, "_unsilence", return_value=was_unsilenced): with mock.patch.object(self.cog, "send_message") as send_message: with self.subTest(was_unsilenced=was_unsilenced, overwrite=overwrite, target=target): await self.cog.unsilence.callback(self.cog, ctx, channel=target) call_args = (message, ctx.channel, target or ctx.channel) send_message.assert_awaited_once_with(*call_args, alert_target=was_unsilenced)
async def test_set_slowmode_with_channel(self) -> None: """Set slowmode with a given channel.""" test_cases = ( ('bot-commands', 12, True, f'{Emojis.check_mark} The slowmode delay for #bot-commands is now 12 seconds.'), ('mod-spam', 21, True, f'{Emojis.check_mark} The slowmode delay for #mod-spam is now 21 seconds.'), ('admin-spam', 4323598, False, f'{Emojis.cross_mark} The slowmode delay must be between 0 and 6 hours.') ) for channel_name, seconds, edited, result_msg in test_cases: with self.subTest( channel_mention=channel_name, seconds=seconds, edited=edited, result_msg=result_msg ): text_channel = MockTextChannel(name=channel_name) await self.cog.set_slowmode(self.cog, self.ctx, text_channel, relativedelta(seconds=seconds)) if edited: text_channel.edit.assert_awaited_once_with(slowmode_delay=float(seconds)) else: text_channel.edit.assert_not_called() self.ctx.send.assert_called_once_with(result_msg) self.ctx.reset_mock()
async def test_all_args(self): """Test the parser when both channel and duration are passed.""" expected_channel = MockTextChannel() actual_channel, duration = self.cog.parse_silence_args(MockContext(), expected_channel, 15) self.assertEqual(expected_channel, actual_channel) self.assertEqual(15, duration)
async def test_channel_only(self): """Test the parser when just the channel argument is passed.""" expected_channel = MockTextChannel() actual_channel, duration = self.cog.parse_silence_args(MockContext(), expected_channel, 10) self.assertEqual(expected_channel, actual_channel) self.assertEqual(10, duration)
async def test_get_slowmode_no_channel(self) -> None: """Get slowmode without a given channel.""" self.ctx.channel = MockTextChannel(name='python-general', slowmode_delay=5) await self.cog.get_slowmode(self.cog, self.ctx, None) self.ctx.send.assert_called_once_with( "The slowmode delay for #python-general is 5 seconds.")
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") as muted_channels: await self.cog._unsilence(channel) muted_channels.discard.assert_called_once_with(channel)
def setUp(self): """For each test, ensure `bot.get_channel` returns a channel with 1 arbitrary message.""" super().setUp() # First ensure we get `cog_instance` from parent incidents_history = MagicMock( return_value=MockAsyncIterable([MockMessage()])) self.cog_instance.bot.get_channel = MagicMock( return_value=MockTextChannel(history=incidents_history))
def setUp(self) -> None: self.bot = MockBot() self.cog = silence.Silence(self.bot) self.text_channels = [MockTextChannel() for _ in range(2)] self.bot.get_channel.return_value = self.text_channels[1] self.voice_channel = MockVoiceChannel()
async def test_get_slowmode_with_channel(self) -> None: """Get slowmode with a given channel.""" text_channel = MockTextChannel(name='python-language', slowmode_delay=2) await self.cog.get_slowmode(self.cog, self.ctx, text_channel) self.ctx.send.assert_called_once_with( 'The slowmode delay for #python-language is 2 seconds.')
async def test_reset_slowmode_sets_delay_to_zero(self) -> None: """Reset slowmode with a given channel.""" text_channel = MockTextChannel(name='meta', slowmode_delay=1) self.cog.set_slowmode = mock.AsyncMock() await self.cog.reset_slowmode(self.cog, self.ctx, text_channel) self.cog.set_slowmode.assert_awaited_once_with( self.ctx, text_channel, relativedelta(seconds=0))
async def test_reset_slowmode_with_channel(self) -> None: """Reset slowmode with a given channel.""" text_channel = MockTextChannel(name='meta', slowmode_delay=1) await self.cog.reset_slowmode(self.cog, self.ctx, text_channel) self.ctx.send.assert_called_once_with( f'{Emojis.check_mark} The slowmode delay for #meta has been reset to 0 seconds.' )
def setUp(self) -> None: """Prepare a mock message which should qualify as an incident.""" self.incident = MockMessage( channel=MockTextChannel(id=123), content="this is an incident", author=MockUser(bot=False), pinned=False, )
async def test_reset_slowmode_no_channel(self) -> None: """Reset slowmode without a given channel.""" self.ctx.channel = MockTextChannel(name='careers', slowmode_delay=6) await self.cog.reset_slowmode(self.cog, self.ctx, None) self.ctx.send.assert_called_once_with( f'{Emojis.check_mark} The slowmode delay for #careers has been reset to 0 seconds.' )
async def test_skipped_already_unsilenced(self): """Permissions were not set and `False` was returned for an already unsilenced channel.""" self.cog.scheduler.__contains__.return_value = False self.cog.previous_overwrites.get.return_value = None channel = MockTextChannel() self.assertFalse(await self.cog._unsilence(channel)) channel.set_permissions.assert_not_called()
def setUp(self) -> None: self.bot = MockBot(get_channel=lambda _: MockTextChannel()) self.cog = silence.Silence(self.bot) self.cog._init_task = asyncio.Future() self.cog._init_task.set_result(None) # Avoid unawaited coroutine warnings. self.cog.scheduler.schedule_later.side_effect = lambda delay, task_id, coro: coro.close() asyncio.run(self.cog._async_init()) # Populate instance attributes. self.text_channel = MockTextChannel() self.text_overwrite = PermissionOverwrite(send_messages=True, add_reactions=False) self.text_channel.overwrites_for.return_value = self.text_overwrite self.voice_channel = MockVoiceChannel() self.voice_overwrite = PermissionOverwrite(connect=True, speak=True) self.voice_channel.overwrites_for.return_value = self.voice_overwrite
async def test_skipped_already_silenced(self): """Permissions were not set and `False` was returned for an already silenced channel.""" subtests = ( (False, MockTextChannel(), PermissionOverwrite(send_messages=False, add_reactions=False)), (True, MockTextChannel(), PermissionOverwrite(send_messages=True, add_reactions=True)), (True, MockTextChannel(), PermissionOverwrite(send_messages=False, add_reactions=False)), (False, MockVoiceChannel(), PermissionOverwrite(connect=False, speak=False)), (True, MockVoiceChannel(), PermissionOverwrite(connect=True, speak=True)), (True, MockVoiceChannel(), PermissionOverwrite(connect=False, speak=False)), ) for contains, channel, overwrite in subtests: with self.subTest(contains=contains, is_text=isinstance(channel, MockTextChannel), overwrite=overwrite): self.cog.scheduler.__contains__.return_value = contains channel.overwrites_for.return_value = overwrite self.assertFalse(await self.cog._set_silence_overwrites(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)) self.assertTrue(await self.cog._unsilence(channel)) channel.set_permissions.assert_called_once() self.assertIsNone( channel.set_permissions.call_args.kwargs['send_messages'])