aboutsummaryrefslogtreecommitdiffstats
path: root/tests
diff options
context:
space:
mode:
Diffstat (limited to 'tests')
-rw-r--r--tests/bot/exts/info/test_information.py74
-rw-r--r--tests/bot/exts/moderation/infraction/test_infractions.py49
-rw-r--r--tests/bot/exts/moderation/infraction/test_utils.py29
-rw-r--r--tests/helpers.py2
-rw-r--r--tests/test_helpers.py2
5 files changed, 126 insertions, 30 deletions
diff --git a/tests/bot/exts/info/test_information.py b/tests/bot/exts/info/test_information.py
index d896b7652..9f5143c01 100644
--- a/tests/bot/exts/info/test_information.py
+++ b/tests/bot/exts/info/test_information.py
@@ -2,6 +2,7 @@ import textwrap
import unittest
import unittest.mock
from datetime import datetime
+from textwrap import shorten
import discord
@@ -573,3 +574,76 @@ class UserCommandTests(unittest.IsolatedAsyncioTestCase):
create_embed.assert_called_once_with(ctx, self.target, False)
ctx.send.assert_called_once()
+
+
+class RuleCommandTests(unittest.IsolatedAsyncioTestCase):
+ """Tests for the `!rule` command."""
+
+ def setUp(self) -> None:
+ """Set up steps executed before each test is run."""
+ self.bot = helpers.MockBot()
+ self.cog = information.Information(self.bot)
+ self.ctx = helpers.MockContext(author=helpers.MockMember(id=1, name="Bellaluma"))
+ self.full_rules = [
+ (
+ "First rule",
+ ["first", "number_one"]
+ ),
+ (
+ "Second rule",
+ ["second", "number_two"]
+ ),
+ (
+ "Third rule",
+ ["third", "number_three"]
+ )
+ ]
+ self.bot.api_client.get.return_value = self.full_rules
+
+ async def test_return_none_if_one_rule_number_is_invalid(self):
+
+ test_cases = [
+ (('1', '6', '7', '8'), (6, 7, 8)),
+ (('10', "first"), (10, )),
+ (("first", 10), (10, ))
+ ]
+
+ for raw_user_input, extracted_rule_numbers in test_cases:
+ with self.subTest(identifier=raw_user_input):
+ invalid = ", ".join(
+ str(rule_number) for rule_number in extracted_rule_numbers
+ if rule_number < 1 or rule_number > len(self.full_rules))
+
+ final_rule_numbers = await self.cog.rules(self.cog, self.ctx, *raw_user_input)
+
+ self.assertEqual(
+ self.ctx.send.call_args,
+ unittest.mock.call(shorten(":x: Invalid rule indices: " + invalid, 75, placeholder=" ...")))
+ self.assertEqual(None, final_rule_numbers)
+
+ async def test_return_correct_rule_numbers(self):
+
+ test_cases = [
+ (("1", "2", "first"), {1, 2}),
+ (("1", "hello", "2", "second"), {1}),
+ (("second", "third", "unknown", "999"), {2, 3})
+ ]
+
+ for raw_user_input, expected_matched_rule_numbers in test_cases:
+ with self.subTest(identifier=raw_user_input):
+ final_rule_numbers = await self.cog.rules(self.cog, self.ctx, *raw_user_input)
+ self.assertEqual(expected_matched_rule_numbers, final_rule_numbers)
+
+ async def test_return_default_rules_when_no_input_or_no_match_are_found(self):
+ test_cases = [
+ ((), None),
+ (("hello", "2", "second"), None),
+ (("hello", "999"), None),
+ ]
+
+ for raw_user_input, expected_matched_rule_numbers in test_cases:
+ with self.subTest(identifier=raw_user_input):
+ final_rule_numbers = await self.cog.rules(self.cog, self.ctx, *raw_user_input)
+ embed = self.ctx.send.call_args.kwargs['embed']
+ self.assertEqual(information.DEFAULT_RULES_DESCRIPTION, embed.description)
+ self.assertEqual(expected_matched_rule_numbers, final_rule_numbers)
diff --git a/tests/bot/exts/moderation/infraction/test_infractions.py b/tests/bot/exts/moderation/infraction/test_infractions.py
index 052048053..b78328137 100644
--- a/tests/bot/exts/moderation/infraction/test_infractions.py
+++ b/tests/bot/exts/moderation/infraction/test_infractions.py
@@ -35,17 +35,20 @@ class TruncationTests(unittest.IsolatedAsyncioTestCase):
self.cog.apply_infraction = AsyncMock()
self.bot.get_cog.return_value = AsyncMock()
self.cog.mod_log.ignore = Mock()
- self.ctx.guild.ban = Mock()
+ self.ctx.guild.ban = AsyncMock()
await self.cog.apply_ban(self.ctx, self.target, "foo bar" * 3000)
- self.ctx.guild.ban.assert_called_once_with(
+ self.cog.apply_infraction.assert_awaited_once_with(
+ self.ctx, {"foo": "bar", "purge": ""}, self.target, ANY
+ )
+
+ action = self.cog.apply_infraction.call_args.args[-1]
+ await action()
+ self.ctx.guild.ban.assert_awaited_once_with(
self.target,
reason=textwrap.shorten("foo bar" * 3000, 512, placeholder="..."),
delete_message_days=0
)
- self.cog.apply_infraction.assert_awaited_once_with(
- self.ctx, {"foo": "bar", "purge": ""}, self.target, self.ctx.guild.ban.return_value
- )
@patch("bot.exts.moderation.infraction._utils.post_infraction")
async def test_apply_kick_reason_truncation(self, post_infraction_mock):
@@ -54,14 +57,17 @@ class TruncationTests(unittest.IsolatedAsyncioTestCase):
self.cog.apply_infraction = AsyncMock()
self.cog.mod_log.ignore = Mock()
- self.target.kick = Mock()
+ self.target.kick = AsyncMock()
await self.cog.apply_kick(self.ctx, self.target, "foo bar" * 3000)
- self.target.kick.assert_called_once_with(reason=textwrap.shorten("foo bar" * 3000, 512, placeholder="..."))
self.cog.apply_infraction.assert_awaited_once_with(
- self.ctx, {"foo": "bar"}, self.target, self.target.kick.return_value
+ self.ctx, {"foo": "bar"}, self.target, ANY
)
+ action = self.cog.apply_infraction.call_args.args[-1]
+ await action()
+ self.target.kick.assert_awaited_once_with(reason=textwrap.shorten("foo bar" * 3000, 512, placeholder="..."))
+
@patch("bot.exts.moderation.infraction.infractions.constants.Roles.voice_verified", new=123456)
class VoiceMuteTests(unittest.IsolatedAsyncioTestCase):
@@ -79,19 +85,25 @@ class VoiceMuteTests(unittest.IsolatedAsyncioTestCase):
"""Should call voice mute applying function without expiry."""
self.cog.apply_voice_mute = AsyncMock()
self.assertIsNone(await self.cog.voicemute(self.cog, self.ctx, self.user, reason="foobar"))
- self.cog.apply_voice_mute.assert_awaited_once_with(self.ctx, self.user, "foobar", expires_at=None)
+ self.cog.apply_voice_mute.assert_awaited_once_with(self.ctx, self.user, "foobar", duration_or_expiry=None)
async def test_temporary_voice_mute(self):
"""Should call voice mute applying function with expiry."""
self.cog.apply_voice_mute = AsyncMock()
self.assertIsNone(await self.cog.tempvoicemute(self.cog, self.ctx, self.user, "baz", reason="foobar"))
- self.cog.apply_voice_mute.assert_awaited_once_with(self.ctx, self.user, "foobar", expires_at="baz")
+ self.cog.apply_voice_mute.assert_awaited_once_with(self.ctx, self.user, "foobar", duration_or_expiry="baz")
async def test_voice_unmute(self):
"""Should call infraction pardoning function."""
self.cog.pardon_infraction = AsyncMock()
+ self.assertIsNone(await self.cog.unvoicemute(self.cog, self.ctx, self.user, pardon_reason="foobar"))
+ self.cog.pardon_infraction.assert_awaited_once_with(self.ctx, "voice_mute", self.user, "foobar")
+
+ async def test_voice_unmute_reasonless(self):
+ """Should call infraction pardoning function without a pardon reason."""
+ self.cog.pardon_infraction = AsyncMock()
self.assertIsNone(await self.cog.unvoicemute(self.cog, self.ctx, self.user))
- self.cog.pardon_infraction.assert_awaited_once_with(self.ctx, "voice_mute", self.user)
+ self.cog.pardon_infraction.assert_awaited_once_with(self.ctx, "voice_mute", self.user, None)
@patch("bot.exts.moderation.infraction.infractions._utils.post_infraction")
@patch("bot.exts.moderation.infraction.infractions._utils.get_active_infraction")
@@ -141,8 +153,8 @@ class VoiceMuteTests(unittest.IsolatedAsyncioTestCase):
async def action_tester(self, action, reason: str) -> None:
"""Helper method to test voice mute action."""
- self.assertTrue(inspect.iscoroutine(action))
- await action
+ self.assertTrue(inspect.iscoroutinefunction(action))
+ await action()
self.user.move_to.assert_called_once_with(None, reason=ANY)
self.user.remove_roles.assert_called_once_with(self.cog._voice_verified_role, reason=reason)
@@ -189,13 +201,14 @@ class VoiceMuteTests(unittest.IsolatedAsyncioTestCase):
user = MockUser()
await self.cog.voicemute(self.cog, self.ctx, user, reason=None)
- post_infraction_mock.assert_called_once_with(self.ctx, user, "voice_mute", None, active=True, expires_at=None)
+ post_infraction_mock.assert_called_once_with(self.ctx, user, "voice_mute", None, active=True,
+ duration_or_expiry=None)
apply_infraction_mock.assert_called_once_with(self.cog, self.ctx, infraction, user, ANY)
# Test action
action = self.cog.apply_infraction.call_args[0][-1]
- self.assertTrue(inspect.iscoroutine(action))
- await action
+ self.assertTrue(inspect.iscoroutinefunction(action))
+ await action()
async def test_voice_unmute_user_not_found(self):
"""Should include info to return dict when user was not found from guild."""
@@ -273,7 +286,7 @@ class CleanBanTests(unittest.IsolatedAsyncioTestCase):
self.user,
"FooBar",
purge_days=1,
- expires_at=None,
+ duration_or_expiry=None,
)
async def test_cleanban_doesnt_purge_messages_if_clean_cog_available(self):
@@ -285,7 +298,7 @@ class CleanBanTests(unittest.IsolatedAsyncioTestCase):
self.ctx,
self.user,
"FooBar",
- expires_at=None,
+ duration_or_expiry=None,
)
@patch("bot.exts.moderation.infraction.infractions.Age")
diff --git a/tests/bot/exts/moderation/infraction/test_utils.py b/tests/bot/exts/moderation/infraction/test_utils.py
index 5cf02033d..29dadf372 100644
--- a/tests/bot/exts/moderation/infraction/test_utils.py
+++ b/tests/bot/exts/moderation/infraction/test_utils.py
@@ -1,7 +1,7 @@
import unittest
from collections import namedtuple
from datetime import datetime
-from unittest.mock import AsyncMock, MagicMock, call, patch
+from unittest.mock import AsyncMock, MagicMock, patch
from botcore.site_api import ResponseCodeError
from discord import Embed, Forbidden, HTTPException, NotFound
@@ -309,8 +309,8 @@ class TestPostInfraction(unittest.IsolatedAsyncioTestCase):
async def test_normal_post_infraction(self):
"""Should return response from POST request if there are no errors."""
- now = datetime.now()
- payload = {
+ now = datetime.utcnow()
+ expected = {
"actor": self.ctx.author.id,
"hidden": True,
"reason": "Test reason",
@@ -318,14 +318,17 @@ class TestPostInfraction(unittest.IsolatedAsyncioTestCase):
"user": self.member.id,
"active": False,
"expires_at": now.isoformat(),
- "dm_sent": False
+ "dm_sent": False,
}
self.ctx.bot.api_client.post.return_value = "foo"
actual = await utils.post_infraction(self.ctx, self.member, "ban", "Test reason", now, True, False)
-
self.assertEqual(actual, "foo")
- self.ctx.bot.api_client.post.assert_awaited_once_with("bot/infractions", json=payload)
+ self.ctx.bot.api_client.post.assert_awaited_once()
+
+ # Since `last_applied` is based on current time, just check if expected is a subset of payload
+ payload: dict = self.ctx.bot.api_client.post.await_args_list[0].kwargs["json"]
+ self.assertEqual(payload, payload | expected)
async def test_unknown_error_post_infraction(self):
"""Should send an error message to chat when a non-400 error occurs."""
@@ -349,19 +352,25 @@ class TestPostInfraction(unittest.IsolatedAsyncioTestCase):
@patch("bot.exts.moderation.infraction._utils.post_user", return_value="bar")
async def test_first_fail_second_success_user_post_infraction(self, post_user_mock):
"""Should post the user if they don't exist, POST infraction again, and return the response if successful."""
- payload = {
+ expected = {
"actor": self.ctx.author.id,
"hidden": False,
"reason": "Test reason",
"type": "mute",
"user": self.user.id,
"active": True,
- "dm_sent": False
+ "dm_sent": False,
}
self.bot.api_client.post.side_effect = [ResponseCodeError(MagicMock(status=400), {"user": "foo"}), "foo"]
-
actual = await utils.post_infraction(self.ctx, self.user, "mute", "Test reason")
self.assertEqual(actual, "foo")
- self.bot.api_client.post.assert_has_awaits([call("bot/infractions", json=payload)] * 2)
+ await_args = self.bot.api_client.post.await_args_list
+ self.assertEqual(len(await_args), 2, "Expected 2 awaits")
+
+ # Since `last_applied` is based on current time, just check if expected is a subset of payload
+ for args in await_args:
+ payload: dict = args.kwargs["json"]
+ self.assertEqual(payload, payload | expected)
+
post_user_mock.assert_awaited_once_with(self.ctx, self.user)
diff --git a/tests/helpers.py b/tests/helpers.py
index 687e15b96..a4b919dcb 100644
--- a/tests/helpers.py
+++ b/tests/helpers.py
@@ -317,7 +317,7 @@ class MockBot(CustomMockMixin, unittest.mock.MagicMock):
guild_id=1,
intents=discord.Intents.all(),
)
- additional_spec_asyncs = ("wait_for", "redis_ready")
+ additional_spec_asyncs = ("wait_for",)
def __init__(self, **kwargs) -> None:
super().__init__(**kwargs)
diff --git a/tests/test_helpers.py b/tests/test_helpers.py
index f3040b305..b2686b1d0 100644
--- a/tests/test_helpers.py
+++ b/tests/test_helpers.py
@@ -14,7 +14,7 @@ class DiscordMocksTests(unittest.TestCase):
"""Test if the default initialization of MockRole results in the correct object."""
role = helpers.MockRole()
- # The `spec` argument makes sure `isistance` checks with `discord.Role` pass
+ # The `spec` argument makes sure `isinstance` checks with `discord.Role` pass
self.assertIsInstance(role, discord.Role)
self.assertEqual(role.name, "role")