Example #1
0
    def test_on_raw_reaction_add_returns_on_message_with_green_checkmark_placed_by_bot(
            self, count_ducks, is_staff):
        """The `on_raw_reaction_add` event should return when the message has a green check mark placed by the bot."""
        channel_id = 31415926535
        message_id = 27182818284
        user_id = 16180339887

        channel, message, member, payload = self._raw_reaction_mocks(
            channel_id, message_id, user_id)

        payload.emoji = helpers.MockPartialEmoji(name=self.unicode_duck_emoji)
        payload.emoji.is_custom_emoji.return_value = False

        message.reactions = [
            helpers.MockReaction(emoji=self.checkmark_emoji,
                                 users=[self.bot.user])
        ]

        is_staff.return_value = True
        count_ducks.side_effect = AssertionError(
            "Expected method to return before calling `self.count_ducks`")

        self.assertIsNone(asyncio.run(self.cog.on_raw_reaction_add(payload)))

        # Assert that we've made it past `self.is_staff`
        is_staff.assert_called_once()
Example #2
0
 def _get_reaction(self,
                   emoji: typing.Union[str, helpers.MockEmoji],
                   staff: int = 0,
                   nonstaff: int = 0) -> helpers.MockReaction:
     staffers = [
         helpers.MockMember(roles=[self.staff_role]) for _ in range(staff)
     ]
     nonstaffers = [helpers.MockMember() for _ in range(nonstaff)]
     return helpers.MockReaction(emoji=emoji, users=staffers + nonstaffers)
Example #3
0
    async def test_has_green_checkmark_correctly_detects_presence_of_green_checkmark_emoji(
            self):
        """The `has_green_checkmark` method should only return `True` if one is present."""
        test_cases = (
            ("No reactions", helpers.MockMessage(),
             False), ("No green check mark reactions",
                      helpers.MockMessage(reactions=[
                          helpers.MockReaction(emoji=self.unicode_duck_emoji,
                                               users=[self.bot.user]),
                          helpers.MockReaction(emoji=self.thumbs_up_emoji,
                                               users=[self.bot.user])
                      ]), False),
            ("Green check mark reaction, but not from our bot",
             helpers.MockMessage(reactions=[
                 helpers.MockReaction(emoji=self.unicode_duck_emoji,
                                      users=[self.bot.user]),
                 helpers.MockReaction(emoji=self.checkmark_emoji,
                                      users=[self.staff_member])
             ]), False),
            ("Green check mark reaction, with one from the bot",
             helpers.MockMessage(reactions=[
                 helpers.MockReaction(emoji=self.unicode_duck_emoji,
                                      users=[self.bot.user]),
                 helpers.MockReaction(emoji=self.checkmark_emoji,
                                      users=[self.staff_member, self.bot.user])
             ]), True))

        for description, message, expected_return in test_cases:
            actual_return = await self.cog.has_green_checkmark(message)
            with self.subTest(test_case=description,
                              expected_return=expected_return,
                              actual_return=actual_return):
                self.assertEqual(expected_return, actual_return)
Example #4
0
    async def test_wait_for_confirmation(self):
        """The message should always be edited and only return True if the emoji is a check mark."""
        subtests = (
            (constants.Emojis.check_mark, True, None),
            ("InVaLiD", False, None),
            (None, False, asyncio.TimeoutError),
        )

        for emoji, ret_val, side_effect in subtests:
            for bot in (True, False):
                with self.subTest(emoji=emoji,
                                  ret_val=ret_val,
                                  side_effect=side_effect,
                                  bot=bot):
                    # Set up mocks
                    message = helpers.MockMessage()
                    member = helpers.MockMember(bot=bot)

                    self.bot.wait_for.reset_mock()
                    self.bot.wait_for.return_value = (helpers.MockReaction(
                        emoji=emoji), None)
                    self.bot.wait_for.side_effect = side_effect

                    # Call the function
                    actual_return = await self.syncer._wait_for_confirmation(
                        member, message)

                    # Perform assertions
                    self.bot.wait_for.assert_called_once()
                    self.assertIn("reaction_add",
                                  self.bot.wait_for.call_args[0])

                    message.edit.assert_called_once()
                    kwargs = message.edit.call_args[1]
                    self.assertIn("content", kwargs)

                    # Core devs should only be mentioned if the author is a bot.
                    if bot:
                        self.assertIn(self.syncer._CORE_DEV_MENTION,
                                      kwargs["content"])
                    else:
                        self.assertNotIn(self.syncer._CORE_DEV_MENTION,
                                         kwargs["content"])

                    self.assertIs(actual_return, ret_val)
Example #5
0
    def test_reaction_check_for_invalid_reactions(self):
        """Should return False for invalid reaction events."""
        valid_emoji = self.syncer._REACTION_EMOJIS[0]
        subtests = (
            (
                helpers.MockMember(id=77),
                *self.get_message_reaction(valid_emoji),
                helpers.MockMember(id=43, roles=[self.core_dev_role]),
                "users are not identical",
            ),
            (
                helpers.MockMember(id=77, bot=True),
                *self.get_message_reaction(valid_emoji),
                helpers.MockMember(id=43),
                "reactor lacks the core-dev role",
            ),
            (
                helpers.MockMember(id=77, bot=True,
                                   roles=[self.core_dev_role]),
                *self.get_message_reaction(valid_emoji),
                helpers.MockMember(id=77, bot=True,
                                   roles=[self.core_dev_role]),
                "reactor is a bot",
            ),
            (
                helpers.MockMember(id=77),
                helpers.MockMessage(id=95),
                helpers.MockReaction(emoji=valid_emoji,
                                     message=helpers.MockMessage(id=26)),
                helpers.MockMember(id=77),
                "messages are not identical",
            ),
            (
                helpers.MockMember(id=77),
                *self.get_message_reaction("InVaLiD"),
                helpers.MockMember(id=77),
                "emoji is invalid",
            ),
        )

        for *args, msg in subtests:
            kwargs = dict(zip(("author", "message", "reaction", "user"), args))
            with self.subTest(**kwargs, msg=msg):
                ret_val = self.syncer._reaction_check(*args)
                self.assertFalse(ret_val)
