Enhance /hottest command with optional limit

This commit is contained in:
Artur Mukhamadiev 2026-03-15 01:34:33 +03:00
parent 9fdb4b35cd
commit a0eeba0918
3 changed files with 89 additions and 10 deletions

View File

@ -51,7 +51,7 @@ def get_router(storage: IVectorStore, processor: ILLMProvider, allowed_chat_id:
"/start - Start the bot\n"
"/help - Show this help message\n"
"/latest [category] - Show the latest enriched news trends\n"
"/hottest - Show top 10 ranked hot trends\n"
"/hottest [limit] - Show top ranked hot trends (default 10, max 50)\n"
"/search query - Search for news\n"
"/stats - Show database statistics\n"
"/params - Show LLM processor parameters\n"
@ -95,11 +95,22 @@ def get_router(storage: IVectorStore, processor: ILLMProvider, allowed_chat_id:
await message.answer("Latest news:", reply_markup=builder.as_markup())
@router.message(Command("hottest"))
async def command_hottest_handler(message: Message) -> None:
async def command_hottest_handler(message: Message, command: CommandObject) -> None:
"""
This handler receives messages with `/hottest` command
"""
items = await storage.get_top_ranked(limit=10)
limit = 10
if command.args:
try:
limit = int(command.args)
if limit <= 0:
limit = 10
elif limit > 50:
limit = 50
except ValueError:
pass
items = await storage.get_top_ranked(limit=limit)
if not items:
await message.answer("No hot trends found yet.")
@ -113,7 +124,7 @@ def get_router(storage: IVectorStore, processor: ILLMProvider, allowed_chat_id:
callback_data=f"detail:{item_id}"
))
await message.answer("Top 10 Hottest Trends:", reply_markup=builder.as_markup())
await message.answer(f"Top {len(items)} Hottest Trends:", reply_markup=builder.as_markup())
@router.message(Command("search"))
async def command_search_handler(message: Message, command: CommandObject) -> None:

View File

@ -176,15 +176,16 @@ async def test_command_hottest_handler(router, mock_storage, allowed_chat_id, mo
message = AsyncMock()
message.chat.id = int(allowed_chat_id)
message.answer = AsyncMock()
command = CommandObject(prefix="/", command="hottest", args=None)
mock_storage.get_top_ranked.return_value = [mock_item]
await handler(message=message)
await handler(message=message, command=command)
mock_storage.get_top_ranked.assert_called_once_with(limit=10)
message.answer.assert_called_once()
args, kwargs = message.answer.call_args
assert "Top 10 Hottest Trends:" in args[0]
assert "Top 1 Hottest Trends:" in args[0]
assert "reply_markup" in kwargs
assert "🔥" in str(kwargs["reply_markup"])
@ -194,10 +195,11 @@ async def test_command_hottest_handler_empty(router, mock_storage, allowed_chat_
message = AsyncMock()
message.chat.id = int(allowed_chat_id)
message.answer = AsyncMock()
command = CommandObject(prefix="/", command="hottest", args=None)
mock_storage.get_top_ranked.return_value = []
await handler(message=message)
await handler(message=message, command=command)
message.answer.assert_called_once_with("No hot trends found yet.")

View File

@ -2,6 +2,7 @@ import uuid
import pytest
from unittest.mock import AsyncMock, MagicMock
from aiogram.types import Message, InlineKeyboardMarkup
from aiogram.filters import CommandObject
from datetime import datetime
from src.bot.handlers import get_router
@ -59,14 +60,15 @@ async def test_command_hottest_handler_success(router, mock_storage, allowed_cha
mock_storage.get_top_ranked.return_value = mock_items
# 2. Act
await handler(message=message)
command = CommandObject(prefix='/', command='hottest', args=None)
await handler(message=message, command=command)
# 3. Assert
mock_storage.get_top_ranked.assert_called_once_with(limit=10)
message.answer.assert_called_once()
args, kwargs = message.answer.call_args
assert "Top 10 Hottest Trends:" in args[0]
assert "Top 3 Hottest Trends:" in args[0]
assert "reply_markup" in kwargs
assert isinstance(kwargs["reply_markup"], InlineKeyboardMarkup)
@ -95,8 +97,72 @@ async def test_command_hottest_handler_empty(router, mock_storage, allowed_chat_
mock_storage.get_top_ranked.return_value = []
# 2. Act
await handler(message=message)
command = CommandObject(prefix='/', command='hottest', args=None)
await handler(message=message, command=command)
# 3. Assert
mock_storage.get_top_ranked.assert_called_once_with(limit=10)
message.answer.assert_called_once_with("No hot trends found yet.")
@pytest.mark.asyncio
async def test_command_hottest_handler_custom_limit(router, mock_storage, allowed_chat_id):
"""
Test that /hottest command with custom limit correctly passes it to storage.
"""
# 1. Arrange
handler = get_handler(router, "command_hottest_handler")
message = AsyncMock()
message.chat = MagicMock()
message.chat.id = int(allowed_chat_id)
message.answer = AsyncMock()
mock_storage.get_top_ranked.return_value = []
# 2. Act
command = CommandObject(prefix='/', command='hottest', args='25')
await handler(message=message, command=command)
# 3. Assert
mock_storage.get_top_ranked.assert_called_once_with(limit=25)
@pytest.mark.asyncio
async def test_command_hottest_handler_max_limit(router, mock_storage, allowed_chat_id):
"""
Test that /hottest command enforces maximum limit.
"""
# 1. Arrange
handler = get_handler(router, "command_hottest_handler")
message = AsyncMock()
message.chat = MagicMock()
message.chat.id = int(allowed_chat_id)
message.answer = AsyncMock()
mock_storage.get_top_ranked.return_value = []
# 2. Act
command = CommandObject(prefix='/', command='hottest', args='1000')
await handler(message=message, command=command)
# 3. Assert
mock_storage.get_top_ranked.assert_called_once_with(limit=50)
@pytest.mark.asyncio
async def test_command_hottest_handler_invalid_limit(router, mock_storage, allowed_chat_id):
"""
Test that /hottest command handles invalid limit by falling back to default.
"""
# 1. Arrange
handler = get_handler(router, "command_hottest_handler")
message = AsyncMock()
message.chat = MagicMock()
message.chat.id = int(allowed_chat_id)
message.answer = AsyncMock()
mock_storage.get_top_ranked.return_value = []
# 2. Act
command = CommandObject(prefix='/', command='hottest', args='invalid')
await handler(message=message, command=command)
# 3. Assert
mock_storage.get_top_ranked.assert_called_once_with(limit=10)