"""Тесты для commands/cat.py — команда !cat.""" import sys from pathlib import Path from unittest.mock import AsyncMock, MagicMock, patch import discord import pytest ROOT_DIR = Path(__file__).resolve().parent.parent sys.path.insert(0, str(ROOT_DIR)) def make_context() -> MagicMock: """Создать мокированный ctx.""" ctx = MagicMock() ctx.author.name = "TestUser" ctx.send = AsyncMock(return_value=None) return ctx class TestCatInit: """Тесты инициализации Cat cog.""" def test_cat_cog_instantiates(self) -> None: """Cat должен создаваться без параметров.""" from commands.cat import Cat cog = Cat() assert cog is not None def test_cat_has_command(self) -> None: """Cat должен содержать команду cat.""" from commands.cat import Cat cog = Cat() assert cog.cat.name == "cat" class TestCatCommand: """Тесты команды !cat.""" @pytest.mark.asyncio async def test_cat_success(self) -> None: """Успешный ответ API -> embed с котиком.""" from commands.cat import Cat cog = Cat() ctx = make_context() with patch("commands.cat.fetch_cat", new_callable=AsyncMock) as mock: mock.return_value = "https://example.com/cat.jpg" await cog.cat(cog, ctx) ctx.send.assert_awaited_once() embed = ctx.send.call_args[1]["embed"] assert embed.title == "Котик для тебя!" assert embed.image.url == "https://example.com/cat.jpg" @pytest.mark.asyncio async def test_cat_api_returns_none(self) -> None: """API вернул None -> fallback сообщение.""" from commands.cat import Cat cog = Cat() ctx = make_context() with patch("commands.cat.fetch_cat", new_callable=AsyncMock) as mock: mock.return_value = None await cog.cat(cog, ctx) ctx.send.assert_awaited_once() content = ctx.send.call_args[0][0] assert "Не удалось получить котика" in content @pytest.mark.asyncio async def test_cat_embed_color_orange(self) -> None: """Embed должен быть оранжевого цвета.""" from commands.cat import Cat cog = Cat() ctx = make_context() with patch("commands.cat.fetch_cat", new_callable=AsyncMock) as mock: mock.return_value = "https://example.com/cat.jpg" await cog.cat(cog, ctx) embed = ctx.send.call_args[1]["embed"] assert embed.color == discord.Color.orange() @pytest.mark.asyncio async def test_cat_image_set_via_set_image(self) -> None: """URL должен быть установлен через embed.set_image.""" from commands.cat import Cat cog = Cat() ctx = make_context() with patch("commands.cat.fetch_cat", new_callable=AsyncMock) as mock: mock.return_value = "https://example.com/cat.jpg" await cog.cat(cog, ctx) embed = ctx.send.call_args[1]["embed"] assert embed.image is not None assert embed.image.url == "https://example.com/cat.jpg" @pytest.mark.asyncio async def test_cat_with_special_url(self) -> None: """URL со спецсимволами должен корректно встраиваться.""" from commands.cat import Cat cog = Cat() ctx = make_context() with patch("commands.cat.fetch_cat", new_callable=AsyncMock) as mock: mock.return_value = "https://example.com/cat.jpg?size=large&format=webp" await cog.cat(cog, ctx) embed = ctx.send.call_args[1]["embed"] assert embed.image.url == "https://example.com/cat.jpg?size=large&format=webp" @pytest.mark.asyncio async def test_cat_send_raises(self) -> None: """Ошибка при отправке — fetch_cat вызывался.""" from commands.cat import Cat cog = Cat() ctx = make_context() ctx.send.side_effect = Exception("channel error") with patch("commands.cat.fetch_cat", new_callable=AsyncMock) as mock: mock.return_value = "https://example.com/cat.jpg" with pytest.raises(Exception, match="channel error"): await cog.cat(cog, ctx) mock.assert_awaited_once()