From 5afc066f035eda2b38f0ebe0cdd802d1a7a6a64a Mon Sep 17 00:00:00 2001 From: salmonik Date: Sun, 19 Apr 2026 15:43:42 +0200 Subject: chore: add pycord dependency, update main --- main.py | 15 +++++++-------- 1 file changed, 7 insertions(+), 8 deletions(-) (limited to 'main.py') diff --git a/main.py b/main.py index 6c8c35b..1f5e3f6 100644 --- a/main.py +++ b/main.py @@ -19,11 +19,17 @@ from cogs.utils import settings def setup_logging(debug: bool = False): """Configure logging based on debug flag.""" level = logging.DEBUG if debug else logging.INFO + + class DecryptionFilter(logging.Filter): + def filter(self, record): + return "Decryption failed" not in record.getMessage() + logging.basicConfig( level=level, format="%(levelname)s - %(filename)s - %(name)s - %(message)s", handlers=[logging.StreamHandler(sys.stdout)], ) + logging.getLogger().addFilter(DecryptionFilter()) # Create a new event loop and set it as the current loop @@ -39,12 +45,6 @@ async def on_ready(): logger = logging.getLogger(__name__) logger.info("ŁUKASZ SPERMA AKTYWACJA") - channel_id = os.getenv("STATUS_CHANNEL_ID") - if channel_id: - channel = bot.get_channel(int(channel_id)) - if channel: - await channel.send("ŁUKASZ SPERMA AKTYWACJA") - await settings.load_settings() @@ -74,7 +74,6 @@ if __name__ == "__main__": "cogs.trigger", "cogs.cron", "cogs.qr", - "cogs.plot", "cogs.voice", ] @@ -93,4 +92,4 @@ if __name__ == "__main__": except Exception as e: logging.getLogger(__name__).error(f"Error starting the bot: {e}") - sys.exit(1) \ No newline at end of file + sys.exit(1) -- cgit v1.2.3 From b343381fea3eab26e334a1b3bba202d715f9ea2e Mon Sep 17 00:00:00 2001 From: salmonik Date: Sun, 19 Apr 2026 15:44:33 +0200 Subject: test: improve test assertions and edge cases --- main.py | 95 ------------------------------- pycord | 1 - tests/cogs/test_ai.py | 40 ++++++++----- tests/cogs/test_assistant.py | 20 +++---- tests/cogs/test_compression_conversion.py | 26 ++++----- tests/cogs/test_downloader.py | 18 +++--- tests/cogs/test_math_commands.py | 12 ++-- tests/cogs/test_music_audio.py | 36 ++++++------ tests/cogs/test_music_join.py | 14 ++--- tests/cogs/test_music_play.py | 20 +++---- tests/cogs/test_plot.py | 85 --------------------------- tests/cogs/test_qr.py | 14 ++--- tests/cogs/test_say.py | 8 +-- tests/cogs/test_search.py | 20 +++---- tests/cogs/test_trigger.py | 22 +++---- tests/cogs/test_tts.py | 14 ++--- tests/cogs/test_vclogs.py | 20 +++---- tests/cogs/test_voice.py | 32 +++++------ tests/cogs/test_web.py | 14 ++--- 19 files changed, 172 insertions(+), 339 deletions(-) delete mode 100644 main.py delete mode 160000 pycord delete mode 100644 tests/cogs/test_plot.py (limited to 'main.py') diff --git a/main.py b/main.py deleted file mode 100644 index 1f5e3f6..0000000 --- a/main.py +++ /dev/null @@ -1,95 +0,0 @@ -# This file is part of Senator Sperma -# Licensed under the GPL-3.0 License -# Copyright (C) 2026 Salmonik @ salmonik@tuta.io -# https://codeberg.org/salmonik/senator-sperma - -import asyncio -import logging -import os -import sys -import argparse - -import discord -from discord.ext import commands -from dotenv import load_dotenv - -from cogs.utils import settings - - -def setup_logging(debug: bool = False): - """Configure logging based on debug flag.""" - level = logging.DEBUG if debug else logging.INFO - - class DecryptionFilter(logging.Filter): - def filter(self, record): - return "Decryption failed" not in record.getMessage() - - logging.basicConfig( - level=level, - format="%(levelname)s - %(filename)s - %(name)s - %(message)s", - handlers=[logging.StreamHandler(sys.stdout)], - ) - logging.getLogger().addFilter(DecryptionFilter()) - - -# Create a new event loop and set it as the current loop -loop = asyncio.new_event_loop() -asyncio.set_event_loop(loop) - -intents = discord.Intents.all() -bot = commands.Bot(intents=intents, loop=loop) - - -@bot.event -async def on_ready(): - logger = logging.getLogger(__name__) - logger.info("ŁUKASZ SPERMA AKTYWACJA") - - await settings.load_settings() - - -if __name__ == "__main__": - parser = argparse.ArgumentParser(description="Run Senator Sperma bot") - parser.add_argument("--debug", action="store_true", help="Enable debug logging") - args, unknown = parser.parse_known_args() - - load_dotenv() - setup_logging(args.debug) - - extensions = [ - "cogs.vclogs", - "cogs.compression", - "cogs.tts", - "cogs.web", - "cogs.ai", - "cogs.conversion", - "cogs.math_commands", - "cogs.downloader", - "cogs.say", - "cogs.assistant", - "cogs.music.play_commands", - "cogs.music.stop", - "cogs.music.join", - "cogs.search", - "cogs.trigger", - "cogs.cron", - "cogs.qr", - "cogs.voice", - ] - - try: - for i, extension in enumerate(extensions, 1): - bot.load_extension(extension) - logging.getLogger(__name__).info(f"Loaded {i}/{len(extensions)} extensions") - - token = os.getenv("TOKEN") - if not token: - raise ValueError( - "No token provided. Please set the TOKEN environment variable." - ) - - bot.run(token) - - except Exception as e: - logging.getLogger(__name__).error(f"Error starting the bot: {e}") - sys.exit(1) diff --git a/pycord b/pycord deleted file mode 160000 index 3dd5306..0000000 --- a/pycord +++ /dev/null @@ -1 +0,0 @@ -Subproject commit 3dd5306672933c9ea2cd995fc3f5daf28f105511 diff --git a/tests/cogs/test_ai.py b/tests/cogs/test_ai.py index bd8f813..a1c3fd4 100644 --- a/tests/cogs/test_ai.py +++ b/tests/cogs/test_ai.py @@ -1,6 +1,7 @@ import pytest from unittest.mock import AsyncMock, patch, MagicMock import discord +import httpx from tests.conftest import MockApplicationContext @@ -27,12 +28,18 @@ def mock_ai_response(): @pytest.mark.asyncio async def test_senator_command_success(ai_cog, mock_channel, mock_guild, bot, mock_ai_response): ctx = MockApplicationContext(bot=bot, channel=mock_channel, guild=mock_guild) - + mock_response = MagicMock() mock_response.json = MagicMock(return_value=mock_ai_response) - mock_response.status_code = 200 - - with patch('cogs.ai.requests.post', return_value=mock_response): + + mock_client = MagicMock() + mock_client.post = AsyncMock(return_value=mock_response) + mock_client.__aenter__ = AsyncMock(return_value=mock_response) + mock_client.__aexit__ = AsyncMock(return_value=None) + + with patch('cogs.ai.httpx.AsyncClient') as mock_httpx: + instance = mock_httpx.return_value.__aenter__.return_value + instance.post = AsyncMock(return_value=mock_response) with patch.object(ctx, 'send_followup', new_callable=AsyncMock) as mock_followup: await ai_cog.senator.callback(ai_cog, ctx, text="Hello", tts=False) mock_followup.assert_called_once_with("Test response from AI") @@ -41,12 +48,18 @@ async def test_senator_command_success(ai_cog, mock_channel, mock_guild, bot, mo @pytest.mark.asyncio async def test_senator_command_empty_choices(ai_cog, mock_channel, mock_guild, bot): ctx = MockApplicationContext(bot=bot, channel=mock_channel, guild=mock_guild) - + mock_response = MagicMock() mock_response.json = MagicMock(return_value={"choices": []}) - mock_response.status_code = 200 - - with patch('cogs.ai.requests.post', return_value=mock_response): + + mock_client = MagicMock() + mock_client.post = AsyncMock(return_value=mock_response) + mock_client.__aenter__ = AsyncMock(return_value=mock_response) + mock_client.__aexit__ = AsyncMock(return_value=None) + + with patch('cogs.ai.httpx.AsyncClient') as mock_httpx: + instance = mock_httpx.return_value.__aenter__.return_value + instance.post = AsyncMock(return_value=mock_response) with patch.object(ctx, 'send_followup', new_callable=AsyncMock) as mock_followup: await ai_cog.senator.callback(ai_cog, ctx, text="Hello", tts=False) mock_followup.assert_called_once_with("bot siem zesroł") @@ -55,15 +68,16 @@ async def test_senator_command_empty_choices(ai_cog, mock_channel, mock_guild, b @pytest.mark.asyncio async def test_senator_command_no_choices_key(ai_cog, mock_channel, mock_guild, bot): ctx = MockApplicationContext(bot=bot, channel=mock_channel, guild=mock_guild) - + mock_response = MagicMock() mock_response.json = MagicMock(return_value={}) - mock_response.status_code = 200 - - with patch('cogs.ai.requests.post', return_value=mock_response): + + with patch('cogs.ai.httpx.AsyncClient') as mock_httpx: + instance = mock_httpx.return_value.__aenter__.return_value + instance.post = AsyncMock(return_value=mock_response) with patch('cogs.ai.logger') as mock_logger: try: await ai_cog.senator.callback(ai_cog, ctx, text="Hello", tts=False) except KeyError: pass - assert mock_logger.info.called \ No newline at end of file + assert mock_logger.info.called diff --git a/tests/cogs/test_assistant.py b/tests/cogs/test_assistant.py index 09c3934..9a33232 100644 --- a/tests/cogs/test_assistant.py +++ b/tests/cogs/test_assistant.py @@ -7,11 +7,11 @@ from tests.conftest import MockApplicationContext def assistant_cog(): with patch('os.getenv', return_value="test_keyword"): from cogs.assistant import Jarvis - + mock_bot = MagicMock() mock_bot.user = MagicMock() mock_bot.user.id = 111 - + cog = Jarvis(mock_bot) return cog @@ -25,10 +25,10 @@ async def test_assistant_on_message_ignored_bot_message(assistant_cog): mock_author = MagicMock() mock_author.id = 456 mock_author.bot = True - + mock_message = MagicMock() mock_message.author = mock_author - + with patch.object(assistant_cog, 'assistant', new_callable=AsyncMock) as mock_assistant: await assistant_cog.on_message(mock_message) mock_assistant.assert_not_called() @@ -39,12 +39,12 @@ async def test_assistant_on_message_mentions_bot(assistant_cog): mock_message = MagicMock() mock_message.author = MagicMock() mock_message.author.id = 123 - + mock_mention = MagicMock() mock_mention.id = 111 mock_message.mentions = [mock_mention] mock_message.content = "test" - + with patch.object(assistant_cog, 'assistant', new_callable=AsyncMock) as mock_assistant: await assistant_cog.on_message(mock_message) mock_assistant.assert_called_once_with(mock_message) @@ -53,14 +53,14 @@ async def test_assistant_on_message_mentions_bot(assistant_cog): @pytest.mark.asyncio async def test_assistant_on_message_keyword_match(assistant_cog): assistant_cog.keyword = "test" - + mock_message = MagicMock() mock_message.author = MagicMock() mock_message.author.id = 123 - + mock_message.mentions = [] mock_message.content = "test message with test keyword" - + with patch.object(assistant_cog, 'assistant', new_callable=AsyncMock) as mock_assistant: await assistant_cog.on_message(mock_message) - mock_assistant.assert_called_once_with(mock_message) \ No newline at end of file + mock_assistant.assert_called_once_with(mock_message) diff --git a/tests/cogs/test_compression_conversion.py b/tests/cogs/test_compression_conversion.py index f9f74ad..f9d3427 100644 --- a/tests/cogs/test_compression_conversion.py +++ b/tests/cogs/test_compression_conversion.py @@ -40,11 +40,11 @@ async def test_build_conversion_command_video(): import cogs.conversion importlib.reload(cogs.conversion) from cogs.conversion import Conversion - + cog = Conversion.__new__(Conversion) cog._baseurl = "https://example.com" cog._uploadurl = "https://example.com" - + cmd = cog._build_conversion_command("Video", "/tmp/test.mp4", "/tmp/output.mp4", "") assert cmd is not None assert "ffmpeg" in cmd @@ -59,11 +59,11 @@ async def test_build_conversion_command_image(): import cogs.conversion importlib.reload(cogs.conversion) from cogs.conversion import Conversion - + cog = Conversion.__new__(Conversion) cog._baseurl = "https://example.com" cog._uploadurl = "https://example.com" - + cmd = cog._build_conversion_command("Image", "/tmp/test.jpg", "/tmp/output.png", "") assert cmd is not None assert "magick" in cmd @@ -78,11 +78,11 @@ async def test_build_conversion_command_unknown(): import cogs.conversion importlib.reload(cogs.conversion) from cogs.conversion import Conversion - + cog = Conversion.__new__(Conversion) cog._baseurl = "https://example.com" cog._uploadurl = "https://example.com" - + cmd = cog._build_conversion_command("Unknown", "/tmp/test.xyz", "/tmp/output.abc", "") assert cmd is None @@ -96,10 +96,10 @@ async def test_compression_get_command_video(): import cogs.compression importlib.reload(cogs.compression) from cogs.compression import Compression - + cog = Compression.__new__(Compression) cog.temp_dir = "/tmp" - + cmd = cog._get_compression_command("Video", "/tmp/test.mp4", "/tmp/output.mp4") assert cmd is not None assert "ffmpeg" in cmd @@ -114,10 +114,10 @@ async def test_compression_get_command_image(): import cogs.compression importlib.reload(cogs.compression) from cogs.compression import Compression - + cog = Compression.__new__(Compression) cog.temp_dir = "/tmp" - + cmd = cog._get_compression_command("Image", "/tmp/test.jpg", "/tmp/output.jpg") assert cmd is not None @@ -131,9 +131,9 @@ async def test_compression_get_command_unknown(): import cogs.compression importlib.reload(cogs.compression) from cogs.compression import Compression - + cog = Compression.__new__(Compression) cog.temp_dir = "/tmp" - + cmd = cog._get_compression_command("Unknown", "/tmp/test.xyz", "/tmp/output.xyz") - assert cmd is None \ No newline at end of file + assert cmd is None diff --git a/tests/cogs/test_downloader.py b/tests/cogs/test_downloader.py index 91eef93..6ac8ae7 100644 --- a/tests/cogs/test_downloader.py +++ b/tests/cogs/test_downloader.py @@ -14,9 +14,9 @@ def downloader_cog(bot): @pytest.mark.asyncio async def test_download_command_success_file(downloader_cog, mock_channel, mock_guild, bot): ctx = MockApplicationContext(bot=bot, channel=mock_channel, guild=mock_guild) - + mock_file_path = "/tmp/test_video.mp4" - + with patch('cogs.downloader.Downloader.download_standalone', return_value={ "status": "success", "type": "file", @@ -34,7 +34,7 @@ async def test_download_command_success_file(downloader_cog, mock_channel, mock_ @pytest.mark.asyncio async def test_download_command_success_url(downloader_cog, mock_channel, mock_guild, bot): ctx = MockApplicationContext(bot=bot, channel=mock_channel, guild=mock_guild) - + with patch('cogs.downloader.Downloader.download_standalone', return_value={ "status": "success", "type": "url", @@ -50,7 +50,7 @@ async def test_download_command_success_url(downloader_cog, mock_channel, mock_g @pytest.mark.asyncio async def test_download_command_error(downloader_cog, mock_channel, mock_guild, bot): ctx = MockApplicationContext(bot=bot, channel=mock_channel, guild=mock_guild) - + with patch('cogs.downloader.Downloader.download_standalone', return_value={ "status": "error", "type": "error", @@ -65,10 +65,10 @@ async def test_download_command_error(downloader_cog, mock_channel, mock_guild, @pytest.mark.asyncio async def test_message_download_with_url(downloader_cog, mock_channel, mock_guild, bot, mock_user): ctx = MockApplicationContext(bot=bot, channel=mock_channel, guild=mock_guild) - + mock_message = MagicMock() mock_message.content = "Check this out https://example.com/video" - + with patch('cogs.downloader.Downloader.download_standalone', return_value={ "status": "success", "type": "file", @@ -82,12 +82,12 @@ async def test_message_download_with_url(downloader_cog, mock_channel, mock_guil @pytest.mark.asyncio async def test_message_download_no_url(downloader_cog, mock_channel, mock_guild, bot): ctx = MockApplicationContext(bot=bot, channel=mock_channel, guild=mock_guild) - + mock_message = MagicMock() mock_message.content = "No URL here" - + with patch.object(ctx, 'respond', new_callable=AsyncMock) as mock_respond: await downloader_cog.message_download.callback(downloader_cog, ctx, message=mock_message) mock_respond.assert_called_once() call_args = mock_respond.call_args - assert "Brak" in str(call_args) \ No newline at end of file + assert "Brak" in str(call_args) diff --git a/tests/cogs/test_math_commands.py b/tests/cogs/test_math_commands.py index 0acac4a..5c78027 100644 --- a/tests/cogs/test_math_commands.py +++ b/tests/cogs/test_math_commands.py @@ -13,11 +13,11 @@ def math_cog(bot): @pytest.mark.asyncio async def test_math_command_valid_expression(math_cog, mock_channel, mock_guild, bot): ctx = MockApplicationContext(bot=bot, channel=mock_channel, guild=mock_guild) - + mock_process = MagicMock() mock_process.returncode = 0 mock_process.communicate = AsyncMock(return_value=(b"4", b"")) - + with patch('cogs.math_commands.asyncio.create_subprocess_exec', return_value=mock_process) as mock_subprocess: with patch('cogs.math_commands.re.search', return_value=None): with patch.object(ctx, 'respond', new_callable=AsyncMock) as mock_respond: @@ -29,7 +29,7 @@ async def test_math_command_valid_expression(math_cog, mock_channel, mock_guild, @pytest.mark.asyncio async def test_math_command_invalid_expression(math_cog, mock_channel, mock_guild, bot): ctx = MockApplicationContext(bot=bot, channel=mock_channel, guild=mock_guild) - + with patch('cogs.math_commands.re.search', return_value=MagicMock()): with patch.object(ctx, 'respond', new_callable=AsyncMock) as mock_respond: await math_cog.math.callback(math_cog, ctx, equation="eval(1)") @@ -41,15 +41,15 @@ async def test_math_command_invalid_expression(math_cog, mock_channel, mock_guil @pytest.mark.asyncio async def test_math_command_process_error(math_cog, mock_channel, mock_guild, bot): ctx = MockApplicationContext(bot=bot, channel=mock_channel, guild=mock_guild) - + mock_process = MagicMock() mock_process.returncode = 1 mock_process.communicate = AsyncMock(return_value=(b"", b"Error: invalid expression")) - + with patch('cogs.math_commands.asyncio.create_subprocess_exec', return_value=mock_process): with patch('cogs.math_commands.re.search', return_value=None): with patch.object(ctx, 'respond', new_callable=AsyncMock) as mock_respond: await math_cog.math.callback(math_cog, ctx, equation="2++") mock_respond.assert_called_once() args = mock_respond.call_args - assert "error" in str(args).lower() or "Error" in str(args) \ No newline at end of file + assert "error" in str(args).lower() or "Error" in str(args) diff --git a/tests/cogs/test_music_audio.py b/tests/cogs/test_music_audio.py index b53cf95..7ea902e 100644 --- a/tests/cogs/test_music_audio.py +++ b/tests/cogs/test_music_audio.py @@ -7,13 +7,13 @@ from tests.conftest import MockApplicationContext @pytest.mark.asyncio async def test_validate_voice_channel_not_in_voice(): from cogs.music.audio_playback import AudioPlaybackManager - + mock_ctx = MagicMock() mock_ctx.author.voice = None mock_ctx.respond = AsyncMock() - + result = await AudioPlaybackManager.validate_voice_channel(mock_ctx) - + assert result is None mock_ctx.respond.assert_called_once() @@ -21,24 +21,24 @@ async def test_validate_voice_channel_not_in_voice(): @pytest.mark.asyncio async def test_validate_voice_channel_in_voice(): from cogs.music.audio_playback import AudioPlaybackManager - + mock_channel = MagicMock() mock_ctx = MagicMock() mock_ctx.author.voice = MagicMock() mock_ctx.author.voice.channel = mock_channel mock_ctx.respond = AsyncMock() - + result = await AudioPlaybackManager.validate_voice_channel(mock_ctx) - + assert result == mock_channel @pytest.mark.asyncio async def test_prepare_file_source_file_not_found(): from cogs.music.audio_playback import AudioPlaybackManager - + display_name, absolute_path = await AudioPlaybackManager.prepare_file_source("/nonexistent/file.mp3") - + assert display_name is None assert absolute_path is None @@ -46,11 +46,11 @@ async def test_prepare_file_source_file_not_found(): @pytest.mark.asyncio async def test_prepare_file_source_absolute_path(): from cogs.music.audio_playback import AudioPlaybackManager - + with patch('os.path.exists', return_value=True): with patch('os.path.isabs', return_value=True): display_name, absolute_path = await AudioPlaybackManager.prepare_file_source("/tmp/test.mp3") - + assert display_name == "test" assert absolute_path == "/tmp/test.mp3" @@ -58,9 +58,9 @@ async def test_prepare_file_source_absolute_path(): @pytest.mark.asyncio async def test_prepare_source_url(): from cogs.music.audio_playback import AudioPlaybackManager - - source, display_name, is_url = await AudioPlaybackManager.prepare_source(MagicMock(), "https://example.com/stream") - + + source, _, is_url = await AudioPlaybackManager.prepare_source(MagicMock(), "https://example.com/stream") + assert is_url == True assert source == "https://example.com/stream" @@ -68,10 +68,10 @@ async def test_prepare_source_url(): @pytest.mark.asyncio async def test_prepare_source_local_file(): from cogs.music.audio_playback import AudioPlaybackManager - + with patch('os.path.exists', return_value=True): source, display_name, is_url = await AudioPlaybackManager.prepare_source(MagicMock(), "/tmp/test.mp3") - + assert is_url == False assert display_name == "test" @@ -79,7 +79,7 @@ async def test_prepare_source_local_file(): @pytest.mark.asyncio async def test_cleanup_temp_file(): from cogs.music.audio_playback import AudioPlaybackManager - + with patch('os.path.exists', return_value=True): with patch('os.remove'): await AudioPlaybackManager.cleanup_temp_file("/tmp/test.mp3") @@ -88,6 +88,6 @@ async def test_cleanup_temp_file(): @pytest.mark.asyncio async def test_cleanup_temp_file_not_exists(): from cogs.music.audio_playback import AudioPlaybackManager - + with patch('os.path.exists', return_value=False): - await AudioPlaybackManager.cleanup_temp_file("/nonexistent/file.mp3") \ No newline at end of file + await AudioPlaybackManager.cleanup_temp_file("/nonexistent/file.mp3") diff --git a/tests/cogs/test_music_join.py b/tests/cogs/test_music_join.py index 5fc66f6..3c7ca6e 100644 --- a/tests/cogs/test_music_join.py +++ b/tests/cogs/test_music_join.py @@ -22,14 +22,14 @@ async def test_join_command_success(join_cog, mock_channel, mock_guild, bot, moc ctx = MockApplicationContext(bot=bot, channel=mock_channel, guild=mock_guild) ctx.user = mock_user ctx.author = mock_user - + mock_voice_channel = MagicMock() mock_voice = MagicMock() mock_voice_channel.connect = AsyncMock(return_value=mock_voice) - + ctx.author.voice = MagicMock() ctx.author.voice.channel = mock_voice_channel - + with patch.object(mock_voice_channel, 'connect', new_callable=AsyncMock, return_value=mock_voice): with patch.object(ctx, 'respond', new_callable=AsyncMock): with patch.object(ctx.interaction, 'delete_original_response', new_callable=AsyncMock): @@ -41,13 +41,13 @@ async def test_stop_command_success(stop_cog, mock_channel, mock_guild, bot, moc ctx = MockApplicationContext(bot=bot, channel=mock_channel, guild=mock_guild) ctx.user = mock_user ctx.author = mock_user - + mock_voice_client = MagicMock() mock_voice_client.disconnect = AsyncMock() ctx.voice_client = mock_voice_client - + with patch.object(ctx, 'respond', new_callable=AsyncMock): with patch.object(ctx.interaction, 'delete_original_response', new_callable=AsyncMock): await stop_cog.stop.callback(stop_cog, ctx) - - mock_voice_client.disconnect.assert_called_once() \ No newline at end of file + + mock_voice_client.disconnect.assert_called_once() diff --git a/tests/cogs/test_music_play.py b/tests/cogs/test_music_play.py index abdd81c..e720c9a 100644 --- a/tests/cogs/test_music_play.py +++ b/tests/cogs/test_music_play.py @@ -22,7 +22,7 @@ def loop_cog(bot): @pytest.mark.asyncio async def test_create_search_embed_empty(play_commands_cog): embed, view = await play_commands_cog._create_search_embed([]) - + assert embed.title == "Wyniki wyszukiwania" assert len(view.children) == 0 @@ -33,9 +33,9 @@ async def test_create_search_embed_with_candidates(play_commands_cog): "https://example.com/test1.mp3", "https://example.com/test2.mp3" ] - + embed, view = await play_commands_cog._create_search_embed(candidates) - + assert embed.title == "Wyniki wyszukiwania" assert len(embed.fields) == 2 @@ -43,7 +43,7 @@ async def test_create_search_embed_with_candidates(play_commands_cog): @pytest.mark.asyncio async def test_play_command_no_file_or_search(play_commands_cog, mock_channel, mock_guild, bot): ctx = MockApplicationContext(bot=bot, channel=mock_channel, guild=mock_guild) - + with patch.object(ctx, 'respond', new_callable=AsyncMock) as mock_respond: await play_commands_cog.play.callback(play_commands_cog, ctx, melodia=None, file=None, compressed=False) mock_respond.assert_called_once() @@ -54,10 +54,10 @@ async def test_play_command_no_file_or_search(play_commands_cog, mock_channel, m @pytest.mark.asyncio async def test_play_command_both_file_and_search(play_commands_cog, mock_channel, mock_guild, bot): ctx = MockApplicationContext(bot=bot, channel=mock_channel, guild=mock_guild) - + mock_file = MagicMock() mock_file.filename = "test.mp3" - + with patch.object(ctx, 'respond', new_callable=AsyncMock) as mock_respond: await play_commands_cog.play.callback(play_commands_cog, ctx, melodia="test", file=mock_file, compressed=False) mock_respond.assert_called_once() @@ -80,7 +80,7 @@ async def test_loop_command_toggle_on(loop_cog, mock_channel, mock_guild, bot, m ctx.user = mock_user ctx.author = mock_user ctx.guild.id = 123 - + with patch.object(ctx, 'respond', new_callable=AsyncMock) as mock_respond: await loop_cog.loop.callback(loop_cog, ctx) mock_respond.assert_called_once() @@ -94,11 +94,11 @@ async def test_loop_command_toggle_off(loop_cog, mock_channel, mock_guild, bot, ctx.user = mock_user ctx.author = mock_user ctx.guild.id = 456 - + loop_cog.set_looping(456, True) - + with patch.object(ctx, 'respond', new_callable=AsyncMock) as mock_respond: await loop_cog.loop.callback(loop_cog, ctx) mock_respond.assert_called_once() args = mock_respond.call_args - assert "wyłączony" in str(args) \ No newline at end of file + assert "wyłączony" in str(args) diff --git a/tests/cogs/test_plot.py b/tests/cogs/test_plot.py deleted file mode 100644 index e38a2c7..0000000 --- a/tests/cogs/test_plot.py +++ /dev/null @@ -1,85 +0,0 @@ -import pytest -from unittest.mock import AsyncMock, patch, MagicMock -import os -from tests.conftest import MockApplicationContext - - -def test_parse_expression(): - from cogs.plot import parse_expression - - assert parse_expression("x^2") == "x**2" - assert parse_expression("x!") == "factorial(x)" - assert parse_expression("2x") == "2*x" - assert parse_expression("x2") == "x*2" - assert parse_expression("sin(x)") == "sin(x)" - - -def test_is_implicit(): - from cogs.plot import is_implicit - - assert is_implicit("x^2 + y^2 = 1") == True - assert is_implicit("x^2 = y") == True - assert is_implicit("x^2 + 1") == False - - -def test_parse_implicit(): - from cogs.plot import parse_implicit - - lhs, rhs = parse_implicit("x^2 + y = 2") - assert "x**2" in lhs - assert "+ y" in lhs or "+y" in lhs - assert rhs == "2" - - -@pytest.fixture -def plot_cog(bot): - from cogs.plot import Plot - cog = Plot(bot) - return cog - - -@pytest.mark.asyncio -async def test_plot_command_not_available(plot_cog, mock_channel, mock_guild, bot): - ctx = MockApplicationContext(bot=bot, channel=mock_channel, guild=mock_guild) - - with patch('cogs.plot._ensure_plot', return_value=False): - with patch.object(ctx, 'respond', new_callable=AsyncMock) as mock_respond: - await plot_cog.plot.callback(plot_cog, ctx, funkcja="x^2") - mock_respond.assert_called_once() - args = mock_respond.call_args - assert "matplotlib" in str(args).lower() or "nie jest dostępne" in str(args) - - -@pytest.mark.asyncio -async def test_plot_command_success(plot_cog, mock_channel, mock_guild, bot): - ctx = MockApplicationContext(bot=bot, channel=mock_channel, guild=mock_guild) - - with patch('cogs.plot._ensure_plot', return_value=True): - with patch('cogs.plot._plt_module') as mock_plt: - with patch('cogs.utils.temp.get_temp_dir', return_value="/tmp"): - with patch('os.path.exists', return_value=True): - with patch('os.unlink'): - with patch.object(ctx, 'followup', send=AsyncMock()) as mock_followup: - mock_fig = MagicMock() - mock_plt.subplots.return_value = (mock_fig, MagicMock()) - - await plot_cog.plot.callback(plot_cog, ctx, funkcja="x^2") - mock_followup.send.assert_called_once() - - -@pytest.mark.asyncio -async def test_plot_command_error_handling(plot_cog, mock_channel, mock_guild, bot): - ctx = MockApplicationContext(bot=bot, channel=mock_channel, guild=mock_guild) - - with patch('cogs.plot._ensure_plot', return_value=True): - with patch('cogs.plot._plt_module') as mock_plt: - with patch('cogs.utils.temp.get_temp_dir', return_value="/tmp"): - with patch('os.path.exists', return_value=True): - with patch('os.unlink'): - with patch.object(ctx, 'followup', send=AsyncMock()) as mock_followup: - mock_plt.subplots.side_effect = ValueError("Test error") - - await plot_cog.plot.callback(plot_cog, ctx, funkcja="invalid!!") - mock_followup.send.assert_called_once() - args = mock_followup.send.call_args - assert "Nie można" in str(args) or "Błąd" in str(args) \ No newline at end of file diff --git a/tests/cogs/test_qr.py b/tests/cogs/test_qr.py index f3688e3..2a132ca 100644 --- a/tests/cogs/test_qr.py +++ b/tests/cogs/test_qr.py @@ -23,7 +23,7 @@ def mock_temp_file(): @pytest.mark.asyncio async def test_qr_generate_success(qr_cog, mock_channel, mock_guild, bot, mock_temp_file): ctx = MockApplicationContext(bot=bot, channel=mock_channel, guild=mock_guild) - + with patch('cogs.qr.QR._generate_qr') as mock_generate: with patch.object(ctx, 'respond', new_callable=AsyncMock) as mock_respond: with patch('os.path.exists', return_value=True): @@ -36,7 +36,7 @@ async def test_qr_generate_success(qr_cog, mock_channel, mock_guild, bot, mock_t @pytest.mark.asyncio async def test_qr_generate_empty_text(qr_cog, mock_channel, mock_guild, bot): ctx = MockApplicationContext(bot=bot, channel=mock_channel, guild=mock_guild) - + with patch('cogs.qr.QR._generate_qr'): with patch.object(ctx, 'respond', new_callable=AsyncMock) as mock_respond: with patch('os.path.exists', return_value=False): @@ -47,10 +47,10 @@ async def test_qr_generate_empty_text(qr_cog, mock_channel, mock_guild, bot): @pytest.mark.asyncio async def test_qr_decode_not_available(qr_cog, mock_channel, mock_guild, bot): ctx = MockApplicationContext(bot=bot, channel=mock_channel, guild=mock_guild) - + mock_attachment = MagicMock() mock_attachment.url = "https://example.com/qr.png" - + with patch('cogs.qr._ensure_qr', return_value=False): with patch.object(ctx, 'respond', new_callable=AsyncMock) as mock_respond: await qr_cog.decode.callback(qr_cog, ctx, image=mock_attachment) @@ -62,14 +62,14 @@ async def test_qr_decode_not_available(qr_cog, mock_channel, mock_guild, bot): @pytest.mark.asyncio async def test_qr_decode_download_failure(qr_cog, mock_channel, mock_guild, bot): ctx = MockApplicationContext(bot=bot, channel=mock_channel, guild=mock_guild) - + mock_attachment = MagicMock() mock_attachment.url = "https://example.com/qr.png" - + with patch('cogs.qr._ensure_qr', return_value=True): with patch.object(qr_cog, '_download_image', return_value=None): with patch.object(ctx, 'respond', new_callable=AsyncMock) as mock_respond: await qr_cog.decode.callback(qr_cog, ctx, image=mock_attachment) mock_respond.assert_called_once() args = mock_respond.call_args - assert "Nie udało się" in str(args) or "failed" in str(args).lower() \ No newline at end of file + assert "Nie udało się" in str(args) or "failed" in str(args).lower() diff --git a/tests/cogs/test_say.py b/tests/cogs/test_say.py index 12f2d2a..13cad40 100644 --- a/tests/cogs/test_say.py +++ b/tests/cogs/test_say.py @@ -13,7 +13,7 @@ def say_cog(bot): @pytest.mark.asyncio async def test_say_command(say_cog, mock_channel, mock_guild, bot): ctx = MockApplicationContext(bot=bot, channel=mock_channel, guild=mock_guild) - + with patch.object(ctx, 'send', new_callable=AsyncMock) as mock_send: await say_cog.say.callback(say_cog, ctx, "Hello World") mock_send.assert_called_once_with(content="Hello World") @@ -22,7 +22,7 @@ async def test_say_command(say_cog, mock_channel, mock_guild, bot): @pytest.mark.asyncio async def test_say_command_empty_text(say_cog, mock_channel, mock_guild, bot): ctx = MockApplicationContext(bot=bot, channel=mock_channel, guild=mock_guild) - + with patch.object(ctx, 'send', new_callable=AsyncMock) as mock_send: await say_cog.say.callback(say_cog, ctx, "") mock_send.assert_called_once_with(content="") @@ -32,7 +32,7 @@ async def test_say_command_empty_text(say_cog, mock_channel, mock_guild, bot): async def test_say_command_long_text(say_cog, mock_channel, mock_guild, bot): ctx = MockApplicationContext(bot=bot, channel=mock_channel, guild=mock_guild) long_text = "A" * 2000 - + with patch.object(ctx, 'send', new_callable=AsyncMock) as mock_send: await say_cog.say.callback(say_cog, ctx, long_text) - mock_send.assert_called_once_with(content=long_text) \ No newline at end of file + mock_send.assert_called_once_with(content=long_text) diff --git a/tests/cogs/test_search.py b/tests/cogs/test_search.py index 4fde494..8c04dfc 100644 --- a/tests/cogs/test_search.py +++ b/tests/cogs/test_search.py @@ -16,11 +16,11 @@ async def test_search_command_success(search_cog, mock_channel, mock_guild, bot, ctx = MockApplicationContext(bot=bot, channel=mock_channel, guild=mock_guild) ctx.user = mock_user ctx.author = mock_user - + search_cog._cached_results[mock_user.id] = { "testfile.mp4": "https://example.com/files/testfile.mp4" } - + with patch.object(ctx, 'send_followup', new_callable=AsyncMock) as mock_followup: await search_cog.search.callback(search_cog, ctx, filename="testfile.mp4") mock_followup.assert_called_once_with("https://example.com/files/testfile.mp4") @@ -32,7 +32,7 @@ async def test_search_command_no_cache(search_cog, mock_channel, mock_guild, bot ctx = MockApplicationContext(bot=bot, channel=mock_channel, guild=mock_guild) ctx.user = mock_user ctx.author = mock_user - + with patch.object(ctx, 'send_followup', new_callable=AsyncMock) as mock_followup: await search_cog.search.callback(search_cog, ctx, filename="testfile.mp4") mock_followup.assert_called_once_with("Search results expired. Please search again.") @@ -43,11 +43,11 @@ async def test_search_command_file_not_found(search_cog, mock_channel, mock_guil ctx = MockApplicationContext(bot=bot, channel=mock_channel, guild=mock_guild) ctx.user = mock_user ctx.author = mock_user - + search_cog._cached_results[mock_user.id] = { "testfile.mp4": "https://example.com/files/testfile.mp4" } - + with patch.object(ctx, 'send_followup', new_callable=AsyncMock) as mock_followup: await search_cog.search.callback(search_cog, ctx, filename="nonexistent.mp4") mock_followup.assert_called_once_with("File 'nonexistent.mp4' not found.") @@ -58,7 +58,7 @@ async def test_search_command_empty_filename(search_cog, mock_channel, mock_guil ctx = MockApplicationContext(bot=bot, channel=mock_channel, guild=mock_guild) ctx.user = mock_user ctx.author = mock_user - + with patch.object(ctx, 'reply', new_callable=AsyncMock) as mock_reply: await search_cog.search.callback(search_cog, ctx, filename="") mock_reply.assert_called_once_with("Please select a file from the autocomplete options.") @@ -70,14 +70,14 @@ async def test_file_autocomplete(search_cog, mock_channel, mock_guild, bot, mock mock_autocomplete_ctx.value = "test" mock_autocomplete_ctx.interaction = MagicMock() mock_autocomplete_ctx.interaction.user = mock_user - + with patch('cogs.utils.file_search.UniversalSearcher.search_copyparty_autocomplete', new_callable=AsyncMock) as mock_search: mock_search.return_value = [ "https://example.com/files/test1.mp4", "https://example.com/files/test2.mp4" ] - + choices = await search_cog.file_autocomplete(mock_autocomplete_ctx) - + assert len(choices) == 2 - assert mock_user.id in search_cog._cached_results \ No newline at end of file + assert mock_user.id in search_cog._cached_results diff --git a/tests/cogs/test_trigger.py b/tests/cogs/test_trigger.py index befc360..6aaaa11 100644 --- a/tests/cogs/test_trigger.py +++ b/tests/cogs/test_trigger.py @@ -28,17 +28,17 @@ def mock_db_connection(): @pytest.mark.asyncio async def test_trigger_create_command(trigger_cog, mock_channel, mock_guild, bot, mock_db_connection): ctx = MockApplicationContext(bot=bot, channel=mock_channel, guild=mock_guild) - + mock_conn, mock_cursor = mock_db_connection mock_cursor.fetchone.return_value = None - + with patch('cogs.trigger.get_connection') as mock_get_conn: mock_conn = MagicMock() mock_cursor = MagicMock() mock_conn.cursor.return_value = mock_cursor mock_get_conn.return_value.__enter__ = MagicMock(return_value=mock_conn) mock_get_conn.return_value.__exit__ = MagicMock(return_value=False) - + with patch.object(ctx, 'respond', new_callable=AsyncMock) as mock_respond: await trigger_cog.create.callback(trigger_cog, ctx, name="test_trigger") mock_respond.assert_called_once_with("trigger added") @@ -47,7 +47,7 @@ async def test_trigger_create_command(trigger_cog, mock_channel, mock_guild, bot @pytest.mark.asyncio async def test_trigger_add_command(trigger_cog, mock_channel, mock_guild, bot, mock_db_connection): ctx = MockApplicationContext(bot=bot, channel=mock_channel, guild=mock_guild) - + with patch('cogs.trigger.get_connection') as mock_get_conn: mock_conn = MagicMock() mock_cursor = MagicMock() @@ -55,7 +55,7 @@ async def test_trigger_add_command(trigger_cog, mock_channel, mock_guild, bot, m mock_conn.cursor.return_value = mock_cursor mock_get_conn.return_value.__enter__ = MagicMock(return_value=mock_conn) mock_get_conn.return_value.__exit__ = MagicMock(return_value=False) - + with patch.object(ctx, 'respond', new_callable=AsyncMock) as mock_respond: await trigger_cog.add.callback(trigger_cog, ctx, name="test_trigger", trigger="hello", response="Hi there!") mock_respond.assert_called_once_with("trigger updated") @@ -64,7 +64,7 @@ async def test_trigger_add_command(trigger_cog, mock_channel, mock_guild, bot, m @pytest.mark.asyncio async def test_trigger_add_command_not_found(trigger_cog, mock_channel, mock_guild, bot, mock_db_connection): ctx = MockApplicationContext(bot=bot, channel=mock_channel, guild=mock_guild) - + with patch('cogs.trigger.get_connection') as mock_get_conn: mock_conn = MagicMock() mock_cursor = MagicMock() @@ -72,7 +72,7 @@ async def test_trigger_add_command_not_found(trigger_cog, mock_channel, mock_gui mock_conn.cursor.return_value = mock_cursor mock_get_conn.return_value.__enter__ = MagicMock(return_value=mock_conn) mock_get_conn.return_value.__exit__ = MagicMock(return_value=False) - + with patch.object(ctx, 'respond', new_callable=AsyncMock) as mock_respond: await trigger_cog.add.callback(trigger_cog, ctx, name="nonexistent", trigger="hello", response="Hi") mock_respond.assert_called_once_with("Trigger not found.") @@ -81,7 +81,7 @@ async def test_trigger_add_command_not_found(trigger_cog, mock_channel, mock_gui @pytest.mark.asyncio async def test_trigger_delete_command(trigger_cog, mock_channel, mock_guild, bot, mock_db_connection): ctx = MockApplicationContext(bot=bot, channel=mock_channel, guild=mock_guild) - + with patch('cogs.trigger.get_connection') as mock_get_conn: mock_conn = MagicMock() mock_cursor = MagicMock() @@ -89,7 +89,7 @@ async def test_trigger_delete_command(trigger_cog, mock_channel, mock_guild, bot mock_conn.cursor.return_value = mock_cursor mock_get_conn.return_value.__enter__ = MagicMock(return_value=mock_conn) mock_get_conn.return_value.__exit__ = MagicMock(return_value=False) - + with patch.object(ctx, 'respond', new_callable=AsyncMock) as mock_respond: await trigger_cog.delete.callback(trigger_cog, ctx, name="test_trigger") mock_respond.assert_called_once_with("trigger deleted") @@ -98,9 +98,9 @@ async def test_trigger_delete_command(trigger_cog, mock_channel, mock_guild, bot @pytest.mark.asyncio async def test_trigger_help_command(trigger_cog, mock_channel, mock_guild, bot): ctx = MockApplicationContext(bot=bot, channel=mock_channel, guild=mock_guild) - + with patch.object(ctx, 'respond', new_callable=AsyncMock) as mock_respond: await trigger_cog.help.callback(trigger_cog, ctx) mock_respond.assert_called_once() args = mock_respond.call_args - assert "Trigger create" in str(args) \ No newline at end of file + assert "Trigger create" in str(args) diff --git a/tests/cogs/test_tts.py b/tests/cogs/test_tts.py index 8c95670..de68580 100644 --- a/tests/cogs/test_tts.py +++ b/tests/cogs/test_tts.py @@ -16,10 +16,10 @@ async def test_tts_file_output(tts_cog, mock_channel, mock_guild, bot, mock_user ctx = MockApplicationContext(bot=bot, channel=mock_channel, guild=mock_guild) ctx.user = mock_user ctx.author = mock_user - - mock_temp_path = "/tmp/test_tts.mp3" - - with patch('cogs.tts.gTTS') as mock_gtts: + + "/tmp/test_tts.mp3" + + with patch('cogs.tts.gTTS') as _: with patch('os.path.exists', return_value=True): with patch('os.unlink'): with patch.object(ctx, 'respond', new_callable=AsyncMock) as mock_respond: @@ -34,7 +34,7 @@ async def test_tts_voice_output_not_in_channel(tts_cog, mock_channel, mock_guild ctx.user = mock_user ctx.author = mock_user ctx.author.voice = None - + with patch('cogs.tts.gTTS'): with patch('os.path.exists', return_value=True): with patch('os.unlink'): @@ -48,11 +48,11 @@ async def test_tts_error_handling(tts_cog, mock_channel, mock_guild, bot, mock_u ctx = MockApplicationContext(bot=bot, channel=mock_channel, guild=mock_guild) ctx.user = mock_user ctx.author = mock_user - + with patch('cogs.tts.gTTS', side_effect=Exception("TTS Error")): with patch('os.path.exists', return_value=False): with patch.object(ctx, 'respond', new_callable=AsyncMock) as mock_respond: await tts_cog.tts.callback(tts_cog, ctx, text="Hello", output="file") mock_respond.assert_called_once() args = mock_respond.call_args - assert "Error" in str(args) or "eror" in str(args) \ No newline at end of file + assert "Error" in str(args) or "eror" in str(args) diff --git a/tests/cogs/test_vclogs.py b/tests/cogs/test_vclogs.py index 14bc6d5..2003478 100644 --- a/tests/cogs/test_vclogs.py +++ b/tests/cogs/test_vclogs.py @@ -6,7 +6,7 @@ from tests.conftest import MockApplicationContext def test_format_duration(): from cogs.vclogs import format_duration - + assert format_duration(30) == "30s" assert format_duration(90) == "1m 30s" assert format_duration(3661) == "1h 1m 1s" @@ -44,9 +44,9 @@ async def test_handle_state_change_deaf_true(vclogs_cog): mock_member = MagicMock() mock_member.display_name = "TestUser" mock_channel = MagicMock() - + tts_text, channel = await vclogs_cog.handle_state_change(mock_member, mock_channel, 'deaf', True, None) - + assert "jest bity przez ojca" in tts_text @@ -55,9 +55,9 @@ async def test_handle_state_change_deaf_false(vclogs_cog): mock_member = MagicMock() mock_member.display_name = "TestUser" mock_channel = MagicMock() - + tts_text, channel = await vclogs_cog.handle_state_change(mock_member, mock_channel, 'deaf', False, None) - + assert "uciek od ojca" in tts_text @@ -66,9 +66,9 @@ async def test_handle_state_change_mute_true(vclogs_cog): mock_member = MagicMock() mock_member.display_name = "TestUser" mock_channel = MagicMock() - + tts_text, channel = await vclogs_cog.handle_state_change(mock_member, mock_channel, 'mute', True, None) - + assert "idzie robić jajecznice" in tts_text @@ -77,7 +77,7 @@ async def test_handle_state_change_mute_false(vclogs_cog): mock_member = MagicMock() mock_member.display_name = "TestUser" mock_channel = MagicMock() - + tts_text, channel = await vclogs_cog.handle_state_change(mock_member, mock_channel, 'mute', False, None) - - assert "zrobił jajecznice" in tts_text \ No newline at end of file + + assert "zrobił jajecznice" in tts_text diff --git a/tests/cogs/test_voice.py b/tests/cogs/test_voice.py index f5784f6..ade29cb 100644 --- a/tests/cogs/test_voice.py +++ b/tests/cogs/test_voice.py @@ -7,14 +7,14 @@ from tests.conftest import MockApplicationContext @pytest.mark.asyncio async def test_get_voice_manager(): from cogs.voice import get_voice_manager, VoiceManager - + mock_bot = MagicMock() mock_bot.user = MagicMock() mock_bot.user.id = 12345 - + manager1 = get_voice_manager(mock_bot) manager2 = get_voice_manager(mock_bot) - + assert isinstance(manager1, VoiceManager) assert manager1 is manager2 @@ -22,41 +22,41 @@ async def test_get_voice_manager(): @pytest.mark.asyncio async def test_voice_manager_join_channel_not_found(): from cogs.voice import VoiceManager - + mock_bot = MagicMock() mock_bot.get_channel.return_value = None - + manager = VoiceManager(mock_bot) result = await manager.join_by_channel_id(999) - + assert result is None @pytest.mark.asyncio async def test_voice_manager_join_invalid_channel(): from cogs.voice import VoiceManager - + mock_bot = MagicMock() mock_channel = MagicMock() mock_bot.get_channel.return_value = mock_channel - + manager = VoiceManager(mock_bot) result = await manager.join_by_channel_id(999) - + assert result is None @pytest.mark.asyncio async def test_voice_manager_get_voice_status_not_connected(): from cogs.voice import VoiceManager - + mock_bot = MagicMock() mock_guild = MagicMock() - + with patch('cogs.voice.VoiceManager.get_voice_client', return_value=None): manager = VoiceManager(mock_bot) voice_client, is_connected, is_playing = await manager.get_voice_status(mock_guild) - + assert voice_client is None assert is_connected == False assert is_playing == False @@ -65,15 +65,15 @@ async def test_voice_manager_get_voice_status_not_connected(): @pytest.mark.asyncio async def test_voice_manager_stop(): from cogs.voice import VoiceManager - + mock_bot = MagicMock() mock_guild = MagicMock() mock_voice_client = MagicMock() mock_voice_client.disconnect = AsyncMock() - + with patch('cogs.voice.VoiceManager.get_voice_client', return_value=mock_voice_client): manager = VoiceManager(mock_bot) await manager.stop(mock_guild) - + mock_voice_client.stop.assert_called_once() - mock_voice_client.disconnect.assert_called_once() \ No newline at end of file + mock_voice_client.disconnect.assert_called_once() diff --git a/tests/cogs/test_web.py b/tests/cogs/test_web.py index 53a44e5..e0d2208 100644 --- a/tests/cogs/test_web.py +++ b/tests/cogs/test_web.py @@ -13,7 +13,7 @@ def web_cog(bot): @pytest.mark.asyncio async def test_web_command_success(web_cog, mock_channel, mock_guild, bot): ctx = MockApplicationContext(bot=bot, channel=mock_channel, guild=mock_guild) - + mock_response = MagicMock() mock_response.status_code = 200 mock_response.text = ''' @@ -22,7 +22,7 @@ async def test_web_command_success(web_cog, mock_channel, mock_guild, bot): Test Result 2 ''' - + with patch('cogs.web.requests.get', return_value=mock_response) as mock_get: with patch.object(ctx, 'respond', new_callable=AsyncMock) as mock_respond: await web_cog.web.callback(web_cog, ctx, query="test query") @@ -33,11 +33,11 @@ async def test_web_command_success(web_cog, mock_channel, mock_guild, bot): @pytest.mark.asyncio async def test_web_command_no_results(web_cog, mock_channel, mock_guild, bot): ctx = MockApplicationContext(bot=bot, channel=mock_channel, guild=mock_guild) - + mock_response = MagicMock() mock_response.status_code = 200 mock_response.text = '' - + with patch('cogs.web.requests.get', return_value=mock_response): with patch.object(ctx, 'respond', new_callable=AsyncMock) as mock_respond: await web_cog.web.callback(web_cog, ctx, query="test") @@ -47,11 +47,11 @@ async def test_web_command_no_results(web_cog, mock_channel, mock_guild, bot): @pytest.mark.asyncio async def test_web_command_http_error(web_cog, mock_channel, mock_guild, bot): ctx = MockApplicationContext(bot=bot, channel=mock_channel, guild=mock_guild) - + mock_response = MagicMock() mock_response.status_code = 500 - + with patch('cogs.web.requests.get', return_value=mock_response): with patch.object(ctx, 'respond', new_callable=AsyncMock) as mock_respond: await web_cog.web.callback(web_cog, ctx, query="test") - mock_respond.assert_called_once_with(content="Error: 500", ephemeral=True) \ No newline at end of file + mock_respond.assert_called_once_with(content="Error: 500", ephemeral=True) -- cgit v1.2.3 From fe8fc54836a33121eba308922019eab75a92879d Mon Sep 17 00:00:00 2001 From: salmonik Date: Sun, 19 Apr 2026 15:45:17 +0200 Subject: readd main.py Signed-off-by: salmonik --- main.py | 95 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 95 insertions(+) create mode 100644 main.py (limited to 'main.py') diff --git a/main.py b/main.py new file mode 100644 index 0000000..1f5e3f6 --- /dev/null +++ b/main.py @@ -0,0 +1,95 @@ +# This file is part of Senator Sperma +# Licensed under the GPL-3.0 License +# Copyright (C) 2026 Salmonik @ salmonik@tuta.io +# https://codeberg.org/salmonik/senator-sperma + +import asyncio +import logging +import os +import sys +import argparse + +import discord +from discord.ext import commands +from dotenv import load_dotenv + +from cogs.utils import settings + + +def setup_logging(debug: bool = False): + """Configure logging based on debug flag.""" + level = logging.DEBUG if debug else logging.INFO + + class DecryptionFilter(logging.Filter): + def filter(self, record): + return "Decryption failed" not in record.getMessage() + + logging.basicConfig( + level=level, + format="%(levelname)s - %(filename)s - %(name)s - %(message)s", + handlers=[logging.StreamHandler(sys.stdout)], + ) + logging.getLogger().addFilter(DecryptionFilter()) + + +# Create a new event loop and set it as the current loop +loop = asyncio.new_event_loop() +asyncio.set_event_loop(loop) + +intents = discord.Intents.all() +bot = commands.Bot(intents=intents, loop=loop) + + +@bot.event +async def on_ready(): + logger = logging.getLogger(__name__) + logger.info("ŁUKASZ SPERMA AKTYWACJA") + + await settings.load_settings() + + +if __name__ == "__main__": + parser = argparse.ArgumentParser(description="Run Senator Sperma bot") + parser.add_argument("--debug", action="store_true", help="Enable debug logging") + args, unknown = parser.parse_known_args() + + load_dotenv() + setup_logging(args.debug) + + extensions = [ + "cogs.vclogs", + "cogs.compression", + "cogs.tts", + "cogs.web", + "cogs.ai", + "cogs.conversion", + "cogs.math_commands", + "cogs.downloader", + "cogs.say", + "cogs.assistant", + "cogs.music.play_commands", + "cogs.music.stop", + "cogs.music.join", + "cogs.search", + "cogs.trigger", + "cogs.cron", + "cogs.qr", + "cogs.voice", + ] + + try: + for i, extension in enumerate(extensions, 1): + bot.load_extension(extension) + logging.getLogger(__name__).info(f"Loaded {i}/{len(extensions)} extensions") + + token = os.getenv("TOKEN") + if not token: + raise ValueError( + "No token provided. Please set the TOKEN environment variable." + ) + + bot.run(token) + + except Exception as e: + logging.getLogger(__name__).error(f"Error starting the bot: {e}") + sys.exit(1) -- cgit v1.2.3