mirror of
https://github.com/FerraSoft/bottohelp.git
synced 2026-08-06 21:55:03 +00:00
297 lines
11 KiB
Python
297 lines
11 KiB
Python
"""
|
|
Тесты для MessageTypeRouter.
|
|
"""
|
|
|
|
import pytest
|
|
from unittest.mock import Mock, AsyncMock
|
|
from telegram import Update, Message, User, CallbackQuery
|
|
|
|
from core.message_router import MessageTypeRouter, MessageHandlerConfig
|
|
from core.permissions import UserRole
|
|
|
|
|
|
class TestMessageTypeRouter:
|
|
"""Тесты маршрутизатора типов сообщений"""
|
|
|
|
@pytest.fixture
|
|
def message_router(self):
|
|
"""Фикстура для MessageTypeRouter"""
|
|
return MessageTypeRouter()
|
|
|
|
@pytest.fixture
|
|
def mock_update_text(self):
|
|
"""Мок-объект для текстового сообщения"""
|
|
update = Mock(spec=Update)
|
|
message = Mock(spec=Message)
|
|
user = Mock(spec=User)
|
|
user.id = 123456789
|
|
|
|
message.text = "Hello world"
|
|
message.voice = None
|
|
message.photo = None
|
|
update.message = message
|
|
update.effective_user = user
|
|
|
|
# Mock chat for permission checking
|
|
chat = Mock()
|
|
member = Mock()
|
|
member.status = 'member'
|
|
chat.get_member = AsyncMock(return_value=member)
|
|
update.effective_chat = chat
|
|
|
|
return update
|
|
|
|
@pytest.fixture
|
|
def mock_update_voice(self):
|
|
"""Мок-объект для голосового сообщения"""
|
|
update = Mock(spec=Update)
|
|
message = Mock(spec=Message)
|
|
user = Mock(spec=User)
|
|
user.id = 123456789
|
|
voice = Mock()
|
|
|
|
message.text = None
|
|
message.voice = voice
|
|
message.photo = None
|
|
update.message = message
|
|
update.effective_user = user
|
|
|
|
# Mock chat for permission checking
|
|
chat = Mock()
|
|
member = Mock()
|
|
member.status = 'member'
|
|
chat.get_member = AsyncMock(return_value=member)
|
|
update.effective_chat = chat
|
|
|
|
return update
|
|
|
|
@pytest.fixture
|
|
def mock_update_callback(self):
|
|
"""Мок-объект для callback запроса"""
|
|
update = Mock(spec=Update)
|
|
callback_query = Mock(spec=CallbackQuery)
|
|
user = Mock(spec=User)
|
|
user.id = 123456789
|
|
|
|
callback_query.data = "test_callback"
|
|
update.callback_query = callback_query
|
|
update.effective_user = user
|
|
|
|
# Mock chat for permission checking
|
|
chat = Mock()
|
|
member = Mock()
|
|
member.status = 'member'
|
|
chat.get_member = AsyncMock(return_value=member)
|
|
update.effective_chat = chat
|
|
|
|
return update
|
|
|
|
@pytest.fixture
|
|
def mock_context(self):
|
|
"""Мок-объект для контекста"""
|
|
return Mock()
|
|
|
|
def test_initialization(self, message_router):
|
|
"""Тест инициализации маршрутизатора"""
|
|
assert message_router.text_handlers == {}
|
|
assert message_router.callback_handlers == {}
|
|
assert message_router.voice_handlers == []
|
|
assert len(message_router.photo_handlers) == 0
|
|
|
|
def test_register_text_handler(self, message_router):
|
|
"""Тест регистрации обработчика текста"""
|
|
async def handler(update, context):
|
|
pass
|
|
|
|
message_router.register_text_handler(
|
|
r'hello', handler, UserRole.USER, 1, 'Test handler'
|
|
)
|
|
|
|
assert len(message_router.text_handlers) == 1
|
|
pattern, config = list(message_router.text_handlers.items())[0]
|
|
assert config.required_role == UserRole.USER
|
|
assert config.priority == 1
|
|
assert config.description == 'Test handler'
|
|
|
|
def test_register_text_handler_invalid_regex(self, message_router):
|
|
"""Тест регистрации обработчика с невалидным regex"""
|
|
async def handler(update, context):
|
|
pass
|
|
|
|
# Неверный regex не должен вызывать исключение, но и не регистрироваться
|
|
initial_count = len(message_router.text_handlers)
|
|
|
|
message_router.register_text_handler(
|
|
r'[invalid', handler, UserRole.USER
|
|
)
|
|
|
|
assert len(message_router.text_handlers) == initial_count
|
|
|
|
def test_register_callback_handler(self, message_router):
|
|
"""Тест регистрации обработчика callback"""
|
|
async def handler(update, context):
|
|
pass
|
|
|
|
message_router.register_callback_handler(
|
|
'test_callback', handler, UserRole.USER, 'Test callback handler'
|
|
)
|
|
|
|
assert 'test_callback' in message_router.callback_handlers
|
|
config = message_router.callback_handlers['test_callback']
|
|
assert config.required_role == UserRole.USER
|
|
assert config.description == 'Test callback handler'
|
|
|
|
def test_register_media_handler(self, message_router):
|
|
"""Тест регистрации обработчика медиа"""
|
|
async def handler(update, context):
|
|
pass
|
|
|
|
message_router.register_media_handler(
|
|
'photo', handler, UserRole.USER, 'Photo handler'
|
|
)
|
|
|
|
assert len(message_router.photo_handlers) == 1
|
|
config = message_router.photo_handlers[0]
|
|
assert config.required_role == UserRole.USER
|
|
assert config.description == 'Photo handler'
|
|
|
|
def test_register_voice_handler(self, message_router):
|
|
"""Тест регистрации обработчика голосовых сообщений"""
|
|
async def handler(update, context):
|
|
pass
|
|
|
|
message_router.register_media_handler(
|
|
'voice', handler, UserRole.USER, 'Voice handler'
|
|
)
|
|
|
|
assert len(message_router.voice_handlers) == 1
|
|
config = message_router.voice_handlers[0]
|
|
assert config.required_role == UserRole.USER
|
|
|
|
@pytest.mark.asyncio
|
|
async def test_route_text_message_no_match(self, message_router, mock_update_text, mock_context):
|
|
"""Тест маршрутизации текста без совпадений"""
|
|
result = await message_router.route_text_message(mock_update_text, mock_context)
|
|
|
|
assert result == False
|
|
|
|
@pytest.mark.asyncio
|
|
async def test_route_text_message_with_match(self, message_router, mock_update_text, mock_context):
|
|
"""Тест маршрутизации текста с совпадением"""
|
|
handler_called = False
|
|
|
|
async def test_handler(update, context):
|
|
nonlocal handler_called
|
|
handler_called = True
|
|
|
|
message_router.register_text_handler(r'hello', test_handler, UserRole.USER)
|
|
|
|
result = await message_router.route_text_message(mock_update_text, mock_context)
|
|
|
|
# Проверяем, что обработчик был вызван
|
|
assert handler_called == True
|
|
assert result == True
|
|
|
|
@pytest.mark.asyncio
|
|
async def test_route_text_message_insufficient_permissions(self, message_router, mock_update_text, mock_context):
|
|
"""Тест маршрутизации текста при недостаточных правах"""
|
|
handler_called = False
|
|
|
|
async def test_handler(update, context):
|
|
nonlocal handler_called
|
|
handler_called = True
|
|
|
|
# Регистрируем обработчик требующий админские права
|
|
message_router.register_text_handler(r'hello', test_handler, UserRole.ADMIN)
|
|
|
|
result = await message_router.route_text_message(mock_update_text, mock_context)
|
|
|
|
assert result == False
|
|
assert handler_called == False
|
|
|
|
@pytest.mark.asyncio
|
|
async def test_route_callback_exact_match(self, message_router, mock_update_callback, mock_context):
|
|
"""Тест маршрутизации callback с точным совпадением"""
|
|
handler_called = False
|
|
|
|
async def test_handler(update, context):
|
|
nonlocal handler_called
|
|
handler_called = True
|
|
|
|
message_router.register_callback_handler('test_callback', test_handler, UserRole.USER)
|
|
|
|
result = await message_router.route_callback(mock_update_callback, mock_context)
|
|
|
|
# Проверяем, что обработчик был вызван
|
|
assert handler_called == True
|
|
assert result == True
|
|
|
|
@pytest.mark.asyncio
|
|
async def test_route_callback_prefix_match(self, message_router, mock_update_callback, mock_context):
|
|
"""Тест маршрутизации callback по префиксу"""
|
|
handler_called = False
|
|
|
|
async def test_handler(update, context):
|
|
nonlocal handler_called
|
|
handler_called = True
|
|
|
|
message_router.register_callback_handler('test_', test_handler, UserRole.USER)
|
|
|
|
result = await message_router.route_callback(mock_update_callback, mock_context)
|
|
|
|
# Проверяем, что обработчик был вызван
|
|
assert handler_called == True
|
|
assert result == True
|
|
|
|
@pytest.mark.asyncio
|
|
async def test_route_callback_no_match(self, message_router, mock_update_callback, mock_context):
|
|
"""Тест маршрутизации callback без совпадений"""
|
|
result = await message_router.route_callback(mock_update_callback, mock_context)
|
|
|
|
assert result == False
|
|
|
|
@pytest.mark.asyncio
|
|
async def test_route_voice_message(self, message_router, mock_update_voice, mock_context):
|
|
"""Тест маршрутизации голосовых сообщений"""
|
|
handler_called = False
|
|
|
|
async def test_handler(update, context):
|
|
nonlocal handler_called
|
|
handler_called = True
|
|
|
|
message_router.register_media_handler('voice', test_handler, UserRole.USER)
|
|
|
|
result = await message_router.route_voice_message(mock_update_voice, mock_context)
|
|
|
|
# Проверяем, что обработчик был вызван
|
|
assert handler_called == True
|
|
assert result == True
|
|
|
|
def test_get_registered_handlers_count(self, message_router):
|
|
"""Тест получения статистики обработчиков"""
|
|
# Регистрируем несколько обработчиков
|
|
async def handler(update, context):
|
|
pass
|
|
|
|
message_router.register_text_handler(r'test', handler)
|
|
message_router.register_callback_handler('callback', handler)
|
|
message_router.register_media_handler('photo', handler)
|
|
|
|
stats = message_router.get_registered_handlers_count()
|
|
|
|
assert stats['text'] == 1
|
|
assert stats['callback'] == 1
|
|
assert stats['photo'] == 1
|
|
assert stats['voice'] == 0
|
|
|
|
def test_message_handler_config(self):
|
|
"""Тест конфигурации обработчика"""
|
|
async def handler():
|
|
pass
|
|
|
|
config = MessageHandlerConfig(handler, UserRole.MODERATOR, 5, 'Test config')
|
|
|
|
assert config.handler == handler
|
|
assert config.required_role == UserRole.MODERATOR
|
|
assert config.priority == 5
|
|
assert config.description == 'Test config' |