mirror of
https://github.com/agessaman/meshcore-bot.git
synced 2026-03-31 04:25:39 +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.
226 lines
7.8 KiB
Python
226 lines
7.8 KiB
Python
"""Tests for modules.commands.dadjoke_command — pure logic functions."""
|
|
|
|
import configparser
|
|
from unittest.mock import MagicMock, Mock
|
|
|
|
from modules.commands.dadjoke_command import DadJokeCommand
|
|
from tests.conftest import mock_message
|
|
|
|
|
|
def _make_bot():
|
|
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")
|
|
config.add_section("DadJoke_Command")
|
|
config.set("DadJoke_Command", "enabled", "true")
|
|
config.set("DadJoke_Command", "long_jokes", "false")
|
|
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 TestFormatDadJoke:
|
|
"""Tests for format_dad_joke."""
|
|
|
|
def setup_method(self):
|
|
self.cmd = DadJokeCommand(_make_bot())
|
|
|
|
def test_formats_joke_with_emoji(self):
|
|
data = {"joke": "Why did the chicken cross the road?"}
|
|
result = self.cmd.format_dad_joke(data)
|
|
assert result.startswith("🥸")
|
|
assert "chicken" in result
|
|
|
|
def test_empty_joke_returns_fallback(self):
|
|
data = {"joke": ""}
|
|
result = self.cmd.format_dad_joke(data)
|
|
assert "🥸" in result
|
|
|
|
def test_missing_joke_key_returns_fallback(self):
|
|
data = {}
|
|
result = self.cmd.format_dad_joke(data)
|
|
assert "🥸" in result
|
|
|
|
|
|
class TestSplitDadJoke:
|
|
"""Tests for split_dad_joke."""
|
|
|
|
def setup_method(self):
|
|
self.cmd = DadJokeCommand(_make_bot())
|
|
|
|
def test_splits_at_period(self):
|
|
joke = "🥸 Why did the chicken cross? It was there. The other side was better."
|
|
result = self.cmd.split_dad_joke(joke)
|
|
assert len(result) == 2
|
|
assert result[0] and result[1]
|
|
|
|
def test_splits_at_question_mark(self):
|
|
joke = "🥸 Why did the chicken cross the road? To get to the other side!"
|
|
result = self.cmd.split_dad_joke(joke)
|
|
assert len(result) == 2
|
|
|
|
def test_each_part_has_emoji(self):
|
|
joke = "🥸 Part one sentence here. Part two sentence continues."
|
|
result = self.cmd.split_dad_joke(joke)
|
|
for part in result:
|
|
assert "🥸" in part
|
|
|
|
def test_no_split_point_splits_at_midpoint(self):
|
|
# Joke with no punctuation split points
|
|
joke = "🥸 abcdefghijklmnopqrstuvwxyz abcdefghijklmnopqrstuvwxyz"
|
|
result = self.cmd.split_dad_joke(joke)
|
|
assert len(result) == 2
|
|
|
|
def test_short_joke_without_emoji(self):
|
|
joke = "Why did the chicken cross the road? To get to the other side!"
|
|
result = self.cmd.split_dad_joke(joke)
|
|
assert len(result) == 2
|
|
|
|
|
|
class TestDadJokeLength:
|
|
"""Tests for length-based behavior."""
|
|
|
|
def setup_method(self):
|
|
self.cmd = DadJokeCommand(_make_bot())
|
|
|
|
def test_short_joke_fits_in_130(self):
|
|
data = {"joke": "Why? Because!"}
|
|
text = self.cmd.format_dad_joke(data)
|
|
assert len(text) <= 130
|
|
|
|
def test_long_joke_exceeds_130(self):
|
|
long_joke = "a" * 200
|
|
data = {"joke": long_joke}
|
|
text = self.cmd.format_dad_joke(data)
|
|
assert len(text) > 130
|
|
|
|
|
|
class TestDadJokeMatchesKeyword:
|
|
"""Tests for matches_keyword."""
|
|
|
|
def setup_method(self):
|
|
self.cmd = DadJokeCommand(_make_bot())
|
|
|
|
def test_dadjoke_matches(self):
|
|
msg = mock_message(content="dadjoke")
|
|
assert self.cmd.matches_keyword(msg) is True
|
|
|
|
def test_dad_joke_matches(self):
|
|
msg = mock_message(content="dad joke")
|
|
assert self.cmd.matches_keyword(msg) is True
|
|
|
|
def test_other_does_not_match(self):
|
|
msg = mock_message(content="joke")
|
|
assert self.cmd.matches_keyword(msg) is False
|
|
|
|
def test_exclamation_prefix_handled(self):
|
|
msg = mock_message(content="!dadjoke")
|
|
assert self.cmd.matches_keyword(msg) is True
|
|
|
|
|
|
class TestDadJokeCanExecute:
|
|
def test_enabled_can_execute(self):
|
|
cmd = DadJokeCommand(_make_bot())
|
|
msg = mock_message(content="dadjoke", channel="general")
|
|
assert cmd.can_execute(msg) is True
|
|
|
|
def test_disabled_cannot_execute(self):
|
|
bot = _make_bot()
|
|
bot.config.set("DadJoke_Command", "enabled", "false")
|
|
cmd = DadJokeCommand(bot)
|
|
cmd.dadjoke_enabled = False
|
|
msg = mock_message(content="dadjoke", channel="general")
|
|
assert cmd.can_execute(msg) is False
|
|
|
|
|
|
class TestDadJokeGetHelpText:
|
|
def test_returns_usage_string(self):
|
|
cmd = DadJokeCommand(_make_bot())
|
|
result = cmd.get_help_text()
|
|
assert "dadjoke" in result.lower() or "Usage" in result
|
|
|
|
|
|
class TestDadJokeExecute:
|
|
def test_execute_returns_true_with_joke(self):
|
|
import asyncio
|
|
from unittest.mock import AsyncMock, patch
|
|
|
|
bot = _make_bot()
|
|
bot.command_manager.send_response = AsyncMock(return_value=True)
|
|
cmd = DadJokeCommand(bot)
|
|
msg = mock_message(content="dadjoke", channel="general")
|
|
|
|
with patch.object(cmd, "get_dad_joke_with_length_handling", new_callable=AsyncMock,
|
|
return_value={"joke": "Why did the chicken cross? Because!"}):
|
|
result = asyncio.run(cmd.execute(msg))
|
|
assert result is True
|
|
|
|
def test_execute_returns_true_when_no_joke(self):
|
|
import asyncio
|
|
from unittest.mock import AsyncMock, patch
|
|
|
|
bot = _make_bot()
|
|
bot.command_manager.send_response = AsyncMock(return_value=True)
|
|
cmd = DadJokeCommand(bot)
|
|
msg = mock_message(content="dadjoke", channel="general")
|
|
|
|
with patch.object(cmd, "get_dad_joke_with_length_handling", new_callable=AsyncMock,
|
|
return_value=None):
|
|
result = asyncio.run(cmd.execute(msg))
|
|
assert result is True
|
|
bot.command_manager.send_response.assert_called_once()
|
|
|
|
def test_execute_handles_exception(self):
|
|
import asyncio
|
|
from unittest.mock import AsyncMock, patch
|
|
|
|
bot = _make_bot()
|
|
bot.command_manager.send_response = AsyncMock(return_value=True)
|
|
cmd = DadJokeCommand(bot)
|
|
msg = mock_message(content="dadjoke", channel="general")
|
|
|
|
with patch.object(cmd, "get_dad_joke_with_length_handling", new_callable=AsyncMock,
|
|
side_effect=Exception("API error")):
|
|
result = asyncio.run(cmd.execute(msg))
|
|
assert result is True
|
|
|
|
|
|
class TestSendDadJokeWithLengthHandling:
|
|
def test_short_joke_sends_single_message(self):
|
|
import asyncio
|
|
from unittest.mock import AsyncMock
|
|
|
|
bot = _make_bot()
|
|
bot.command_manager.send_response = AsyncMock(return_value=True)
|
|
cmd = DadJokeCommand(bot)
|
|
msg = mock_message(content="dadjoke")
|
|
|
|
joke_data = {"joke": "Short joke!"}
|
|
asyncio.run(cmd.send_dad_joke_with_length_handling(msg, joke_data))
|
|
bot.command_manager.send_response.assert_called_once()
|
|
|
|
def test_long_joke_split_sends_two_messages(self):
|
|
import asyncio
|
|
from unittest.mock import AsyncMock
|
|
|
|
bot = _make_bot()
|
|
bot.command_manager.send_response = AsyncMock(return_value=True)
|
|
cmd = DadJokeCommand(bot)
|
|
msg = mock_message(content="dadjoke")
|
|
|
|
# Create a joke that's long enough to split (>130 chars)
|
|
long_joke = "Why did the chicken cross the road? " + "x" * 100 + ". Then it went back home."
|
|
joke_data = {"joke": long_joke}
|
|
asyncio.run(cmd.send_dad_joke_with_length_handling(msg, joke_data))
|
|
# Should have been called (either once or twice depending on split)
|
|
assert bot.command_manager.send_response.call_count >= 1
|