aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorGravatar Leon Sandøy <[email protected]>2019-11-11 07:19:07 +0100
committerGravatar Leon Sandøy <[email protected]>2019-11-11 07:19:07 +0100
commitaac8404f65b419e212e5372015b63871fab7f3d1 (patch)
tree7b51e0ef3578370b8c537c99dffa55ef11e3cc03
parentTest is_staff and has_green_checkmark. (diff)
Adding ducky count tests and a new AsyncIteratorMock
-rw-r--r--tests/bot/cogs/test_duck_pond.py70
-rw-r--r--tests/helpers.py38
2 files changed, 93 insertions, 15 deletions
diff --git a/tests/bot/cogs/test_duck_pond.py b/tests/bot/cogs/test_duck_pond.py
index 31c7e9f89..af8ef0e4d 100644
--- a/tests/bot/cogs/test_duck_pond.py
+++ b/tests/bot/cogs/test_duck_pond.py
@@ -1,8 +1,10 @@
+import asyncio
import logging
import unittest
+from bot import constants
from bot.cogs import duck_pond
-from tests.helpers import MockBot, MockMember, MockMessage, MockReaction, MockRole
+from tests.helpers import MockBot, MockEmoji, MockMember, MockMessage, MockReaction, MockRole
class DuckPondTest(unittest.TestCase):
@@ -13,49 +15,89 @@ class DuckPondTest(unittest.TestCase):
self.bot = MockBot()
self.cog = duck_pond.DuckPond(bot=self.bot)
+ # Override the constants we'll be needing
+ constants.STAFF_ROLES = (123,)
+ constants.DuckPond.custom_emojis = (789,)
+ constants.DuckPond.threshold = 1
+
# Set up some roles
- self.admin_role = MockRole(name="Admins", role_id=476190234653229056)
- self.contrib_role = MockRole(name="Contributor", role_id=476190302659543061)
+ self.admin_role = MockRole(name="Admins", role_id=123)
+ self.contrib_role = MockRole(name="Contributor", role_id=456)
# Set up some users
- self.admin_member = MockMember(roles=(self.admin_role,))
+ self.admin_member_1 = MockMember(roles=(self.admin_role,), id=1)
+ self.admin_member_2 = MockMember(roles=(self.admin_role,), id=2)
self.contrib_member = MockMember(roles=(self.contrib_role,))
self.no_role_member = MockMember()
# Set up emojis
self.checkmark_emoji = "✅"
self.thumbs_up_emoji = "👍"
+ self.unicode_duck_emoji = "🦆"
+ self.yellow_ducky_emoji = MockEmoji(id=789)
# Set up reactions
- self.checkmark_reaction = MockReaction(emoji=self.checkmark_emoji)
- self.thumbs_up_reaction = MockReaction(emoji=self.thumbs_up_emoji)
+ self.checkmark_reaction = MockReaction(
+ emoji=self.checkmark_emoji,
+ user_list=[self.admin_member_1]
+ )
+ self.thumbs_up_reaction = MockReaction(
+ emoji=self.thumbs_up_emoji,
+ user_list=[self.admin_member_1, self.contrib_member]
+ )
+ self.yellow_ducky_reaction = MockReaction(
+ emoji=self.yellow_ducky_emoji,
+ user_list=[self.admin_member_1, self.contrib_member]
+ )
+ self.unicode_duck_reaction_1 = MockReaction(
+ emoji=self.unicode_duck_emoji,
+ user_list=[self.admin_member_1]
+ )
+ self.unicode_duck_reaction_2 = MockReaction(
+ emoji=self.unicode_duck_emoji,
+ user_list=[self.admin_member_2]
+ )
# Set up a messages
self.checkmark_message = MockMessage(reactions=(self.checkmark_reaction,))
self.thumbs_up_message = MockMessage(reactions=(self.thumbs_up_reaction,))
+ self.yellow_ducky_message = MockMessage(reactions=(self.yellow_ducky_reaction,))
+ self.unicode_duck_message = MockMessage(reactions=(self.unicode_duck_reaction_1,))
+ self.double_duck_message = MockMessage(reactions=(self.unicode_duck_reaction_1, self.unicode_duck_reaction_2))
self.no_reaction_message = MockMessage()
def test_is_staff_correctly_identifies_staff(self):
"""Test that is_staff correctly identifies a staff member."""
with self.subTest():
- self.assertTrue(duck_pond.DuckPond.is_staff(self.admin_member))
- self.assertFalse(duck_pond.DuckPond.is_staff(self.contrib_member))
- self.assertFalse(duck_pond.DuckPond.is_staff(self.no_role_member))
+ self.assertTrue(self.cog.is_staff(self.admin_member_1))
+ self.assertFalse(self.cog.is_staff(self.contrib_member))
+ self.assertFalse(self.cog.is_staff(self.no_role_member))
def test_has_green_checkmark_correctly_identifies_messages(self):
"""Test that has_green_checkmark recognizes messages with checkmarks."""
with self.subTest():
- self.assertTrue(duck_pond.DuckPond.has_green_checkmark(self.checkmark_message))
- self.assertFalse(duck_pond.DuckPond.has_green_checkmark(self.thumbs_up_message))
- self.assertFalse(duck_pond.DuckPond.has_green_checkmark(self.no_reaction_message))
+ self.assertTrue(self.cog.has_green_checkmark(self.checkmark_message))
+ self.assertFalse(self.cog.has_green_checkmark(self.thumbs_up_message))
+ self.assertFalse(self.cog.has_green_checkmark(self.no_reaction_message))
def test_count_custom_duck_emojis(self):
"""A string decoding to numeric characters is a valid user ID."""
- pass
+ count_one_duck = self.cog.count_ducks(self.yellow_ducky_message)
+ count_no_ducks = self.cog.count_ducks(self.thumbs_up_message)
+ with self.subTest():
+ self.assertEqual(asyncio.run(count_one_duck), 1)
+ self.assertEqual(asyncio.run(count_no_ducks), 0)
def test_count_unicode_duck_emojis(self):
"""A string decoding to numeric characters is a valid user ID."""
- pass
+ count_no_ducks = self.cog.count_ducks(self.thumbs_up_message)
+ count_one_duck = self.cog.count_ducks(self.unicode_duck_message)
+ count_two_ducks = self.cog.count_ducks(self.double_duck_message)
+
+ with self.subTest():
+ self.assertEqual(asyncio.run(count_no_ducks), 0)
+ self.assertEqual(asyncio.run(count_one_duck), 1)
+ self.assertEqual(asyncio.run(count_two_ducks), 2)
def test_count_mixed_duck_emojis(self):
"""A string decoding to numeric characters is a valid user ID."""
diff --git a/tests/helpers.py b/tests/helpers.py
index 8496ba031..fd79141ec 100644
--- a/tests/helpers.py
+++ b/tests/helpers.py
@@ -102,8 +102,30 @@ class AsyncMock(CustomMockMixin, unittest.mock.MagicMock):
Python 3.8 will introduce an AsyncMock class in the standard library that will have some more
features; this stand-in only overwrites the `__call__` method to an async version.
"""
+
async def __call__(self, *args, **kwargs):
- return super(AsyncMock, self).__call__(*args, **kwargs)
+ return super().__call__(*args, **kwargs)
+
+
+class AsyncIteratorMock:
+ """
+ A class to mock asyncronous iterators.
+
+ This allows async for, which is used in certain Discord.py objects. For example,
+ an async iterator is returned by the Reaction.users() coroutine.
+ """
+
+ def __init__(self, sequence):
+ self.iter = iter(sequence)
+
+ def __aiter__(self):
+ return self
+
+ async def __anext__(self):
+ try:
+ return next(self.iter)
+ except StopIteration:
+ raise StopAsyncIteration
# Create a guild instance to get a realistic Mock of `discord.Guild`
@@ -155,6 +177,7 @@ class MockGuild(CustomMockMixin, unittest.mock.Mock, HashableMixin):
For more info, see the `Mocking` section in `tests/README.md`.
"""
+
def __init__(
self,
guild_id: int = 1,
@@ -187,6 +210,7 @@ class MockRole(CustomMockMixin, unittest.mock.Mock, ColourMixin, HashableMixin):
Instances of this class will follow the specifications of `discord.Role` instances. For more
information, see the `MockGuild` docstring.
"""
+
def __init__(self, name: str = "role", role_id: int = 1, position: int = 1, **kwargs) -> None:
super().__init__(spec=role_instance, **kwargs)
@@ -213,6 +237,7 @@ class MockMember(CustomMockMixin, unittest.mock.Mock, ColourMixin, HashableMixin
Instances of this class will follow the specifications of `discord.Member` instances. For more
information, see the `MockGuild` docstring.
"""
+
def __init__(
self,
name: str = "member",
@@ -243,6 +268,7 @@ class MockBot(CustomMockMixin, unittest.mock.MagicMock):
Instances of this class will follow the specifications of `discord.ext.commands.Bot` instances.
For more information, see the `MockGuild` docstring.
"""
+
def __init__(self, **kwargs) -> None:
super().__init__(spec=bot_instance, **kwargs)
@@ -279,6 +305,7 @@ class MockTextChannel(CustomMockMixin, unittest.mock.Mock, HashableMixin):
Instances of this class will follow the specifications of `discord.TextChannel` instances. For
more information, see the `MockGuild` docstring.
"""
+
def __init__(self, name: str = 'channel', channel_id: int = 1, **kwargs) -> None:
super().__init__(spec=channel_instance, **kwargs)
self.id = channel_id
@@ -320,6 +347,7 @@ class MockContext(CustomMockMixin, unittest.mock.MagicMock):
Instances of this class will follow the specifications of `discord.ext.commands.Context`
instances. For more information, see the `MockGuild` docstring.
"""
+
def __init__(self, **kwargs) -> None:
super().__init__(spec=context_instance, **kwargs)
self.bot = kwargs.get('bot', MockBot())
@@ -336,6 +364,7 @@ class MockMessage(CustomMockMixin, unittest.mock.MagicMock):
Instances of this class will follow the specifications of `discord.Message` instances. For more
information, see the `MockGuild` docstring.
"""
+
def __init__(self, **kwargs) -> None:
super().__init__(spec=message_instance, **kwargs)
self.author = kwargs.get('author', MockMember())
@@ -353,6 +382,7 @@ class MockEmoji(CustomMockMixin, unittest.mock.MagicMock):
Instances of this class will follow the specifications of `discord.Emoji` instances. For more
information, see the `MockGuild` docstring.
"""
+
def __init__(self, **kwargs) -> None:
super().__init__(spec=emoji_instance, **kwargs)
self.guild = kwargs.get('guild', MockGuild())
@@ -371,6 +401,7 @@ class MockPartialEmoji(CustomMockMixin, unittest.mock.MagicMock):
Instances of this class will follow the specifications of `discord.PartialEmoji` instances. For
more information, see the `MockGuild` docstring.
"""
+
def __init__(self, **kwargs) -> None:
super().__init__(spec=partial_emoji_instance, **kwargs)
@@ -385,7 +416,12 @@ class MockReaction(CustomMockMixin, unittest.mock.MagicMock):
Instances of this class will follow the specifications of `discord.Reaction` instances. For
more information, see the `MockGuild` docstring.
"""
+
def __init__(self, **kwargs) -> None:
super().__init__(spec=reaction_instance, **kwargs)
self.emoji = kwargs.get('emoji', MockEmoji())
self.message = kwargs.get('message', MockMessage())
+ self.user_list = AsyncIteratorMock(kwargs.get('user_list', []))
+
+ def users(self):
+ return self.user_list