""" Тесты для helper_bot.handlers.admin.dependencies: AdminAccessMiddleware, get_bot_db, get_settings. """ from unittest.mock import AsyncMock, MagicMock, patch import pytest from helper_bot.handlers.admin.dependencies import ( AdminAccessMiddleware, get_bot_db, get_settings, ) @pytest.mark.unit @pytest.mark.asyncio class TestAdminAccessMiddleware: """Тесты для AdminAccessMiddleware.""" @pytest.fixture def middleware(self): """Экземпляр middleware.""" return AdminAccessMiddleware() @pytest.fixture def mock_handler(self): """Мок handler.""" return AsyncMock(return_value="handler_result") @patch("helper_bot.handlers.admin.dependencies.check_access", new_callable=AsyncMock) async def test_access_granted_calls_handler(self, mock_check_access, middleware, mock_handler): """При доступе разрешён вызывается handler с event и data.""" mock_check_access.return_value = True event = MagicMock() event.from_user = MagicMock() event.from_user.id = 123 event.from_user.username = "admin" data = {"bot_db": MagicMock()} result = await middleware(mock_handler, event, data) mock_check_access.assert_awaited_once_with(123, data["bot_db"]) mock_handler.assert_awaited_once_with(event, data) assert result == "handler_result" @patch("helper_bot.handlers.admin.dependencies.check_access", new_callable=AsyncMock) async def test_access_denied_answers_and_does_not_call_handler( self, mock_check_access, middleware, mock_handler ): """При доступе запрещён отправляется ответ и handler не вызывается.""" mock_check_access.return_value = False event = MagicMock() event.from_user = MagicMock() event.from_user.id = 456 event.from_user.username = "user" event.answer = AsyncMock() data = {"bot_db": MagicMock()} result = await middleware(mock_handler, event, data) mock_check_access.assert_awaited_once() event.answer.assert_awaited_once_with("Доступ запрещен!") mock_handler.assert_not_awaited() assert result is None @patch("helper_bot.handlers.admin.dependencies.check_access", new_callable=AsyncMock) @patch("helper_bot.handlers.admin.dependencies.get_global_instance") async def test_fallback_get_db_from_global_when_bot_db_missing( self, mock_get_global, mock_check_access, middleware, mock_handler ): """Если bot_db нет в data, берётся из get_global_instance().get_db().""" mock_check_access.return_value = True mock_bdf = MagicMock() mock_bdf.get_db.return_value = MagicMock() mock_get_global.return_value = mock_bdf event = MagicMock() event.from_user = MagicMock() event.from_user.id = 1 event.from_user.username = "u" data = {} await middleware(mock_handler, event, data) mock_get_global.assert_called_once() mock_bdf.get_db.assert_called_once() mock_check_access.assert_awaited_once_with(1, mock_bdf.get_db.return_value) @patch("helper_bot.handlers.admin.dependencies.check_access", new_callable=AsyncMock) async def test_event_without_from_user_calls_handler(self, mock_check_access, middleware, mock_handler): """Если у event нет from_user, handler вызывается (проверка доступа не выполняется).""" class EventWithoutUser: pass event = EventWithoutUser() data = {} result = await middleware(mock_handler, event, data) mock_check_access.assert_not_awaited() mock_handler.assert_awaited_once_with(event, data) assert result == "handler_result" @patch("helper_bot.handlers.admin.dependencies.check_access", new_callable=AsyncMock) async def test_handler_typeerror_missing_data_calls_handler_without_data( self, mock_check_access, middleware ): """При TypeError из-за отсутствия data вызывается handler(event) без data.""" mock_check_access.return_value = True call_count = 0 async def handler(event, data=None): nonlocal call_count call_count += 1 if call_count == 1 and data is not None: raise TypeError("missing 1 required positional argument: 'data'") return "ok" handler.__name__ = "test_handler" event = MagicMock() event.from_user = MagicMock() event.from_user.id = 1 event.from_user.username = "u" data = {"bot_db": MagicMock()} result = await middleware(handler, event, data) assert call_count == 2 assert result == "ok" @patch("helper_bot.handlers.admin.dependencies.check_access", new_callable=AsyncMock) async def test_handler_other_exception_reraises(self, mock_check_access, middleware): """При другом исключении в handler оно пробрасывается.""" mock_check_access.return_value = True async def handler(event, data): raise ValueError("other error") event = MagicMock() event.from_user = MagicMock() event.from_user.id = 1 event.from_user.username = "u" data = {"bot_db": MagicMock()} with pytest.raises(ValueError, match="other error"): await middleware(handler, event, data) @pytest.mark.unit class TestDependencyProviders: """Тесты для get_bot_db и get_settings.""" @patch("helper_bot.handlers.admin.dependencies.get_global_instance") def test_get_bot_db_returns_bdf_get_db(self, mock_get_global): """get_bot_db возвращает bdf.get_db().""" mock_bdf = MagicMock() mock_db = MagicMock() mock_bdf.get_db.return_value = mock_db mock_get_global.return_value = mock_bdf result = get_bot_db() mock_get_global.assert_called_once() mock_bdf.get_db.assert_called_once() assert result is mock_db @patch("helper_bot.handlers.admin.dependencies.get_global_instance") def test_get_settings_returns_bdf_settings(self, mock_get_global): """get_settings возвращает bdf.settings.""" mock_bdf = MagicMock() mock_bdf.settings = {"Telegram": {"bot_token": "x"}} mock_get_global.return_value = mock_bdf result = get_settings() mock_get_global.assert_called_once() assert result == {"Telegram": {"bot_token": "x"}}