"""Тесты для AutoModerationService.""" from unittest.mock import AsyncMock, MagicMock, patch import pytest from helper_bot.handlers.private.services import AutoModerationService, BotSettings class TestAutoModerationService: """Тесты для сервиса авто-модерации.""" @pytest.fixture def mock_db(self): """Создает мок базы данных.""" db = MagicMock() db.get_auto_moderation_settings = AsyncMock() return db @pytest.fixture def settings(self): """Создает настройки бота.""" return BotSettings( group_for_posts="-123", group_for_message="-456", main_public="@test_channel", group_for_logs="-789", important_logs="-999", preview_link="false", logs="false", test="false", ) @pytest.fixture def service(self, mock_db, settings): """Создает экземпляр сервиса.""" return AutoModerationService(mock_db, settings) @pytest.mark.asyncio async def test_check_auto_action_returns_manual_when_score_is_none( self, service, mock_db ): """Тест: возвращает manual когда score равен None.""" result = await service.check_auto_action(None) assert result == "manual" @pytest.mark.asyncio async def test_check_auto_action_returns_publish_when_score_above_threshold( self, service, mock_db ): """Тест: возвращает publish когда score выше порога.""" mock_db.get_auto_moderation_settings.return_value = { "auto_publish_enabled": True, "auto_decline_enabled": False, "auto_publish_threshold": 0.8, "auto_decline_threshold": 0.4, } result = await service.check_auto_action(0.9) assert result == "publish" @pytest.mark.asyncio async def test_check_auto_action_returns_decline_when_score_below_threshold( self, service, mock_db ): """Тест: возвращает decline когда score ниже порога.""" mock_db.get_auto_moderation_settings.return_value = { "auto_publish_enabled": False, "auto_decline_enabled": True, "auto_publish_threshold": 0.8, "auto_decline_threshold": 0.4, } result = await service.check_auto_action(0.3) assert result == "decline" @pytest.mark.asyncio async def test_check_auto_action_returns_manual_when_disabled( self, service, mock_db ): """Тест: возвращает manual когда авто-действия отключены.""" mock_db.get_auto_moderation_settings.return_value = { "auto_publish_enabled": False, "auto_decline_enabled": False, "auto_publish_threshold": 0.8, "auto_decline_threshold": 0.4, } result = await service.check_auto_action(0.9) assert result == "manual" @pytest.mark.asyncio async def test_check_auto_action_returns_manual_when_score_in_middle( self, service, mock_db ): """Тест: возвращает manual когда score между порогами.""" mock_db.get_auto_moderation_settings.return_value = { "auto_publish_enabled": True, "auto_decline_enabled": True, "auto_publish_threshold": 0.8, "auto_decline_threshold": 0.4, } result = await service.check_auto_action(0.6) assert result == "manual" @pytest.mark.asyncio async def test_check_auto_action_publish_at_exact_threshold( self, service, mock_db ): """Тест: возвращает publish когда score равен порогу.""" mock_db.get_auto_moderation_settings.return_value = { "auto_publish_enabled": True, "auto_decline_enabled": False, "auto_publish_threshold": 0.8, "auto_decline_threshold": 0.4, } result = await service.check_auto_action(0.8) assert result == "publish" @pytest.mark.asyncio async def test_check_auto_action_decline_at_exact_threshold( self, service, mock_db ): """Тест: возвращает decline когда score равен порогу.""" mock_db.get_auto_moderation_settings.return_value = { "auto_publish_enabled": False, "auto_decline_enabled": True, "auto_publish_threshold": 0.8, "auto_decline_threshold": 0.4, } result = await service.check_auto_action(0.4) assert result == "decline" @pytest.mark.asyncio async def test_log_auto_action_publish(self, service, settings): """Тест отправки лога для авто-публикации.""" mock_bot = MagicMock() mock_bot.send_message = AsyncMock() await service.log_auto_action( bot=mock_bot, action="publish", author_id=12345, author_name="Test User", author_username="testuser", rag_score=0.85, post_text="Test post text", ) mock_bot.send_message.assert_called_once() call_kwargs = mock_bot.send_message.call_args[1] assert call_kwargs["chat_id"] == settings.important_logs assert "АВТО-ПУБЛИКАЦИЯ" in call_kwargs["text"] assert "Test User" in call_kwargs["text"] assert "0.85" in call_kwargs["text"] @pytest.mark.asyncio async def test_log_auto_action_decline(self, service, settings): """Тест отправки лога для авто-отклонения.""" mock_bot = MagicMock() mock_bot.send_message = AsyncMock() await service.log_auto_action( bot=mock_bot, action="decline", author_id=12345, author_name="Test User", author_username="testuser", rag_score=0.25, post_text="Test post text", ) mock_bot.send_message.assert_called_once() call_kwargs = mock_bot.send_message.call_args[1] assert "АВТО-ОТКЛОНЕНИЕ" in call_kwargs["text"] @pytest.mark.asyncio async def test_log_auto_action_handles_exception(self, service): """Тест обработки исключения при отправке лога.""" mock_bot = MagicMock() mock_bot.send_message = AsyncMock(side_effect=Exception("Network error")) # Не должно выбрасывать исключение await service.log_auto_action( bot=mock_bot, action="publish", author_id=12345, author_name="Test User", author_username="testuser", rag_score=0.85, post_text="Test post text", ) @pytest.mark.asyncio async def test_log_auto_action_truncates_long_text(self, service): """Тест обрезки длинного текста в логе.""" mock_bot = MagicMock() mock_bot.send_message = AsyncMock() long_text = "a" * 300 await service.log_auto_action( bot=mock_bot, action="publish", author_id=12345, author_name="Test User", author_username="testuser", rag_score=0.85, post_text=long_text, ) call_kwargs = mock_bot.send_message.call_args[1] # Текст должен быть обрезан до 200 символов + "..." assert "..." in call_kwargs["text"]