Files
derp/tests/test_remind.py
user 70d203f96e feat: add remind plugin with one-shot and repeating reminders
Supports duration parsing (5m, 1h30m, 2d12h), short hex IDs for
tracking, list/cancel subcommands, and repeating intervals via
`!remind every <duration> <text>`. Includes 23 unit tests.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-15 12:09:34 +01:00

105 lines
2.7 KiB
Python

"""Tests for the remind plugin."""
import importlib.util
import sys
from pathlib import Path
# plugins/ is not a Python package -- load the module from file path
_spec = importlib.util.spec_from_file_location(
"plugins.remind", Path(__file__).resolve().parent.parent / "plugins" / "remind.py",
)
_mod = importlib.util.module_from_spec(_spec)
sys.modules[_spec.name] = _mod
_spec.loader.exec_module(_mod)
from plugins.remind import ( # noqa: E402
_format_duration,
_make_id,
_parse_duration,
)
class TestParseDurationRawSeconds:
def test_positive_integer(self):
assert _parse_duration("60") == 60
def test_zero_returns_none(self):
assert _parse_duration("0") is None
def test_negative_returns_none(self):
assert _parse_duration("-5") is None
def test_large_value(self):
assert _parse_duration("86400") == 86400
class TestParseDurationSpecs:
def test_minutes(self):
assert _parse_duration("5m") == 300
def test_hours_and_minutes(self):
assert _parse_duration("1h30m") == 5400
def test_days(self):
assert _parse_duration("2d") == 172800
def test_seconds_suffix(self):
assert _parse_duration("90s") == 90
def test_full_combo(self):
assert _parse_duration("1d12h30m15s") == 131415
class TestParseDurationInvalid:
def test_empty_string(self):
assert _parse_duration("") is None
def test_letters_only(self):
assert _parse_duration("abc") is None
def test_all_zeros(self):
assert _parse_duration("0m0s") is None
class TestParseDurationEdgeCases:
def test_uppercase_works(self):
assert _parse_duration("5M") == 300
def test_hours_with_zero_minutes(self):
assert _parse_duration("1h0m") == 3600
def test_all_zeros_except_one_second(self):
assert _parse_duration("0d0h0m1s") == 1
class TestFormatDuration:
def test_minutes_and_seconds(self):
assert _format_duration(90) == "1m30s"
def test_exact_hour(self):
assert _format_duration(3600) == "1h"
def test_exact_day(self):
assert _format_duration(86400) == "1d"
def test_zero(self):
assert _format_duration(0) == "0s"
def test_full_combo(self):
assert _format_duration(90061) == "1d1h1m1s"
def test_seconds_only(self):
assert _format_duration(45) == "45s"
class TestMakeId:
def test_returns_six_char_hex(self):
rid = _make_id("user", "check oven")
assert len(rid) == 6
assert all(c in "0123456789abcdef" for c in rid)
def test_different_inputs_differ(self):
rid1 = _make_id("alice", "task one")
rid2 = _make_id("bob", "task two")
assert rid1 != rid2