Ejemplo n.º 1
0
    async def test_continue_eval_does_not_continue(self):
        ctx = MockContext(message=MockMessage(clear_reactions=AsyncMock()))
        self.bot.wait_for.side_effect = asyncio.TimeoutError

        actual = await self.cog.continue_eval(ctx, MockMessage())
        self.assertEqual(actual, None)
        ctx.message.clear_reactions.assert_called_once()
Ejemplo n.º 2
0
    async def test_continue_eval_does_continue(self, partial_mock):
        """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()
        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.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),
             call('reaction_add',
                  check=partial_mock(snekbox.predicate_eval_emoji_reaction,
                                     ctx),
                  timeout=10)))
        ctx.message.add_reaction.assert_called_once_with(snekbox.REEVAL_EMOJI)
        ctx.message.clear_reactions.assert_called_once()
        response.delete.assert_called_once()
Ejemplo n.º 3
0
    def test_predicate_eval_emoji_reaction(self):
        """Test the predicate_eval_emoji_reaction function."""
        valid_reaction = MockReaction(message=MockMessage(id=1))
        valid_reaction.__str__.return_value = snekbox.REEVAL_EMOJI
        valid_ctx = MockContext(message=MockMessage(id=1),
                                author=MockUser(id=2))
        valid_user = MockUser(id=2)

        invalid_reaction_id = MockReaction(message=MockMessage(id=42))
        invalid_reaction_id.__str__.return_value = snekbox.REEVAL_EMOJI
        invalid_user_id = MockUser(id=42)
        invalid_reaction_str = MockReaction(message=MockMessage(id=1))
        invalid_reaction_str.__str__.return_value = ':longbeard:'

        cases = ((invalid_reaction_id, valid_user, False,
                  'invalid reaction ID'), (valid_reaction, invalid_user_id,
                                           False, 'invalid user ID'),
                 (invalid_reaction_str, valid_user, False,
                  'invalid reaction __str__'), (valid_reaction, valid_user,
                                                True, 'matching attributes'))
        for reaction, user, expected, testname in cases:
            with self.subTest(
                    msg=f'Test with {testname} and expected return {expected}'
            ):
                actual = snekbox.predicate_eval_emoji_reaction(
                    valid_ctx, reaction, user)
                self.assertEqual(actual, expected)
Ejemplo n.º 4
0
    async def test_on_message_ignores_dms_bots(self, find_token_in_message):
        """Shouldn't parse a message if it is a DM or authored by a bot."""
        cog = TokenRemover(self.bot)
        dm_msg = MockMessage(guild=None)
        bot_msg = MockMessage(author=MagicMock(bot=True))

        for msg in (dm_msg, bot_msg):
            await cog.on_message(msg)
            find_token_in_message.assert_not_called()
Ejemplo n.º 5
0
    def test_update_replaces_old_element(self):
        """Test if an update replaced the old message with the same ID."""
        cache = MessageCache(maxlen=5)
        message = MockMessage(id=1234)

        cache.append(message)
        message = MockMessage(id=1234)
        cache.update(message)

        self.assertIs(cache.get_message(1234), message)
        self.assertEqual(len(cache), 1)
Ejemplo n.º 6
0
    def test_append_adds_in_the_right_order(self):
        """Test if two appends are added in the same order if newest_first is False, or in reverse order otherwise."""
        messages = [MockMessage(), MockMessage()]

        cache = MessageCache(maxlen=10, newest_first=False)
        for msg in messages:
            cache.append(msg)
        self.assertListEqual(messages, list(cache))

        cache = MessageCache(maxlen=10, newest_first=True)
        for msg in messages:
            cache.append(msg)
        self.assertListEqual(messages[::-1], list(cache))
Ejemplo n.º 7
0
    async def test_on_message_non_incident(self):
        """Messages not qualifying as incidents are ignored."""
        with patch("bot.exts.moderation.incidents.add_signals",
                   AsyncMock()) as mock_add_signals:
            await self.cog_instance.on_message(MockMessage())

        mock_add_signals.assert_not_called()
