aboutsummaryrefslogtreecommitdiffstats
path: root/tests/test_converters.py
diff options
context:
space:
mode:
authorGravatar Sebastiaan Zeeff <[email protected]>2019-09-23 21:13:47 +0200
committerGravatar Sebastiaan Zeeff <[email protected]>2019-09-23 21:31:19 +0200
commitfba165037943fda90039ec9cadf0649cfae0e781 (patch)
tree4469b2b431316ca7e4829fdbc21aeb52844eba0d /tests/test_converters.py
parentMake DEFCON days subcommand enable DEFCON (#405) (diff)
Fix failing duration conversion
https://github.com/python-discord/bot/issues/446 The current ExpirationDate converter does not convert duration strings to `datetime.datetime` objects correctly. To remedy the problem, I've written a new Duration converter that uses regex matching to extract the relevant duration units and `dateutil.relativedelta.relativedelta` to compute a `datetime.datetime` that's the given duration in the future. I've left the old `ExpirationDate` converter in place for now, since the new Duration converter may not be the most optimal method. However, given the importance of being able to convert durations for moderation tasks, I think it's better to implement Duration now and rethink the approach later. This commit closes #446
Diffstat (limited to 'tests/test_converters.py')
-rw-r--r--tests/test_converters.py82
1 files changed, 78 insertions, 4 deletions
diff --git a/tests/test_converters.py b/tests/test_converters.py
index 3cf774c80..3cf00035f 100644
--- a/tests/test_converters.py
+++ b/tests/test_converters.py
@@ -1,11 +1,12 @@
import asyncio
-from datetime import datetime
-from unittest.mock import MagicMock
+import datetime
+from unittest.mock import MagicMock, patch
import pytest
from discord.ext.commands import BadArgument
from bot.converters import (
+ Duration,
ExpirationDate,
TagContentConverter,
TagNameConverter,
@@ -17,10 +18,10 @@ from bot.converters import (
('value', 'expected'),
(
# sorry aliens
- ('2199-01-01T00:00:00', datetime(2199, 1, 1)),
+ ('2199-01-01T00:00:00', datetime.datetime(2199, 1, 1)),
)
)
-def test_expiration_date_converter_for_valid(value: str, expected: datetime):
+def test_expiration_date_converter_for_valid(value: str, expected: datetime.datetime):
converter = ExpirationDate()
assert asyncio.run(converter.convert(None, value)) == expected
@@ -91,3 +92,76 @@ def test_valid_python_identifier_for_valid(value: str):
def test_valid_python_identifier_for_invalid(value: str):
with pytest.raises(BadArgument, match=f'`{value}` is not a valid Python identifier'):
asyncio.run(ValidPythonIdentifier.convert(None, value))
+
+
+FIXED_UTC_NOW = datetime.datetime.fromisoformat('2019-01-01T00:00:00')
+
+
+ ('duration', 'expected'),
+ (
+ # Simple duration strings
+ ('1Y', datetime.datetime.fromisoformat('2020-01-01T00:00:00')),
+ ('1y', datetime.datetime.fromisoformat('2020-01-01T00:00:00')),
+ ('1year', datetime.datetime.fromisoformat('2020-01-01T00:00:00')),
+ ('1years', datetime.datetime.fromisoformat('2020-01-01T00:00:00')),
+ ('1m', datetime.datetime.fromisoformat('2019-02-01T00:00:00')),
+ ('1month', datetime.datetime.fromisoformat('2019-02-01T00:00:00')),
+ ('1months', datetime.datetime.fromisoformat('2019-02-01T00:00:00')),
+ ('1w', datetime.datetime.fromisoformat('2019-01-08T00:00:00')),
+ ('1W', datetime.datetime.fromisoformat('2019-01-08T00:00:00')),
+ ('1week', datetime.datetime.fromisoformat('2019-01-08T00:00:00')),
+ ('1weeks', datetime.datetime.fromisoformat('2019-01-08T00:00:00')),
+ ('1d', datetime.datetime.fromisoformat('2019-01-02T00:00:00')),
+ ('1D', datetime.datetime.fromisoformat('2019-01-02T00:00:00')),
+ ('1day', datetime.datetime.fromisoformat('2019-01-02T00:00:00')),
+ ('1days', datetime.datetime.fromisoformat('2019-01-02T00:00:00')),
+ ('1h', datetime.datetime.fromisoformat('2019-01-01T01:00:00')),
+ ('1H', datetime.datetime.fromisoformat('2019-01-01T01:00:00')),
+ ('1hour', datetime.datetime.fromisoformat('2019-01-01T01:00:00')),
+ ('1hours', datetime.datetime.fromisoformat('2019-01-01T01:00:00')),
+ ('1M', datetime.datetime.fromisoformat('2019-01-01T00:01:00')),
+ ('1minute', datetime.datetime.fromisoformat('2019-01-01T00:01:00')),
+ ('1minutes', datetime.datetime.fromisoformat('2019-01-01T00:01:00')),
+ ('1s', datetime.datetime.fromisoformat('2019-01-01T00:00:01')),
+ ('1S', datetime.datetime.fromisoformat('2019-01-01T00:00:01')),
+ ('1second', datetime.datetime.fromisoformat('2019-01-01T00:00:01')),
+ ('1seconds', datetime.datetime.fromisoformat('2019-01-01T00:00:01')),
+
+ # Complex duration strings
+ ('1y1m1w1d1H1M1S', datetime.datetime.fromisoformat('2020-02-09T01:01:01')),
+ ('5y100S', datetime.datetime.fromisoformat('2024-01-01T00:01:40')),
+ ('2w28H', datetime.datetime.fromisoformat('2019-01-16T04:00:00')),
+ )
+)
+def test_duration_converter_for_valid(duration: str, expected: datetime):
+ converter = Duration()
+
+ with patch('bot.converters.datetime') as mock_datetime:
+ mock_datetime.utcnow.return_value = FIXED_UTC_NOW
+ assert asyncio.run(converter.convert(None, duration)) == expected
+
+
+ ('duration'),
+ (
+ # Units in wrong order
+ ('1d1w'),
+ ('1s1y'),
+
+ # Unknown substrings
+ ('1MVes'),
+ ('1y3breads'),
+
+ # Missing amount
+ ('ym'),
+
+ # Garbage
+ ('Guido van Rossum'),
+ ('lemon lemon lemon lemon lemon lemon lemon'),
+ )
+)
+def test_duration_converter_for_invalid(duration: str):
+ converter = Duration()
+ with pytest.raises(BadArgument, match=f'`{duration}` is not a valid duration string.'):
+ asyncio.run(converter.convert(None, duration))