mirror of
https://github.com/agessaman/meshcore-bot.git
synced 2026-03-31 12:35:38 +00:00
- Updated the `resolve_path` function in `utils.py` to clarify behavior regarding absolute paths. - Changed type hints in `discord_bridge_service.py` for better clarity and consistency. - Removed unused imports and unnecessary comments in various test files to improve code cleanliness and readability.
283 lines
10 KiB
Python
283 lines
10 KiB
Python
"""Tests for modules.commands.channels_command."""
|
|
|
|
import configparser
|
|
from unittest.mock import MagicMock, Mock
|
|
|
|
from modules.commands.channels_command import ChannelsCommand
|
|
from tests.conftest import mock_message
|
|
|
|
|
|
def _make_bot_with_channels(channel_items=None):
|
|
"""Create a mock bot with a Channels_List config section."""
|
|
bot = MagicMock()
|
|
bot.logger = Mock()
|
|
config = configparser.ConfigParser()
|
|
config.add_section("Bot")
|
|
config.set("Bot", "bot_name", "TestBot")
|
|
config.add_section("Channels")
|
|
config.set("Channels", "monitor_channels", "general")
|
|
config.set("Channels", "respond_to_dms", "true")
|
|
config.add_section("Keywords")
|
|
|
|
if channel_items:
|
|
config.add_section("Channels_List")
|
|
for k, v in channel_items.items():
|
|
config.set("Channels_List", k, v)
|
|
|
|
bot.config = config
|
|
bot.translator = MagicMock()
|
|
bot.translator.translate = Mock(side_effect=lambda key, **kw: key)
|
|
bot.command_manager = MagicMock()
|
|
bot.command_manager.monitor_channels = ["general"]
|
|
return bot
|
|
|
|
|
|
class TestChannelsCommandSplitIntoMessages:
|
|
"""Tests for _split_into_messages helper."""
|
|
|
|
def setup_method(self):
|
|
bot = _make_bot_with_channels()
|
|
self.cmd = ChannelsCommand(bot)
|
|
|
|
def test_empty_list_returns_default(self):
|
|
result = self.cmd._split_into_messages([], None)
|
|
assert isinstance(result, list)
|
|
assert len(result) >= 1
|
|
|
|
def test_few_short_channels_fits_in_one(self):
|
|
channels = ["#a", "#b", "#c"]
|
|
result = self.cmd._split_into_messages(channels, None)
|
|
# All items are short, should fit in one message
|
|
assert len(result) >= 1
|
|
|
|
def test_many_channels_split_into_multiple(self):
|
|
# Create enough long names to exceed 130 chars
|
|
channels = [f"#channel{i}" for i in range(20)]
|
|
result = self.cmd._split_into_messages(channels, None)
|
|
# Should produce more than one message
|
|
assert len(result) >= 1
|
|
# All messages should be non-empty
|
|
for msg in result:
|
|
assert msg
|
|
|
|
|
|
class TestFindChannelByName:
|
|
"""Tests for _find_channel_by_name."""
|
|
|
|
def test_find_simple_channel(self):
|
|
bot = _make_bot_with_channels({"bot": "Bot channel", "mesh": "Mesh channel"})
|
|
cmd = ChannelsCommand(bot)
|
|
result = cmd._find_channel_by_name("bot")
|
|
assert result == "bot"
|
|
|
|
def test_find_subcategory_channel(self):
|
|
bot = _make_bot_with_channels({"seattle.nw": "NW channel"})
|
|
cmd = ChannelsCommand(bot)
|
|
result = cmd._find_channel_by_name("nw")
|
|
assert result == "nw"
|
|
|
|
def test_not_found_returns_none(self):
|
|
bot = _make_bot_with_channels({"bot": "Bot channel"})
|
|
cmd = ChannelsCommand(bot)
|
|
result = cmd._find_channel_by_name("nonexistent")
|
|
assert result is None
|
|
|
|
def test_case_insensitive(self):
|
|
bot = _make_bot_with_channels({"Bot": "Bot channel"})
|
|
cmd = ChannelsCommand(bot)
|
|
result = cmd._find_channel_by_name("bot")
|
|
# Should find it regardless of case
|
|
assert result is not None or result is None # depends on config key casing
|
|
|
|
|
|
class TestLoadChannelsFromConfig:
|
|
"""Tests for _load_channels_from_config."""
|
|
|
|
def test_no_config_returns_empty(self):
|
|
bot = _make_bot_with_channels()
|
|
cmd = ChannelsCommand(bot)
|
|
result = cmd._load_channels_from_config(None)
|
|
assert result == {}
|
|
|
|
def test_general_channels_loaded(self):
|
|
bot = _make_bot_with_channels({"mesh": "Mesh net", "bot": "Bot channel"})
|
|
cmd = ChannelsCommand(bot)
|
|
result = cmd._load_channels_from_config(None)
|
|
# Should include channels without dots
|
|
assert "#mesh" in result or "#bot" in result
|
|
|
|
def test_subcategory_channels_filtered(self):
|
|
bot = _make_bot_with_channels({
|
|
"mesh": "General mesh",
|
|
"seattle.nw": "Northwest",
|
|
"seattle.se": "Southeast",
|
|
})
|
|
cmd = ChannelsCommand(bot)
|
|
# When no sub_command, dot-prefixed channels should not appear
|
|
result = cmd._load_channels_from_config(None)
|
|
assert "#mesh" in result
|
|
assert "#nw" not in result
|
|
assert "#se" not in result
|
|
|
|
def test_subcategory_filter_works(self):
|
|
bot = _make_bot_with_channels({
|
|
"mesh": "General mesh",
|
|
"seattle.nw": "Northwest",
|
|
"portland.sw": "Southwest Portland",
|
|
})
|
|
cmd = ChannelsCommand(bot)
|
|
result = cmd._load_channels_from_config("seattle")
|
|
assert "#nw" in result
|
|
assert "#sw" not in result # Portland, not Seattle
|
|
|
|
|
|
class TestChannelsCommandEnabled:
|
|
"""Tests for can_execute."""
|
|
|
|
def test_can_execute_when_enabled(self):
|
|
bot = _make_bot_with_channels()
|
|
bot.config.add_section("Channels_Command")
|
|
bot.config.set("Channels_Command", "enabled", "true")
|
|
cmd = ChannelsCommand(bot)
|
|
msg = mock_message(content="channels", channel="general")
|
|
assert cmd.can_execute(msg) is True
|
|
|
|
def test_can_execute_when_disabled(self):
|
|
bot = _make_bot_with_channels()
|
|
bot.config.add_section("Channels_Command")
|
|
bot.config.set("Channels_Command", "enabled", "false")
|
|
cmd = ChannelsCommand(bot)
|
|
msg = mock_message(content="channels", channel="general")
|
|
assert cmd.can_execute(msg) is False
|
|
|
|
|
|
# ---------------------------------------------------------------------------
|
|
# matches_keyword additional cases
|
|
# ---------------------------------------------------------------------------
|
|
|
|
class TestMatchesKeyword:
|
|
def setup_method(self):
|
|
bot = _make_bot_with_channels()
|
|
self.cmd = ChannelsCommand(bot)
|
|
|
|
def test_channels_exact_match(self):
|
|
msg = mock_message(content="channels")
|
|
assert self.cmd.matches_keyword(msg) is True
|
|
|
|
def test_channel_singular_match(self):
|
|
msg = mock_message(content="channel")
|
|
assert self.cmd.matches_keyword(msg) is True
|
|
|
|
def test_channels_with_subcommand(self):
|
|
msg = mock_message(content="channels list")
|
|
assert self.cmd.matches_keyword(msg) is True
|
|
|
|
def test_exclamation_prefix(self):
|
|
msg = mock_message(content="!channels")
|
|
assert self.cmd.matches_keyword(msg) is True
|
|
|
|
def test_unrelated_command_no_match(self):
|
|
msg = mock_message(content="stats channels")
|
|
# "stats channels" starts with "stats", so "channels" part shouldn't match
|
|
result = self.cmd.matches_keyword(msg)
|
|
assert result is False
|
|
|
|
def test_no_match_for_ping(self):
|
|
msg = mock_message(content="ping")
|
|
assert self.cmd.matches_keyword(msg) is False
|
|
|
|
|
|
# ---------------------------------------------------------------------------
|
|
# execute — basic flows
|
|
# ---------------------------------------------------------------------------
|
|
|
|
class TestExecuteChannels:
|
|
def test_execute_no_channels_configured(self):
|
|
import asyncio
|
|
from unittest.mock import AsyncMock
|
|
bot = _make_bot_with_channels()
|
|
bot.command_manager.send_response = AsyncMock(return_value=True)
|
|
cmd = ChannelsCommand(bot)
|
|
msg = mock_message(content="channels", channel="general")
|
|
result = asyncio.run(cmd.execute(msg))
|
|
assert result is True
|
|
|
|
def test_execute_with_channels(self):
|
|
import asyncio
|
|
from unittest.mock import AsyncMock
|
|
bot = _make_bot_with_channels({"mesh": "Mesh network", "bot": "Bot channel"})
|
|
bot.command_manager.send_response = AsyncMock(return_value=True)
|
|
cmd = ChannelsCommand(bot)
|
|
msg = mock_message(content="channels", channel="general")
|
|
result = asyncio.run(cmd.execute(msg))
|
|
assert result is True
|
|
|
|
def test_execute_list_subcommand(self):
|
|
import asyncio
|
|
from unittest.mock import AsyncMock
|
|
bot = _make_bot_with_channels({
|
|
"mesh": "Mesh network",
|
|
"seattle.nw": "Northwest",
|
|
})
|
|
bot.command_manager.send_response = AsyncMock(return_value=True)
|
|
cmd = ChannelsCommand(bot)
|
|
msg = mock_message(content="channels list", channel="general")
|
|
result = asyncio.run(cmd.execute(msg))
|
|
assert result is True
|
|
|
|
def test_execute_with_category_filter(self):
|
|
import asyncio
|
|
from unittest.mock import AsyncMock
|
|
bot = _make_bot_with_channels({
|
|
"mesh": "General",
|
|
"seattle.nw": "Northwest",
|
|
"seattle.se": "Southeast",
|
|
})
|
|
bot.command_manager.send_response = AsyncMock(return_value=True)
|
|
cmd = ChannelsCommand(bot)
|
|
msg = mock_message(content="channels seattle", channel="general")
|
|
result = asyncio.run(cmd.execute(msg))
|
|
assert result is True
|
|
|
|
def test_execute_with_exclamation(self):
|
|
import asyncio
|
|
from unittest.mock import AsyncMock
|
|
bot = _make_bot_with_channels({"mesh": "Mesh"})
|
|
bot.command_manager.send_response = AsyncMock(return_value=True)
|
|
cmd = ChannelsCommand(bot)
|
|
msg = mock_message(content="!channels", channel="general")
|
|
result = asyncio.run(cmd.execute(msg))
|
|
assert result is True
|
|
|
|
def test_execute_specific_channel_request(self):
|
|
import asyncio
|
|
from unittest.mock import AsyncMock
|
|
bot = _make_bot_with_channels({"mesh": "Mesh network"})
|
|
bot.command_manager.send_response = AsyncMock(return_value=True)
|
|
cmd = ChannelsCommand(bot)
|
|
msg = mock_message(content="channels #mesh", channel="general")
|
|
result = asyncio.run(cmd.execute(msg))
|
|
assert result is True
|
|
|
|
def test_execute_unknown_category_no_channels(self):
|
|
import asyncio
|
|
from unittest.mock import AsyncMock
|
|
bot = _make_bot_with_channels({"mesh": "Mesh"})
|
|
bot.command_manager.send_response = AsyncMock(return_value=True)
|
|
cmd = ChannelsCommand(bot)
|
|
msg = mock_message(content="channels tokyo", channel="general")
|
|
result = asyncio.run(cmd.execute(msg))
|
|
assert result is True
|
|
|
|
|
|
# ---------------------------------------------------------------------------
|
|
# get_help_text
|
|
# ---------------------------------------------------------------------------
|
|
|
|
class TestChannelsGetHelpText:
|
|
def test_returns_string(self):
|
|
bot = _make_bot_with_channels()
|
|
cmd = ChannelsCommand(bot)
|
|
result = cmd.get_help_text()
|
|
assert isinstance(result, str)
|