Ejemplo n.º 8
0
    async def test_on_raw_reaction_add_valid_event_is_processed(self):
        """
        If the reaction event is valid, it is passed to `process_event`.

        This is the case when everything goes right:
            * The reaction was placed in #incidents, and not by a bot
            * The message was found successfully
            * The message qualifies as an incident

        Additionally, we check that all arguments were passed as expected.
        """
        incident = MockMessage(id=1)

        self.cog_instance.process_event = AsyncMock()
        self.cog_instance.resolve_message = AsyncMock(return_value=incident)

        with patch("bot.exts.moderation.incidents.is_incident",
                   MagicMock(return_value=True)):
            await self.cog_instance.on_raw_reaction_add(self.payload)

        self.cog_instance.process_event.assert_called_with(
            "reaction",  # Defined in `self.payload`
            incident,
            self.payload.member,
        )
Ejemplo n.º 9
0
    async def test_process_event_bad_role(self):
        """The reaction is removed when the author lacks all allowed roles."""
        incident = MockMessage()
        member = MockMember(roles=[MockRole(id=0)])  # Must have role 1 or 2

        await self.cog_instance.process_event("reaction", incident, member)
        incident.remove_reaction.assert_called_once_with("reaction", member)
Ejemplo n.º 10
0
    def test_make_confirmation_task_check(self):
        """
        The internal check will recognize the passed incident.

        This is a little tricky - we first pass a message with a specific `id` in, and then
        retrieve the built check from the `call_args` of the `wait_for` method. This relies
        on the check being passed as a kwarg.

        Once the check is retrieved, we assert that it gives True for our incident's `id`,
        and False for any other.

        If this function begins to fail, first check that `created_check` is being retrieved
        correctly. It should be the function that is built locally in the tested method.
        """
        self.cog_instance.make_confirmation_task(MockMessage(id=123))

        self.cog_instance.bot.wait_for.assert_called_once()
        created_check = self.cog_instance.bot.wait_for.call_args.kwargs[
            "check"]

        # The `message_id` matches the `id` of our incident
        self.assertTrue(created_check(payload=MagicMock(message_id=123)))

        # This `message_id` does not match
        self.assertFalse(created_check(payload=MagicMock(message_id=0)))
Ejemplo n.º 11
0
    async def test_archive_relays_incident(self):
        """
        If webhook is found, method relays `incident` properly.

        This test will assert that the fetched webhook's `send` method is fed the correct arguments,
        and that the `archive` method returns True.
        """
        webhook = MockAsyncWebhook()
        self.cog_instance.bot.fetch_webhook = AsyncMock(
            return_value=webhook)  # Patch in our webhook

        # Define our own `incident` to be archived
        incident = MockMessage(
            content="this is an incident",
            author=MockUser(name="author_name",
                            display_avatar=Mock(url="author_avatar")),
            id=123,
        )
        built_embed = MagicMock(discord.Embed,
                                id=123)  # We patch `make_embed` to return this

        with patch("bot.exts.moderation.incidents.make_embed",
                   AsyncMock(return_value=(built_embed, None))):
            archive_return = await self.cog_instance.archive(
                incident, MagicMock(value="A"), MockMember())

        # Now we check that the webhook was given the correct args, and that `archive` returned True
        webhook.send.assert_called_once_with(
            embed=built_embed,
            username="******",
            avatar_url="author_avatar",
            file=None,
        )
        self.assertTrue(archive_return)
Ejemplo n.º 12
0
def make_msg(author: str,
             total_user_mentions: int,
             total_bot_mentions: int = 0) -> MockMessage:
    """Makes a message with `total_mentions` mentions."""
    user_mentions = [MockMember() for _ in range(total_user_mentions)]
    bot_mentions = [MockMember(bot=True) for _ in range(total_bot_mentions)]
    return MockMessage(author=author, mentions=user_mentions + bot_mentions)
