"""Тесты для bot.TextHelpCommand — текстовая справка по командам.""" import sys from pathlib import Path from unittest.mock import AsyncMock, MagicMock, patch import pytest ROOT_DIR = Path(__file__).resolve().parent.parent sys.path.insert(0, str(ROOT_DIR)) @pytest.fixture def help_command() -> "bot.TextHelpCommand": """Создать экземпляр TextHelpCommand.""" import bot return bot.TextHelpCommand() class TestGetCommandSignature: """Тесты get_command_signature.""" def test_simple_command_no_signature(self, help_command) -> None: """Команда без параметров.""" cmd = MagicMock() cmd.qualified_name = "pg" cmd.signature = "" result = help_command.get_command_signature(cmd) assert result == "!pg " def test_command_with_signature(self, help_command) -> None: """Команда с параметрами.""" cmd = MagicMock() cmd.qualified_name = "search" cmd.signature = "" result = help_command.get_command_signature(cmd) assert result == "!search " def test_group_command(self, help_command) -> None: """Групповая команда.""" cmd = MagicMock() cmd.qualified_name = "mod ban" cmd.signature = "" result = help_command.get_command_signature(cmd) assert result == "!mod ban " class TestSendBotHelp: """Тесты send_bot_help.""" @pytest.mark.asyncio async def test_send_bot_help_shows_commands(self, help_command) -> None: """Должен показать список команд по когам.""" cmd = MagicMock() cmd.name = "pg" cmd.hidden = False cmd.short_doc = "Прогноз погоды" cog = MagicMock() cog.qualified_name = "Pg" destination = MagicMock() destination.send = AsyncMock(return_value=None) with patch.object(help_command, "get_destination", return_value=destination): mapping = {cog: [cmd], None: []} await help_command.send_bot_help(mapping) destination.send.assert_awaited_once() message = destination.send.call_args[0][0] assert "Доступные команды:" in message assert "!pg - Прогноз погоды" in message assert "!<название команды>" in message @pytest.mark.asyncio async def test_send_bot_help_skips_hidden(self, help_command) -> None: """Скрытые команды не должны показываться.""" cmd = MagicMock() cmd.name = "hidden_cmd" cmd.hidden = True cmd.short_doc = "Скрытая" cog = MagicMock() destination = MagicMock() destination.send = AsyncMock(return_value=None) with patch.object(help_command, "get_destination", return_value=destination): mapping = {cog: [cmd]} await help_command.send_bot_help(mapping) destination.send.assert_awaited_once() message = destination.send.call_args[0][0] assert "hidden_cmd" not in message @pytest.mark.asyncio async def test_send_bot_help_skips_none_cog(self, help_command) -> None: """Команды без cog (None) должны пропускаться.""" cmd = MagicMock() cmd.name = "built_in" cmd.hidden = False cmd.short_doc = "Встроенная" destination = MagicMock() destination.send = AsyncMock(return_value=None) with patch.object(help_command, "get_destination", return_value=destination): mapping = {None: [cmd]} await help_command.send_bot_help(mapping) destination.send.assert_awaited_once() message = destination.send.call_args[0][0] assert "built_in" not in message @pytest.mark.asyncio async def test_send_bot_help_empty_doc(self, help_command) -> None: """Команда без doc -> пустая строка описания.""" cmd = MagicMock() cmd.name = "cat" cmd.hidden = False cmd.short_doc = "" cog = MagicMock() destination = MagicMock() destination.send = AsyncMock(return_value=None) with patch.object(help_command, "get_destination", return_value=destination): mapping = {cog: [cmd]} await help_command.send_bot_help(mapping) message = destination.send.call_args[0][0] assert "!cat - " in message class TestSendCommandHelp: """Тесты send_command_help.""" @pytest.mark.asyncio async def test_send_command_help_basic(self, help_command) -> None: """Базовая справка по команде.""" cmd = MagicMock() cmd.qualified_name = "pg" cmd.signature = "" cmd.doc = "Прогноз погоды" cmd.short_doc = "Прогноз погоды" cmd.aliases = [] destination = MagicMock() destination.send = AsyncMock(return_value=None) with patch.object(help_command, "get_destination", return_value=destination): await help_command.send_command_help(cmd) message = destination.send.call_args[0][0] assert "!pg " in message assert "Прогноз погоды" in message @pytest.mark.asyncio async def test_send_command_help_with_aliases(self, help_command) -> None: """Команда с алиасами.""" cmd = MagicMock() cmd.qualified_name = "pg" cmd.signature = "" cmd.doc = "Погода" cmd.short_doc = "Погода" cmd.aliases = ["weather", "w"] destination = MagicMock() destination.send = AsyncMock(return_value=None) with patch.object(help_command, "get_destination", return_value=destination): await help_command.send_command_help(cmd) message = destination.send.call_args[0][0] assert "!weather, !w" in message class TestSendCogHelp: """Тесты send_cog_help.""" @pytest.mark.asyncio async def test_send_cog_help(self, help_command) -> None: """Справка по когу.""" cmd = MagicMock() cmd.name = "pg" cmd.hidden = False cmd.short_doc = "Погода" cog = MagicMock() cog.qualified_name = "Pg" cog.get_commands.return_value = [cmd] destination = MagicMock() destination.send = AsyncMock(return_value=None) with patch.object(help_command, "get_destination", return_value=destination): await help_command.send_cog_help(cog) message = destination.send.call_args[0][0] assert "[Pg]:" in message assert "!pg - Погода" in message class TestSendErrorMessage: """Тесты send_error_message.""" @pytest.mark.asyncio async def test_send_error_message(self, help_command) -> None: """Сообщение об ошибке.""" destination = MagicMock() destination.send = AsyncMock(return_value=None) with patch.object(help_command, "get_destination", return_value=destination): await help_command.send_error_message("Command not found") destination.send.assert_awaited_once_with("Command not found")