Merge remote-tracking branch 'origin/master' into fix-1

This commit is contained in:
2026-02-02 00:41:51 +03:00
116 changed files with 9801 additions and 6456 deletions

View File

@@ -3,240 +3,276 @@ from pathlib import Path
from unittest.mock import AsyncMock, MagicMock, Mock, patch
import pytest
from helper_bot.handlers.voice.exceptions import (AudioProcessingError,
VoiceMessageError)
from helper_bot.handlers.voice.exceptions import AudioProcessingError, VoiceMessageError
from helper_bot.handlers.voice.services import VoiceBotService
class TestVoiceBotService:
"""Тесты для VoiceBotService"""
@pytest.fixture
def mock_bot_db(self):
"""Мок для базы данных"""
mock_db = Mock()
mock_db.settings = {
'Settings': {'logs': True},
'Telegram': {'important_logs': 'test_chat_id'}
"Settings": {"logs": True},
"Telegram": {"important_logs": "test_chat_id"},
}
return mock_db
@pytest.fixture
def mock_settings(self):
"""Мок для настроек"""
return {
'Settings': {'logs': True},
'Telegram': {'preview_link': True}
}
return {"Settings": {"logs": True}, "Telegram": {"preview_link": True}}
@pytest.fixture
def voice_service(self, mock_bot_db, mock_settings):
"""Экземпляр VoiceBotService для тестов"""
return VoiceBotService(mock_bot_db, mock_settings)
@pytest.mark.asyncio
async def test_get_welcome_sticker_success(self, voice_service, mock_settings):
"""Тест успешного получения стикера"""
with patch('pathlib.Path.rglob') as mock_rglob:
mock_rglob.return_value = ['/path/to/sticker1.tgs', '/path/to/sticker2.tgs']
with patch("pathlib.Path.rglob") as mock_rglob:
mock_rglob.return_value = ["/path/to/sticker1.tgs", "/path/to/sticker2.tgs"]
sticker = await voice_service.get_welcome_sticker()
assert sticker is not None
mock_rglob.assert_called_once()
@pytest.mark.asyncio
async def test_get_welcome_sticker_no_stickers(self, voice_service, mock_settings):
"""Тест получения стикера когда их нет"""
with patch('pathlib.Path.rglob') as mock_rglob:
with patch("pathlib.Path.rglob") as mock_rglob:
mock_rglob.return_value = []
sticker = await voice_service.get_welcome_sticker()
assert sticker is None
@pytest.mark.asyncio
async def test_get_welcome_sticker_only_webp_files(self, voice_service, mock_settings):
async def test_get_welcome_sticker_only_webp_files(
self, voice_service, mock_settings
):
"""Тест получения стикера когда есть только webp файлы"""
with patch('pathlib.Path.rglob') as mock_rglob:
mock_rglob.return_value = ['/path/to/sticker1.webp', '/path/to/sticker2.webp']
with patch("pathlib.Path.rglob") as mock_rglob:
mock_rglob.return_value = [
"/path/to/sticker1.webp",
"/path/to/sticker2.webp",
]
sticker = await voice_service.get_welcome_sticker()
# Проверяем, что стикер не None (метод ищет файлы по паттерну Hello_*)
assert sticker is not None
@pytest.mark.asyncio
async def test_get_welcome_sticker_mixed_files(self, voice_service, mock_settings):
"""Тест получения стикера когда есть смешанные файлы"""
with patch('pathlib.Path.rglob') as mock_rglob:
with patch("pathlib.Path.rglob") as mock_rglob:
mock_rglob.return_value = [
'/path/to/sticker1.webp',
'/path/to/sticker2.tgs',
'/path/to/sticker3.webp'
"/path/to/sticker1.webp",
"/path/to/sticker2.tgs",
"/path/to/sticker3.webp",
]
sticker = await voice_service.get_welcome_sticker()
assert sticker is not None
# Проверяем, что стикер не None (метод возвращает FSInputFile объект)
@pytest.mark.asyncio
async def test_get_random_audio_success(self, voice_service, mock_bot_db):
"""Тест успешного получения случайного аудио"""
mock_bot_db.check_listen_audio = AsyncMock(return_value=['audio1', 'audio2'])
mock_bot_db.check_listen_audio = AsyncMock(return_value=["audio1", "audio2"])
mock_bot_db.get_user_id_by_file_name = AsyncMock(return_value=123)
mock_bot_db.get_date_by_file_name = AsyncMock(return_value='2025-01-01 12:00:00')
mock_bot_db.get_user_emoji = AsyncMock(return_value='😊')
mock_bot_db.get_date_by_file_name = AsyncMock(
return_value="2025-01-01 12:00:00"
)
mock_bot_db.get_user_emoji = AsyncMock(return_value="😊")
result = await voice_service.get_random_audio(456)
assert result is not None
assert len(result) == 3
# Проверяем, что результат содержит ожидаемые данные, но не проверяем точное значение audio
assert result[0] in ['audio1', 'audio2']
assert result[1] == '2025-01-01 12:00:00'
assert result[2] == '😊'
assert result[0] in ["audio1", "audio2"]
assert result[1] == "2025-01-01 12:00:00"
assert result[2] == "😊"
@pytest.mark.asyncio
async def test_get_random_audio_no_audio(self, voice_service, mock_bot_db):
"""Тест получения аудио когда их нет"""
mock_bot_db.check_listen_audio = AsyncMock(return_value=[])
result = await voice_service.get_random_audio(456)
assert result is None
@pytest.mark.asyncio
async def test_get_random_audio_single_audio(self, voice_service, mock_bot_db):
"""Тест получения аудио когда есть только одно"""
mock_bot_db.check_listen_audio = AsyncMock(return_value=['audio1'])
mock_bot_db.check_listen_audio = AsyncMock(return_value=["audio1"])
mock_bot_db.get_user_id_by_file_name = AsyncMock(return_value=123)
mock_bot_db.get_date_by_file_name = AsyncMock(return_value='2025-01-01 12:00:00')
mock_bot_db.get_user_emoji = AsyncMock(return_value='😊')
mock_bot_db.get_date_by_file_name = AsyncMock(
return_value="2025-01-01 12:00:00"
)
mock_bot_db.get_user_emoji = AsyncMock(return_value="😊")
result = await voice_service.get_random_audio(456)
assert result is not None
assert len(result) == 3
assert result[0] == 'audio1'
assert result[0] == "audio1"
@pytest.mark.asyncio
async def test_mark_audio_as_listened_success(self, voice_service, mock_bot_db):
"""Тест успешной пометки аудио как прослушанного"""
mock_bot_db.mark_listened_audio = AsyncMock()
await voice_service.mark_audio_as_listened('test_audio', 123)
mock_bot_db.mark_listened_audio.assert_called_once_with('test_audio', user_id=123)
await voice_service.mark_audio_as_listened("test_audio", 123)
mock_bot_db.mark_listened_audio.assert_called_once_with(
"test_audio", user_id=123
)
@pytest.mark.asyncio
async def test_clear_user_listenings_success(self, voice_service, mock_bot_db):
"""Тест успешной очистки прослушиваний"""
mock_bot_db.delete_listen_count_for_user = AsyncMock()
await voice_service.clear_user_listenings(123)
mock_bot_db.delete_listen_count_for_user.assert_called_once_with(123)
@pytest.mark.asyncio
async def test_get_remaining_audio_count_success(self, voice_service, mock_bot_db):
"""Тест получения количества оставшихся аудио"""
mock_bot_db.check_listen_audio = AsyncMock(return_value=['audio1', 'audio2', 'audio3'])
mock_bot_db.check_listen_audio = AsyncMock(
return_value=["audio1", "audio2", "audio3"]
)
result = await voice_service.get_remaining_audio_count(123)
assert result == 3
mock_bot_db.check_listen_audio.assert_called_once_with(user_id=123)
@pytest.mark.asyncio
async def test_get_remaining_audio_count_zero(self, voice_service, mock_bot_db):
"""Тест получения количества оставшихся аудио когда их нет"""
mock_bot_db.check_listen_audio = AsyncMock(return_value=[])
result = await voice_service.get_remaining_audio_count(123)
assert result == 0
mock_bot_db.check_listen_audio.assert_called_once_with(user_id=123)
@pytest.mark.asyncio
async def test_send_welcome_messages_success(self, voice_service, mock_bot_db, mock_settings):
"""Тест успешной отправки приветственных сообщений"""
async def test_send_welcome_messages_success(
self, voice_service, mock_bot_db, mock_settings
):
"""Тест успешной отправки приветственных сообщений."""
mock_message = Mock()
mock_message.from_user.id = 123
mock_message.answer = AsyncMock()
mock_message.answer.return_value = Mock()
mock_message.answer_sticker = AsyncMock()
with patch.object(voice_service, 'get_welcome_sticker') as mock_sticker:
mock_sticker.return_value = 'test_sticker.tgs'
await voice_service.send_welcome_messages(mock_message, '😊')
# Проверяем, что сообщения отправлены
assert mock_message.answer.call_count >= 1
with patch.object(
voice_service,
"get_welcome_sticker",
new_callable=AsyncMock,
return_value="test_sticker.tgs",
):
with patch(
"helper_bot.handlers.voice.services.asyncio.sleep",
new_callable=AsyncMock,
):
await voice_service.send_welcome_messages(mock_message, "😊")
assert mock_message.answer.call_count >= 1
@pytest.mark.asyncio
async def test_send_welcome_messages_no_sticker(self, voice_service, mock_bot_db, mock_settings):
"""Тест отправки приветственных сообщений без стикера"""
async def test_send_welcome_messages_no_sticker(
self, voice_service, mock_bot_db, mock_settings
):
"""Тест отправки приветственных сообщений без стикера."""
mock_message = Mock()
mock_message.from_user.id = 123
mock_message.answer = AsyncMock()
mock_message.answer.return_value = Mock()
with patch.object(voice_service, 'get_welcome_sticker') as mock_sticker:
mock_sticker.return_value = None
await voice_service.send_welcome_messages(mock_message, '😊')
# Проверяем, что сообщения отправлены
assert mock_message.answer.call_count >= 1
with patch.object(
voice_service,
"get_welcome_sticker",
new_callable=AsyncMock,
return_value=None,
):
with patch(
"helper_bot.handlers.voice.services.asyncio.sleep",
new_callable=AsyncMock,
):
await voice_service.send_welcome_messages(mock_message, "😊")
assert mock_message.answer.call_count >= 1
@pytest.mark.asyncio
async def test_send_welcome_messages_with_sticker(self, voice_service, mock_bot_db, mock_settings):
"""Тест отправки приветственных сообщений со стикером"""
async def test_send_welcome_messages_with_sticker(
self, voice_service, mock_bot_db, mock_settings
):
"""Тест отправки приветственных сообщений со стикером."""
mock_message = Mock()
mock_message.from_user.id = 123
mock_message.answer = AsyncMock()
mock_message.answer.return_value = Mock()
mock_message.answer_sticker = AsyncMock()
with patch.object(voice_service, 'get_welcome_sticker') as mock_sticker:
mock_sticker.return_value = 'test_sticker.tgs'
await voice_service.send_welcome_messages(mock_message, '😊')
# Проверяем, что сообщения отправлены
assert mock_message.answer.call_count >= 1
with patch.object(
voice_service,
"get_welcome_sticker",
new_callable=AsyncMock,
return_value="test_sticker.tgs",
):
with patch(
"helper_bot.handlers.voice.services.asyncio.sleep",
new_callable=AsyncMock,
):
await voice_service.send_welcome_messages(mock_message, "😊")
assert mock_message.answer.call_count >= 1
@pytest.mark.asyncio
async def test_get_welcome_sticker_with_tgs_files(self, voice_service, mock_settings):
async def test_get_welcome_sticker_with_tgs_files(
self, voice_service, mock_settings
):
"""Тест получения стикера когда есть .tgs файлы"""
with patch('pathlib.Path.rglob') as mock_rglob:
mock_rglob.return_value = ['/path/to/sticker1.tgs', '/path/to/sticker2.tgs']
with patch("pathlib.Path.rglob") as mock_rglob:
mock_rglob.return_value = ["/path/to/sticker1.tgs", "/path/to/sticker2.tgs"]
sticker = await voice_service.get_welcome_sticker()
assert sticker is not None
# Проверяем, что стикер не None (метод возвращает FSInputFile объект)
def test_service_initialization(self, mock_bot_db, mock_settings):
"""Тест инициализации сервиса"""
service = VoiceBotService(mock_bot_db, mock_settings)
assert service.bot_db == mock_bot_db
assert service.settings == mock_settings
def test_service_attributes(self, voice_service):
"""Тест атрибутов сервиса"""
assert hasattr(voice_service, 'bot_db')
assert hasattr(voice_service, 'settings')
assert hasattr(voice_service, 'get_welcome_sticker')
assert hasattr(voice_service, 'get_random_audio')
assert hasattr(voice_service, 'mark_audio_as_listened')
assert hasattr(voice_service, 'clear_user_listenings')
assert hasattr(voice_service, 'get_remaining_audio_count')
assert hasattr(voice_service, 'send_welcome_messages')
assert hasattr(voice_service, "bot_db")
assert hasattr(voice_service, "settings")
assert hasattr(voice_service, "get_welcome_sticker")
assert hasattr(voice_service, "get_random_audio")
assert hasattr(voice_service, "mark_audio_as_listened")
assert hasattr(voice_service, "clear_user_listenings")
assert hasattr(voice_service, "get_remaining_audio_count")
assert hasattr(voice_service, "send_welcome_messages")
@pytest.mark.asyncio
async def test_get_welcome_sticker_exception_returns_none(self, voice_service, mock_settings):
@@ -324,5 +360,5 @@ class TestVoiceBotService:
mock_send.assert_awaited_once()
if __name__ == '__main__':
if __name__ == "__main__":
pytest.main([__file__])