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 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 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 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 From ce1fd8e56286300803b6cb10e4e4d4f996733301 Mon Sep 17 00:00:00 2001 From: Shivansh Date: Fri, 7 May 2021 10:42:00 +0530 Subject: (infractions): Modify voice ban tests according to new changes in 3272605 --- tests/bot/exts/moderation/infraction/test_infractions.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'tests') diff --git a/tests/bot/exts/moderation/infraction/test_infractions.py b/tests/bot/exts/moderation/infraction/test_infractions.py index 08f39cd50..b9d527770 100644 --- a/tests/bot/exts/moderation/infraction/test_infractions.py +++ b/tests/bot/exts/moderation/infraction/test_infractions.py @@ -74,7 +74,7 @@ class VoiceBanTests(unittest.IsolatedAsyncioTestCase): """Should call voice ban applying function without expiry.""" self.cog.apply_voice_ban = AsyncMock() self.assertIsNone(await self.cog.voiceban(self.cog, self.ctx, self.user, reason="foobar")) - self.cog.apply_voice_ban.assert_awaited_once_with(self.ctx, self.user, "foobar") + self.cog.apply_voice_ban.assert_awaited_once_with(self.ctx, self.user, "foobar", expires_at=None) async def test_temporary_voice_ban(self): """Should call voice ban applying function with expiry.""" @@ -184,7 +184,7 @@ class VoiceBanTests(unittest.IsolatedAsyncioTestCase): user = MockUser() await self.cog.voiceban(self.cog, self.ctx, user, reason=None) - post_infraction_mock.assert_called_once_with(self.ctx, user, "voice_ban", None, active=True) + post_infraction_mock.assert_called_once_with(self.ctx, user, "voice_ban", None, active=True, expires_at=None) apply_infraction_mock.assert_called_once_with(self.cog, self.ctx, infraction, user, ANY) # Test action -- cgit v1.2.3 From 714f8f8faeee8abc7e6f153cb8cbb64fea1c2eeb Mon Sep 17 00:00:00 2001 From: rohan Date: Mon, 10 May 2021 02:01:16 +0530 Subject: Remove test for un-available function. --- tests/bot/utils/test_time.py | 13 ------------- 1 file changed, 13 deletions(-) (limited to 'tests') diff --git a/tests/bot/utils/test_time.py b/tests/bot/utils/test_time.py index 694d3a40f..115ddfb0d 100644 --- a/tests/bot/utils/test_time.py +++ b/tests/bot/utils/test_time.py @@ -1,7 +1,5 @@ -import asyncio import unittest from datetime import datetime, timezone -from unittest.mock import AsyncMock, patch from dateutil.relativedelta import relativedelta @@ -56,17 +54,6 @@ class TimeTests(unittest.TestCase): """Testing format_infraction.""" self.assertEqual(time.format_infraction('2019-12-12T00:01:00Z'), '2019-12-12 00:01') - @patch('asyncio.sleep', new_callable=AsyncMock) - def test_wait_until(self, mock): - """Testing wait_until.""" - start = datetime(2019, 1, 1, 0, 0) - then = datetime(2019, 1, 1, 0, 10) - - # No return value - self.assertIs(asyncio.run(time.wait_until(then, start)), None) - - mock.assert_called_once_with(10 * 60) - def test_format_infraction_with_duration_none_expiry(self): """format_infraction_with_duration should work for None expiry.""" test_cases = ( -- cgit v1.2.3 From 1db39d0c3cd1c3f4731f4c494a892d15a07f00fe Mon Sep 17 00:00:00 2001 From: Hassan Abouelela Date: Tue, 11 May 2021 20:58:45 +0300 Subject: Updates Usages Of Pipenv To Poetry Updates the Dockerfile, pre-commit, CI, and documentation to reflect the new dependency manager. Dockerfile is also updated to 3.9. Signed-off-by: Hassan Abouelela --- .github/workflows/lint-test.yml | 19 ++++++++----------- .pre-commit-config.yaml | 4 ++-- Dockerfile | 20 +++++++------------- tests/README.md | 10 +++++----- 4 files changed, 22 insertions(+), 31 deletions(-) (limited to 'tests') diff --git a/.github/workflows/lint-test.yml b/.github/workflows/lint-test.yml index 95bed2e14..d96f324ec 100644 --- a/.github/workflows/lint-test.yml +++ b/.github/workflows/lint-test.yml @@ -23,15 +23,12 @@ jobs: PIP_NO_CACHE_DIR: false PIP_USER: 1 - # Hide the graphical elements from pipenv's output - PIPENV_HIDE_EMOJIS: 1 - PIPENV_NOSPIN: 1 - - # Make sure pipenv does not try reuse an environment it's running in - PIPENV_IGNORE_VIRTUALENVS: 1 + # Make sure package manager does not use virtualenv + POETRY_VIRTUALENVS_CREATE: false # Specify explicit paths for python dependencies and the pre-commit # environment so we know which directories to cache + POETRY_CACHE_DIR: ${{ github.workspace }}/.cache/py-user-base PYTHONUSERBASE: ${{ github.workspace }}/.cache/py-user-base PRE_COMMIT_HOME: ${{ github.workspace }}/.cache/pre-commit-cache @@ -46,7 +43,7 @@ jobs: id: python uses: actions/setup-python@v2 with: - python-version: '3.8' + python-version: '3.9' # This step caches our Python dependencies. To make sure we # only restore a cache when the dependencies, the python version, @@ -61,14 +58,14 @@ jobs: path: ${{ env.PYTHONUSERBASE }} key: "python-0-${{ runner.os }}-${{ env.PYTHONUSERBASE }}-\ ${{ steps.python.outputs.python-version }}-\ - ${{ hashFiles('./Pipfile', './Pipfile.lock') }}" + ${{ hashFiles('./pyproject.toml', './poetry.lock') }}" # Install our dependencies if we did not restore a dependency cache - - name: Install dependencies using pipenv + - name: Install dependencies using poetry if: steps.python_cache.outputs.cache-hit != 'true' run: | - pip install pipenv - pipenv install --dev --deploy --system + pip install poetry + poetry install # This step caches our pre-commit environment. To make sure we # do create a new environment when our pre-commit setup changes, diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 52500a282..131ba9453 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -17,8 +17,8 @@ repos: hooks: - id: flake8 name: Flake8 - description: This hook runs flake8 within our project's pipenv environment. - entry: pipenv run flake8 + description: This hook runs flake8 within our project's environment. + entry: poetry run task flake8 language: system types: [python] require_serial: true diff --git a/Dockerfile b/Dockerfile index 1a75e5669..91e9ce18e 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,25 +1,19 @@ -FROM python:3.8-slim +FROM python:3.9.5-slim -# Set pip to have cleaner logs and no saved cache +# Set pip to have no saved cache ENV PIP_NO_CACHE_DIR=false \ - PIPENV_HIDE_EMOJIS=1 \ - PIPENV_IGNORE_VIRTUALENVS=1 \ - PIPENV_NOSPIN=1 + POETRY_VIRTUALENVS_CREATE=false -RUN apt-get -y update \ - && apt-get install -y \ - git \ - && rm -rf /var/lib/apt/lists/* -# Install pipenv -RUN pip install -U pipenv +# Install poetry +RUN pip install -U poetry # Create the working directory WORKDIR /bot # Install project dependencies -COPY Pipfile* ./ -RUN pipenv install --system --deploy +COPY pyproject.toml poetry.lock ./ +RUN poetry install --prod # Define Git SHA build argument ARG git_sha="development" diff --git a/tests/README.md b/tests/README.md index 092324123..1a17c09bd 100644 --- a/tests/README.md +++ b/tests/README.md @@ -12,13 +12,13 @@ We are using the following modules and packages for our unit tests: - [unittest.mock](https://docs.python.org/3/library/unittest.mock.html) (standard library) - [coverage.py](https://coverage.readthedocs.io/en/stable/) -To ensure the results you obtain on your personal machine are comparable to those generated in the Azure pipeline, please make sure to run your tests with the virtual environment defined by our [Pipfile](/Pipfile). To run your tests with `pipenv`, we've provided two "scripts" shortcuts: +To ensure the results you obtain on your personal machine are comparable to those generated in the CI, please make sure to run your tests with the virtual environment defined by our [Poetry Project](/pyproject.toml). To run your tests with `poetry`, we've provided two "scripts" shortcuts: -- `pipenv run test` will run `unittest` with `coverage.py` -- `pipenv run test path/to/test.py` will run a specific test. -- `pipenv run report` will generate a coverage report of the tests you've run with `pipenv run test`. If you append the `-m` flag to this command, the report will include the lines and branches not covered by tests in addition to the test coverage report. +- `poetry run task test` will run `unittest` with `coverage.py` +- `poetry run task test path/to/test.py` will run a specific test. +- `poetry run task report` will generate a coverage report of the tests you've run with `poetry run task test`. If you append the `-m` flag to this command, the report will include the lines and branches not covered by tests in addition to the test coverage report. -If you want a coverage report, make sure to run the tests with `pipenv run test` *first*. +If you want a coverage report, make sure to run the tests with `poetry run task test` *first*. ## Writing tests -- cgit v1.2.3