Files
meshcore-bot/tests/test_dadjoke_command.py
agessaman 53112c5f05 Refactor: streamline imports and enhance documentation in utility and service files
- 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.
2026-03-18 18:27:05 -07:00

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