Ejemplo n.º 13
0
    def test_predicate_eval_message_edit(self):
        """Test the predicate_eval_message_edit function."""
        msg0 = MockMessage(id=1, content='abc')
        msg1 = MockMessage(id=2, content='abcdef')
        msg2 = MockMessage(id=1, content='abcdef')

        cases = (
            (msg0, msg0, False, 'same ID, same content'),
            (msg0, msg1, False, 'different ID, different content'),
            (msg0, msg2, True, 'same ID, different content')
        )
        for ctx_msg, new_msg, expected, testname in cases:
            with self.subTest(msg=f'Messages with {testname} return {expected}'):
                ctx = MockContext(message=ctx_msg)
                actual = snekbox.predicate_eval_message_edit(ctx, ctx_msg, new_msg)
                self.assertEqual(actual, expected)
Ejemplo n.º 14
0
    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)
Ejemplo n.º 15
0
    async def test_on_message_edit_uses_on_message(self):
        """The edit listener should delegate handling of the message to the normal listener."""
        self.cog.on_message = mock.create_autospec(self.cog.on_message,
                                                   spec_set=True)

        await self.cog.on_message_edit(MockMessage(), self.msg)
        self.cog.on_message.assert_awaited_once_with(self.msg)
Ejemplo n.º 16
0
    async def test_send_eval_with_non_zero_eval(self):
        """Test the send_eval function with a code returning a non-zero code."""
        ctx = MockContext()
        ctx.message = MockMessage()
        ctx.send = AsyncMock()
        ctx.author.mention = '@LemonLemonishBeard#0042'
        self.cog.post_eval = AsyncMock(return_value={
            'stdout': 'ERROR',
            'returncode': 127
        })
        self.cog.get_results_message = MagicMock(
            return_value=('Return code 127', 'Beard got stuck in the eval'))
        self.cog.get_status_emoji = MagicMock(return_value=':nope!:')
        self.cog.format_output = AsyncMock()  # This function isn't called

        await self.cog.send_eval(ctx, 'MyAwesomeCode')
        ctx.send.assert_called_once_with(
            '@LemonLemonishBeard#0042 :nope!: Return code 127.\n\n```py\nBeard got stuck in the eval\n```'
        )
        self.cog.post_eval.assert_called_once_with('MyAwesomeCode')
        self.cog.get_status_emoji.assert_called_once_with({
            'stdout': 'ERROR',
            'returncode': 127
        })
        self.cog.get_results_message.assert_called_once_with({
            'stdout': 'ERROR',
            'returncode': 127
        })
        self.cog.format_output.assert_not_called()
Ejemplo n.º 17
0
    async def test_send_eval_with_paste_link(self):
        """Test the send_eval function with a too long output that generate a paste link."""
        ctx = MockContext()
        ctx.message = MockMessage()
        ctx.send = AsyncMock()
        ctx.author.mention = '@LemonLemonishBeard#0042'

        self.cog.post_eval = AsyncMock(return_value={'stdout': 'Way too long beard', 'returncode': 0})
        self.cog.get_results_message = MagicMock(return_value=('Return code 0', ''))
        self.cog.get_status_emoji = MagicMock(return_value=':yay!:')
        self.cog.format_output = AsyncMock(return_value=('Way too long beard', 'lookatmybeard.com'))

        mocked_filter_cog = MagicMock()
        mocked_filter_cog.filter_eval = AsyncMock(return_value=False)
        self.bot.get_cog.return_value = mocked_filter_cog

        await self.cog.send_eval(ctx, 'MyAwesomeCode')
        ctx.send.assert_called_once_with(
            '@LemonLemonishBeard#0042 :yay!: Return code 0.'
            '\n\n```\nWay too long beard\n```\nFull output: lookatmybeard.com'
        )
        self.cog.post_eval.assert_called_once_with('MyAwesomeCode')
        self.cog.get_status_emoji.assert_called_once_with({'stdout': 'Way too long beard', 'returncode': 0})
        self.cog.get_results_message.assert_called_once_with({'stdout': 'Way too long beard', 'returncode': 0})
        self.cog.format_output.assert_called_once_with('Way too long beard')
Ejemplo n.º 18
0
def make_msg(author: str) -> MockMessage:
    """
    Init a MockMessage instance with author set to `author`.

    This serves as a shorthand / alias to keep the test cases visually clean.
    """
    return MockMessage(author=author)
