From 1ff9aa88628d7c25484da1b85ef4d1eeb0049b63 Mon Sep 17 00:00:00 2001 From: Scragly <29337040+scragly@users.noreply.github.com> Date: Sat, 9 Mar 2019 17:52:23 +1000 Subject: Fix the linting issues with Bot so builds will work. --- tox.ini | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'tox.ini') diff --git a/tox.ini b/tox.ini index c6fa513f4..c84827570 100644 --- a/tox.ini +++ b/tox.ini @@ -2,5 +2,5 @@ max-line-length=120 application_import_names=bot exclude=.cache,.venv -ignore=B311,W503,E226,S311 +ignore=B311,W503,E226,S311,T000 import-order-style=pycharm -- cgit v1.2.3 From 415640933d1b12d932b4c5e1e0c0814f1f8bbdb9 Mon Sep 17 00:00:00 2001 From: sco1 Date: Mon, 9 Sep 2019 21:06:37 -0400 Subject: Update linting dependencies & rules * Add flake8-annotations * Add flake8-docstrings --- Pipfile | 2 ++ Pipfile.lock | 47 ++++++++++++++++++++++++++++++++++++++--------- tox.ini | 16 ++++++++++++++-- 3 files changed, 54 insertions(+), 11 deletions(-) (limited to 'tox.ini') diff --git a/Pipfile b/Pipfile index 2e56a3d7b..1e29bd649 100644 --- a/Pipfile +++ b/Pipfile @@ -22,7 +22,9 @@ urllib3 = ">=1.24.2,<1.25" [dev-packages] flake8 = "~=3.7" +flake8-annotations = "~=1.0" flake8-bugbear = "~=19.8" +flake8-docstrings = "~=1.4" flake8-import-order = "~=0.18" flake8-string-format = "~=0.2" flake8-tidy-imports = "~=2.0" diff --git a/Pipfile.lock b/Pipfile.lock index 6b91ff8aa..e9b64e6cd 100644 --- a/Pipfile.lock +++ b/Pipfile.lock @@ -1,7 +1,7 @@ { "_meta": { "hash": { - "sha256": "61607e940ea00e1197900c04fe1298e048d1f415db2f1a2a3a157406c6ea2b0c" + "sha256": "a953197b27bbc2af413a1ddd465bb95254167e3a0bba525a3ad34ac738dd6ae4" }, "pipfile-spec": 6, "requires": { @@ -18,11 +18,11 @@ "default": { "aio-pika": { "hashes": [ - "sha256:c1424962ef9e28fbda840d76425cdd139605e480a4d68164303cda8d356ba9de", - "sha256:dcfe9c11af2ab9ff6c1c5a366d094c2a7542bab534d98a4aea29518672c9d7ac" + "sha256:31e08189841a8350db5bec70608b4d2fbacb89c0a555a18ec47511716a9bfc41", + "sha256:adfe0acf34356ccd9654a9a1c46f7e8db1dc4497a774c0e54bf2d3af14571bd0" ], "index": "pypi", - "version": "==6.1.0" + "version": "==6.1.1" }, "aiodns": { "hashes": [ @@ -62,10 +62,10 @@ }, "aiormq": { "hashes": [ - "sha256:472734ab3cf18001fb8cedb38ee13008292230a461b6482dbdf65590441ce32c", - "sha256:4b6b2b43616b7a6b353ecf9896ae29ac2f74a38c4c53bfe73824ac2807faca5d" + "sha256:0b755b748d87d5ec63b4b7f162102333bf0901caf1f8a2bf29467bbdd54e637d", + "sha256:f8eef1f98bc331a266404d925745fac589dab30412688564d740754d6d643863" ], - "version": "==2.7.4" + "version": "==2.7.5" }, "alabaster": { "hashes": [ @@ -494,9 +494,9 @@ }, "snowballstemmer": { "hashes": [ - "sha256:9f3b9ffe0809d174f7047e121431acf99c89a7040f0ca84f94ba53a498e6d0c9" + "sha256:713e53b79cbcf97bc5245a06080a33d54a77e7cce2f789c835a143bcdb5c033e" ], - "version": "==1.9.0" + "version": "==1.9.1" }, "soupsieve": { "hashes": [ @@ -692,6 +692,14 @@ "index": "pypi", "version": "==3.7.8" }, + "flake8-annotations": { + "hashes": [ + "sha256:1309f2bc9853a2d77d578b089d331b0b832b40c97932641e136e1b49d3650c82", + "sha256:3ecdd27054c3eed6484139025698465e3c9f4e68dbd5043d0204fcb2550ee27b" + ], + "index": "pypi", + "version": "==1.0.0" + }, "flake8-bugbear": { "hashes": [ "sha256:d8c466ea79d5020cb20bf9f11cf349026e09517a42264f313d3f6fddb83e0571", @@ -700,6 +708,14 @@ "index": "pypi", "version": "==19.8.0" }, + "flake8-docstrings": { + "hashes": [ + "sha256:1666dd069c9c457ee57e80af3c1a6b37b00cc1801c6fde88e455131bb2e186cd", + "sha256:9c0db5a79a1affd70fdf53b8765c8a26bf968e59e0252d7f2fc546b41c0cda06" + ], + "index": "pypi", + "version": "==1.4.0" + }, "flake8-import-order": { "hashes": [ "sha256:90a80e46886259b9c396b578d75c749801a41ee969a235e163cfe1be7afd2543", @@ -809,6 +825,13 @@ ], "version": "==2.5.0" }, + "pydocstyle": { + "hashes": [ + "sha256:04c84e034ebb56eb6396c820442b8c4499ac5eb94a3bda88951ac3dc519b6058", + "sha256:66aff87ffe34b1e49bff2dd03a88ce6843be2f3346b0c9814410d34987fbab59" + ], + "version": "==4.0.1" + }, "pyflakes": { "hashes": [ "sha256:17dbeb2e3f4d772725c777fabc446d5634d1038f234e77343108ce445ea69ce0", @@ -873,6 +896,12 @@ ], "version": "==1.12.0" }, + "snowballstemmer": { + "hashes": [ + "sha256:713e53b79cbcf97bc5245a06080a33d54a77e7cce2f789c835a143bcdb5c033e" + ], + "version": "==1.9.1" + }, "toml": { "hashes": [ "sha256:229f81c57791a41d65e399fc06bf0848bab550a9dfd5ed66df18ce5f05e73d5c", diff --git a/tox.ini b/tox.ini index c84827570..8ff1ff064 100644 --- a/tox.ini +++ b/tox.ini @@ -1,6 +1,18 @@ [flake8] max-line-length=120 application_import_names=bot -exclude=.cache,.venv -ignore=B311,W503,E226,S311,T000 +docstring-convention=all +ignore= + P102,B311,W503,E226,S311,T000 + # Missing Docstrings + D100,D104,D105,D107, + # Docstring Whitespace + D203,D212,D214,D215, + # Docstring Quotes + D301,D302, + # Docstring Content + D400,D401,D402,D404,D405,D406,D407,D408,D409,D410,D411,D412,D413,D414,D416,D417 + # Type Annotations + TYP002,TYP003,TYP101,TYP102,TYP204,TYP206 +exclude=.cache,.venv,tests,constants.py import-order-style=pycharm -- cgit v1.2.3 From 1dd55ae6055bbe320588a7f64de1a2bdd5ebaca3 Mon Sep 17 00:00:00 2001 From: Johannes Christ Date: Sun, 15 Sep 2019 18:07:58 +0200 Subject: Add tests for `bot.cogs.token_remover`. --- tests/cogs/test_token_remover.py | 133 +++++++++++++++++++++++++++++++++++++++ tests/helpers.py | 10 +++ tox.ini | 2 +- 3 files changed, 144 insertions(+), 1 deletion(-) create mode 100644 tests/cogs/test_token_remover.py create mode 100644 tests/helpers.py (limited to 'tox.ini') diff --git a/tests/cogs/test_token_remover.py b/tests/cogs/test_token_remover.py new file mode 100644 index 000000000..9d46b3a05 --- /dev/null +++ b/tests/cogs/test_token_remover.py @@ -0,0 +1,133 @@ +import asyncio +from unittest.mock import MagicMock + +import pytest +from discord import Colour + +from bot.cogs.token_remover import ( + DELETION_MESSAGE_TEMPLATE, + TokenRemover, + setup as setup_cog, +) +from bot.constants import Channels, Colours, Event, Icons +from tests.helpers import AsyncMock + + +@pytest.fixture() +def token_remover(): + bot = MagicMock() + bot.get_cog.return_value = MagicMock() + bot.get_cog.return_value.send_log_message = AsyncMock() + return TokenRemover(bot=bot) + + +@pytest.fixture() +def message(): + message = MagicMock() + message.author.__str__.return_value = 'lemon' + message.author.bot = False + message.author.avatar_url_as.return_value = 'picture-lemon.png' + message.author.id = 42 + message.author.mention = '@lemon' + message.channel.send = AsyncMock() + message.channel.mention = '#lemonade-stand' + message.content = '' + message.delete = AsyncMock() + message.id = 555 + return message + + +@pytest.mark.parametrize( + ('content', 'expected'), + ( + ('MTIz', True), # 123 + ('YWJj', False), # abc + ) +) +def test_is_valid_user_id(content: str, expected: bool): + assert TokenRemover.is_valid_user_id(content) is expected + + +@pytest.mark.parametrize( + ('content', 'expected'), + ( + ('DN9r_A', True), # stolen from dapi, thanks to the author of the 'token' tag! + ('MTIz', False), # 123 + ) +) +def test_is_valid_timestamp(content: str, expected: bool): + assert TokenRemover.is_valid_timestamp(content) is expected + + +def test_mod_log_property(token_remover): + token_remover.bot.get_cog.return_value = 'lemon' + assert token_remover.mod_log == 'lemon' + token_remover.bot.get_cog.assert_called_once_with('ModLog') + + +def test_ignores_bot_messages(token_remover, message): + message.author.bot = True + coroutine = token_remover.on_message(message) + assert asyncio.run(coroutine) is None + + +@pytest.mark.parametrize('content', ('', 'lemon wins')) +def test_ignores_messages_without_tokens(token_remover, message, content): + message.content = content + coroutine = token_remover.on_message(message) + assert asyncio.run(coroutine) is None + + +@pytest.mark.parametrize('content', ('foo.bar.baz', 'x.y.')) +def test_ignores_invalid_tokens(token_remover, message, content): + message.content = content + coroutine = token_remover.on_message(message) + assert asyncio.run(coroutine) is None + + +@pytest.mark.parametrize( + 'content, censored_token', + ( + ('MTIz.DN9R_A.xyz', 'MTIz.DN9R_A.xxx'), + ) +) +def test_censors_valid_tokens( + token_remover, message, content, censored_token, caplog +): + message.content = content + coroutine = token_remover.on_message(message) + assert asyncio.run(coroutine) is None # still no rval + + # asyncio logs some stuff about its reactor, discard it + [_, record] = caplog.records + assert record.message == ( + "Censored a seemingly valid token sent by lemon (`42`) in #lemonade-stand, " + f"token was `{censored_token}`" + ) + + message.delete.assert_called_once_with() + message.channel.send.assert_called_once_with( + DELETION_MESSAGE_TEMPLATE.format(mention='@lemon') + ) + token_remover.bot.get_cog.assert_called_with('ModLog') + message.author.avatar_url_as.assert_called_once_with(static_format='png') + + mod_log = token_remover.bot.get_cog.return_value + mod_log.ignore.assert_called_once_with(Event.message_delete, message.id) + mod_log.send_log_message.assert_called_once_with( + icon_url=Icons.token_removed, + colour=Colour(Colours.soft_red), + title="Token removed!", + text=record.message, + thumbnail='picture-lemon.png', + channel_id=Channels.mod_alerts + ) + + +def test_setup(caplog): + bot = MagicMock() + setup_cog(bot) + [record] = caplog.records + + bot.add_cog.assert_called_once() + assert record.message == "Cog loaded: TokenRemover" diff --git a/tests/helpers.py b/tests/helpers.py new file mode 100644 index 000000000..57c6fcc1a --- /dev/null +++ b/tests/helpers.py @@ -0,0 +1,10 @@ +from unittest.mock import MagicMock + + +__all__ = ('AsyncMock',) + + +# TODO: Remove me on 3.8 +class AsyncMock(MagicMock): + async def __call__(self, *args, **kwargs): + return super(AsyncMock, self).__call__(*args, **kwargs) diff --git a/tox.ini b/tox.ini index c84827570..21097cd97 100644 --- a/tox.ini +++ b/tox.ini @@ -1,6 +1,6 @@ [flake8] max-line-length=120 -application_import_names=bot +application_import_names=bot,tests exclude=.cache,.venv ignore=B311,W503,E226,S311,T000 import-order-style=pycharm -- cgit v1.2.3