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.
209 lines
7.5 KiB
Python
209 lines
7.5 KiB
Python
"""Tests for modules.commands.moon_command — pure logic functions."""
|
|
|
|
import configparser
|
|
from unittest.mock import MagicMock, Mock
|
|
|
|
from modules.commands.moon_command import MoonCommand
|
|
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")
|
|
bot.config = config
|
|
bot.translator = MagicMock()
|
|
# Return first arg key as-is (mimics missing translation)
|
|
bot.translator.translate = Mock(side_effect=lambda key, **kw: key)
|
|
bot.command_manager = MagicMock()
|
|
bot.command_manager.monitor_channels = ["general"]
|
|
return bot
|
|
|
|
|
|
class TestTranslatePhaseName:
|
|
"""Tests for _translate_phase_name."""
|
|
|
|
def setup_method(self):
|
|
self.cmd = MoonCommand(_make_bot())
|
|
|
|
def test_returns_original_when_no_translation(self):
|
|
# With our mock translator, translate returns the key, not a translation
|
|
# so _translate_phase_name should fall back to the original
|
|
result = self.cmd._translate_phase_name("Full Moon")
|
|
# Since translate returns the key (not found), fallback to original
|
|
assert result == "Full Moon" or "full_moon" in result or "Full Moon" in result
|
|
|
|
def test_strips_emoji_before_matching(self):
|
|
# Phase with emoji — should still match
|
|
result = self.cmd._translate_phase_name("🌕 Full Moon")
|
|
# Should not crash and should return something
|
|
assert result is not None
|
|
assert isinstance(result, str)
|
|
|
|
def test_unknown_phase_returned_as_is(self):
|
|
result = self.cmd._translate_phase_name("Totally Unknown Phase")
|
|
assert result == "Totally Unknown Phase"
|
|
|
|
def test_all_known_phases_dont_crash(self):
|
|
phases = [
|
|
"New Moon", "Waxing Crescent", "First Quarter", "Waxing Gibbous",
|
|
"Full Moon", "Waning Gibbous", "Last Quarter", "Waning Crescent"
|
|
]
|
|
for phase in phases:
|
|
result = self.cmd._translate_phase_name(phase)
|
|
assert isinstance(result, str)
|
|
|
|
|
|
class TestFormatMoonResponse:
|
|
"""Tests for _format_moon_response."""
|
|
|
|
def setup_method(self):
|
|
self.cmd = MoonCommand(_make_bot())
|
|
|
|
def test_valid_moon_info_parsed(self):
|
|
moon_info = (
|
|
"MoonRise: Thu 04 06:47PM\n"
|
|
"Set: Fri 05 03:43AM\n"
|
|
"Phase: Full Moon @: 87%\n"
|
|
"FullMoon: Sun Sep 07 11:08AM\n"
|
|
"NewMoon: Sun Sep 21 12:54PM"
|
|
)
|
|
result = self.cmd._format_moon_response(moon_info)
|
|
assert isinstance(result, str)
|
|
assert len(result) > 0
|
|
|
|
def test_partial_moon_info_falls_back(self):
|
|
# Only some keys present — should fall back to original or key
|
|
moon_info = "Phase: Full Moon\nSome: data"
|
|
result = self.cmd._format_moon_response(moon_info)
|
|
assert isinstance(result, str)
|
|
|
|
def test_empty_string_falls_back(self):
|
|
result = self.cmd._format_moon_response("")
|
|
assert isinstance(result, str)
|
|
|
|
def test_malformed_input_falls_back(self):
|
|
result = self.cmd._format_moon_response("This is not key:value format at all")
|
|
assert isinstance(result, str)
|
|
|
|
def test_moon_info_with_dates_format(self):
|
|
moon_info = (
|
|
"MoonRise: Thu 04 06:47PM\n"
|
|
"Set: Fri 05 03:43AM\n"
|
|
"Phase: Full Moon @: 87%\n"
|
|
"FullMoon: Sun Sep 07 11:08AM\n"
|
|
"NewMoon: Sun Sep 21 12:54PM"
|
|
)
|
|
result = self.cmd._format_moon_response(moon_info)
|
|
# Should have used 'format_with_dates' path since all keys present
|
|
# The output is a translated key so may contain the key name
|
|
assert isinstance(result, str)
|
|
|
|
def test_moon_info_without_full_new_moon(self):
|
|
moon_info = (
|
|
"MoonRise: Thu 04 06:47PM\n"
|
|
"Set: Fri 05 03:43AM\n"
|
|
"Phase: Waxing Gibbous @: 60%"
|
|
)
|
|
result = self.cmd._format_moon_response(moon_info)
|
|
assert isinstance(result, str)
|
|
|
|
|
|
class TestMoonCommandEnabled:
|
|
"""Tests for can_execute."""
|
|
|
|
def test_can_execute_enabled(self):
|
|
bot = _make_bot()
|
|
bot.config.add_section("Moon_Command")
|
|
bot.config.set("Moon_Command", "enabled", "true")
|
|
cmd = MoonCommand(bot)
|
|
msg = mock_message(content="moon", channel="general")
|
|
assert cmd.can_execute(msg) is True
|
|
|
|
def test_can_execute_disabled(self):
|
|
bot = _make_bot()
|
|
bot.config.add_section("Moon_Command")
|
|
bot.config.set("Moon_Command", "enabled", "false")
|
|
cmd = MoonCommand(bot)
|
|
msg = mock_message(content="moon", channel="general")
|
|
assert cmd.can_execute(msg) is False
|
|
|
|
|
|
class TestGetHelpTextMoon:
|
|
def test_returns_description(self):
|
|
cmd = MoonCommand(_make_bot())
|
|
result = cmd.get_help_text()
|
|
assert isinstance(result, str)
|
|
assert result == cmd.description
|
|
|
|
|
|
class TestFormatMoonPhaseNoAt:
|
|
"""Test _format_moon_response when Phase has no @: (else branch)."""
|
|
|
|
def setup_method(self):
|
|
self.cmd = MoonCommand(_make_bot())
|
|
|
|
def test_phase_without_at_sign(self):
|
|
moon_info = (
|
|
"MoonRise: Thu 04 06:47PM\n"
|
|
"Set: Fri 05 03:43AM\n"
|
|
"Phase: Waxing Crescent"
|
|
)
|
|
result = self.cmd._format_moon_response(moon_info)
|
|
assert isinstance(result, str)
|
|
|
|
def test_exception_in_format_falls_back(self):
|
|
"""If _format_moon_response raises, fallback is returned."""
|
|
# Force an exception by passing an object with no .split
|
|
result = self.cmd._format_moon_response(None)
|
|
assert isinstance(result, str)
|
|
|
|
|
|
class TestTranslatePhaseNameFound:
|
|
"""Test _translate_phase_name when a translation IS found (line 104)."""
|
|
|
|
def test_translation_returned_when_not_key(self):
|
|
"""When translator returns actual text (not key), it's returned."""
|
|
bot = _make_bot()
|
|
# Override translator to return a real translation for the phase key
|
|
bot.translator.translate = Mock(
|
|
side_effect=lambda key, **kw: "Pleine Lune" if "full_moon" in key else key
|
|
)
|
|
cmd = MoonCommand(bot)
|
|
result = cmd._translate_phase_name("Full Moon")
|
|
assert result == "Pleine Lune"
|
|
|
|
|
|
class TestMoonExecute:
|
|
"""Tests for execute()."""
|
|
|
|
def test_execute_success(self):
|
|
import asyncio
|
|
from unittest.mock import AsyncMock, patch
|
|
bot = _make_bot()
|
|
cmd = MoonCommand(bot)
|
|
cmd.send_response = AsyncMock(return_value=True)
|
|
with patch("modules.commands.moon_command.get_moon", return_value="MoonRise: Thu 04 06:47PM\nSet: Fri 05 03:43AM\nPhase: Full Moon @: 87%"):
|
|
msg = mock_message(content="moon", channel="general")
|
|
result = asyncio.run(cmd.execute(msg))
|
|
assert result is True
|
|
cmd.send_response.assert_called_once()
|
|
|
|
def test_execute_error_returns_false(self):
|
|
import asyncio
|
|
from unittest.mock import AsyncMock, patch
|
|
bot = _make_bot()
|
|
cmd = MoonCommand(bot)
|
|
cmd.send_response = AsyncMock(return_value=True)
|
|
with patch("modules.commands.moon_command.get_moon", side_effect=Exception("API error")):
|
|
msg = mock_message(content="moon", channel="general")
|
|
result = asyncio.run(cmd.execute(msg))
|
|
assert result is False
|
|
cmd.send_response.assert_called_once()
|