Ejemplo n.º 19
0
    async def test_send_eval(self):
        """Test the send_eval function."""
        ctx = MockContext()
        ctx.message = MockMessage()
        ctx.send = AsyncMock()
        ctx.author.mention = '@LemonLemonishBeard#0042'

        self.cog.post_eval = AsyncMock(return_value={
            'stdout': '',
            'returncode': 0
        })
        self.cog.get_results_message = MagicMock(return_value=('Return code 0',
                                                               ''))
        self.cog.get_status_emoji = MagicMock(return_value=':yay!:')
        self.cog.format_output = AsyncMock(return_value=('[No output]', None))

        await self.cog.send_eval(ctx, 'MyAwesomeCode')
        ctx.send.assert_called_once_with(
            '@LemonLemonishBeard#0042 :yay!: Return code 0.\n\n```py\n[No output]\n```'
        )
        self.cog.post_eval.assert_called_once_with('MyAwesomeCode')
        self.cog.get_status_emoji.assert_called_once_with({
            'stdout': '',
            'returncode': 0
        })
        self.cog.get_results_message.assert_called_once_with({
            'stdout': '',
            'returncode': 0
        })
        self.cog.format_output.assert_called_once_with('')
Ejemplo n.º 20
0
    def test_first_append_sets_the_first_value(self):
        """Test if the first append adds the message to the first cell."""
        cache = MessageCache(maxlen=10)
        message = MockMessage()

        cache.append(message)

        self.assertEqual(cache[0], message)
Ejemplo n.º 21
0
    def test_get_message_returns_none(self):
        """Test if get_message returns None for an ID of a non-cached message."""
        cache = MessageCache(maxlen=5)
        message = MockMessage(id=1234)

        cache.append(message)

        self.assertIsNone(cache.get_message(4321))
Ejemplo n.º 22
0
    def test_length(self):
        """Test if len returns the correct number of items in the cache."""
        cache = MessageCache(maxlen=5)

        for current_loop in range(10):
            with self.subTest(current_loop=current_loop):
                self.assertEqual(len(cache), min(current_loop, 5))
                cache.append(MockMessage())
Ejemplo n.º 23
0
    def test_get_message_returns_the_message(self):
        """Test if get_message returns the cached message."""
        cache = MessageCache(maxlen=5)
        message = MockMessage(id=1234)

        cache.append(message)

        self.assertEqual(cache.get_message(1234), message)
Ejemplo n.º 24
0
    def test_has_signals_false(self):
        """False when `own_reactions` does not return all emoji in `ALL_SIGNALS`."""
        message = MockMessage()
        own_reactions = MagicMock(return_value={"A", "C"})

        with patch("bot.exts.moderation.incidents.own_reactions",
                   own_reactions):
            self.assertFalse(incidents.has_signals(message))
Ejemplo n.º 25
0
    def test_contains_returns_false_for_non_cached_message(self):
        """Test if contains returns False for an ID of a non-cached message."""
        cache = MessageCache(maxlen=5)
        message = MockMessage(id=1234)

        cache.append(message)

        self.assertNotIn(4321, cache)
Ejemplo n.º 26
0
 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,
     )
Ejemplo n.º 27
0
    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))
Ejemplo n.º 28
0
    async def test_make_embed_actioned(self):
        """Embed is coloured green and footer contains 'Actioned' when `outcome=Signal.ACTIONED`."""
        embed, file = await incidents.make_embed(MockMessage(),
                                                 incidents.Signal.ACTIONED,
                                                 MockMember())

        self.assertEqual(embed.colour.value, Colours.soft_green)
        self.assertIn("Actioned", embed.footer.text)
Ejemplo n.º 29
0
    def test_contains_returns_true_for_cached_message(self):
        """Test if contains returns True for an ID of a cached message."""
        cache = MessageCache(maxlen=5)
        message = MockMessage(id=1234)

        cache.append(message)

        self.assertIn(1234, cache)
Ejemplo n.º 30
0
    async def test_make_embed_content(self):
        """Incident content appears as embed description."""
        incident = MockMessage(content="this is an incident")
        embed, file = await incidents.make_embed(incident,
                                                 incidents.Signal.ACTIONED,
                                                 MockMember())

        self.assertEqual(incident.content, embed.description)