194 lines
8.0 KiB
Python
194 lines
8.0 KiB
Python
from datetime import datetime, timedelta, timezone
|
||
|
||
import pytest
|
||
from sqlalchemy import select, Sequence
|
||
from sqlalchemy.ext.asyncio import AsyncSession
|
||
|
||
from database import User, UserMessage, BotDatabase
|
||
|
||
|
||
@pytest.mark.asyncio
|
||
class TestUserStatistics:
|
||
"""Тесты для статистики пользователей с полной строгой типизацией"""
|
||
|
||
async def test_add_user(self, test_db: BotDatabase, test_session: AsyncSession) -> None:
|
||
"""
|
||
Тест добавления пользователя.
|
||
Проверяет, что пользователь создаётся с правильными данными и статусом 'active'.
|
||
"""
|
||
user_id: int = 111222333
|
||
|
||
await test_db.add_user(
|
||
user_id=user_id,
|
||
username="new_user",
|
||
full_name="New User"
|
||
)
|
||
|
||
user: User | None = await test_session.get(User, user_id)
|
||
assert user is not None
|
||
assert user.username == "new_user"
|
||
assert user.status.value == "active"
|
||
|
||
async def test_add_message_creates_user(
|
||
self, test_db: BotDatabase, test_session: AsyncSession
|
||
) -> None:
|
||
"""
|
||
Тест, что добавление сообщения создаёт пользователя, если его нет.
|
||
Проверяет, что пользователь и сообщение корректно создаются.
|
||
"""
|
||
user_id: int = 111222333
|
||
|
||
await test_db.add_message(
|
||
user_id=user_id,
|
||
message_text="Тестовое сообщение"
|
||
)
|
||
|
||
user: User | None = await test_session.get(User, user_id)
|
||
assert user is not None
|
||
assert user.status.value == "active"
|
||
|
||
stmt = select(UserMessage).where(UserMessage.user_id == user_id)
|
||
result = await test_session.execute(stmt)
|
||
messages: Sequence[UserMessage] = result.scalars().all()
|
||
|
||
assert len(messages) == 1
|
||
assert messages[0].message_text == "Тестовое сообщение"
|
||
|
||
async def test_message_stats_calculation(
|
||
self, test_db: BotDatabase, test_user_with_messages: int
|
||
) -> None:
|
||
"""
|
||
Тест расчёта статистики сообщений пользователя.
|
||
Проверяет корректность статистики по дням, неделям, месяцам и общему количеству сообщений.
|
||
"""
|
||
user_id: int = test_user_with_messages
|
||
|
||
# Получаем статистику
|
||
day: int
|
||
week: int
|
||
month: int
|
||
total: int
|
||
day, week, month, total = await test_db.get_message_stats(user_id)
|
||
|
||
assert total >= 10, f"Ожидается минимум 10 сообщений, получено {total}"
|
||
assert day >= 0
|
||
assert week >= 0
|
||
assert month >= 0
|
||
assert total >= 0
|
||
assert day <= week <= month <= total
|
||
|
||
async def test_message_stats_with_dates(
|
||
self, test_db: BotDatabase, test_user: int
|
||
) -> None:
|
||
"""
|
||
Тест статистики с конкретными известными датами сообщений.
|
||
Проверяет подсчёт сообщений за день, неделю, месяц и общее количество.
|
||
"""
|
||
user_id: int = test_user
|
||
now: datetime = datetime.now(timezone.utc)
|
||
|
||
# Очищаем старые сообщения
|
||
async with test_db.session_factory() as session:
|
||
stmt = select(UserMessage).where(UserMessage.user_id == user_id)
|
||
result = await session.execute(stmt)
|
||
old_messages: Sequence[UserMessage] = result.scalars().all()
|
||
for msg in old_messages:
|
||
await session.delete(msg)
|
||
await session.commit()
|
||
|
||
# Создаём сообщения с фиксированными датами
|
||
test_messages: list[tuple[datetime, str]] = [
|
||
(now - timedelta(days=45), "45 дней назад"),
|
||
(now - timedelta(days=30), "30 дней назад"),
|
||
(now - timedelta(days=15), "15 дней назад"),
|
||
(now - timedelta(days=7), "7 дней назад"),
|
||
(now - timedelta(days=3), "3 дня назад"),
|
||
(now - timedelta(hours=6), "6 часов назад"),
|
||
(now, "сейчас")
|
||
]
|
||
|
||
for date, text in test_messages:
|
||
await test_db.add_message(user_id, text, date)
|
||
|
||
day: int
|
||
week: int
|
||
month: int
|
||
total: int
|
||
day, week, month, total = await test_db.get_message_stats(user_id)
|
||
|
||
assert total == 7, f"Ожидалось 7 сообщений, получено {total}"
|
||
|
||
day_start: datetime = now.replace(hour=0, minute=0, second=0, microsecond=0)
|
||
expected_day: int = sum(1 for date, _ in test_messages if date >= day_start)
|
||
assert day == expected_day, f"За день: ожидалось {expected_day}, получено {day}"
|
||
|
||
monday: datetime = (now - timedelta(days=now.weekday())).replace(hour=0, minute=0, second=0, microsecond=0)
|
||
expected_week: int = sum(1 for date, _ in test_messages if date >= monday)
|
||
assert week == expected_week, f"За неделю: ожидалось {expected_week}, получено {week}"
|
||
|
||
month_start: datetime = now.replace(day=1, hour=0, minute=0, second=0, microsecond=0)
|
||
expected_month: int = sum(1 for date, _ in test_messages if date >= month_start)
|
||
assert month == expected_month, f"За месяц: ожидалось {expected_month}, получено {month}"
|
||
|
||
async def test_empty_user_stats(self, test_db: BotDatabase) -> None:
|
||
"""
|
||
Тест статистики для пользователя без сообщений.
|
||
Все значения должны быть равны нулю.
|
||
"""
|
||
user_id: int = 0o00111222
|
||
await test_db.add_user(user_id, "empty_user", "Empty User")
|
||
|
||
day: int
|
||
week: int
|
||
month: int
|
||
total: int
|
||
day, week, month, total = await test_db.get_message_stats(user_id)
|
||
|
||
assert day == 0
|
||
assert week == 0
|
||
assert month == 0
|
||
assert total == 0
|
||
|
||
async def test_user_management(self, test_db: BotDatabase) -> None:
|
||
"""
|
||
Тест управления пользователями.
|
||
Проверяет добавление, назначение админа, бан/разбан и возврат статуса пользователя.
|
||
"""
|
||
user_id: int = 555666777
|
||
|
||
# Добавление пользователя
|
||
await test_db.add_user(user_id, "managed_user", "Managed User")
|
||
|
||
async with test_db.session_factory() as session:
|
||
user: User | None = await session.get(User, user_id)
|
||
assert user is not None
|
||
assert user.status.value == "active"
|
||
|
||
# Назначение админом
|
||
await test_db.set_admin(user_id, True)
|
||
async with test_db.session_factory() as session:
|
||
user = await session.get(User, user_id)
|
||
assert user is not None
|
||
assert user.status.value == "admin"
|
||
|
||
# Бан пользователя
|
||
await test_db.ban_user(user_id)
|
||
async with test_db.session_factory() as session:
|
||
user = await session.get(User, user_id)
|
||
assert user is not None
|
||
assert user.status.value == "banned"
|
||
|
||
# Разбан
|
||
await test_db.unban_user(user_id)
|
||
async with test_db.session_factory() as session:
|
||
user = await session.get(User, user_id)
|
||
assert user is not None
|
||
assert user.status.value == "active"
|
||
|
||
# Снятие админки
|
||
await test_db.set_admin(user_id, False)
|
||
async with test_db.session_factory() as session:
|
||
user = await session.get(User, user_id)
|
||
assert user is not None
|
||
assert user.status.value == "active"
|