Example #6
0
    def get_message_reaction(emoji):
        """Fixture to return a mock message an reaction from the given `emoji`."""
        message = helpers.MockMessage()
        reaction = helpers.MockReaction(emoji=emoji, message=message)

        return message, reaction
Example #7
0
    async def test_count_ducks_correctly_counts_the_number_of_eligible_duck_emojis(
            self):
        """The `count_ducks` method should return the number of unique staffers who gave a duck."""
        test_cases = (
            # Simple test cases
            # A message without reactions should return 0
            ("No reactions", helpers.MockMessage(), 0),
            # A message with a non-duck reaction from a non-staffer should return 0
            ("Non-duck reaction from non-staffer",
             helpers.MockMessage(reactions=[
                 self._get_reaction(emoji=self.thumbs_up_emoji, nonstaff=1)
             ]), 0),
            # A message with a non-duck reaction from a staffer should return 0
            ("Non-duck reaction from staffer",
             helpers.MockMessage(reactions=[
                 self._get_reaction(emoji=self.non_duck_custom_emoji, staff=1)
             ]), 0),
            # A message with a non-duck reaction from a non-staffer and staffer should return 0
            ("Non-duck reaction from staffer + non-staffer",
             helpers.MockMessage(reactions=[
                 self._get_reaction(
                     emoji=self.thumbs_up_emoji, staff=1, nonstaff=1)
             ]), 0),
            # A message with a unicode duck reaction from a non-staffer should return 0
            ("Unicode Duck Reaction from non-staffer",
             helpers.MockMessage(reactions=[
                 self._get_reaction(emoji=self.unicode_duck_emoji, nonstaff=1)
             ]), 0),
            # A message with a unicode duck reaction from a staffer should return 1
            ("Unicode Duck Reaction from staffer",
             helpers.MockMessage(reactions=[
                 self._get_reaction(emoji=self.unicode_duck_emoji, staff=1)
             ]), 1),
            # A message with a unicode duck reaction from a non-staffer and staffer should return 1
            ("Unicode Duck Reaction from staffer + non-staffer",
             helpers.MockMessage(reactions=[
                 self._get_reaction(
                     emoji=self.unicode_duck_emoji, staff=1, nonstaff=1)
             ]), 1),
            # A message with a duckpond duck reaction from a non-staffer should return 0
            ("Duckpond Duck Reaction from non-staffer",
             helpers.MockMessage(reactions=[
                 self._get_reaction(emoji=self.duck_pond_emoji, nonstaff=1)
             ]), 0),
            # A message with a duckpond duck reaction from a staffer should return 1
            ("Duckpond Duck Reaction from staffer",
             helpers.MockMessage(reactions=[
                 self._get_reaction(emoji=self.duck_pond_emoji, staff=1)
             ]), 1),
            # A message with a duckpond duck reaction from a non-staffer and staffer should return 1
            ("Duckpond Duck Reaction from staffer + non-staffer",
             helpers.MockMessage(reactions=[
                 self._get_reaction(
                     emoji=self.duck_pond_emoji, staff=1, nonstaff=1)
             ]), 1),

            # Complex test cases
            # A message with duckpond duck reactions from 3 staffers and 2 non-staffers returns 3
            ("Duckpond Duck Reaction from 3 staffers + 2 non-staffers",
             helpers.MockMessage(reactions=[
                 self._get_reaction(
                     emoji=self.duck_pond_emoji, staff=3, nonstaff=2)
             ]), 3),
            # A staffer with multiple duck reactions only counts once
            ("Two different duck reactions from the same staffer",
             helpers.MockMessage(reactions=[
                 helpers.MockReaction(emoji=self.duck_pond_emoji,
                                      users=[self.staff_member]),
                 helpers.MockReaction(emoji=self.unicode_duck_emoji,
                                      users=[self.staff_member]),
             ]), 1),
            # A non-string emoji does not count (to test the `isinstance(reaction.emoji, str)` elif)
            ("Reaction with non-Emoji/str emoij from 3 staffers + 2 non-staffers",
             helpers.MockMessage(reactions=[
                 self._get_reaction(emoji=100, staff=3, nonstaff=2)
             ]), 0),
            # We correctly sum when multiple reactions are provided.
            ("Duckpond Duck Reaction from 3 staffers + 2 non-staffers",
             helpers.MockMessage(reactions=[
                 self._get_reaction(
                     emoji=self.duck_pond_emoji, staff=3, nonstaff=2),
                 self._get_reaction(
                     emoji=self.unicode_duck_emoji, staff=4, nonstaff=9),
             ]), 3 + 4),
        )

        for description, message, expected_count in test_cases:
            actual_count = await self.cog.count_ducks(message)
            with self.subTest(test_case=description,
                              expected_count=expected_count,
                              actual_count=actual_count):
                self.assertEqual(expected_count, actual_count)