aboutsummaryrefslogtreecommitdiffstats
path: root/tests
diff options
context:
space:
mode:
Diffstat (limited to 'tests')
-rw-r--r--tests/README.md2
-rw-r--r--tests/bot/exts/filters/test_token_remover.py4
-rw-r--r--tests/bot/exts/info/doc/__init__.py0
-rw-r--r--tests/bot/exts/info/doc/test_parsing.py66
-rw-r--r--tests/bot/exts/info/test_information.py22
-rw-r--r--tests/bot/exts/moderation/infraction/test_infractions.py2
-rw-r--r--tests/bot/exts/moderation/infraction/test_utils.py12
-rw-r--r--tests/bot/test_converters.py21
-rw-r--r--tests/bot/utils/test_services.py4
9 files changed, 100 insertions, 33 deletions
diff --git a/tests/README.md b/tests/README.md
index 4f62edd68..092324123 100644
--- a/tests/README.md
+++ b/tests/README.md
@@ -114,7 +114,7 @@ class BotCogTests(unittest.TestCase):
### Mocking coroutines
-By default, the `unittest.mock.Mock` and `unittest.mock.MagicMock` classes cannot mock coroutines, since the `__call__` method they provide is synchronous. In anticipation of the `AsyncMock` that will be [introduced in Python 3.8](https://docs.python.org/3.9/whatsnew/3.8.html#unittest), we have added an `AsyncMock` helper to [`helpers.py`](/tests/helpers.py). Do note that this drop-in replacement only implements an asynchronous `__call__` method, not the additional assertions that will come with the new `AsyncMock` type in Python 3.8.
+By default, the `unittest.mock.Mock` and `unittest.mock.MagicMock` classes cannot mock coroutines, since the `__call__` method they provide is synchronous. The [`AsyncMock`](https://docs.python.org/3/library/unittest.mock.html#unittest.mock.AsyncMock) that has been [introduced in Python 3.8](https://docs.python.org/3.9/whatsnew/3.8.html#unittest) is an asynchronous version of `MagicMock` that can be used anywhere a coroutine is expected.
### Special mocks for some `discord.py` types
diff --git a/tests/bot/exts/filters/test_token_remover.py b/tests/bot/exts/filters/test_token_remover.py
index f99cc3370..51feae9cb 100644
--- a/tests/bot/exts/filters/test_token_remover.py
+++ b/tests/bot/exts/filters/test_token_remover.py
@@ -291,7 +291,7 @@ class TokenRemoverTests(unittest.IsolatedAsyncioTestCase):
channel=self.msg.channel.mention,
user_id=token.user_id,
timestamp=token.timestamp,
- hmac="x" * len(token.hmac),
+ hmac="xxxxxxxxxxxxxxxxxxxxxxxxjf4",
)
@autospec("bot.exts.filters.token_remover", "UNKNOWN_USER_LOG_MESSAGE")
@@ -318,7 +318,7 @@ class TokenRemoverTests(unittest.IsolatedAsyncioTestCase):
return_value = TokenRemover.format_userid_log_message(msg, token)
- self.assertEqual(return_value, (known_user_log_message.format.return_value, False))
+ self.assertEqual(return_value, (known_user_log_message.format.return_value, True))
known_user_log_message.format.assert_called_once_with(
user_id=472265943062413332,
diff --git a/tests/bot/exts/info/doc/__init__.py b/tests/bot/exts/info/doc/__init__.py
new file mode 100644
index 000000000..e69de29bb
--- /dev/null
+++ b/tests/bot/exts/info/doc/__init__.py
diff --git a/tests/bot/exts/info/doc/test_parsing.py b/tests/bot/exts/info/doc/test_parsing.py
new file mode 100644
index 000000000..1663d8491
--- /dev/null
+++ b/tests/bot/exts/info/doc/test_parsing.py
@@ -0,0 +1,66 @@
+from unittest import TestCase
+
+from bot.exts.info.doc import _parsing as parsing
+
+
+class SignatureSplitter(TestCase):
+
+ def test_basic_split(self):
+ test_cases = (
+ ("0,0,0", ["0", "0", "0"]),
+ ("0,a=0,a=0", ["0", "a=0", "a=0"]),
+ )
+ self._run_tests(test_cases)
+
+ def test_commas_ignored_in_brackets(self):
+ test_cases = (
+ ("0,[0,0],0,[0,0],0", ["0", "[0,0]", "0", "[0,0]", "0"]),
+ ("(0,),0,(0,(0,),0),0", ["(0,)", "0", "(0,(0,),0)", "0"]),
+ )
+ self._run_tests(test_cases)
+
+ def test_mixed_brackets(self):
+ tests_cases = (
+ ("[0,{0},0],0,{0:0},0", ["[0,{0},0]", "0", "{0:0}", "0"]),
+ ("([0],0,0),0,(0,0),0", ["([0],0,0)", "0", "(0,0)", "0"]),
+ ("([(0,),(0,)],0),0", ["([(0,),(0,)],0)", "0"]),
+ )
+ self._run_tests(tests_cases)
+
+ def test_string_contents_ignored(self):
+ test_cases = (
+ ("'0,0',0,',',0", ["'0,0'", "0", "','", "0"]),
+ ("0,[']',0],0", ["0", "[']',0]", "0"]),
+ ("{0,0,'}}',0,'{'},0", ["{0,0,'}}',0,'{'}", "0"]),
+ )
+ self._run_tests(test_cases)
+
+ def test_mixed_quotes(self):
+ test_cases = (
+ ("\"0',0',\",'0,0',0", ["\"0',0',\"", "'0,0'", "0"]),
+ ("\",',\",'\",',0", ["\",',\"", "'\",'", "0"]),
+ )
+ self._run_tests(test_cases)
+
+ def test_quote_escaped(self):
+ test_cases = (
+ (r"'\',','\\',0", [r"'\','", r"'\\'", "0"]),
+ (r"'0\',0\\\'\\',0", [r"'0\',0\\\'\\'", "0"]),
+ )
+ self._run_tests(test_cases)
+
+ def test_real_signatures(self):
+ test_cases = (
+ ("start, stop[, step]", ["start", " stop[, step]"]),
+ ("object=b'', encoding='utf-8', errors='strict'", ["object=b''", " encoding='utf-8'", " errors='strict'"]),
+ (
+ "typename, field_names, *, rename=False, defaults=None, module=None",
+ ["typename", " field_names", " *", " rename=False", " defaults=None", " module=None"]
+ ),
+ )
+ self._run_tests(test_cases)
+
+ def _run_tests(self, test_cases):
+ for input_string, expected_output in test_cases:
+ with self.subTest(input_string=input_string):
+ self.assertEqual(list(parsing._split_parameters(input_string)), expected_output)
diff --git a/tests/bot/exts/info/test_information.py b/tests/bot/exts/info/test_information.py
index 80731c9f0..770660fe3 100644
--- a/tests/bot/exts/info/test_information.py
+++ b/tests/bot/exts/info/test_information.py
@@ -281,8 +281,10 @@ class UserEmbedTests(unittest.IsolatedAsyncioTestCase):
"""The embed should use the string representation of the user if they don't have a nick."""
ctx = helpers.MockContext(channel=helpers.MockTextChannel(id=1))
user = helpers.MockMember()
+ user.public_flags = unittest.mock.MagicMock(verified_bot=False)
user.nick = None
user.__str__ = unittest.mock.Mock(return_value="Mr. Hemlock")
+ user.colour = 0
embed = await self.cog.create_user_embed(ctx, user)
@@ -296,8 +298,10 @@ class UserEmbedTests(unittest.IsolatedAsyncioTestCase):
"""The embed should use the nick if it's available."""
ctx = helpers.MockContext(channel=helpers.MockTextChannel(id=1))
user = helpers.MockMember()
+ user.public_flags = unittest.mock.MagicMock(verified_bot=False)
user.nick = "Cat lover"
user.__str__ = unittest.mock.Mock(return_value="Mr. Hemlock")
+ user.colour = 0
embed = await self.cog.create_user_embed(ctx, user)
@@ -311,10 +315,9 @@ class UserEmbedTests(unittest.IsolatedAsyncioTestCase):
"""Created `!user` embeds should not contain mention of the @everyone-role."""
ctx = helpers.MockContext(channel=helpers.MockTextChannel(id=1))
admins_role = helpers.MockRole(name='Admins')
- admins_role.colour = 100
# A `MockMember` has the @Everyone role by default; we add the Admins to that.
- user = helpers.MockMember(roles=[admins_role], top_role=admins_role)
+ user = helpers.MockMember(roles=[admins_role], colour=100)
embed = await self.cog.create_user_embed(ctx, user)
@@ -332,12 +335,11 @@ class UserEmbedTests(unittest.IsolatedAsyncioTestCase):
ctx = helpers.MockContext(channel=helpers.MockTextChannel(id=50))
moderators_role = helpers.MockRole(name='Moderators')
- moderators_role.colour = 100
infraction_counts.return_value = ("Infractions", "expanded infractions info")
nomination_counts.return_value = ("Nominations", "nomination info")
- user = helpers.MockMember(id=314, roles=[moderators_role], top_role=moderators_role)
+ user = helpers.MockMember(id=314, roles=[moderators_role], colour=100)
embed = await self.cog.create_user_embed(ctx, user)
infraction_counts.assert_called_once_with(user)
@@ -367,11 +369,10 @@ class UserEmbedTests(unittest.IsolatedAsyncioTestCase):
ctx = helpers.MockContext(channel=helpers.MockTextChannel(id=100))
moderators_role = helpers.MockRole(name='Moderators')
- moderators_role.colour = 100
infraction_counts.return_value = ("Infractions", "basic infractions info")
- user = helpers.MockMember(id=314, roles=[moderators_role], top_role=moderators_role)
+ user = helpers.MockMember(id=314, roles=[moderators_role], colour=100)
embed = await self.cog.create_user_embed(ctx, user)
infraction_counts.assert_called_once_with(user)
@@ -407,12 +408,11 @@ class UserEmbedTests(unittest.IsolatedAsyncioTestCase):
ctx = helpers.MockContext()
moderators_role = helpers.MockRole(name='Moderators')
- moderators_role.colour = 100
- user = helpers.MockMember(id=314, roles=[moderators_role], top_role=moderators_role)
+ user = helpers.MockMember(id=314, roles=[moderators_role], colour=100)
embed = await self.cog.create_user_embed(ctx, user)
- self.assertEqual(embed.colour, discord.Colour(moderators_role.colour))
+ self.assertEqual(embed.colour, discord.Colour(100))
@unittest.mock.patch(
f"{COG_PATH}.basic_user_infraction_counts",
@@ -422,7 +422,7 @@ class UserEmbedTests(unittest.IsolatedAsyncioTestCase):
"""The embed should be created with a blurple colour if the user has no assigned roles."""
ctx = helpers.MockContext()
- user = helpers.MockMember(id=217)
+ user = helpers.MockMember(id=217, colour=discord.Colour.default())
embed = await self.cog.create_user_embed(ctx, user)
self.assertEqual(embed.colour, discord.Colour.blurple())
@@ -435,7 +435,7 @@ class UserEmbedTests(unittest.IsolatedAsyncioTestCase):
"""The embed thumbnail should be set to the user's avatar in `png` format."""
ctx = helpers.MockContext()
- user = helpers.MockMember(id=217)
+ user = helpers.MockMember(id=217, colour=0)
user.avatar_url_as.return_value = "avatar url"
embed = await self.cog.create_user_embed(ctx, user)
diff --git a/tests/bot/exts/moderation/infraction/test_infractions.py b/tests/bot/exts/moderation/infraction/test_infractions.py
index 86c2617ea..08f39cd50 100644
--- a/tests/bot/exts/moderation/infraction/test_infractions.py
+++ b/tests/bot/exts/moderation/infraction/test_infractions.py
@@ -39,7 +39,7 @@ class TruncationTests(unittest.IsolatedAsyncioTestCase):
delete_message_days=0
)
self.cog.apply_infraction.assert_awaited_once_with(
- self.ctx, {"foo": "bar"}, self.target, self.ctx.guild.ban.return_value
+ self.ctx, {"foo": "bar", "purge": ""}, self.target, self.ctx.guild.ban.return_value
)
@patch("bot.exts.moderation.infraction._utils.post_infraction")
diff --git a/tests/bot/exts/moderation/infraction/test_utils.py b/tests/bot/exts/moderation/infraction/test_utils.py
index 5b62463e0..ee9ff650c 100644
--- a/tests/bot/exts/moderation/infraction/test_utils.py
+++ b/tests/bot/exts/moderation/infraction/test_utils.py
@@ -146,7 +146,7 @@ class ModerationUtilsTests(unittest.IsolatedAsyncioTestCase):
name=utils.INFRACTION_AUTHOR_NAME,
url=utils.RULES_URL,
icon_url=Icons.token_removed
- ).set_footer(text=utils.INFRACTION_APPEAL_FOOTER),
+ ).set_footer(text=utils.INFRACTION_APPEAL_MODMAIL_FOOTER),
"send_result": True
},
{
@@ -164,9 +164,11 @@ class ModerationUtilsTests(unittest.IsolatedAsyncioTestCase):
name=utils.INFRACTION_AUTHOR_NAME,
url=utils.RULES_URL,
icon_url=Icons.token_removed
- ),
+ ).set_footer(text=utils.INFRACTION_APPEAL_MODMAIL_FOOTER),
"send_result": False
},
+ # Note that this test case asserts that the DM that *would* get sent to the user is formatted
+ # correctly, even though that message is deliberately never sent.
{
"args": (self.user, "note", None, None, Icons.defcon_denied),
"expected_output": Embed(
@@ -182,7 +184,7 @@ class ModerationUtilsTests(unittest.IsolatedAsyncioTestCase):
name=utils.INFRACTION_AUTHOR_NAME,
url=utils.RULES_URL,
icon_url=Icons.defcon_denied
- ),
+ ).set_footer(text=utils.INFRACTION_APPEAL_MODMAIL_FOOTER),
"send_result": False
},
{
@@ -200,7 +202,7 @@ class ModerationUtilsTests(unittest.IsolatedAsyncioTestCase):
name=utils.INFRACTION_AUTHOR_NAME,
url=utils.RULES_URL,
icon_url=Icons.defcon_denied
- ).set_footer(text=utils.INFRACTION_APPEAL_FOOTER),
+ ).set_footer(text=utils.INFRACTION_APPEAL_MODMAIL_FOOTER),
"send_result": False
},
{
@@ -218,7 +220,7 @@ class ModerationUtilsTests(unittest.IsolatedAsyncioTestCase):
name=utils.INFRACTION_AUTHOR_NAME,
url=utils.RULES_URL,
icon_url=Icons.defcon_denied
- ).set_footer(text=utils.INFRACTION_APPEAL_FOOTER),
+ ).set_footer(text=utils.INFRACTION_APPEAL_MODMAIL_FOOTER),
"send_result": True
}
]
diff --git a/tests/bot/test_converters.py b/tests/bot/test_converters.py
index c42111f3f..4af84dde5 100644
--- a/tests/bot/test_converters.py
+++ b/tests/bot/test_converters.py
@@ -10,9 +10,9 @@ from bot.converters import (
Duration,
HushDurationConverter,
ISODateTime,
+ PackageName,
TagContentConverter,
TagNameConverter,
- ValidPythonIdentifier,
)
@@ -78,24 +78,23 @@ class ConverterTests(unittest.IsolatedAsyncioTestCase):
with self.assertRaisesRegex(BadArgument, re.escape(exception_message)):
await TagNameConverter.convert(self.context, invalid_name)
- async def test_valid_python_identifier_for_valid(self):
- """ValidPythonIdentifier returns valid identifiers unchanged."""
- test_values = ('foo', 'lemon')
+ async def test_package_name_for_valid(self):
+ """PackageName returns valid package names unchanged."""
+ test_values = ('foo', 'le_mon', 'num83r')
for name in test_values:
with self.subTest(identifier=name):
- conversion = await ValidPythonIdentifier.convert(self.context, name)
+ conversion = await PackageName.convert(self.context, name)
self.assertEqual(name, conversion)
- async def test_valid_python_identifier_for_invalid(self):
- """ValidPythonIdentifier raises the proper exception for invalid identifiers."""
- test_values = ('nested.stuff', '#####')
+ async def test_package_name_for_invalid(self):
+ """PackageName raises the proper exception for invalid package names."""
+ test_values = ('text_with_a_dot.', 'UpperCaseName', 'dashed-name')
for name in test_values:
with self.subTest(identifier=name):
- exception_message = f'`{name}` is not a valid Python identifier'
- with self.assertRaisesRegex(BadArgument, re.escape(exception_message)):
- await ValidPythonIdentifier.convert(self.context, name)
+ with self.assertRaises(BadArgument):
+ await PackageName.convert(self.context, name)
async def test_duration_converter_for_valid(self):
"""Duration returns the correct `datetime` for valid duration strings."""
diff --git a/tests/bot/utils/test_services.py b/tests/bot/utils/test_services.py
index 1b48f6560..3b71022db 100644
--- a/tests/bot/utils/test_services.py
+++ b/tests/bot/utils/test_services.py
@@ -30,9 +30,9 @@ class PasteTests(unittest.IsolatedAsyncioTestCase):
"""Url with specified extension is returned on successful requests."""
key = "paste_key"
test_cases = (
- (f"https://paste_service.com/{key}.txt", "txt"),
+ (f"https://paste_service.com/{key}.txt?noredirect", "txt"),
(f"https://paste_service.com/{key}.py", "py"),
- (f"https://paste_service.com/{key}", ""),
+ (f"https://paste_service.com/{key}?noredirect", ""),
)
response = MagicMock(
json=AsyncMock(return_value={"key": key})