Files
derp/tests/test_chanmgmt.py
user 7606280358 fix: repair broken tests across alert, chanmgmt, and integration
- test_alert: remove stale _MAX_ANNOUNCE import/test, update _errors
  assertions for per-backend dict, fix announcement checks (action vs
  send), mock _fetch_og_batch in seeding tests, fix YouTube/SearX mock
  targets (urllib.request.urlopen), include keyword in fake data titles
- test_chanmgmt: add _FakeState to _FakeBot (on_invite now persists)
- test_integration: update help assertion for new output format

696 tests pass, 0 failures.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-17 21:14:44 +01:00

103 lines
2.8 KiB
Python

"""Tests for the chanmgmt plugin (invite-join)."""
import asyncio
import importlib.util
import sys
from pathlib import Path
from derp.irc import Message
# plugins/ is not a Python package -- load the module from file path
_spec = importlib.util.spec_from_file_location(
"plugins.chanmgmt",
Path(__file__).resolve().parent.parent / "plugins" / "chanmgmt.py",
)
_mod = importlib.util.module_from_spec(_spec)
sys.modules[_spec.name] = _mod
_spec.loader.exec_module(_mod)
from plugins.chanmgmt import on_invite # noqa: E402 # isort: skip
# -- Helpers -----------------------------------------------------------------
class _FakeConn:
"""Minimal connection stand-in."""
def __init__(self):
self.sent: list[str] = []
async def send(self, raw: str) -> None:
self.sent.append(raw)
class _FakeState:
"""In-memory stand-in for bot.state."""
def __init__(self):
self._store: dict[str, dict[str, str]] = {}
def get(self, plugin: str, key: str, default: str | None = None) -> str | None:
return self._store.get(plugin, {}).get(key, default)
def set(self, plugin: str, key: str, value: str) -> None:
self._store.setdefault(plugin, {})[key] = value
def delete(self, plugin: str, key: str) -> bool:
try:
del self._store[plugin][key]
return True
except KeyError:
return False
class _FakeBot:
"""Minimal bot stand-in."""
def __init__(self, *, admin: bool = False):
self.joined: list[str] = []
self._admin = admin
self.conn = _FakeConn()
self.state = _FakeState()
def _is_admin(self, message) -> bool:
return self._admin
async def join(self, channel: str) -> None:
self.joined.append(channel)
def _invite(nick: str, channel: str) -> Message:
"""Create an INVITE message: :nick!user@host INVITE botname #channel."""
return Message(
raw="",
prefix=f"{nick}!~{nick}@host",
nick=nick,
command="INVITE",
params=["derp", channel],
tags={},
)
# -- Tests -------------------------------------------------------------------
class TestOnInvite:
def test_admin_joins(self):
bot = _FakeBot(admin=True)
asyncio.run(on_invite(bot, _invite("oper", "#secret")))
assert "#secret" in bot.joined
def test_non_admin_ignored(self):
bot = _FakeBot(admin=False)
asyncio.run(on_invite(bot, _invite("rando", "#trap")))
assert bot.joined == []
def test_missing_channel_ignored(self):
bot = _FakeBot(admin=True)
msg = Message(
raw="", prefix="oper!~oper@host", nick="oper",
command="INVITE", params=["derp"], tags={},
)
asyncio.run(on_invite(bot, msg))
assert bot.joined == []