From be9cb47eddb2c4920a7e0956a79ca555a7243bf7 Mon Sep 17 00:00:00 2001 From: ks129 <45097959+ks129@users.noreply.github.com> Date: Mon, 18 May 2020 11:15:05 +0300 Subject: EH Tests: Created test cases set + already handled error test Created test that make sure when error is already handled in local error handler, this don't await `ctx.send` to make sure that this don't move forward. --- tests/bot/cogs/test_error_handler.py | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) create mode 100644 tests/bot/cogs/test_error_handler.py (limited to 'tests') diff --git a/tests/bot/cogs/test_error_handler.py b/tests/bot/cogs/test_error_handler.py new file mode 100644 index 000000000..6aca03030 --- /dev/null +++ b/tests/bot/cogs/test_error_handler.py @@ -0,0 +1,22 @@ +import unittest + +from discord.ext.commands import errors + +from bot.cogs.error_handler import ErrorHandler +from tests.helpers import MockBot, MockContext + + +class ErrorHandlerTests(unittest.IsolatedAsyncioTestCase): + """Tests for error handler functionality.""" + + def setUp(self): + self.bot = MockBot() + self.ctx = MockContext(bot=self.bot) + self.cog = ErrorHandler(self.bot) + + async def test_error_handler_already_handled(self): + """Should not do anything when error is already handled by local error handler.""" + error = errors.CommandError() + error.handled = "foo" + await self.cog.on_command_error(self.ctx, error) + self.ctx.send.assert_not_awaited() -- cgit v1.2.3 From 8229d2191bf3c3dfd4eeca5188e6463d41c6c6ff Mon Sep 17 00:00:00 2001 From: ks129 <45097959+ks129@users.noreply.github.com> Date: Mon, 18 May 2020 12:58:57 +0300 Subject: EH Tests: Created test for `CommandNotFound` error when call isn't by EH --- tests/bot/cogs/test_error_handler.py | 49 ++++++++++++++++++++++++++++++++++++ 1 file changed, 49 insertions(+) (limited to 'tests') diff --git a/tests/bot/cogs/test_error_handler.py b/tests/bot/cogs/test_error_handler.py index 6aca03030..510c66b29 100644 --- a/tests/bot/cogs/test_error_handler.py +++ b/tests/bot/cogs/test_error_handler.py @@ -1,4 +1,5 @@ import unittest +from unittest.mock import AsyncMock, patch from discord.ext.commands import errors @@ -20,3 +21,51 @@ class ErrorHandlerTests(unittest.IsolatedAsyncioTestCase): error.handled = "foo" await self.cog.on_command_error(self.ctx, error) self.ctx.send.assert_not_awaited() + + async def test_error_handler_command_not_found_error_not_invoked_by_handler(self): + """Should try first (un)silence channel, when fail and channel is not verification channel try to get tag.""" + error = errors.CommandNotFound() + test_cases = ( + { + "try_silence_return": True, + "patch_verification_id": False, + "called_try_get_tag": False + }, + { + "try_silence_return": False, + "patch_verification_id": True, + "called_try_get_tag": False + }, + { + "try_silence_return": False, + "patch_verification_id": False, + "called_try_get_tag": True + } + ) + self.cog.try_silence = AsyncMock() + self.cog.try_get_tag = AsyncMock() + + for case in test_cases: + with self.subTest(try_silence_return=case["try_silence_return"], try_get_tag=case["called_try_get_tag"]): + self.ctx.reset_mock() + self.cog.try_silence.reset_mock(return_value=True) + self.cog.try_get_tag.reset_mock() + + self.cog.try_silence.return_value = case["try_silence_return"] + self.ctx.channel.id = 1234 + + if case["patch_verification_id"]: + with patch("bot.cogs.error_handler.Channels.verification", new=1234): + self.assertIsNone(await self.cog.on_command_error(self.ctx, error)) + else: + self.assertIsNone(await self.cog.on_command_error(self.ctx, error)) + if case["try_silence_return"]: + self.cog.try_get_tag.assert_not_awaited() + self.cog.try_silence.assert_awaited_once() + else: + self.cog.try_silence.assert_awaited_once() + if case["patch_verification_id"]: + self.cog.try_get_tag.assert_not_awaited() + else: + self.cog.try_get_tag.assert_awaited_once() + self.ctx.send.assert_not_awaited() -- cgit v1.2.3 From 28e83216c6c976064e3295911df428baad3419e9 Mon Sep 17 00:00:00 2001 From: ks129 <45097959+ks129@users.noreply.github.com> Date: Mon, 18 May 2020 13:03:23 +0300 Subject: EH Tests: Remove class member `cog` + other small changes - Added `assertIsNone` to `test_error_handler_already_handled`. - Removed `ErrorHandlerTests.cog`, moved it to each test recreation. --- tests/bot/cogs/test_error_handler.py | 29 +++++++++++++++-------------- 1 file changed, 15 insertions(+), 14 deletions(-) (limited to 'tests') diff --git a/tests/bot/cogs/test_error_handler.py b/tests/bot/cogs/test_error_handler.py index 510c66b29..3945bbb90 100644 --- a/tests/bot/cogs/test_error_handler.py +++ b/tests/bot/cogs/test_error_handler.py @@ -13,13 +13,13 @@ class ErrorHandlerTests(unittest.IsolatedAsyncioTestCase): def setUp(self): self.bot = MockBot() self.ctx = MockContext(bot=self.bot) - self.cog = ErrorHandler(self.bot) async def test_error_handler_already_handled(self): """Should not do anything when error is already handled by local error handler.""" + cog = ErrorHandler(self.bot) error = errors.CommandError() error.handled = "foo" - await self.cog.on_command_error(self.ctx, error) + self.assertIsNone(await cog.on_command_error(self.ctx, error)) self.ctx.send.assert_not_awaited() async def test_error_handler_command_not_found_error_not_invoked_by_handler(self): @@ -42,30 +42,31 @@ class ErrorHandlerTests(unittest.IsolatedAsyncioTestCase): "called_try_get_tag": True } ) - self.cog.try_silence = AsyncMock() - self.cog.try_get_tag = AsyncMock() + cog = ErrorHandler(self.bot) + cog.try_silence = AsyncMock() + cog.try_get_tag = AsyncMock() for case in test_cases: with self.subTest(try_silence_return=case["try_silence_return"], try_get_tag=case["called_try_get_tag"]): self.ctx.reset_mock() - self.cog.try_silence.reset_mock(return_value=True) - self.cog.try_get_tag.reset_mock() + cog.try_silence.reset_mock(return_value=True) + cog.try_get_tag.reset_mock() - self.cog.try_silence.return_value = case["try_silence_return"] + cog.try_silence.return_value = case["try_silence_return"] self.ctx.channel.id = 1234 if case["patch_verification_id"]: with patch("bot.cogs.error_handler.Channels.verification", new=1234): - self.assertIsNone(await self.cog.on_command_error(self.ctx, error)) + self.assertIsNone(await cog.on_command_error(self.ctx, error)) else: - self.assertIsNone(await self.cog.on_command_error(self.ctx, error)) + self.assertIsNone(await cog.on_command_error(self.ctx, error)) if case["try_silence_return"]: - self.cog.try_get_tag.assert_not_awaited() - self.cog.try_silence.assert_awaited_once() + cog.try_get_tag.assert_not_awaited() + cog.try_silence.assert_awaited_once() else: - self.cog.try_silence.assert_awaited_once() + cog.try_silence.assert_awaited_once() if case["patch_verification_id"]: - self.cog.try_get_tag.assert_not_awaited() + cog.try_get_tag.assert_not_awaited() else: - self.cog.try_get_tag.assert_awaited_once() + cog.try_get_tag.assert_awaited_once() self.ctx.send.assert_not_awaited() -- cgit v1.2.3 From 28e962bcaa47efca836ad20df5721266336d028e Mon Sep 17 00:00:00 2001 From: ks129 <45097959+ks129@users.noreply.github.com> Date: Mon, 18 May 2020 14:29:07 +0300 Subject: Test Helpers: Added new attribute to `MockContext` Added `invoked_from_error_handler` attribute that is `False` default. --- tests/helpers.py | 2 ++ 1 file changed, 2 insertions(+) (limited to 'tests') diff --git a/tests/helpers.py b/tests/helpers.py index 2b79a6c2a..0e1581e23 100644 --- a/tests/helpers.py +++ b/tests/helpers.py @@ -368,6 +368,7 @@ message_instance = discord.Message(state=state, channel=channel, data=message_da # Create a Context instance to get a realistic MagicMock of `discord.ext.commands.Context` context_instance = Context(message=unittest.mock.MagicMock(), prefix=unittest.mock.MagicMock()) +context_instance.invoked_from_error_handler = None class MockContext(CustomMockMixin, unittest.mock.MagicMock): @@ -385,6 +386,7 @@ class MockContext(CustomMockMixin, unittest.mock.MagicMock): self.guild = kwargs.get('guild', MockGuild()) self.author = kwargs.get('author', MockMember()) self.channel = kwargs.get('channel', MockTextChannel()) + self.invoked_from_error_handler = kwargs.get('invoked_from_error_handler', False) attachment_instance = discord.Attachment(data=unittest.mock.MagicMock(id=1), state=unittest.mock.MagicMock()) -- cgit v1.2.3 From 68ba2920c86a6705aebbb7ea1249123cec699827 Mon Sep 17 00:00:00 2001 From: ks129 <45097959+ks129@users.noreply.github.com> Date: Mon, 18 May 2020 14:31:18 +0300 Subject: EH Tests: Added another test for `CommandNotFound` error handling Added test for case when `Context.invoked_from_error_handler` is `True` --- tests/bot/cogs/test_error_handler.py | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) (limited to 'tests') diff --git a/tests/bot/cogs/test_error_handler.py b/tests/bot/cogs/test_error_handler.py index 3945bbb90..16b4e9742 100644 --- a/tests/bot/cogs/test_error_handler.py +++ b/tests/bot/cogs/test_error_handler.py @@ -16,6 +16,7 @@ class ErrorHandlerTests(unittest.IsolatedAsyncioTestCase): async def test_error_handler_already_handled(self): """Should not do anything when error is already handled by local error handler.""" + self.ctx.reset_mock() cog = ErrorHandler(self.bot) error = errors.CommandError() error.handled = "foo" @@ -70,3 +71,19 @@ class ErrorHandlerTests(unittest.IsolatedAsyncioTestCase): else: cog.try_get_tag.assert_awaited_once() self.ctx.send.assert_not_awaited() + + async def test_error_handler_command_not_found_error_invoked_by_handler(self): + """Should do nothing when error is `CommandNotFound` and have attribute `invoked_from_error_handler`.""" + ctx = MockContext(bot=self.bot, invoked_from_error_handler=True) + + cog = ErrorHandler(self.bot) + cog.try_silence = AsyncMock() + cog.try_get_tag = AsyncMock() + + error = errors.CommandNotFound() + + self.assertIsNone(await cog.on_command_error(ctx, error)) + + cog.try_silence.assert_not_awaited() + cog.try_get_tag.assert_not_awaited() + self.ctx.send.assert_not_awaited() -- cgit v1.2.3 From 8eacf9c3070443aa213f50484cf2d7510f768d08 Mon Sep 17 00:00:00 2001 From: ks129 <45097959+ks129@users.noreply.github.com> Date: Mon, 18 May 2020 15:02:46 +0300 Subject: EH Tests: Added test for `UserInputError` handling on handler --- tests/bot/cogs/test_error_handler.py | 9 +++++++++ 1 file changed, 9 insertions(+) (limited to 'tests') diff --git a/tests/bot/cogs/test_error_handler.py b/tests/bot/cogs/test_error_handler.py index 16b4e9742..a974b421a 100644 --- a/tests/bot/cogs/test_error_handler.py +++ b/tests/bot/cogs/test_error_handler.py @@ -87,3 +87,12 @@ class ErrorHandlerTests(unittest.IsolatedAsyncioTestCase): cog.try_silence.assert_not_awaited() cog.try_get_tag.assert_not_awaited() self.ctx.send.assert_not_awaited() + + async def test_error_handler_user_input_error(self): + """Should await `ErrorHandler.handle_user_input_error` when error is `UserInputError`.""" + self.ctx.reset_mock() + cog = ErrorHandler(self.bot) + cog.handle_user_input_error = AsyncMock() + error = errors.UserInputError() + self.assertIsNone(await cog.on_command_error(self.ctx, error)) + cog.handle_user_input_error.assert_awaited_once_with(self.ctx, error) -- cgit v1.2.3 From c050dee853a2fb7432b263cda30becf760310377 Mon Sep 17 00:00:00 2001 From: ks129 <45097959+ks129@users.noreply.github.com> Date: Mon, 18 May 2020 15:51:48 +0300 Subject: EH Tests: Added test for `CheckFailure` handling on handler --- tests/bot/cogs/test_error_handler.py | 9 +++++++++ 1 file changed, 9 insertions(+) (limited to 'tests') diff --git a/tests/bot/cogs/test_error_handler.py b/tests/bot/cogs/test_error_handler.py index a974b421a..1cae8a517 100644 --- a/tests/bot/cogs/test_error_handler.py +++ b/tests/bot/cogs/test_error_handler.py @@ -96,3 +96,12 @@ class ErrorHandlerTests(unittest.IsolatedAsyncioTestCase): error = errors.UserInputError() self.assertIsNone(await cog.on_command_error(self.ctx, error)) cog.handle_user_input_error.assert_awaited_once_with(self.ctx, error) + + async def test_error_handler_check_failure(self): + """Should await `ErrorHandler.handle_check_failure` when error is `CheckFailure`.""" + self.ctx.reset_mock() + cog = ErrorHandler(self.bot) + cog.handle_check_failure = AsyncMock() + error = errors.CheckFailure() + self.assertIsNone(await cog.on_command_error(self.ctx, error)) + cog.handle_check_failure.assert_awaited_once_with(self.ctx, error) -- cgit v1.2.3 From ae9766a2cc01ddcc15b4d64568e2cfc67673f138 Mon Sep 17 00:00:00 2001 From: ks129 <45097959+ks129@users.noreply.github.com> Date: Mon, 18 May 2020 15:57:01 +0300 Subject: EH Tests: Added test for `CommandOnCooldown` handling on handler --- tests/bot/cogs/test_error_handler.py | 8 ++++++++ 1 file changed, 8 insertions(+) (limited to 'tests') diff --git a/tests/bot/cogs/test_error_handler.py b/tests/bot/cogs/test_error_handler.py index 1cae8a517..2acca7450 100644 --- a/tests/bot/cogs/test_error_handler.py +++ b/tests/bot/cogs/test_error_handler.py @@ -105,3 +105,11 @@ class ErrorHandlerTests(unittest.IsolatedAsyncioTestCase): error = errors.CheckFailure() self.assertIsNone(await cog.on_command_error(self.ctx, error)) cog.handle_check_failure.assert_awaited_once_with(self.ctx, error) + + async def test_error_handler_command_on_cooldown(self): + """Should send error with `ctx.send` when error is `CommandOnCooldown`.""" + self.ctx.reset_mock() + cog = ErrorHandler(self.bot) + error = errors.CommandOnCooldown(10, 9) + self.assertIsNone(await cog.on_command_error(self.ctx, error)) + self.ctx.send.assert_awaited_once_with(error) -- cgit v1.2.3 From 6d9698fd3b6fd0b6a02898546c665ef7f302127a Mon Sep 17 00:00:00 2001 From: ks129 <45097959+ks129@users.noreply.github.com> Date: Mon, 18 May 2020 16:08:37 +0300 Subject: EH Tests: Added test for `CommandInvokeError` handling on handler --- tests/bot/cogs/test_error_handler.py | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) (limited to 'tests') diff --git a/tests/bot/cogs/test_error_handler.py b/tests/bot/cogs/test_error_handler.py index 2acca7450..09543b56d 100644 --- a/tests/bot/cogs/test_error_handler.py +++ b/tests/bot/cogs/test_error_handler.py @@ -3,6 +3,7 @@ from unittest.mock import AsyncMock, patch from discord.ext.commands import errors +from bot.api import ResponseCodeError from bot.cogs.error_handler import ErrorHandler from tests.helpers import MockBot, MockContext @@ -113,3 +114,24 @@ class ErrorHandlerTests(unittest.IsolatedAsyncioTestCase): error = errors.CommandOnCooldown(10, 9) self.assertIsNone(await cog.on_command_error(self.ctx, error)) self.ctx.send.assert_awaited_once_with(error) + + async def test_error_handler_command_invoke_error(self): + """Should call `handle_api_error` or `handle_unexpected_error` depending on original error.""" + cog = ErrorHandler(self.bot) + cog.handle_api_error = AsyncMock() + cog.handle_unexpected_error = AsyncMock() + test_cases = ( + { + "args": (self.ctx, errors.CommandInvokeError(ResponseCodeError(AsyncMock()))), + "expect_mock_call": cog.handle_api_error + }, + { + "args": (self.ctx, errors.CommandInvokeError(TypeError)), + "expect_mock_call": cog.handle_unexpected_error + } + ) + + for case in test_cases: + with self.subTest(args=case["args"], expect_mock_call=case["expect_mock_call"]): + self.assertIsNone(await cog.on_command_error(*case["args"])) + case["expect_mock_call"].assert_awaited_once_with(self.ctx, case["args"][1].original) -- cgit v1.2.3 From cf89c5be49bfe57934d2fea9408a44f78c4db3b6 Mon Sep 17 00:00:00 2001 From: ks129 <45097959+ks129@users.noreply.github.com> Date: Mon, 18 May 2020 16:18:40 +0300 Subject: EH Tests: Added test for 3 errors handling on handler These 3 errors is: - `ConversionError` - `MaxConcurrencyReached` - `ExtensionError` --- tests/bot/cogs/test_error_handler.py | 18 +++++++++++++++++- 1 file changed, 17 insertions(+), 1 deletion(-) (limited to 'tests') diff --git a/tests/bot/cogs/test_error_handler.py b/tests/bot/cogs/test_error_handler.py index 09543b56d..bc67e9d7c 100644 --- a/tests/bot/cogs/test_error_handler.py +++ b/tests/bot/cogs/test_error_handler.py @@ -1,5 +1,5 @@ import unittest -from unittest.mock import AsyncMock, patch +from unittest.mock import AsyncMock, MagicMock, patch from discord.ext.commands import errors @@ -135,3 +135,19 @@ class ErrorHandlerTests(unittest.IsolatedAsyncioTestCase): with self.subTest(args=case["args"], expect_mock_call=case["expect_mock_call"]): self.assertIsNone(await cog.on_command_error(*case["args"])) case["expect_mock_call"].assert_awaited_once_with(self.ctx, case["args"][1].original) + + async def test_error_handler_three_other_errors(self): + """Should call `handle_unexpected_error` when `ConversionError`, `MaxConcurrencyReached` or `ExtensionError`.""" + cog = ErrorHandler(self.bot) + cog.handle_unexpected_error = AsyncMock() + errs = ( + errors.ConversionError(MagicMock(), MagicMock()), + errors.MaxConcurrencyReached(1, MagicMock()), + errors.ExtensionError(name="foo") + ) + + for err in errs: + with self.subTest(error=err): + cog.handle_unexpected_error.reset_mock() + self.assertIsNone(await cog.on_command_error(self.ctx, err)) + cog.handle_unexpected_error.assert_awaited_once_with(self.ctx, err) -- cgit v1.2.3 From 800909176c3799b12d8bbb41fba4be336b199933 Mon Sep 17 00:00:00 2001 From: ks129 <45097959+ks129@users.noreply.github.com> Date: Mon, 18 May 2020 16:25:59 +0300 Subject: EH Tests: Created test for all other errors --- tests/bot/cogs/test_error_handler.py | 8 ++++++++ 1 file changed, 8 insertions(+) (limited to 'tests') diff --git a/tests/bot/cogs/test_error_handler.py b/tests/bot/cogs/test_error_handler.py index bc67e9d7c..d0a5ba21b 100644 --- a/tests/bot/cogs/test_error_handler.py +++ b/tests/bot/cogs/test_error_handler.py @@ -151,3 +151,11 @@ class ErrorHandlerTests(unittest.IsolatedAsyncioTestCase): cog.handle_unexpected_error.reset_mock() self.assertIsNone(await cog.on_command_error(self.ctx, err)) cog.handle_unexpected_error.assert_awaited_once_with(self.ctx, err) + + @patch("bot.cogs.error_handler.log") + async def test_error_handler_other_errors(self, log_mock): + """Should `log.debug` other errors.""" + cog = ErrorHandler(self.bot) + error = errors.DisabledCommand() # Use this just as a other error + self.assertIsNone(await cog.on_command_error(self.ctx, error)) + log_mock.debug.assert_called_once() -- cgit v1.2.3 From faf9737548c82cff5369ec145530f6fc86f8c0cc Mon Sep 17 00:00:00 2001 From: ks129 <45097959+ks129@users.noreply.github.com> Date: Mon, 18 May 2020 19:17:25 +0300 Subject: EH Tests: Created first test for `try_silence` --- tests/bot/cogs/test_error_handler.py | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) (limited to 'tests') diff --git a/tests/bot/cogs/test_error_handler.py b/tests/bot/cogs/test_error_handler.py index d0a5ba21b..f409cf6bc 100644 --- a/tests/bot/cogs/test_error_handler.py +++ b/tests/bot/cogs/test_error_handler.py @@ -5,6 +5,7 @@ from discord.ext.commands import errors from bot.api import ResponseCodeError from bot.cogs.error_handler import ErrorHandler +from bot.cogs.moderation.silence import Silence from tests.helpers import MockBot, MockContext @@ -159,3 +160,20 @@ class ErrorHandlerTests(unittest.IsolatedAsyncioTestCase): error = errors.DisabledCommand() # Use this just as a other error self.assertIsNone(await cog.on_command_error(self.ctx, error)) log_mock.debug.assert_called_once() + + +class TrySilenceTests(unittest.IsolatedAsyncioTestCase): + """Test for helper functions that handle `CommandNotFound` error.""" + + def setUp(self): + self.bot = MockBot() + + async def test_try_silence_context_invoked_from_error_handler(self): + """Should set `Context.invoked_from_error_handler` to `True`.""" + cog = ErrorHandler(self.bot) + ctx = MockContext(bot=self.bot) + ctx.invoked_with = "foo" + self.bot.get_command.return_value = Silence(self.bot).silence + await cog.try_silence(ctx) + self.assertTrue(hasattr(ctx, "invoked_from_error_handler")) + self.assertTrue(ctx.invoked_from_error_handler) -- cgit v1.2.3 From c1ac5c00d211eda081aec948fe74a6a083854e49 Mon Sep 17 00:00:00 2001 From: ks129 <45097959+ks129@users.noreply.github.com> Date: Mon, 18 May 2020 19:20:55 +0300 Subject: EH Tests: Created `try_silence` test for `get_command` --- tests/bot/cogs/test_error_handler.py | 9 +++++++++ 1 file changed, 9 insertions(+) (limited to 'tests') diff --git a/tests/bot/cogs/test_error_handler.py b/tests/bot/cogs/test_error_handler.py index f409cf6bc..90f4c64a6 100644 --- a/tests/bot/cogs/test_error_handler.py +++ b/tests/bot/cogs/test_error_handler.py @@ -177,3 +177,12 @@ class TrySilenceTests(unittest.IsolatedAsyncioTestCase): await cog.try_silence(ctx) self.assertTrue(hasattr(ctx, "invoked_from_error_handler")) self.assertTrue(ctx.invoked_from_error_handler) + + async def test_try_silence_get_command(self): + """Should call `get_command` with `silence`.""" + cog = ErrorHandler(self.bot) + ctx = MockContext(bot=self.bot) + ctx.invoked_with = "foo" + self.bot.get_command.return_value = Silence(self.bot).silence + await cog.try_silence(ctx) + self.bot.get_command.assert_called_once_with("silence") -- cgit v1.2.3 From 187998fe0436f60b831a4bf5af44c37e37d1ea34 Mon Sep 17 00:00:00 2001 From: ks129 <45097959+ks129@users.noreply.github.com> Date: Mon, 18 May 2020 19:24:19 +0300 Subject: EH Tests: Created `try_silence` test to check no permission response --- tests/bot/cogs/test_error_handler.py | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) (limited to 'tests') diff --git a/tests/bot/cogs/test_error_handler.py b/tests/bot/cogs/test_error_handler.py index 90f4c64a6..941b57ecb 100644 --- a/tests/bot/cogs/test_error_handler.py +++ b/tests/bot/cogs/test_error_handler.py @@ -167,13 +167,13 @@ class TrySilenceTests(unittest.IsolatedAsyncioTestCase): def setUp(self): self.bot = MockBot() + self.bot.get_command.return_value = Silence(self.bot).silence async def test_try_silence_context_invoked_from_error_handler(self): """Should set `Context.invoked_from_error_handler` to `True`.""" cog = ErrorHandler(self.bot) ctx = MockContext(bot=self.bot) ctx.invoked_with = "foo" - self.bot.get_command.return_value = Silence(self.bot).silence await cog.try_silence(ctx) self.assertTrue(hasattr(ctx, "invoked_from_error_handler")) self.assertTrue(ctx.invoked_from_error_handler) @@ -183,6 +183,13 @@ class TrySilenceTests(unittest.IsolatedAsyncioTestCase): cog = ErrorHandler(self.bot) ctx = MockContext(bot=self.bot) ctx.invoked_with = "foo" - self.bot.get_command.return_value = Silence(self.bot).silence await cog.try_silence(ctx) self.bot.get_command.assert_called_once_with("silence") + + async def test_try_silence_no_permissions_to_run(self): + """Should return `False` because missing permissions.""" + cog = ErrorHandler(self.bot) + ctx = MockContext(bot=self.bot) + ctx.invoked_with = "foo" + self.bot.get_command.return_value.can_run = AsyncMock(return_value=False) + self.assertFalse(await cog.try_silence(ctx)) -- cgit v1.2.3 From ec3b4eefbf3f1e67a0ade32522667fcc397539c5 Mon Sep 17 00:00:00 2001 From: ks129 <45097959+ks129@users.noreply.github.com> Date: Mon, 18 May 2020 19:46:15 +0300 Subject: EH Tests: Created `try_silence` test to check no permission with except --- tests/bot/cogs/test_error_handler.py | 8 ++++++++ 1 file changed, 8 insertions(+) (limited to 'tests') diff --git a/tests/bot/cogs/test_error_handler.py b/tests/bot/cogs/test_error_handler.py index 941b57ecb..8c51467e5 100644 --- a/tests/bot/cogs/test_error_handler.py +++ b/tests/bot/cogs/test_error_handler.py @@ -193,3 +193,11 @@ class TrySilenceTests(unittest.IsolatedAsyncioTestCase): ctx.invoked_with = "foo" self.bot.get_command.return_value.can_run = AsyncMock(return_value=False) self.assertFalse(await cog.try_silence(ctx)) + + async def test_try_silence_no_permissions_to_run_command_error(self): + """Should return `False` because `CommandError` raised (no permissions).""" + cog = ErrorHandler(self.bot) + ctx = MockContext(bot=self.bot) + ctx.invoked_with = "foo" + self.bot.get_command.return_value.can_run = AsyncMock(side_effect=errors.CommandError()) + self.assertFalse(await cog.try_silence(ctx)) -- cgit v1.2.3 From f324b0166516687100ad1362807d59be9918b739 Mon Sep 17 00:00:00 2001 From: ks129 <45097959+ks129@users.noreply.github.com> Date: Mon, 18 May 2020 19:54:47 +0300 Subject: EH Tests: Created `try_silence` test to test silence command calling --- tests/bot/cogs/test_error_handler.py | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) (limited to 'tests') diff --git a/tests/bot/cogs/test_error_handler.py b/tests/bot/cogs/test_error_handler.py index 8c51467e5..30326d445 100644 --- a/tests/bot/cogs/test_error_handler.py +++ b/tests/bot/cogs/test_error_handler.py @@ -201,3 +201,20 @@ class TrySilenceTests(unittest.IsolatedAsyncioTestCase): ctx.invoked_with = "foo" self.bot.get_command.return_value.can_run = AsyncMock(side_effect=errors.CommandError()) self.assertFalse(await cog.try_silence(ctx)) + + async def test_try_silence_silencing(self): + """Should run silence command with correct arguments.""" + cog = ErrorHandler(self.bot) + ctx = MockContext(bot=self.bot) + self.bot.get_command.return_value.can_run = AsyncMock(return_value=True) + test_cases = ("shh", "shhh", "shhhhhh", "shhhhhhhhhhhhhhhhhhh") + + for case in test_cases: + with self.subTest(message=case): + ctx.reset_mock() + ctx.invoked_with = case + self.assertTrue(await cog.try_silence(ctx)) + ctx.invoke.assert_awaited_once_with( + self.bot.get_command.return_value, + duration=min(case.count("h")*2, 15) + ) -- cgit v1.2.3 From 2c488838dec67daa40e11249c9e578c1450ce594 Mon Sep 17 00:00:00 2001 From: ks129 <45097959+ks129@users.noreply.github.com> Date: Mon, 18 May 2020 20:05:19 +0300 Subject: EH Tests: Created `try_silence` test to test unsilence command calling --- tests/bot/cogs/test_error_handler.py | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) (limited to 'tests') diff --git a/tests/bot/cogs/test_error_handler.py b/tests/bot/cogs/test_error_handler.py index 30326d445..610d3ace5 100644 --- a/tests/bot/cogs/test_error_handler.py +++ b/tests/bot/cogs/test_error_handler.py @@ -218,3 +218,20 @@ class TrySilenceTests(unittest.IsolatedAsyncioTestCase): self.bot.get_command.return_value, duration=min(case.count("h")*2, 15) ) + + async def test_try_silence_unsilence(self): + """Should call unsilence command.""" + bot = MockBot() + silence = Silence(bot) + silence.silence.can_run = AsyncMock(return_value=True) + cog = ErrorHandler(bot) + ctx = MockContext(bot=bot) + test_cases = ("unshh", "unshhhhh", "unshhhhhhhhh") + + for case in test_cases: + with self.subTest(message=case): + bot.get_command.side_effect = (silence.silence, silence.unsilence) + ctx.reset_mock() + ctx.invoked_with = case + self.assertTrue(await cog.try_silence(ctx)) + ctx.invoke.assert_awaited_once_with(silence.unsilence) -- cgit v1.2.3 From 555857c07829b537e048ae030e6b864576d4ef8a Mon Sep 17 00:00:00 2001 From: ks129 <45097959+ks129@users.noreply.github.com> Date: Mon, 18 May 2020 20:07:16 +0300 Subject: EH Tests: Added test for `try_silence` no match message --- tests/bot/cogs/test_error_handler.py | 6 ++++++ 1 file changed, 6 insertions(+) (limited to 'tests') diff --git a/tests/bot/cogs/test_error_handler.py b/tests/bot/cogs/test_error_handler.py index 610d3ace5..8be562473 100644 --- a/tests/bot/cogs/test_error_handler.py +++ b/tests/bot/cogs/test_error_handler.py @@ -235,3 +235,9 @@ class TrySilenceTests(unittest.IsolatedAsyncioTestCase): ctx.invoked_with = case self.assertTrue(await cog.try_silence(ctx)) ctx.invoke.assert_awaited_once_with(silence.unsilence) + + async def test_try_silence_no_match(self): + cog = ErrorHandler(self.bot) + ctx = MockContext(bot=self.bot) + ctx.invoked_with = "foo" + self.assertFalse(await cog.try_silence(ctx)) -- cgit v1.2.3 From 048916fbf6ecf272c89e325055ff5d755276d75b Mon Sep 17 00:00:00 2001 From: ks129 <45097959+ks129@users.noreply.github.com> Date: Mon, 18 May 2020 20:12:57 +0300 Subject: EH Tests: Cleanup `try_silence` tests --- tests/bot/cogs/test_error_handler.py | 66 +++++++++++++++--------------------- 1 file changed, 27 insertions(+), 39 deletions(-) (limited to 'tests') diff --git a/tests/bot/cogs/test_error_handler.py b/tests/bot/cogs/test_error_handler.py index 8be562473..bfb1cfe61 100644 --- a/tests/bot/cogs/test_error_handler.py +++ b/tests/bot/cogs/test_error_handler.py @@ -167,77 +167,65 @@ class TrySilenceTests(unittest.IsolatedAsyncioTestCase): def setUp(self): self.bot = MockBot() - self.bot.get_command.return_value = Silence(self.bot).silence + self.silence = Silence(self.bot) + self.bot.get_command.return_value = self.silence.silence + self.ctx = MockContext(bot=self.bot) + self.cog = ErrorHandler(self.bot) async def test_try_silence_context_invoked_from_error_handler(self): """Should set `Context.invoked_from_error_handler` to `True`.""" - cog = ErrorHandler(self.bot) - ctx = MockContext(bot=self.bot) - ctx.invoked_with = "foo" - await cog.try_silence(ctx) - self.assertTrue(hasattr(ctx, "invoked_from_error_handler")) - self.assertTrue(ctx.invoked_from_error_handler) + self.ctx.invoked_with = "foo" + await self.cog.try_silence(self.ctx) + self.assertTrue(hasattr(self.ctx, "invoked_from_error_handler")) + self.assertTrue(self.ctx.invoked_from_error_handler) async def test_try_silence_get_command(self): """Should call `get_command` with `silence`.""" - cog = ErrorHandler(self.bot) - ctx = MockContext(bot=self.bot) - ctx.invoked_with = "foo" - await cog.try_silence(ctx) + self.ctx.invoked_with = "foo" + await self.cog.try_silence(self.ctx) self.bot.get_command.assert_called_once_with("silence") async def test_try_silence_no_permissions_to_run(self): """Should return `False` because missing permissions.""" - cog = ErrorHandler(self.bot) - ctx = MockContext(bot=self.bot) - ctx.invoked_with = "foo" + self.ctx.invoked_with = "foo" self.bot.get_command.return_value.can_run = AsyncMock(return_value=False) - self.assertFalse(await cog.try_silence(ctx)) + self.assertFalse(await self.cog.try_silence(self.ctx)) async def test_try_silence_no_permissions_to_run_command_error(self): """Should return `False` because `CommandError` raised (no permissions).""" - cog = ErrorHandler(self.bot) - ctx = MockContext(bot=self.bot) - ctx.invoked_with = "foo" + self.ctx.invoked_with = "foo" self.bot.get_command.return_value.can_run = AsyncMock(side_effect=errors.CommandError()) - self.assertFalse(await cog.try_silence(ctx)) + self.assertFalse(await self.cog.try_silence(self.ctx)) async def test_try_silence_silencing(self): """Should run silence command with correct arguments.""" - cog = ErrorHandler(self.bot) - ctx = MockContext(bot=self.bot) self.bot.get_command.return_value.can_run = AsyncMock(return_value=True) test_cases = ("shh", "shhh", "shhhhhh", "shhhhhhhhhhhhhhhhhhh") for case in test_cases: with self.subTest(message=case): - ctx.reset_mock() - ctx.invoked_with = case - self.assertTrue(await cog.try_silence(ctx)) - ctx.invoke.assert_awaited_once_with( + self.ctx.reset_mock() + self.ctx.invoked_with = case + self.assertTrue(await self.cog.try_silence(self.ctx)) + self.ctx.invoke.assert_awaited_once_with( self.bot.get_command.return_value, duration=min(case.count("h")*2, 15) ) async def test_try_silence_unsilence(self): """Should call unsilence command.""" - bot = MockBot() - silence = Silence(bot) - silence.silence.can_run = AsyncMock(return_value=True) - cog = ErrorHandler(bot) - ctx = MockContext(bot=bot) + self.silence.silence.can_run = AsyncMock(return_value=True) test_cases = ("unshh", "unshhhhh", "unshhhhhhhhh") for case in test_cases: with self.subTest(message=case): - bot.get_command.side_effect = (silence.silence, silence.unsilence) - ctx.reset_mock() - ctx.invoked_with = case - self.assertTrue(await cog.try_silence(ctx)) - ctx.invoke.assert_awaited_once_with(silence.unsilence) + self.bot.get_command.side_effect = (self.silence.silence, self.silence.unsilence) + self.ctx.reset_mock() + self.ctx.invoked_with = case + self.assertTrue(await self.cog.try_silence(self.ctx)) + self.ctx.invoke.assert_awaited_once_with(self.silence.unsilence) async def test_try_silence_no_match(self): - cog = ErrorHandler(self.bot) - ctx = MockContext(bot=self.bot) - ctx.invoked_with = "foo" - self.assertFalse(await cog.try_silence(ctx)) + """Should return `False` when message don't match.""" + self.ctx.invoked_with = "foo" + self.assertFalse(await self.cog.try_silence(self.ctx)) -- cgit v1.2.3 From 33231d5881063c720ab54b295d36030b4b304002 Mon Sep 17 00:00:00 2001 From: ks129 <45097959+ks129@users.noreply.github.com> Date: Tue, 19 May 2020 08:18:55 +0300 Subject: EH Tests: Added tests for `get_help_command`in `OtherErrorHandlerTests` --- tests/bot/cogs/test_error_handler.py | 32 ++++++++++++++++++++++++++++++++ 1 file changed, 32 insertions(+) (limited to 'tests') diff --git a/tests/bot/cogs/test_error_handler.py b/tests/bot/cogs/test_error_handler.py index bfb1cfe61..615c0e455 100644 --- a/tests/bot/cogs/test_error_handler.py +++ b/tests/bot/cogs/test_error_handler.py @@ -229,3 +229,35 @@ class TrySilenceTests(unittest.IsolatedAsyncioTestCase): """Should return `False` when message don't match.""" self.ctx.invoked_with = "foo" self.assertFalse(await self.cog.try_silence(self.ctx)) + + +class OtherErrorHandlerTests(unittest.IsolatedAsyncioTestCase): + """Other `ErrorHandler` tests.""" + + def setUp(self): + self.bot = MockBot() + self.ctx = MockContext() + + async def test_get_help_command_command_specified(self): + """Should return coroutine of help command of specified command.""" + self.ctx.command = "foo" + result = ErrorHandler.get_help_command(self.ctx) + expected = self.ctx.send_help("foo") + self.assertEqual(result.__qualname__, expected.__qualname__) + self.assertEqual(result.cr_frame.f_locals, expected.cr_frame.f_locals) + + # Await coroutines to avoid warnings + await result + await expected + + async def test_get_help_command_no_command_specified(self): + """Should return coroutine of help command.""" + self.ctx.command = None + result = ErrorHandler.get_help_command(self.ctx) + expected = self.ctx.send_help() + self.assertEqual(result.__qualname__, expected.__qualname__) + self.assertEqual(result.cr_frame.f_locals, expected.cr_frame.f_locals) + + # Await coroutines to avoid warnings + await result + await expected -- cgit v1.2.3 From eb9909f90706803694a37ae30336c3d6a4b475ab Mon Sep 17 00:00:00 2001 From: ks129 <45097959+ks129@users.noreply.github.com> Date: Tue, 19 May 2020 08:27:49 +0300 Subject: EH Tests: Added test for `try_get_tag` `get_command` calling --- tests/bot/cogs/test_error_handler.py | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) (limited to 'tests') diff --git a/tests/bot/cogs/test_error_handler.py b/tests/bot/cogs/test_error_handler.py index 615c0e455..b92a67fbe 100644 --- a/tests/bot/cogs/test_error_handler.py +++ b/tests/bot/cogs/test_error_handler.py @@ -6,6 +6,7 @@ from discord.ext.commands import errors from bot.api import ResponseCodeError from bot.cogs.error_handler import ErrorHandler from bot.cogs.moderation.silence import Silence +from bot.cogs.tags import Tags from tests.helpers import MockBot, MockContext @@ -231,6 +232,24 @@ class TrySilenceTests(unittest.IsolatedAsyncioTestCase): self.assertFalse(await self.cog.try_silence(self.ctx)) +class TryGetTagTests(unittest.IsolatedAsyncioTestCase): + """Tests for `try_get_tag` function.""" + + def setUp(self): + self.bot = MockBot() + self.ctx = MockContext() + self.tag = Tags(self.bot) + self.cog = ErrorHandler(self.bot) + self.bot.get_command.return_value = self.tag.get_command + + async def test_try_get_tag_get_command(self): + """Should call `Bot.get_command` with `tags get` argument.""" + self.bot.get_command.reset_mock() + self.ctx.invoked_with = "my_some_not_existing_tag" + await self.cog.try_get_tag(self.ctx) + self.bot.get_command.assert_called_once_with("tags get") + + class OtherErrorHandlerTests(unittest.IsolatedAsyncioTestCase): """Other `ErrorHandler` tests.""" -- cgit v1.2.3 From 1a796c472273a0e1d98ae52a13550791592f856c Mon Sep 17 00:00:00 2001 From: ks129 <45097959+ks129@users.noreply.github.com> Date: Tue, 19 May 2020 08:30:25 +0300 Subject: EH Tests: Added test for `try_get_tag` `invoked_from_error_handler` --- tests/bot/cogs/test_error_handler.py | 7 +++++++ 1 file changed, 7 insertions(+) (limited to 'tests') diff --git a/tests/bot/cogs/test_error_handler.py b/tests/bot/cogs/test_error_handler.py index b92a67fbe..35c223fcc 100644 --- a/tests/bot/cogs/test_error_handler.py +++ b/tests/bot/cogs/test_error_handler.py @@ -249,6 +249,13 @@ class TryGetTagTests(unittest.IsolatedAsyncioTestCase): await self.cog.try_get_tag(self.ctx) self.bot.get_command.assert_called_once_with("tags get") + async def test_try_get_tag_invoked_from_error_handler(self): + """`self.ctx` should have `invoked_from_error_handler` `True`.""" + self.ctx.invoked_from_error_handler = False + self.ctx.invoked_with = "my_some_not_existing_tag" + await self.cog.try_get_tag(self.ctx) + self.assertTrue(self.ctx.invoked_from_error_handler) + class OtherErrorHandlerTests(unittest.IsolatedAsyncioTestCase): """Other `ErrorHandler` tests.""" -- cgit v1.2.3 From 0ffded4eaa2427a04f43aa3bb6088c3ac1e91f0e Mon Sep 17 00:00:00 2001 From: ks129 <45097959+ks129@users.noreply.github.com> Date: Tue, 19 May 2020 08:35:15 +0300 Subject: EH Tests: Added test for `try_get_tag` checks fail --- tests/bot/cogs/test_error_handler.py | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) (limited to 'tests') diff --git a/tests/bot/cogs/test_error_handler.py b/tests/bot/cogs/test_error_handler.py index 35c223fcc..ba05076dd 100644 --- a/tests/bot/cogs/test_error_handler.py +++ b/tests/bot/cogs/test_error_handler.py @@ -245,17 +245,23 @@ class TryGetTagTests(unittest.IsolatedAsyncioTestCase): async def test_try_get_tag_get_command(self): """Should call `Bot.get_command` with `tags get` argument.""" self.bot.get_command.reset_mock() - self.ctx.invoked_with = "my_some_not_existing_tag" + self.ctx.invoked_with = "foo" await self.cog.try_get_tag(self.ctx) self.bot.get_command.assert_called_once_with("tags get") async def test_try_get_tag_invoked_from_error_handler(self): """`self.ctx` should have `invoked_from_error_handler` `True`.""" self.ctx.invoked_from_error_handler = False - self.ctx.invoked_with = "my_some_not_existing_tag" + self.ctx.invoked_with = "foo" await self.cog.try_get_tag(self.ctx) self.assertTrue(self.ctx.invoked_from_error_handler) + async def test_try_get_tag_no_permissions(self): + """Should return `False` because checks fail.""" + self.tag.get_command.can_run = AsyncMock(return_value=False) + self.ctx.invoked_with = "foo" + self.assertFalse(await self.cog.try_get_tag(self.ctx)) + class OtherErrorHandlerTests(unittest.IsolatedAsyncioTestCase): """Other `ErrorHandler` tests.""" -- cgit v1.2.3 From c2d111f32a04a4f0c5a7b02d4418b2c628b0115a Mon Sep 17 00:00:00 2001 From: ks129 <45097959+ks129@users.noreply.github.com> Date: Tue, 19 May 2020 08:41:07 +0300 Subject: EH Tests: Added test for `try_get_tag` error handling --- tests/bot/cogs/test_error_handler.py | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) (limited to 'tests') diff --git a/tests/bot/cogs/test_error_handler.py b/tests/bot/cogs/test_error_handler.py index ba05076dd..a22724aff 100644 --- a/tests/bot/cogs/test_error_handler.py +++ b/tests/bot/cogs/test_error_handler.py @@ -257,10 +257,19 @@ class TryGetTagTests(unittest.IsolatedAsyncioTestCase): self.assertTrue(self.ctx.invoked_from_error_handler) async def test_try_get_tag_no_permissions(self): - """Should return `False` because checks fail.""" + """Test how to handle checks failing.""" self.tag.get_command.can_run = AsyncMock(return_value=False) self.ctx.invoked_with = "foo" - self.assertFalse(await self.cog.try_get_tag(self.ctx)) + self.assertIsNone(await self.cog.try_get_tag(self.ctx)) + + async def test_try_get_tag_command_error(self): + """Should call `on_command_error` when `CommandError` raised.""" + err = errors.CommandError() + self.tag.get_command.can_run = AsyncMock(side_effect=err) + self.cog.on_command_error = AsyncMock() + self.ctx.invoked_with = "foo" + self.assertIsNone(await self.cog.try_get_tag(self.ctx)) + self.cog.on_command_error.assert_awaited_once_with(self.ctx, err) class OtherErrorHandlerTests(unittest.IsolatedAsyncioTestCase): -- cgit v1.2.3 From 2c1cbc21e5f7046f765d9ed5145a4f06464a8f6f Mon Sep 17 00:00:00 2001 From: ks129 <45097959+ks129@users.noreply.github.com> Date: Tue, 19 May 2020 08:49:40 +0300 Subject: EH Tests: Added test for `try_get_tag` successful tag name converting --- tests/bot/cogs/test_error_handler.py | 9 +++++++++ 1 file changed, 9 insertions(+) (limited to 'tests') diff --git a/tests/bot/cogs/test_error_handler.py b/tests/bot/cogs/test_error_handler.py index a22724aff..c95453c8c 100644 --- a/tests/bot/cogs/test_error_handler.py +++ b/tests/bot/cogs/test_error_handler.py @@ -271,6 +271,15 @@ class TryGetTagTests(unittest.IsolatedAsyncioTestCase): self.assertIsNone(await self.cog.try_get_tag(self.ctx)) self.cog.on_command_error.assert_awaited_once_with(self.ctx, err) + @patch("bot.cogs.error_handler.TagNameConverter") + async def test_try_get_tag_convert_success(self, tag_converter): + """Converting tag should successful.""" + self.ctx.invoked_with = "foo" + tag_converter.convert = AsyncMock(return_value="foo") + self.assertIsNone(await self.cog.try_get_tag(self.ctx)) + tag_converter.convert.assert_awaited_once_with(self.ctx, "foo") + self.ctx.invoke.assert_awaited_once() + class OtherErrorHandlerTests(unittest.IsolatedAsyncioTestCase): """Other `ErrorHandler` tests.""" -- cgit v1.2.3 From 558b5d86c37f81dd71b19aed9ef9dc4a1d899dd0 Mon Sep 17 00:00:00 2001 From: ks129 <45097959+ks129@users.noreply.github.com> Date: Tue, 19 May 2020 08:52:30 +0300 Subject: EH Tests: Added test for `try_get_tag` tag name converting failing --- tests/bot/cogs/test_error_handler.py | 9 +++++++++ 1 file changed, 9 insertions(+) (limited to 'tests') diff --git a/tests/bot/cogs/test_error_handler.py b/tests/bot/cogs/test_error_handler.py index c95453c8c..dfebf3379 100644 --- a/tests/bot/cogs/test_error_handler.py +++ b/tests/bot/cogs/test_error_handler.py @@ -280,6 +280,15 @@ class TryGetTagTests(unittest.IsolatedAsyncioTestCase): tag_converter.convert.assert_awaited_once_with(self.ctx, "foo") self.ctx.invoke.assert_awaited_once() + @patch("bot.cogs.error_handler.TagNameConverter") + async def test_try_get_tag_convert_fail(self, tag_converter): + """Converting tag should raise `BadArgument`.""" + self.ctx.reset_mock() + self.ctx.invoked_with = "bar" + tag_converter.convert = AsyncMock(side_effect=errors.BadArgument()) + self.assertIsNone(await self.cog.try_get_tag(self.ctx)) + self.ctx.invoke.assert_not_awaited() + class OtherErrorHandlerTests(unittest.IsolatedAsyncioTestCase): """Other `ErrorHandler` tests.""" -- cgit v1.2.3 From 9e4e9ef3f00f03e8e4b5260e458a1fc5c9318a57 Mon Sep 17 00:00:00 2001 From: ks129 <45097959+ks129@users.noreply.github.com> Date: Tue, 19 May 2020 08:58:41 +0300 Subject: EH Tests: Added test for `try_get_tag` `ctx.invoke` calling --- tests/bot/cogs/test_error_handler.py | 7 +++++++ 1 file changed, 7 insertions(+) (limited to 'tests') diff --git a/tests/bot/cogs/test_error_handler.py b/tests/bot/cogs/test_error_handler.py index dfebf3379..43092f082 100644 --- a/tests/bot/cogs/test_error_handler.py +++ b/tests/bot/cogs/test_error_handler.py @@ -289,6 +289,13 @@ class TryGetTagTests(unittest.IsolatedAsyncioTestCase): self.assertIsNone(await self.cog.try_get_tag(self.ctx)) self.ctx.invoke.assert_not_awaited() + async def test_try_get_tag_ctx_invoke(self): + """Should call `ctx.invoke` with proper args/kwargs.""" + self.ctx.reset_mock() + self.ctx.invoked_with = "foo" + self.assertIsNone(await self.cog.try_get_tag(self.ctx)) + self.ctx.invoke.assert_awaited_once_with(self.tag.get_command, tag_name="foo") + class OtherErrorHandlerTests(unittest.IsolatedAsyncioTestCase): """Other `ErrorHandler` tests.""" -- cgit v1.2.3 From 1715b2e0461b142009757b04f257cf999779a668 Mon Sep 17 00:00:00 2001 From: ks129 <45097959+ks129@users.noreply.github.com> Date: Tue, 19 May 2020 09:01:48 +0300 Subject: EH Tests: Added test for `try_get_tag` `ResponseCodeError` ignore --- tests/bot/cogs/test_error_handler.py | 6 ++++++ 1 file changed, 6 insertions(+) (limited to 'tests') diff --git a/tests/bot/cogs/test_error_handler.py b/tests/bot/cogs/test_error_handler.py index 43092f082..6dda85304 100644 --- a/tests/bot/cogs/test_error_handler.py +++ b/tests/bot/cogs/test_error_handler.py @@ -296,6 +296,12 @@ class TryGetTagTests(unittest.IsolatedAsyncioTestCase): self.assertIsNone(await self.cog.try_get_tag(self.ctx)) self.ctx.invoke.assert_awaited_once_with(self.tag.get_command, tag_name="foo") + async def test_try_get_tag_response_code_error_suppress(self): + """Should suppress `ResponseCodeError` when calling `ctx.invoke`.""" + self.ctx.invoked_with = "foo" + self.ctx.invoke.side_effect = ResponseCodeError(MagicMock()) + self.assertIsNone(await self.cog.try_get_tag(self.ctx)) + class OtherErrorHandlerTests(unittest.IsolatedAsyncioTestCase): """Other `ErrorHandler` tests.""" -- cgit v1.2.3 From 98c30a30f24feb227bf7e921e825b7124515d640 Mon Sep 17 00:00:00 2001 From: ks129 <45097959+ks129@users.noreply.github.com> Date: Tue, 19 May 2020 09:14:25 +0300 Subject: EH Tests: Created test for `handle_user_input_error` `get_help_command` --- tests/bot/cogs/test_error_handler.py | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) (limited to 'tests') diff --git a/tests/bot/cogs/test_error_handler.py b/tests/bot/cogs/test_error_handler.py index 6dda85304..377fc5228 100644 --- a/tests/bot/cogs/test_error_handler.py +++ b/tests/bot/cogs/test_error_handler.py @@ -303,6 +303,22 @@ class TryGetTagTests(unittest.IsolatedAsyncioTestCase): self.assertIsNone(await self.cog.try_get_tag(self.ctx)) +class UserInputErrorHandlerTests(unittest.IsolatedAsyncioTestCase): + """Tests for `handle_user_input_error`.""" + + def setUp(self): + self.bot = MockBot() + self.ctx = MockContext(bot=self.bot) + self.cog = ErrorHandler(self.bot) + + @patch("bot.cogs.error_handler.ErrorHandler.get_help_command") + async def test_handle_input_error_handler_get_help_command_call(self, get_help_command): + """Should call `ErrorHandler.get_help_command`.""" + get_help_command.return_value = self.ctx.send_help(self.ctx) + await self.cog.handle_user_input_error(self.ctx, errors.UserInputError()) + get_help_command.assert_called_once_with(self.ctx) + + class OtherErrorHandlerTests(unittest.IsolatedAsyncioTestCase): """Other `ErrorHandler` tests.""" -- cgit v1.2.3 From 18938a9238ac1bd7412aa636190d23de155cc15d Mon Sep 17 00:00:00 2001 From: ks129 <45097959+ks129@users.noreply.github.com> Date: Tue, 19 May 2020 09:51:55 +0300 Subject: EH Tests: Create test for `handle_input_error` --- tests/bot/cogs/test_error_handler.py | 42 ++++++++++++++++++++++++++++++------ 1 file changed, 36 insertions(+), 6 deletions(-) (limited to 'tests') diff --git a/tests/bot/cogs/test_error_handler.py b/tests/bot/cogs/test_error_handler.py index 377fc5228..e3d22e82b 100644 --- a/tests/bot/cogs/test_error_handler.py +++ b/tests/bot/cogs/test_error_handler.py @@ -311,12 +311,42 @@ class UserInputErrorHandlerTests(unittest.IsolatedAsyncioTestCase): self.ctx = MockContext(bot=self.bot) self.cog = ErrorHandler(self.bot) - @patch("bot.cogs.error_handler.ErrorHandler.get_help_command") - async def test_handle_input_error_handler_get_help_command_call(self, get_help_command): - """Should call `ErrorHandler.get_help_command`.""" - get_help_command.return_value = self.ctx.send_help(self.ctx) - await self.cog.handle_user_input_error(self.ctx, errors.UserInputError()) - get_help_command.assert_called_once_with(self.ctx) + async def test_handle_input_error_handler_errors(self): + """Should handle each error probably.""" + test_cases = ( + { + "error": errors.MissingRequiredArgument(MagicMock()), + "call_prepared": True + }, + { + "error": errors.TooManyArguments(), + "call_prepared": True + }, + { + "error": errors.BadArgument(), + "call_prepared": True + }, + { + "error": errors.BadUnionArgument(MagicMock(), MagicMock(), MagicMock()), + "call_prepared": False + }, + { + "error": errors.ArgumentParsingError(), + "call_prepared": False + }, + { + "error": errors.UserInputError(), + "call_prepared": True + } + ) + + for case in test_cases: + with self.subTest(error=case["error"], call_prepared=case["call_prepared"]): + self.ctx.reset_mock() + self.assertIsNone(await self.cog.handle_user_input_error(self.ctx, case["error"])) + self.ctx.send.assert_awaited_once() + if case["call_prepared"]: + self.ctx.send_help.assert_awaited_once() class OtherErrorHandlerTests(unittest.IsolatedAsyncioTestCase): -- cgit v1.2.3 From 42083621a48972c784a910961a2357a6b9be4aca Mon Sep 17 00:00:00 2001 From: ks129 <45097959+ks129@users.noreply.github.com> Date: Tue, 19 May 2020 10:02:57 +0300 Subject: EH Tests: Create test for `handle_check_failure` --- tests/bot/cogs/test_error_handler.py | 48 ++++++++++++++++++++++++++++++++++++ 1 file changed, 48 insertions(+) (limited to 'tests') diff --git a/tests/bot/cogs/test_error_handler.py b/tests/bot/cogs/test_error_handler.py index e3d22e82b..b12d21f75 100644 --- a/tests/bot/cogs/test_error_handler.py +++ b/tests/bot/cogs/test_error_handler.py @@ -7,6 +7,7 @@ from bot.api import ResponseCodeError from bot.cogs.error_handler import ErrorHandler from bot.cogs.moderation.silence import Silence from bot.cogs.tags import Tags +from bot.decorators import InWhitelistCheckFailure from tests.helpers import MockBot, MockContext @@ -349,6 +350,53 @@ class UserInputErrorHandlerTests(unittest.IsolatedAsyncioTestCase): self.ctx.send_help.assert_awaited_once() +class CheckFailureHandlingTests(unittest.IsolatedAsyncioTestCase): + """Tests for `handle_check_failure`.""" + + def setUp(self): + self.bot = MockBot() + self.ctx = MockContext(bot=self.bot) + self.cog = ErrorHandler(self.bot) + + async def test_handle_check_failure_errors(self): + """Should await `ctx.send` when error is check failure.""" + test_cases = ( + { + "error": errors.BotMissingPermissions(MagicMock()), + "call_ctx_send": True + }, + { + "error": errors.BotMissingRole(MagicMock()), + "call_ctx_send": True + }, + { + "error": errors.BotMissingAnyRole(MagicMock()), + "call_ctx_send": True + }, + { + "error": errors.NoPrivateMessage(), + "call_ctx_send": True + }, + { + "error": InWhitelistCheckFailure(1234), + "call_ctx_send": True + }, + { + "error": ResponseCodeError(MagicMock()), + "call_ctx_send": False + } + ) + + for case in test_cases: + with self.subTest(error=case["error"], call_ctx_send=case["call_ctx_send"]): + self.ctx.reset_mock() + await self.cog.handle_check_failure(self.ctx, case["error"]) + if case["call_ctx_send"]: + self.ctx.send.assert_awaited_once() + else: + self.ctx.send.assert_not_awaited() + + class OtherErrorHandlerTests(unittest.IsolatedAsyncioTestCase): """Other `ErrorHandler` tests.""" -- cgit v1.2.3 From decd712419d2daecd15d29efdeb6d74a64ec7946 Mon Sep 17 00:00:00 2001 From: ks129 <45097959+ks129@users.noreply.github.com> Date: Tue, 19 May 2020 10:06:01 +0300 Subject: EH Tests: Merge test classes --- tests/bot/cogs/test_error_handler.py | 15 ++++----------- 1 file changed, 4 insertions(+), 11 deletions(-) (limited to 'tests') diff --git a/tests/bot/cogs/test_error_handler.py b/tests/bot/cogs/test_error_handler.py index b12d21f75..32c7c4f46 100644 --- a/tests/bot/cogs/test_error_handler.py +++ b/tests/bot/cogs/test_error_handler.py @@ -304,8 +304,8 @@ class TryGetTagTests(unittest.IsolatedAsyncioTestCase): self.assertIsNone(await self.cog.try_get_tag(self.ctx)) -class UserInputErrorHandlerTests(unittest.IsolatedAsyncioTestCase): - """Tests for `handle_user_input_error`.""" +class IndividualErrorHandlerTests(unittest.IsolatedAsyncioTestCase): + """Individual error categories handler tests.""" def setUp(self): self.bot = MockBot() @@ -348,15 +348,8 @@ class UserInputErrorHandlerTests(unittest.IsolatedAsyncioTestCase): self.ctx.send.assert_awaited_once() if case["call_prepared"]: self.ctx.send_help.assert_awaited_once() - - -class CheckFailureHandlingTests(unittest.IsolatedAsyncioTestCase): - """Tests for `handle_check_failure`.""" - - def setUp(self): - self.bot = MockBot() - self.ctx = MockContext(bot=self.bot) - self.cog = ErrorHandler(self.bot) + else: + self.ctx.send_help.assert_not_awaited() async def test_handle_check_failure_errors(self): """Should await `ctx.send` when error is check failure.""" -- cgit v1.2.3 From 6bd696132a76068dc14f97e8fffbce2781823de2 Mon Sep 17 00:00:00 2001 From: ks129 <45097959+ks129@users.noreply.github.com> Date: Tue, 19 May 2020 12:44:26 +0300 Subject: EH Tests: Create tests for `handle_api_error` --- tests/bot/cogs/test_error_handler.py | 33 +++++++++++++++++++++++++++++++++ 1 file changed, 33 insertions(+) (limited to 'tests') diff --git a/tests/bot/cogs/test_error_handler.py b/tests/bot/cogs/test_error_handler.py index 32c7c4f46..5766727e8 100644 --- a/tests/bot/cogs/test_error_handler.py +++ b/tests/bot/cogs/test_error_handler.py @@ -389,6 +389,39 @@ class IndividualErrorHandlerTests(unittest.IsolatedAsyncioTestCase): else: self.ctx.send.assert_not_awaited() + @patch("bot.cogs.error_handler.log") + async def test_handle_api_error(self, log_mock): + """Should `ctx.send` on HTTP error codes, `log.debug|warning` depends on code.""" + test_cases = ( + { + "error": ResponseCodeError(AsyncMock(status=400)), + "log_level": "debug" + }, + { + "error": ResponseCodeError(AsyncMock(status=404)), + "log_level": "debug" + }, + { + "error": ResponseCodeError(AsyncMock(status=550)), + "log_level": "warning" + }, + { + "error": ResponseCodeError(AsyncMock(status=1000)), + "log_level": "warning" + } + ) + + for case in test_cases: + with self.subTest(error=case["error"], log_level=case["log_level"]): + self.ctx.reset_mock() + log_mock.reset_mock() + await self.cog.handle_api_error(self.ctx, case["error"]) + self.ctx.send.assert_awaited_once() + if case["log_level"] == "warning": + log_mock.warning.assert_called_once() + else: + log_mock.debug.assert_called_once() + class OtherErrorHandlerTests(unittest.IsolatedAsyncioTestCase): """Other `ErrorHandler` tests.""" -- cgit v1.2.3 From 658f73170100e826fe47ea9f23178a5d071f3932 Mon Sep 17 00:00:00 2001 From: ks129 <45097959+ks129@users.noreply.github.com> Date: Tue, 19 May 2020 12:50:43 +0300 Subject: EH Tests: Create test for `ErrorHandler` `setup` function --- tests/bot/cogs/test_error_handler.py | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) (limited to 'tests') diff --git a/tests/bot/cogs/test_error_handler.py b/tests/bot/cogs/test_error_handler.py index 5766727e8..fbe0d58d5 100644 --- a/tests/bot/cogs/test_error_handler.py +++ b/tests/bot/cogs/test_error_handler.py @@ -4,7 +4,7 @@ from unittest.mock import AsyncMock, MagicMock, patch from discord.ext.commands import errors from bot.api import ResponseCodeError -from bot.cogs.error_handler import ErrorHandler +from bot.cogs.error_handler import ErrorHandler, setup from bot.cogs.moderation.silence import Silence from bot.cogs.tags import Tags from bot.decorators import InWhitelistCheckFailure @@ -453,3 +453,13 @@ class OtherErrorHandlerTests(unittest.IsolatedAsyncioTestCase): # Await coroutines to avoid warnings await result await expected + + +class ErrorHandlerSetupTests(unittest.TestCase): + """Tests for `ErrorHandler` `setup` function.""" + + def test_setup(self): + """Should call `bot.add_cog` with `ErrorHandler`.""" + bot = MockBot() + setup(bot) + bot.add_cog.assert_called_once() -- cgit v1.2.3 From 96ddcdd3bd12cc9ceb47aa10d17e7354be9e1218 Mon Sep 17 00:00:00 2001 From: ks129 <45097959+ks129@users.noreply.github.com> Date: Tue, 19 May 2020 13:08:52 +0300 Subject: EH Tests: Create test for `handle_unexpected_error` --- tests/bot/cogs/test_error_handler.py | 39 ++++++++++++++++++++++++++++++++++-- 1 file changed, 37 insertions(+), 2 deletions(-) (limited to 'tests') diff --git a/tests/bot/cogs/test_error_handler.py b/tests/bot/cogs/test_error_handler.py index fbe0d58d5..08b1e0230 100644 --- a/tests/bot/cogs/test_error_handler.py +++ b/tests/bot/cogs/test_error_handler.py @@ -1,5 +1,5 @@ import unittest -from unittest.mock import AsyncMock, MagicMock, patch +from unittest.mock import AsyncMock, MagicMock, call, patch from discord.ext.commands import errors @@ -8,7 +8,7 @@ from bot.cogs.error_handler import ErrorHandler, setup from bot.cogs.moderation.silence import Silence from bot.cogs.tags import Tags from bot.decorators import InWhitelistCheckFailure -from tests.helpers import MockBot, MockContext +from tests.helpers import MockBot, MockContext, MockGuild class ErrorHandlerTests(unittest.IsolatedAsyncioTestCase): @@ -422,6 +422,41 @@ class IndividualErrorHandlerTests(unittest.IsolatedAsyncioTestCase): else: log_mock.debug.assert_called_once() + @patch("bot.cogs.error_handler.push_scope") + @patch("bot.cogs.error_handler.log") + async def test_handle_unexpected_error(self, log_mock, push_scope_mock): + """Should `ctx.send` this error, error log this and sent to Sentry.""" + for case in (None, MockGuild()): + with self.subTest(guild=case): + self.ctx.reset_mock() + log_mock.reset_mock() + push_scope_mock.reset_mock() + + self.ctx.guild = case + await self.cog.handle_unexpected_error(self.ctx, errors.CommandError()) + + self.ctx.send.assert_awaited_once() + log_mock.error.assert_called_once() + push_scope_mock.assert_called_once() + + set_tag_calls = [ + call("command", self.ctx.command.qualified_name), + call("message_id", self.ctx.message.id), + call("channel_id", self.ctx.channel.id), + ] + set_extra_calls = [ + call("full_message", self.ctx.message.content) + ] + if case: + url = ( + f"https://discordapp.com/channels/" + f"{self.ctx.guild.id}/{self.ctx.channel.id}/{self.ctx.message.id}" + ) + set_extra_calls.append(call("jump_to", url)) + + push_scope_mock.set_tag.has_calls(set_tag_calls) + push_scope_mock.set_extra.has_calls(set_extra_calls) + class OtherErrorHandlerTests(unittest.IsolatedAsyncioTestCase): """Other `ErrorHandler` tests.""" -- cgit v1.2.3 From 9f4d602bfa02fce088aaed28ee598c116b655683 Mon Sep 17 00:00:00 2001 From: Numerlor <25886452+Numerlor@users.noreply.github.com> Date: Wed, 22 Jul 2020 16:20:48 +0200 Subject: Change ValidPythonIdentifier tests to PackageName. --- tests/bot/test_converters.py | 21 ++++++++++----------- 1 file changed, 10 insertions(+), 11 deletions(-) (limited to 'tests') diff --git a/tests/bot/test_converters.py b/tests/bot/test_converters.py index ca8cb6825..a3c071168 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.TestCase): with self.assertRaises(BadArgument, msg=exception_message): asyncio.run(TagNameConverter.convert(self.context, invalid_name)) - def test_valid_python_identifier_for_valid(self): - """ValidPythonIdentifier returns valid identifiers unchanged.""" - test_values = ('foo', 'lemon') + def test_package_name_for_valid(self): + """PackageName returns valid package names unchanged.""" + test_values = ('foo', 'le_mon') for name in test_values: with self.subTest(identifier=name): - conversion = asyncio.run(ValidPythonIdentifier.convert(self.context, name)) + conversion = asyncio.run(PackageName.convert(self.context, name)) self.assertEqual(name, conversion) - def test_valid_python_identifier_for_invalid(self): - """ValidPythonIdentifier raises the proper exception for invalid identifiers.""" - test_values = ('nested.stuff', '#####') + def test_package_name_for_invalid(self): + """PackageName raises the proper exception for invalid package names.""" + test_values = ('text_with_a_dot.', 'UpperCaseName', "num83r") for name in test_values: with self.subTest(identifier=name): - exception_message = f'`{name}` is not a valid Python identifier' - with self.assertRaises(BadArgument, msg=exception_message): - asyncio.run(ValidPythonIdentifier.convert(self.context, name)) + with self.assertRaises(BadArgument): + asyncio.run(PackageName.convert(self.context, name)) def test_duration_converter_for_valid(self): """Duration returns the correct `datetime` for valid duration strings.""" -- cgit v1.2.3 From 8716902624668f2cef80656f5e9fae335a0559f2 Mon Sep 17 00:00:00 2001 From: ks129 <45097959+ks129@users.noreply.github.com> Date: Sun, 27 Sep 2020 08:29:03 +0300 Subject: EH Tests: Fix order of imports --- tests/bot/exts/backend/test_error_handler.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'tests') diff --git a/tests/bot/exts/backend/test_error_handler.py b/tests/bot/exts/backend/test_error_handler.py index e8b9c7708..e3641ba21 100644 --- a/tests/bot/exts/backend/test_error_handler.py +++ b/tests/bot/exts/backend/test_error_handler.py @@ -4,10 +4,10 @@ from unittest.mock import AsyncMock, MagicMock, call, patch from discord.ext.commands import errors from bot.api import ResponseCodeError +from bot.decorators import InWhitelistCheckFailure from bot.exts.backend.error_handler import ErrorHandler, setup -from bot.exts.moderation.silence import Silence from bot.exts.info.tags import Tags -from bot.decorators import InWhitelistCheckFailure +from bot.exts.moderation.silence import Silence from tests.helpers import MockBot, MockContext, MockGuild -- cgit v1.2.3 From 5f250690523a4a1c631834d2a8e64898614c5932 Mon Sep 17 00:00:00 2001 From: ks129 <45097959+ks129@users.noreply.github.com> Date: Sun, 27 Sep 2020 08:44:03 +0300 Subject: EH tests: Fix InWhitelistCheckFailure import path --- tests/bot/exts/backend/test_error_handler.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'tests') diff --git a/tests/bot/exts/backend/test_error_handler.py b/tests/bot/exts/backend/test_error_handler.py index e3641ba21..4a0adb03e 100644 --- a/tests/bot/exts/backend/test_error_handler.py +++ b/tests/bot/exts/backend/test_error_handler.py @@ -4,10 +4,10 @@ from unittest.mock import AsyncMock, MagicMock, call, patch from discord.ext.commands import errors from bot.api import ResponseCodeError -from bot.decorators import InWhitelistCheckFailure from bot.exts.backend.error_handler import ErrorHandler, setup from bot.exts.info.tags import Tags from bot.exts.moderation.silence import Silence +from bot.utils.checks import InWhitelistCheckFailure from tests.helpers import MockBot, MockContext, MockGuild -- cgit v1.2.3 From ee0cd08a113192a5e49ddb10c9ef2527d9a4d77b Mon Sep 17 00:00:00 2001 From: ks129 <45097959+ks129@users.noreply.github.com> Date: Fri, 19 Feb 2021 12:50:16 +0200 Subject: Remove verification channel special case from error handler tests We don't have a verification channel anymore, so this have no point and this just give errors. --- tests/bot/exts/backend/test_error_handler.py | 18 +++++------------- 1 file changed, 5 insertions(+), 13 deletions(-) (limited to 'tests') diff --git a/tests/bot/exts/backend/test_error_handler.py b/tests/bot/exts/backend/test_error_handler.py index 4a0adb03e..ea21a9f58 100644 --- a/tests/bot/exts/backend/test_error_handler.py +++ b/tests/bot/exts/backend/test_error_handler.py @@ -28,22 +28,19 @@ class ErrorHandlerTests(unittest.IsolatedAsyncioTestCase): self.ctx.send.assert_not_awaited() async def test_error_handler_command_not_found_error_not_invoked_by_handler(self): - """Should try first (un)silence channel, when fail and channel is not verification channel try to get tag.""" + """Should try first (un)silence channel, when fail, try to get tag.""" error = errors.CommandNotFound() test_cases = ( { "try_silence_return": True, - "patch_verification_id": False, "called_try_get_tag": False }, { "try_silence_return": False, - "patch_verification_id": True, "called_try_get_tag": False }, { "try_silence_return": False, - "patch_verification_id": False, "called_try_get_tag": True } ) @@ -60,20 +57,15 @@ class ErrorHandlerTests(unittest.IsolatedAsyncioTestCase): cog.try_silence.return_value = case["try_silence_return"] self.ctx.channel.id = 1234 - if case["patch_verification_id"]: - with patch("bot.exts.backend.error_handler.Channels.verification", new=1234): - self.assertIsNone(await cog.on_command_error(self.ctx, error)) - else: - self.assertIsNone(await cog.on_command_error(self.ctx, error)) + self.assertIsNone(await cog.on_command_error(self.ctx, error)) + if case["try_silence_return"]: cog.try_get_tag.assert_not_awaited() cog.try_silence.assert_awaited_once() else: cog.try_silence.assert_awaited_once() - if case["patch_verification_id"]: - cog.try_get_tag.assert_not_awaited() - else: - cog.try_get_tag.assert_awaited_once() + cog.try_get_tag.assert_awaited_once() + self.ctx.send.assert_not_awaited() async def test_error_handler_command_not_found_error_invoked_by_handler(self): -- cgit v1.2.3 From 3855b4f81e678d93db99adbd7701599b0b29748c Mon Sep 17 00:00:00 2001 From: ks129 <45097959+ks129@users.noreply.github.com> Date: Fri, 19 Feb 2021 17:17:19 +0200 Subject: Update error handler tests to match with recent changes --- tests/bot/exts/backend/test_error_handler.py | 81 ++++++++++++++++++++++++---- 1 file changed, 72 insertions(+), 9 deletions(-) (limited to 'tests') diff --git a/tests/bot/exts/backend/test_error_handler.py b/tests/bot/exts/backend/test_error_handler.py index ea21a9f58..9b7b66cb2 100644 --- a/tests/bot/exts/backend/test_error_handler.py +++ b/tests/bot/exts/backend/test_error_handler.py @@ -4,11 +4,13 @@ from unittest.mock import AsyncMock, MagicMock, call, patch from discord.ext.commands import errors from bot.api import ResponseCodeError +from bot.errors import InvalidInfractedUser, LockedResourceError +from bot.exts.backend.branding._errors import BrandingError from bot.exts.backend.error_handler import ErrorHandler, setup from bot.exts.info.tags import Tags from bot.exts.moderation.silence import Silence from bot.utils.checks import InWhitelistCheckFailure -from tests.helpers import MockBot, MockContext, MockGuild +from tests.helpers import MockBot, MockContext, MockGuild, MockRole class ErrorHandlerTests(unittest.IsolatedAsyncioTestCase): @@ -123,20 +125,58 @@ class ErrorHandlerTests(unittest.IsolatedAsyncioTestCase): { "args": (self.ctx, errors.CommandInvokeError(TypeError)), "expect_mock_call": cog.handle_unexpected_error + }, + { + "args": (self.ctx, errors.CommandInvokeError(LockedResourceError("abc", "test"))), + "expect_mock_call": "send" + }, + { + "args": (self.ctx, errors.CommandInvokeError(BrandingError())), + "expect_mock_call": "send" + }, + { + "args": (self.ctx, errors.CommandInvokeError(InvalidInfractedUser(self.ctx.author))), + "expect_mock_call": "send" } ) for case in test_cases: with self.subTest(args=case["args"], expect_mock_call=case["expect_mock_call"]): + self.ctx.send.reset_mock() self.assertIsNone(await cog.on_command_error(*case["args"])) - case["expect_mock_call"].assert_awaited_once_with(self.ctx, case["args"][1].original) + if case["expect_mock_call"] == "send": + self.ctx.send.assert_awaited_once() + else: + case["expect_mock_call"].assert_awaited_once_with( + self.ctx, case["args"][1].original + ) - async def test_error_handler_three_other_errors(self): - """Should call `handle_unexpected_error` when `ConversionError`, `MaxConcurrencyReached` or `ExtensionError`.""" + async def test_error_handler_conversion_error(self): + """Should call `handle_api_error` or `handle_unexpected_error` depending on original error.""" + cog = ErrorHandler(self.bot) + cog.handle_api_error = AsyncMock() + cog.handle_unexpected_error = AsyncMock() + cases = ( + { + "error": errors.ConversionError(AsyncMock(), ResponseCodeError(AsyncMock())), + "mock_function_to_call": cog.handle_api_error + }, + { + "error": errors.ConversionError(AsyncMock(), TypeError), + "mock_function_to_call": cog.handle_unexpected_error + } + ) + + for case in cases: + with self.subTest(**case): + self.assertIsNone(await cog.on_command_error(self.ctx, case["error"])) + case["mock_function_to_call"].assert_awaited_once_with(self.ctx, case["error"].original) + + async def test_error_handler_two_other_errors(self): + """Should call `handle_unexpected_error` if error is `MaxConcurrencyReached` or `ExtensionError`.""" cog = ErrorHandler(self.bot) cog.handle_unexpected_error = AsyncMock() errs = ( - errors.ConversionError(MagicMock(), MagicMock()), errors.MaxConcurrencyReached(1, MagicMock()), errors.ExtensionError(name="foo") ) @@ -289,11 +329,34 @@ class TryGetTagTests(unittest.IsolatedAsyncioTestCase): self.assertIsNone(await self.cog.try_get_tag(self.ctx)) self.ctx.invoke.assert_awaited_once_with(self.tag.get_command, tag_name="foo") - async def test_try_get_tag_response_code_error_suppress(self): - """Should suppress `ResponseCodeError` when calling `ctx.invoke`.""" + async def test_dont_call_suggestion_tag_sent(self): + """Should never call command suggestion if tag is already sent.""" self.ctx.invoked_with = "foo" - self.ctx.invoke.side_effect = ResponseCodeError(MagicMock()) - self.assertIsNone(await self.cog.try_get_tag(self.ctx)) + self.ctx.invoke = AsyncMock(return_value=True) + self.cog.send_command_suggestion = AsyncMock() + + await self.cog.try_get_tag(self.ctx) + self.cog.send_command_suggestion.assert_not_awaited() + + @patch("bot.exts.backend.error_handler.MODERATION_ROLES", new=[1234]) + async def test_dont_call_suggestion_if_user_mod(self): + """Should not call command suggestion if user is a mod.""" + self.ctx.invoked_with = "foo" + self.ctx.invoke = AsyncMock(return_value=False) + self.ctx.author.roles = [MockRole(id=1234)] + self.cog.send_command_suggestion = AsyncMock() + + await self.cog.try_get_tag(self.ctx) + self.cog.send_command_suggestion.assert_not_awaited() + + async def test_call_suggestion(self): + """Should call command suggestion if user is not a mod.""" + self.ctx.invoked_with = "foo" + self.ctx.invoke = AsyncMock(return_value=False) + self.cog.send_command_suggestion = AsyncMock() + + await self.cog.try_get_tag(self.ctx) + self.cog.send_command_suggestion.assert_awaited_once_with(self.ctx, "foo") class IndividualErrorHandlerTests(unittest.IsolatedAsyncioTestCase): -- cgit v1.2.3 From 8f6d11a7694d6dea50d94d7918f686834283c858 Mon Sep 17 00:00:00 2001 From: Numerlor <25886452+Numerlor@users.noreply.github.com> Date: Sun, 21 Feb 2021 02:54:09 +0100 Subject: Add unittests for _split_signature --- tests/bot/exts/info/doc/__init__.py | 0 tests/bot/exts/info/doc/test_parsing.py | 59 +++++++++++++++++++++++++++++++++ 2 files changed, 59 insertions(+) create mode 100644 tests/bot/exts/info/doc/__init__.py create mode 100644 tests/bot/exts/info/doc/test_parsing.py (limited to 'tests') 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 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..f302b38fc --- /dev/null +++ b/tests/bot/exts/info/doc/test_parsing.py @@ -0,0 +1,59 @@ +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_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) -- cgit v1.2.3 From 47ed2339e55eb2a0bc245b45c1f0df9cc8b9af36 Mon Sep 17 00:00:00 2001 From: swfarnsworth Date: Thu, 25 Feb 2021 00:53:12 -0500 Subject: Instructions to dispute an infraction vary by infraction type. Previously, the user was instructed to email the appeals email for infraction types that don't remove one from the server. They are now instructed to DM ModMail except for Ban-type infractions. Also removed the URL string literal from the hyperlink to that URL. --- bot/exts/moderation/infraction/_utils.py | 44 +++++++++++----------- tests/bot/exts/moderation/infraction/test_utils.py | 6 +-- 2 files changed, 26 insertions(+), 24 deletions(-) (limited to 'tests') diff --git a/bot/exts/moderation/infraction/_utils.py b/bot/exts/moderation/infraction/_utils.py index e766c1e5c..e58c2b22f 100644 --- a/bot/exts/moderation/infraction/_utils.py +++ b/bot/exts/moderation/infraction/_utils.py @@ -22,7 +22,6 @@ INFRACTION_ICONS = { "voice_ban": (Icons.voice_state_red, Icons.voice_state_green), } RULES_URL = "https://pythondiscord.com/pages/rules" -APPEALABLE_INFRACTIONS = ("ban", "mute", "voice_ban") # Type aliases UserObject = t.Union[discord.Member, discord.User] @@ -31,8 +30,10 @@ Infraction = t.Dict[str, t.Union[str, int, bool]] APPEAL_EMAIL = "appeals@pythondiscord.com" -INFRACTION_TITLE = f"Please review our rules over at {RULES_URL}" -INFRACTION_APPEAL_FOOTER = f"To appeal this infraction, send an e-mail to {APPEAL_EMAIL}" +INFRACTION_TITLE = "Please review our rules" +INFRACTION_APPEAL_EMAIL_FOOTER = f"To appeal this infraction, send an e-mail to {APPEAL_EMAIL}" +INFRACTION_APPEAL_MODMAIL_FOOTER = ('If you would like to discuss or appeal this infraction, ' + 'send a message to the ModMail bot') INFRACTION_AUTHOR_NAME = "Infraction information" INFRACTION_DESCRIPTION_TEMPLATE = ( @@ -71,13 +72,13 @@ async def post_user(ctx: Context, user: UserSnowflake) -> t.Optional[dict]: async def post_infraction( - ctx: Context, - user: UserSnowflake, - infr_type: str, - reason: str, - expires_at: datetime = None, - hidden: bool = False, - active: bool = True + ctx: Context, + user: UserSnowflake, + infr_type: str, + reason: str, + expires_at: datetime = None, + hidden: bool = False, + active: bool = True ) -> t.Optional[dict]: """Posts an infraction to the API.""" if isinstance(user, (discord.Member, discord.User)) and user.bot: @@ -150,11 +151,11 @@ async def get_active_infraction( async def notify_infraction( - user: UserObject, - infr_type: str, - expires_at: t.Optional[str] = None, - reason: t.Optional[str] = None, - icon_url: str = Icons.token_removed + user: UserObject, + infr_type: str, + expires_at: t.Optional[str] = None, + reason: t.Optional[str] = None, + icon_url: str = Icons.token_removed ) -> bool: """DM a user about their new infraction and return True if the DM is successful.""" log.trace(f"Sending {user} a DM about their {infr_type} infraction.") @@ -178,17 +179,18 @@ async def notify_infraction( embed.title = INFRACTION_TITLE embed.url = RULES_URL - if infr_type in APPEALABLE_INFRACTIONS: - embed.set_footer(text=INFRACTION_APPEAL_FOOTER) + embed.set_footer( + text=INFRACTION_APPEAL_EMAIL_FOOTER if infr_type == 'Ban' else INFRACTION_APPEAL_MODMAIL_FOOTER + ) return await send_private_embed(user, embed) async def notify_pardon( - user: UserObject, - title: str, - content: str, - icon_url: str = Icons.user_verified + user: UserObject, + title: str, + content: str, + icon_url: str = Icons.user_verified ) -> bool: """DM a user about their pardoned infraction and return True if the DM is successful.""" log.trace(f"Sending {user} a DM about their pardoned infraction.") diff --git a/tests/bot/exts/moderation/infraction/test_utils.py b/tests/bot/exts/moderation/infraction/test_utils.py index 5b62463e0..ef6127344 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_EMAIL_FOOTER), "send_result": True }, { @@ -200,7 +200,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_EMAIL_FOOTER), "send_result": False }, { @@ -218,7 +218,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_EMAIL_FOOTER), "send_result": True } ] -- cgit v1.2.3 From 75f2b9d5e922db8aca2c873c214455fded02fc4d Mon Sep 17 00:00:00 2001 From: swfarnsworth Date: Sun, 28 Feb 2021 11:33:26 -0500 Subject: Update the tests to reflect changes in expected behavior. The DM sent to infracted users now instructs them to DM modmail if they want to discuss non-ban infractions, so the tests now check if that instruction is present. Note that there already exists a superfluous test for note infractions, for which no DM is sent by design. --- tests/bot/exts/moderation/infraction/test_utils.py | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) (limited to 'tests') diff --git a/tests/bot/exts/moderation/infraction/test_utils.py b/tests/bot/exts/moderation/infraction/test_utils.py index ef6127344..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_EMAIL_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_EMAIL_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_EMAIL_FOOTER), + ).set_footer(text=utils.INFRACTION_APPEAL_MODMAIL_FOOTER), "send_result": True } ] -- cgit v1.2.3 From 74cbe44625a1e6e2e39f77b2663794d3ab5aaf58 Mon Sep 17 00:00:00 2001 From: Numerlor <25886452+Numerlor@users.noreply.github.com> Date: Fri, 5 Mar 2021 18:22:46 +0100 Subject: Correct tests cases The tests were not adjusted after the converter was corrected to accept digits --- tests/bot/test_converters.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'tests') diff --git a/tests/bot/test_converters.py b/tests/bot/test_converters.py index 231798a92..4af84dde5 100644 --- a/tests/bot/test_converters.py +++ b/tests/bot/test_converters.py @@ -80,7 +80,7 @@ class ConverterTests(unittest.IsolatedAsyncioTestCase): async def test_package_name_for_valid(self): """PackageName returns valid package names unchanged.""" - test_values = ('foo', 'le_mon') + test_values = ('foo', 'le_mon', 'num83r') for name in test_values: with self.subTest(identifier=name): @@ -89,7 +89,7 @@ class ConverterTests(unittest.IsolatedAsyncioTestCase): async def test_package_name_for_invalid(self): """PackageName raises the proper exception for invalid package names.""" - test_values = ('text_with_a_dot.', 'UpperCaseName', "num83r") + test_values = ('text_with_a_dot.', 'UpperCaseName', 'dashed-name') for name in test_values: with self.subTest(identifier=name): -- cgit v1.2.3 From dc7eef432189aaaf0ea8b0d16588852306104957 Mon Sep 17 00:00:00 2001 From: Numerlor <25886452+Numerlor@users.noreply.github.com> Date: Sun, 7 Mar 2021 05:18:02 +0100 Subject: Handle arbitrary amount of backslashes preceding the quote char Tests for this were added additionally --- bot/exts/info/doc/_parsing.py | 19 ++++++++----------- tests/bot/exts/info/doc/test_parsing.py | 7 +++++++ 2 files changed, 15 insertions(+), 11 deletions(-) (limited to 'tests') diff --git a/bot/exts/info/doc/_parsing.py b/bot/exts/info/doc/_parsing.py index fc38ff82a..57c991ae0 100644 --- a/bot/exts/info/doc/_parsing.py +++ b/bot/exts/info/doc/_parsing.py @@ -46,15 +46,6 @@ _BRACKET_PAIRS = { } -def _is_closing_quote(search_string: str, index: int) -> bool: - """Check whether the quote at `index` inside `search_string` can be a closing quote.""" - if search_string[index - 1] != "\\": - return True # The quote is not escaped. - elif search_string[index - 2] == "\\": - return True - return False - - def _split_parameters(parameters_string: str) -> Iterator[str]: """ Split parameters of a signature into individual parameter strings on commas. @@ -70,9 +61,15 @@ def _split_parameters(parameters_string: str) -> Iterator[str]: if character in {"'", '"'}: # Skip everything inside of strings, regardless of the depth. quote_character = character # The closing quote must equal the opening quote. - for index, character in enumerated_string: - if character == quote_character and _is_closing_quote(parameters_string, index): + preceding_backslashes = 0 + for _, character in enumerated_string: + # If an odd number of backslashes precedes the quote, it was escaped. + if character == quote_character and not preceding_backslashes % 2: break + if character == "\\": + preceding_backslashes += 1 + else: + preceding_backslashes = 0 elif current_search is None: if (current_search := _BRACKET_PAIRS.get(character)) is not None: diff --git a/tests/bot/exts/info/doc/test_parsing.py b/tests/bot/exts/info/doc/test_parsing.py index f302b38fc..1663d8491 100644 --- a/tests/bot/exts/info/doc/test_parsing.py +++ b/tests/bot/exts/info/doc/test_parsing.py @@ -42,6 +42,13 @@ class SignatureSplitter(TestCase): ) 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]"]), -- cgit v1.2.3 From f76e47bf9b1d9956a36d891e3aa64593c65568c8 Mon Sep 17 00:00:00 2001 From: xithrius Date: Mon, 8 Mar 2021 03:35:54 -0800 Subject: Fixed unittest for purge infraction. --- tests/bot/exts/moderation/infraction/test_infractions.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'tests') 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") -- cgit v1.2.3 From 2759409123d458a4a0a274b835bebb3cc728b83a Mon Sep 17 00:00:00 2001 From: Den4200 Date: Sat, 27 Mar 2021 13:49:22 -0400 Subject: Fix tests for paste uploads. Accounts for no redirects on extensions that are not `.py`. --- tests/bot/utils/test_services.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'tests') 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}) -- cgit v1.2.3 From 61ab2cd4d434def0743e767acdb3f816c20e4dce Mon Sep 17 00:00:00 2001 From: Ben Soyka Date: Sun, 4 Apr 2021 22:35:53 -0600 Subject: Update information tests for new embed color logic --- tests/bot/exts/info/test_information.py | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) (limited to 'tests') diff --git a/tests/bot/exts/info/test_information.py b/tests/bot/exts/info/test_information.py index 80731c9f0..b1b7d37ae 100644 --- a/tests/bot/exts/info/test_information.py +++ b/tests/bot/exts/info/test_information.py @@ -283,6 +283,7 @@ class UserEmbedTests(unittest.IsolatedAsyncioTestCase): user = helpers.MockMember() user.nick = None user.__str__ = unittest.mock.Mock(return_value="Mr. Hemlock") + user.colour = 0 embed = await self.cog.create_user_embed(ctx, user) @@ -298,6 +299,7 @@ class UserEmbedTests(unittest.IsolatedAsyncioTestCase): user = helpers.MockMember() 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) @@ -314,7 +316,7 @@ class UserEmbedTests(unittest.IsolatedAsyncioTestCase): 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], top_role=admins_role, colour=100) embed = await self.cog.create_user_embed(ctx, user) @@ -337,7 +339,7 @@ class UserEmbedTests(unittest.IsolatedAsyncioTestCase): 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], top_role=moderators_role, colour=100) embed = await self.cog.create_user_embed(ctx, user) infraction_counts.assert_called_once_with(user) @@ -371,7 +373,7 @@ class UserEmbedTests(unittest.IsolatedAsyncioTestCase): 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], top_role=moderators_role, colour=100) embed = await self.cog.create_user_embed(ctx, user) infraction_counts.assert_called_once_with(user) @@ -409,7 +411,7 @@ class UserEmbedTests(unittest.IsolatedAsyncioTestCase): 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], top_role=moderators_role, colour=100) embed = await self.cog.create_user_embed(ctx, user) self.assertEqual(embed.colour, discord.Colour(moderators_role.colour)) @@ -422,7 +424,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.blurple()) embed = await self.cog.create_user_embed(ctx, user) self.assertEqual(embed.colour, discord.Colour.blurple()) @@ -435,7 +437,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) -- cgit v1.2.3 From 835a0a6f4a45018d21dacbfbf69afe07361155aa Mon Sep 17 00:00:00 2001 From: Ben Soyka Date: Mon, 5 Apr 2021 08:56:22 -0600 Subject: Minor test changes for the !user embed --- tests/bot/exts/info/test_information.py | 16 ++++++---------- 1 file changed, 6 insertions(+), 10 deletions(-) (limited to 'tests') diff --git a/tests/bot/exts/info/test_information.py b/tests/bot/exts/info/test_information.py index b1b7d37ae..a996ce477 100644 --- a/tests/bot/exts/info/test_information.py +++ b/tests/bot/exts/info/test_information.py @@ -313,10 +313,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, colour=100) + user = helpers.MockMember(roles=[admins_role], colour=100) embed = await self.cog.create_user_embed(ctx, user) @@ -334,12 +333,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, colour=100) + 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) @@ -369,11 +367,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, colour=100) + 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) @@ -409,12 +406,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, colour=100) + 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", @@ -424,7 +420,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, colour=discord.Colour.blurple()) + 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()) -- cgit v1.2.3 From 93c9e536a3e771db2ac03054a5c2470883d59f1f Mon Sep 17 00:00:00 2001 From: Matteo Bertucci Date: Sat, 17 Apr 2021 18:52:19 +0200 Subject: Tests: members shouldn't have any public flags --- tests/bot/exts/info/test_information.py | 8 ++++++++ 1 file changed, 8 insertions(+) (limited to 'tests') diff --git a/tests/bot/exts/info/test_information.py b/tests/bot/exts/info/test_information.py index a996ce477..d2ecee033 100644 --- a/tests/bot/exts/info/test_information.py +++ b/tests/bot/exts/info/test_information.py @@ -281,9 +281,13 @@ 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() + public_flags = unittest.mock.MagicMock() + public_flags.__iter__.return_value = iter(()) + public_flags.verified_bot = False user.nick = None user.__str__ = unittest.mock.Mock(return_value="Mr. Hemlock") user.colour = 0 + user.public_flags = public_flags embed = await self.cog.create_user_embed(ctx, user) @@ -297,9 +301,13 @@ 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() + public_flags = unittest.mock.MagicMock() + public_flags.__iter__.return_value = iter(()) + public_flags.verified_bot = False user.nick = "Cat lover" user.__str__ = unittest.mock.Mock(return_value="Mr. Hemlock") user.colour = 0 + user.public_flags = public_flags embed = await self.cog.create_user_embed(ctx, user) -- cgit v1.2.3 From 9aa2b42aa04724a4ebc74d3ff6c339c33547dce3 Mon Sep 17 00:00:00 2001 From: Matteo Bertucci Date: Tue, 20 Apr 2021 17:20:44 +0200 Subject: Tests: AsyncMock is now in the standard library! The `tests/README.md` file still referenced our old custom `AsyncMock` that has been removed in favour of the standard library one that has been introduced in 3.8. This commit fixes this by updating the section. --- tests/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'tests') 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 -- cgit v1.2.3 From 1fdd5aabd4ef5e356f358fdb6e9b26a5b5da99ce Mon Sep 17 00:00:00 2001 From: Matteo Bertucci Date: Sat, 24 Apr 2021 17:04:48 +0200 Subject: Tests: simplify public flags handling Co_authored-by: Numerlor <25886452+Numerlor@users.noreply.github.com> --- tests/bot/exts/info/test_information.py | 10 ++-------- 1 file changed, 2 insertions(+), 8 deletions(-) (limited to 'tests') diff --git a/tests/bot/exts/info/test_information.py b/tests/bot/exts/info/test_information.py index d2ecee033..770660fe3 100644 --- a/tests/bot/exts/info/test_information.py +++ b/tests/bot/exts/info/test_information.py @@ -281,13 +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() - public_flags = unittest.mock.MagicMock() - public_flags.__iter__.return_value = iter(()) - public_flags.verified_bot = False + user.public_flags = unittest.mock.MagicMock(verified_bot=False) user.nick = None user.__str__ = unittest.mock.Mock(return_value="Mr. Hemlock") user.colour = 0 - user.public_flags = public_flags embed = await self.cog.create_user_embed(ctx, user) @@ -301,13 +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() - public_flags = unittest.mock.MagicMock() - public_flags.__iter__.return_value = iter(()) - public_flags.verified_bot = False + 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 - user.public_flags = public_flags embed = await self.cog.create_user_embed(ctx, user) -- cgit v1.2.3 From 9ffe5b0146354936c7c67e43bd6682195ccedfdd Mon Sep 17 00:00:00 2001 From: kosayoda Date: Wed, 28 Apr 2021 16:43:52 +0800 Subject: Remove BrandingError check. This was removed in the branding manager rewrite: https://github.com/python-discord/bot/pull/1463/ --- tests/bot/exts/backend/test_error_handler.py | 5 ----- 1 file changed, 5 deletions(-) (limited to 'tests') diff --git a/tests/bot/exts/backend/test_error_handler.py b/tests/bot/exts/backend/test_error_handler.py index 9b7b66cb2..1b4729cbc 100644 --- a/tests/bot/exts/backend/test_error_handler.py +++ b/tests/bot/exts/backend/test_error_handler.py @@ -5,7 +5,6 @@ from discord.ext.commands import errors from bot.api import ResponseCodeError from bot.errors import InvalidInfractedUser, LockedResourceError -from bot.exts.backend.branding._errors import BrandingError from bot.exts.backend.error_handler import ErrorHandler, setup from bot.exts.info.tags import Tags from bot.exts.moderation.silence import Silence @@ -130,10 +129,6 @@ class ErrorHandlerTests(unittest.IsolatedAsyncioTestCase): "args": (self.ctx, errors.CommandInvokeError(LockedResourceError("abc", "test"))), "expect_mock_call": "send" }, - { - "args": (self.ctx, errors.CommandInvokeError(BrandingError())), - "expect_mock_call": "send" - }, { "args": (self.ctx, errors.CommandInvokeError(InvalidInfractedUser(self.ctx.author))), "expect_mock_call": "send" -- cgit v1.2.3 From e6bb1b321d9b657309c4c4c6f445f33a0e9e563e Mon Sep 17 00:00:00 2001 From: kosayoda Date: Wed, 28 Apr 2021 16:45:18 +0800 Subject: Address error behavior update. BadUnionArgument sends command help after: https://github.com/python-discord/bot/pull/1434 --- bot/exts/backend/error_handler.py | 4 ++-- tests/bot/exts/backend/test_error_handler.py | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) (limited to 'tests') diff --git a/bot/exts/backend/error_handler.py b/bot/exts/backend/error_handler.py index f3bb3426a..d8de177f5 100644 --- a/bot/exts/backend/error_handler.py +++ b/bot/exts/backend/error_handler.py @@ -230,12 +230,12 @@ class ErrorHandler(Cog): elif isinstance(e, errors.BadUnionArgument): embed = self._get_error_embed("Bad argument", f"{e}\n{e.errors[-1]}") await ctx.send(embed=embed) - await prepared_help_command + await self.get_help_command(ctx) self.bot.stats.incr("errors.bad_union_argument") elif isinstance(e, errors.ArgumentParsingError): embed = self._get_error_embed("Argument parsing error", str(e)) await ctx.send(embed=embed) - prepared_help_command.close() + self.get_help_command(ctx).close() self.bot.stats.incr("errors.argument_parsing_error") else: embed = self._get_error_embed( diff --git a/tests/bot/exts/backend/test_error_handler.py b/tests/bot/exts/backend/test_error_handler.py index 1b4729cbc..bd4fb5942 100644 --- a/tests/bot/exts/backend/test_error_handler.py +++ b/tests/bot/exts/backend/test_error_handler.py @@ -379,7 +379,7 @@ class IndividualErrorHandlerTests(unittest.IsolatedAsyncioTestCase): }, { "error": errors.BadUnionArgument(MagicMock(), MagicMock(), MagicMock()), - "call_prepared": False + "call_prepared": True }, { "error": errors.ArgumentParsingError(), -- cgit v1.2.3