"""Tests for the Mumble adapter.""" import asyncio import struct from unittest.mock import AsyncMock, MagicMock, patch from derp.mumble import ( MumbleBot, MumbleMessage, _escape_html, _scale_pcm, _scale_pcm_ramp, _shell_quote, _strip_html, ) from derp.plugin import PluginRegistry # -- Helpers ----------------------------------------------------------------- def _make_bot(admins=None, operators=None, trusted=None, prefix=None): """Create a MumbleBot with test config.""" config = { "mumble": { "enabled": True, "host": "127.0.0.1", "port": 64738, "username": "derp", "password": "", "admins": admins or [], "operators": operators or [], "trusted": trusted or [], }, "bot": { "prefix": prefix or "!", "paste_threshold": 4, "plugins_dir": "plugins", "rate_limit": 2.0, "rate_burst": 5, }, } registry = PluginRegistry() bot = MumbleBot("mu-test", config, registry) return bot def _mu_msg(text="!ping", nick="Alice", prefix="Alice", target="0", is_channel=True): """Create a MumbleMessage for command testing.""" return MumbleMessage( raw={}, nick=nick, prefix=prefix, text=text, target=target, is_channel=is_channel, params=[target, text], ) # -- Test helpers for registering commands ----------------------------------- async def _echo_handler(bot, msg): """Simple command handler that echoes text.""" args = msg.text.split(None, 1) reply = args[1] if len(args) > 1 else "no args" await bot.reply(msg, reply) async def _admin_handler(bot, msg): """Admin-only command handler.""" await bot.reply(msg, "admin action done") # --------------------------------------------------------------------------- # TestMumbleMessage # --------------------------------------------------------------------------- class TestMumbleMessage: def test_defaults(self): msg = MumbleMessage(raw={}, nick=None, prefix=None, text=None, target=None) assert msg.is_channel is True assert msg.command == "PRIVMSG" assert msg.params == [] assert msg.tags == {} def test_custom_values(self): msg = MumbleMessage( raw={"field": 1}, nick="Alice", prefix="Alice", text="hello", target="0", is_channel=True, command="PRIVMSG", params=["0", "hello"], tags={"key": "val"}, ) assert msg.nick == "Alice" assert msg.prefix == "Alice" assert msg.text == "hello" assert msg.target == "0" assert msg.tags == {"key": "val"} def test_duck_type_compat(self): """MumbleMessage has the same attribute names as IRC Message.""" msg = _mu_msg() attrs = ["raw", "nick", "prefix", "text", "target", "is_channel", "command", "params", "tags"] for attr in attrs: assert hasattr(msg, attr), f"missing attribute: {attr}" def test_dm_message(self): msg = _mu_msg(target="dm", is_channel=False) assert msg.is_channel is False assert msg.target == "dm" def test_prefix_is_username(self): msg = _mu_msg(prefix="admin_user") assert msg.prefix == "admin_user" # --------------------------------------------------------------------------- # TestHtmlHelpers # --------------------------------------------------------------------------- class TestHtmlHelpers: def test_strip_html_simple(self): assert _strip_html("bold") == "bold" def test_strip_html_entities(self): assert _strip_html("& < > "") == '& < > "' def test_strip_html_nested(self): assert _strip_html("
hello world
") == "hello world" def test_strip_html_plain(self): assert _strip_html("no tags here") == "no tags here" def test_escape_html(self): assert _escape_html("