From cd8ed8bc5793985df2c1692072a932ceee517b95 Mon Sep 17 00:00:00 2001 From: salmonik Date: Wed, 8 Jul 2026 02:13:35 +0200 Subject: OPEN THE RUST GATES Signed-off-by: salmonik --- tests/cogs/test_ai.py | 83 ----------- tests/cogs/test_assistant.py | 66 --------- tests/cogs/test_compression_conversion.py | 139 ------------------ tests/cogs/test_cron.py | 147 ------------------- tests/cogs/test_cron_integration.py | 39 ----- tests/cogs/test_downloader.py | 93 ------------ tests/cogs/test_downloader_integration.py | 37 ----- tests/cogs/test_math_commands.py | 55 ------- tests/cogs/test_music_audio.py | 93 ------------ tests/cogs/test_music_external_play.py | 109 -------------- tests/cogs/test_music_integration.py | 46 ------ tests/cogs/test_music_join.py | 56 -------- tests/cogs/test_music_play.py | 104 -------------- tests/cogs/test_qr.py | 75 ---------- tests/cogs/test_say.py | 38 ----- tests/cogs/test_search.py | 83 ----------- tests/cogs/test_trigger.py | 106 -------------- tests/cogs/test_trigger_integration.py | 54 ------- tests/cogs/test_tts.py | 58 -------- tests/cogs/test_uploader.py | 226 ----------------------------- tests/cogs/test_vclogs.py | 88 ------------ tests/cogs/test_vclogs_integration.py | 86 ----------- tests/cogs/test_voice.py | 79 ----------- tests/cogs/test_web.py | 57 -------- tests/conftest.py | 228 ------------------------------ 25 files changed, 2245 deletions(-) delete mode 100644 tests/cogs/test_ai.py delete mode 100644 tests/cogs/test_assistant.py delete mode 100644 tests/cogs/test_compression_conversion.py delete mode 100644 tests/cogs/test_cron.py delete mode 100644 tests/cogs/test_cron_integration.py delete mode 100644 tests/cogs/test_downloader.py delete mode 100644 tests/cogs/test_downloader_integration.py delete mode 100644 tests/cogs/test_math_commands.py delete mode 100644 tests/cogs/test_music_audio.py delete mode 100644 tests/cogs/test_music_external_play.py delete mode 100644 tests/cogs/test_music_integration.py delete mode 100644 tests/cogs/test_music_join.py delete mode 100644 tests/cogs/test_music_play.py delete mode 100644 tests/cogs/test_qr.py delete mode 100644 tests/cogs/test_say.py delete mode 100644 tests/cogs/test_search.py delete mode 100644 tests/cogs/test_trigger.py delete mode 100644 tests/cogs/test_trigger_integration.py delete mode 100644 tests/cogs/test_tts.py delete mode 100644 tests/cogs/test_uploader.py delete mode 100644 tests/cogs/test_vclogs.py delete mode 100644 tests/cogs/test_vclogs_integration.py delete mode 100644 tests/cogs/test_voice.py delete mode 100644 tests/cogs/test_web.py delete mode 100644 tests/conftest.py (limited to 'tests') diff --git a/tests/cogs/test_ai.py b/tests/cogs/test_ai.py deleted file mode 100644 index 6d92f55..0000000 --- a/tests/cogs/test_ai.py +++ /dev/null @@ -1,83 +0,0 @@ -import pytest -from unittest.mock import AsyncMock, patch, MagicMock -import discord -import httpx -from conftest import MockApplicationContext - - -@pytest.fixture -def ai_cog(bot): - from cogs.ai import AI - cog = AI(bot) - return cog - - -@pytest.fixture -def mock_ai_response(): - return { - "choices": [ - { - "message": { - "content": "Test response from AI" - } - } - ] - } - - -@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_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") - - -@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_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ł") - - -@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={}) - - 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 diff --git a/tests/cogs/test_assistant.py b/tests/cogs/test_assistant.py deleted file mode 100644 index 056a868..0000000 --- a/tests/cogs/test_assistant.py +++ /dev/null @@ -1,66 +0,0 @@ -import pytest -from unittest.mock import AsyncMock, patch, MagicMock -from conftest import MockApplicationContext - - -@pytest.fixture -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 - - -def test_assistant_keyword_default(assistant_cog): - assert assistant_cog.keyword == "test_keyword" - - -@pytest.mark.asyncio -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() - - -@pytest.mark.asyncio -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) - - -@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) diff --git a/tests/cogs/test_compression_conversion.py b/tests/cogs/test_compression_conversion.py deleted file mode 100644 index 892482b..0000000 --- a/tests/cogs/test_compression_conversion.py +++ /dev/null @@ -1,139 +0,0 @@ -import pytest -from unittest.mock import AsyncMock, patch, MagicMock -import os -import discord -from conftest import MockApplicationContext - - -def test_compression_filetype_video(): - from cogs.compression import filetype - assert filetype("test.mp4") == "Video" - assert filetype("test.avi") == "Video" - - -def test_compression_filetype_audio(): - from cogs.compression import filetype - assert filetype("test.mp3") == "Audio" - assert filetype("test.wav") == "Audio" - - -def test_compression_filetype_image(): - from cogs.compression import filetype - assert filetype("test.jpg") == "Image" - assert filetype("test.png") == "Image" - - -def test_conversion_filetype(): - from cogs.conversion import filetype - assert filetype("test.mp4") == "Video" - assert filetype("test.mp3") == "Audio" - assert filetype("test.jpg") == "Image" - assert filetype("test.xyz") == "Unknown" - - -@pytest.mark.asyncio -async def test_build_conversion_command_video(): - with patch('os.getenv', return_value="https://example.com"): - with patch('cogs.utils.temp.get_temp_dir', return_value="/tmp"): - with patch('cogs.utils.settings.get_baseurl', return_value="https://example.com"): - import importlib - 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 - - -@pytest.mark.asyncio -async def test_build_conversion_command_image(): - with patch('os.getenv', return_value="https://example.com"): - with patch('cogs.utils.temp.get_temp_dir', return_value="/tmp"): - with patch('cogs.utils.settings.get_baseurl', return_value="https://example.com"): - import importlib - 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 - - -@pytest.mark.asyncio -async def test_build_conversion_command_unknown(): - with patch('os.getenv', return_value="https://example.com"): - with patch('cogs.utils.temp.get_temp_dir', return_value="/tmp"): - with patch('cogs.utils.settings.get_baseurl', return_value="https://example.com"): - import importlib - 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 - - -@pytest.mark.asyncio -async def test_compression_get_command_video(): - with patch('os.getenv', return_value="https://example.com"): - with patch('cogs.utils.temp.get_temp_dir', return_value="/tmp"): - with patch('cogs.utils.settings.get_baseurl', return_value="https://example.com"): - import importlib - 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 - - -@pytest.mark.asyncio -async def test_compression_get_command_image(): - with patch('os.getenv', return_value="https://example.com"): - with patch('cogs.utils.temp.get_temp_dir', return_value="/tmp"): - with patch('cogs.utils.settings.get_baseurl', return_value="https://example.com"): - import importlib - 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 - - -@pytest.mark.asyncio -async def test_compression_get_command_unknown(): - with patch('os.getenv', return_value="https://example.com"): - with patch('cogs.utils.temp.get_temp_dir', return_value="/tmp"): - with patch('cogs.utils.settings.get_baseurl', return_value="https://example.com"): - import importlib - 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 diff --git a/tests/cogs/test_cron.py b/tests/cogs/test_cron.py deleted file mode 100644 index 28ccfe1..0000000 --- a/tests/cogs/test_cron.py +++ /dev/null @@ -1,147 +0,0 @@ -import pytest -from datetime import datetime -from unittest.mock import MagicMock, patch - -from cogs.cron import Cron -from cogs.utils.database import _ConnectionContextManager - - -@pytest.fixture -def mock_bot(): - bot = MagicMock() - bot.loop = MagicMock() - bot.is_closed = MagicMock(return_value=False) - bot.wait_until_ready = MagicMock() - bot.loop.create_task = MagicMock(return_value=MagicMock()) - return bot - - -def create_cog(mock_bot): - with patch.object(Cron, "__init__", lambda self, bot: None): - with patch("cogs.cron.init_database"): - cog = Cron.__new__(Cron) - cog.bot = mock_bot - cog.scheduled_tasks = [] - cog.task = MagicMock() - return cog - - -class TestLoadTasks: - def test_load_tasks_with_data(self, mock_bot): - mock_conn = MagicMock() - mock_cursor = MagicMock() - mock_cursor.fetchall.return_value = [ - (1, "* * * * *", "audio", 123, 1, None, "test message") - ] - mock_conn.cursor.return_value = mock_cursor - - # Create a context manager mock - mock_ctx = MagicMock() - mock_ctx.__enter__ = MagicMock(return_value=mock_conn) - mock_ctx.__exit__ = MagicMock(return_value=False) - - with patch("cogs.cron.get_connection", return_value=mock_ctx): - cog = Cron.__new__(Cron) - cog.bot = mock_bot - cog.scheduled_tasks = [] - cog.task = MagicMock() - cog.load_tasks() - assert len(cog.scheduled_tasks) == 1 - assert cog.scheduled_tasks[0]["id"] == 1 - -class TestSaveTasks: - def test_save_tasks(self, mock_bot): - cog = create_cog(mock_bot) - cog.scheduled_tasks = [{"id": 1, "cron_expression": "* * * * *", "type": "audio", "channel_id": 123, "active": True}] - - mock_conn = MagicMock() - mock_cursor = MagicMock() - mock_conn.cursor.return_value = mock_cursor - - # Create a context manager mock - mock_ctx = MagicMock() - mock_ctx.__enter__ = MagicMock(return_value=mock_conn) - mock_ctx.__exit__ = MagicMock(return_value=False) - - with patch("cogs.cron.get_connection", return_value=mock_ctx): - cog.save_tasks() - assert len(cog.scheduled_tasks) == 1 - -class TestShouldRunTask: - def test_should_run_task_invalid_cron(self, mock_bot): - cog = create_cog(mock_bot) - task = {"cron_expression": "invalid"} - now = datetime.now() - result = cog.should_run_task(task, now) - assert result is False - - def test_should_run_task_missing_cron_expression(self, mock_bot): - cog = create_cog(mock_bot) - task = {} - now = datetime.now() - result = cog.should_run_task(task, now) - assert result is False - -class TestCogUnload: - def test_cog_unload_cancels_task(self, mock_bot): - with patch.object(Cron, "__init__", lambda self, bot: None): - cog = Cron.__new__(Cron) - cog.bot = mock_bot - cog.task = MagicMock() - - cog.cog_unload() - cog.task.cancel.assert_called_once() - -class TestTaskManagement: - def test_add_task_increments_id(self, mock_bot): - cog = create_cog(mock_bot) - cog.scheduled_tasks = [ - {"id": 1, "cron_expression": "* * * * *"}, - {"id": 2, "cron_expression": "0 * * * *"}, - ] - - new_id = max([t["id"] for t in cog.scheduled_tasks], default=0) + 1 - assert new_id == 3 - - def test_find_task_by_id(self, mock_bot): - cog = create_cog(mock_bot) - cog.scheduled_tasks = [ - {"id": 1, "cron_expression": "* * * * *"}, - {"id": 2, "cron_expression": "0 * * * *"}, - ] - - found_task = next((t for t in cog.scheduled_tasks if t["id"] == 2), None) - assert found_task is not None - assert found_task["cron_expression"] == "0 * * * *" - - def test_remove_task_by_index(self, mock_bot): - cog = create_cog(mock_bot) - cog.scheduled_tasks = [ - {"id": 1, "cron_expression": "* * * * *"}, - {"id": 2, "cron_expression": "0 * * * *"}, - ] - - cog.scheduled_tasks.pop(0) - assert len(cog.scheduled_tasks) == 1 - assert cog.scheduled_tasks[0]["id"] == 2 - - def test_toggle_task_active(self, mock_bot): - cog = create_cog(mock_bot) - cog.scheduled_tasks = [{"id": 1, "active": True}] - - cog.scheduled_tasks[0]["active"] = False - assert cog.scheduled_tasks[0]["active"] is False - - cog.scheduled_tasks[0]["active"] = True - assert cog.scheduled_tasks[0]["active"] is True - -class TestTaskTypes: - def test_task_type_audio_aliases(self, mock_bot): - audio_types = ("zagraj_audio", "audio") - for task_type in audio_types: - assert task_type in ("zagraj_audio", "audio") - - def test_task_type_message_aliases(self, mock_bot): - message_types = ("wyślij_wiadomość", "send_message") - for task_type in message_types: - assert task_type in ("wyślij_wiadomość", "send_message") diff --git a/tests/cogs/test_cron_integration.py b/tests/cogs/test_cron_integration.py deleted file mode 100644 index f56fc46..0000000 --- a/tests/cogs/test_cron_integration.py +++ /dev/null @@ -1,39 +0,0 @@ -import pytest -import time -from unittest.mock import MagicMock, AsyncMock, patch - - -@pytest.fixture -def cron_cog(bot): - # Patch create_task to prevent background task creation - with patch.object(bot.loop, 'create_task', return_value=MagicMock()): - from cogs.cron import Cron - cog = Cron(bot) - yield cog - - -@pytest.mark.slow -@pytest.mark.asyncio -async def test_cron_job_execution(cron_cog): - """Test cron job executes when due.""" - cog = cron_cog - - job = { - "id": "test_job", - "cron_expression": "* * * * *", - "type": "message", - "channel_id": 456, - "active": True, - "message": "Test", - } - cog.scheduled_tasks.append(job) - - # Mock the execute_task method - with patch.object(cog, 'execute_task', new_callable=AsyncMock) as mock_exec: - # Mock should_run_task to return True - with patch.object(cog, 'should_run_task', return_value=True): - # Test single iteration of schedule_checker logic - for task in cog.scheduled_tasks: - if task.get("active", True) and cog.should_run_task(task, None): - await cog.execute_task(task) - mock_exec.assert_called_once_with(job) \ No newline at end of file diff --git a/tests/cogs/test_downloader.py b/tests/cogs/test_downloader.py deleted file mode 100644 index 125a103..0000000 --- a/tests/cogs/test_downloader.py +++ /dev/null @@ -1,93 +0,0 @@ -import pytest -from unittest.mock import AsyncMock, patch, MagicMock -import discord -from conftest import MockApplicationContext, MockMessage - - -@pytest.fixture -def downloader_cog(bot): - from cogs.downloader import Downloader - cog = Downloader(bot) - return cog - - -@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", - "content": mock_file_path, - "filename": "test_video.mp4" - }): - with patch('discord.File', return_value=MagicMock()) as mock_file: - with patch.object(ctx, 'respond', new_callable=AsyncMock) as mock_respond: - await downloader_cog.download.callback(downloader_cog, ctx, url="https://example.com/video", catbox=False, fformat="mp4", filename_user=None) - mock_respond.assert_called_once() - call_args = mock_respond.call_args - assert 'file' in str(call_args) or mock_file.called - - -@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", - "content": "https://catbox.2137697.xyz/sperma/test.mp4" - }): - with patch.object(ctx, 'respond', new_callable=AsyncMock) as mock_respond: - await downloader_cog.download.callback(downloader_cog, ctx, url="https://example.com/video", catbox=True, fformat="mp4", filename_user=None) - mock_respond.assert_called_once() - call_args = mock_respond.call_args - assert "pobioron" in str(call_args) - - -@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", - "content": "Download failed", - "details": "Connection timeout" - }): - with patch('cogs.downloader.logger') as mock_logger: - await downloader_cog.download.callback(downloader_cog, ctx, url="https://badurl.com", catbox=False, fformat="mp4", filename_user=None) - assert mock_logger.error.called - - -@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", - "content": "/tmp/test.mp4" - }): - with patch.object(downloader_cog, 'download', new_callable=AsyncMock) as mock_download: - await downloader_cog.message_download.callback(downloader_cog, ctx, message=mock_message) - mock_download.assert_called_once() - - -@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) diff --git a/tests/cogs/test_downloader_integration.py b/tests/cogs/test_downloader_integration.py deleted file mode 100644 index c7c9790..0000000 --- a/tests/cogs/test_downloader_integration.py +++ /dev/null @@ -1,37 +0,0 @@ -import pytest -from unittest.mock import MagicMock, AsyncMock, patch - - -@pytest.fixture -def downloader_cog(bot): - from cogs.downloader import Downloader - cog = Downloader(bot) - return cog - - -@pytest.mark.slow -@pytest.mark.asyncio -async def test_download_command_flow(downloader_cog, bot): - """Test download command with URL processing.""" - cog = downloader_cog - - ctx = MagicMock() - ctx.author = MagicMock() - ctx.guild = MagicMock() - ctx.channel = MagicMock() - ctx.respond = AsyncMock() - ctx.defer = AsyncMock() - ctx.followup = AsyncMock() - ctx.voice_client = None - - # Mock the download_standalone static method - mock_response = { - "status": "success", - "type": "url", - "content": "http://example.com/video.mp4" - } - - with patch.object(cog, 'download_standalone', new_callable=AsyncMock, return_value=mock_response): - await cog.download.callback(cog, ctx, url="http://youtube.com/test") - - ctx.respond.assert_called_once() diff --git a/tests/cogs/test_math_commands.py b/tests/cogs/test_math_commands.py deleted file mode 100644 index 21e9a2e..0000000 --- a/tests/cogs/test_math_commands.py +++ /dev/null @@ -1,55 +0,0 @@ -import pytest -from unittest.mock import AsyncMock, patch, MagicMock -from conftest import MockApplicationContext - - -@pytest.fixture -def math_cog(bot): - from cogs.math_commands import Math - cog = Math(bot) - return cog - - -@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: - await math_cog.math.callback(math_cog, ctx, equation="2+2") - mock_subprocess.assert_called_once() - mock_respond.assert_called_once() - - -@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)") - mock_respond.assert_called_once() - args = mock_respond.call_args - assert "Invalid" in str(args) - - -@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) diff --git a/tests/cogs/test_music_audio.py b/tests/cogs/test_music_audio.py deleted file mode 100644 index 98c6f6b..0000000 --- a/tests/cogs/test_music_audio.py +++ /dev/null @@ -1,93 +0,0 @@ -import pytest -from unittest.mock import AsyncMock, patch, MagicMock -import os -from conftest import MockApplicationContext - - -@pytest.mark.asyncio -async def test_validate_voice_channel_not_in_voice(): - from cogs.voice import VoiceManager as 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() - - -@pytest.mark.asyncio -async def test_validate_voice_channel_in_voice(): - from cogs.voice import VoiceManager as 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.voice import VoiceManager as AudioPlaybackManager - - display_name, absolute_path = await AudioPlaybackManager.prepare_file_source("/nonexistent/file.mp3") - - assert display_name is None - assert absolute_path is None - - -@pytest.mark.asyncio -async def test_prepare_file_source_absolute_path(): - from cogs.voice import VoiceManager as 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" - - -@pytest.mark.asyncio -async def test_prepare_source_url(): - from cogs.voice import VoiceManager as AudioPlaybackManager - - source, _, is_url = await AudioPlaybackManager.prepare_source("https://example.com/stream") - - assert is_url == True - assert source == "https://example.com/stream" - - -@pytest.mark.asyncio -async def test_prepare_source_local_file(): - from cogs.voice import VoiceManager as AudioPlaybackManager - - with patch('os.path.exists', return_value=True): - source, display_name, is_url = await AudioPlaybackManager.prepare_source("/tmp/test.mp3") - - assert is_url == False - assert display_name == "test" - - -@pytest.mark.asyncio -async def test_cleanup_temp_file(): - from cogs.voice import VoiceManager as AudioPlaybackManager - - with patch('os.path.exists', return_value=True): - with patch('os.remove'): - await AudioPlaybackManager.cleanup_temp_file("/tmp/test.mp3") - - -@pytest.mark.asyncio -async def test_cleanup_temp_file_not_exists(): - from cogs.voice import VoiceManager as AudioPlaybackManager - - with patch('os.path.exists', return_value=False): - await AudioPlaybackManager.cleanup_temp_file("/nonexistent/file.mp3") diff --git a/tests/cogs/test_music_external_play.py b/tests/cogs/test_music_external_play.py deleted file mode 100644 index 8e19423..0000000 --- a/tests/cogs/test_music_external_play.py +++ /dev/null @@ -1,109 +0,0 @@ -import pytest -import os -import asyncio -import tempfile -from unittest.mock import AsyncMock, patch, MagicMock -from conftest import MockApplicationContext - - -@pytest.fixture -def play_commands_cog(bot): - with patch('cogs.utils.temp.get_temp_dir', return_value="/tmp"): - from cogs.music.play_commands import PlayCommands - cog = PlayCommands(bot) - return cog - - -@pytest.fixture -def temp_mp3_file(): - with tempfile.NamedTemporaryFile(suffix='.mp3', delete=False) as f: - f.write(b'fake mp3 content') - temp_path = f.name - yield temp_path - if os.path.exists(temp_path): - os.remove(temp_path) - - -@pytest.mark.asyncio -async def test_external_url_pattern_matches_youtube(play_commands_cog): - from cogs.music.play_commands import EXTERNAL_URL_PATTERN - - assert EXTERNAL_URL_PATTERN.match("https://youtube.com/watch?v=test") - assert EXTERNAL_URL_PATTERN.match("https://youtu.be/test") - assert EXTERNAL_URL_PATTERN.match("https://www.youtube.com/watch?v=test") - - -@pytest.mark.asyncio -async def test_external_url_pattern_matches_soundcloud(play_commands_cog): - from cogs.music.play_commands import EXTERNAL_URL_PATTERN - - assert EXTERNAL_URL_PATTERN.match("https://soundcloud.com/artist/track") - assert EXTERNAL_URL_PATTERN.match("https://api.soundcloud.com/tracks") - - -@pytest.mark.asyncio -async def test_external_url_pattern_matches_bandcamp(play_commands_cog): - from cogs.music.play_commands import EXTERNAL_URL_PATTERN - - assert EXTERNAL_URL_PATTERN.match("https://artist.bandcamp.com/track") - - -@pytest.mark.asyncio -async def test_external_url_pattern_rejects_copyparty(play_commands_cog): - from cogs.music.play_commands import EXTERNAL_URL_PATTERN - - assert not EXTERNAL_URL_PATTERN.match("https://catbox.2137697.xyz/sperma/file.mp3") - assert not EXTERNAL_URL_PATTERN.match("some search query") - - -@pytest.mark.asyncio -async def test_play_command_calls_external_handler(play_commands_cog, mock_channel, mock_guild, bot): - ctx = MockApplicationContext(bot=bot, channel=mock_channel, guild=mock_guild) - - with patch.object(play_commands_cog, '_handle_external_url_play', new_callable=AsyncMock) as mock_handler: - mock_handler.return_value = None - mock_defer = AsyncMock() - ctx.defer = mock_defer - ctx.respond = AsyncMock() - - await play_commands_cog.play.callback( - play_commands_cog, ctx, - melodia="https://youtube.com/watch?v=test", - file=None, compressed=False - ) - - mock_handler.assert_called_once_with(ctx, "https://youtube.com/watch?v=test") - - -@pytest.mark.asyncio -async def test_play_command_calls_local_handler(play_commands_cog, mock_channel, mock_guild, bot): - ctx = MockApplicationContext(bot=bot, channel=mock_channel, guild=mock_guild) - - with patch.object(play_commands_cog, '_handle_local_file_play', new_callable=AsyncMock) as mock_handler: - mock_handler.return_value = None - mock_defer = AsyncMock() - ctx.defer = mock_defer - ctx.respond = AsyncMock() - - await play_commands_cog.play.callback( - play_commands_cog, ctx, - melodia="some search query", - file=None, compressed=False - ) - - mock_handler.assert_called_once_with(ctx, "some search query", False) - - -@pytest.mark.asyncio -async def test_upload_to_copyparty_async(play_commands_cog, temp_mp3_file, monkeypatch): - monkeypatch.setenv("COPYPARTY_URL_UPLOAD", "https://catbox.2137697.xyz/sperma/") - monkeypatch.setenv("COPYPARTY_PASSWORD", "testpassword") - - mock_response = MagicMock() - mock_response.status_code = 200 - mock_response.text = '{"fileurl": "https://example.com/file.mp3"}' - mock_response.json = MagicMock(return_value={"fileurl": "https://example.com/file.mp3"}) - - with patch('cogs.music.play_commands.requests.post', return_value=mock_response) as mock_post: - await play_commands_cog._upload_to_copyparty_async(temp_mp3_file) - mock_post.assert_called_once() diff --git a/tests/cogs/test_music_integration.py b/tests/cogs/test_music_integration.py deleted file mode 100644 index 692e1c1..0000000 --- a/tests/cogs/test_music_integration.py +++ /dev/null @@ -1,46 +0,0 @@ -import pytest -from unittest.mock import MagicMock, AsyncMock, patch, PropertyMock -import sys -sys.path.insert(0, '/home/salmon/Documents/botcode/senator-sperma/tests') -from conftest import MockApplicationContext - - -@pytest.fixture -def music_cog(bot): - from cogs.music.play_commands import PlayCommands - cog = PlayCommands(bot) - return cog - - -@pytest.mark.slow -@pytest.mark.asyncio -async def test_music_join_stop(music_cog, bot): - """Test music join and stop commands.""" - from cogs.music.join import Join - from cogs.music.stop import Stop - - join_cog = Join(bot) - stop_cog = Stop(bot) - - ctx = MockApplicationContext(bot=bot) - ctx.author.voice = MagicMock() - ctx.author.voice.channel = MagicMock() - ctx.guild = MagicMock() - - # Test join - mock_vm = MagicMock() - mock_vm.connect = AsyncMock() - with patch('cogs.music.join.get_voice_manager', return_value=mock_vm): - with patch.object(ctx, 'respond', new_callable=AsyncMock): - with patch.object(ctx.interaction, 'delete_original_response', new_callable=AsyncMock): - await join_cog.join.callback(join_cog, ctx) - mock_vm.connect.assert_called_once_with(ctx.author.voice.channel) - - # Test stop - mock_vm_stop = MagicMock() - mock_vm_stop.disconnect = AsyncMock() - with patch('cogs.music.stop.get_voice_manager', return_value=mock_vm_stop): - 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_vm_stop.disconnect.assert_called_once_with(ctx.guild) diff --git a/tests/cogs/test_music_join.py b/tests/cogs/test_music_join.py deleted file mode 100644 index b40d93a..0000000 --- a/tests/cogs/test_music_join.py +++ /dev/null @@ -1,56 +0,0 @@ -import pytest -from unittest.mock import AsyncMock, patch, MagicMock -from conftest import MockApplicationContext - - -@pytest.fixture -def join_cog(bot): - from cogs.music.join import Join - cog = Join(bot) - return cog - - -@pytest.fixture -def stop_cog(bot): - from cogs.music.stop import Stop - cog = Stop(bot) - return cog - - -@pytest.mark.asyncio -async def test_join_command_success(join_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_voice_channel = MagicMock() - ctx.author.voice = MagicMock() - ctx.author.voice.channel = mock_voice_channel - - with patch('cogs.music.join.get_voice_manager') as mock_get_vm: - mock_vm = MagicMock() - mock_vm.connect = AsyncMock() - mock_get_vm.return_value = mock_vm - - with patch.object(ctx, 'respond', new_callable=AsyncMock): - with patch.object(ctx.interaction, 'delete_original_response', new_callable=AsyncMock): - await join_cog.join.callback(join_cog, ctx) - mock_vm.connect.assert_called_once_with(mock_voice_channel) - - -@pytest.mark.asyncio -async def test_stop_command_success(stop_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 - - with patch('cogs.music.stop.get_voice_manager') as mock_get_vm: - mock_vm = MagicMock() - mock_vm.disconnect = AsyncMock() - mock_get_vm.return_value = mock_vm - - 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_vm.disconnect.assert_called_once_with(mock_guild) diff --git a/tests/cogs/test_music_play.py b/tests/cogs/test_music_play.py deleted file mode 100644 index 7684729..0000000 --- a/tests/cogs/test_music_play.py +++ /dev/null @@ -1,104 +0,0 @@ -import pytest -from unittest.mock import AsyncMock, patch, MagicMock -import os -from conftest import MockApplicationContext - - -@pytest.fixture -def play_commands_cog(bot): - with patch('cogs.utils.temp.get_temp_dir', return_value="/tmp"): - from cogs.music.play_commands import PlayCommands - cog = PlayCommands(bot) - return cog - - -@pytest.fixture -def loop_cog(bot): - from cogs.music.loop import Loop - cog = Loop(bot) - return cog - - -@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 - - -@pytest.mark.asyncio -async def test_create_search_embed_with_candidates(play_commands_cog): - candidates = [ - "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 - - -@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() - args = mock_respond.call_args - assert "Musisz podać" in str(args) - - -@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() - args = mock_respond.call_args - assert "nie oba" in str(args) or "LUB" in str(args) - - -def test_loop_cog_is_looping_initial(loop_cog): - assert loop_cog.is_looping(123) == False - - -def test_loop_cog_set_looping(loop_cog): - loop_cog.set_looping(123, True) - assert loop_cog.is_looping(123) == True - - -@pytest.mark.asyncio -async def test_loop_command_toggle_on(loop_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 - 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() - args = mock_respond.call_args - assert "włączony" in str(args) - - -@pytest.mark.asyncio -async def test_loop_command_toggle_off(loop_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 - 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) diff --git a/tests/cogs/test_qr.py b/tests/cogs/test_qr.py deleted file mode 100644 index b5cb31f..0000000 --- a/tests/cogs/test_qr.py +++ /dev/null @@ -1,75 +0,0 @@ -import pytest -from unittest.mock import AsyncMock, patch, MagicMock, mock_open -import os -from cogs.qr import QR -from conftest import MockApplicationContext - - -@pytest.fixture -def qr_cog(bot): - cog = QR(bot) - return cog - - -@pytest.fixture -def mock_temp_file(): - with patch('tempfile.NamedTemporaryFile') as mock: - mock_file = MagicMock() - mock_file.name = "/tmp/test_qr.png" - mock.return_value = mock_file - yield mock_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): - with patch('os.unlink'): - await qr_cog.qr.callback(qr_cog, ctx, text="https://example.com") - mock_generate.assert_called_once() - mock_respond.assert_called_once() - - -@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): - await qr_cog.qr.callback(qr_cog, ctx, text="") - mock_respond.assert_called_once() - - -@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) - mock_respond.assert_called_once() - args = mock_respond.call_args - assert "nie jest dostępne" in str(args) or "not available" in str(args).lower() - - -@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() diff --git a/tests/cogs/test_say.py b/tests/cogs/test_say.py deleted file mode 100644 index 76f1b94..0000000 --- a/tests/cogs/test_say.py +++ /dev/null @@ -1,38 +0,0 @@ -import pytest -from unittest.mock import AsyncMock, patch -from cogs.say import Say -from conftest import MockApplicationContext - - -@pytest.fixture -def say_cog(bot): - cog = Say(bot) - return cog - - -@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") - - -@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="") - - -@pytest.mark.asyncio -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) diff --git a/tests/cogs/test_search.py b/tests/cogs/test_search.py deleted file mode 100644 index c9c7d0e..0000000 --- a/tests/cogs/test_search.py +++ /dev/null @@ -1,83 +0,0 @@ -import pytest -from unittest.mock import AsyncMock, patch, MagicMock -import discord -from conftest import MockApplicationContext - - -@pytest.fixture -def search_cog(bot): - from cogs.search import Search - cog = Search(bot) - return cog - - -@pytest.mark.asyncio -async def test_search_command_success(search_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 - - 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") - assert mock_user.id not in search_cog._cached_results - - -@pytest.mark.asyncio -async def test_search_command_no_cache(search_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 - - 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.") - - -@pytest.mark.asyncio -async def test_search_command_file_not_found(search_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 - - 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.") - - -@pytest.mark.asyncio -async def test_search_command_empty_filename(search_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 - - 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.") - - -@pytest.mark.asyncio -async def test_file_autocomplete(search_cog, mock_channel, mock_guild, bot, mock_user): - mock_autocomplete_ctx = MagicMock() - 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 diff --git a/tests/cogs/test_trigger.py b/tests/cogs/test_trigger.py deleted file mode 100644 index a60a139..0000000 --- a/tests/cogs/test_trigger.py +++ /dev/null @@ -1,106 +0,0 @@ -import pytest -from unittest.mock import AsyncMock, patch, MagicMock -import sqlite3 -from conftest import MockApplicationContext - - -@pytest.fixture -def trigger_cog(bot): - with patch('cogs.trigger.get_connection') as mock_conn: - mock_conn.return_value.__enter__ = MagicMock(return_value=MagicMock()) - mock_conn.return_value.__exit__ = MagicMock(return_value=False) - from cogs.trigger import Trigger - cog = Trigger(bot) - return cog - - -@pytest.fixture -def mock_db_connection(): - 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) - yield mock_conn, mock_cursor - - -@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") - - -@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() - mock_cursor.fetchone.return_value = (1,) # trigger exists - 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") - - -@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() - mock_cursor.fetchone.return_value = None # trigger not found - 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.") - - -@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() - mock_cursor.fetchone.return_value = (1,) # trigger exists - 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") - - -@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) diff --git a/tests/cogs/test_trigger_integration.py b/tests/cogs/test_trigger_integration.py deleted file mode 100644 index 4828387..0000000 --- a/tests/cogs/test_trigger_integration.py +++ /dev/null @@ -1,54 +0,0 @@ -import pytest -from unittest.mock import MagicMock, AsyncMock, patch -from cogs.trigger import Trigger - - -@pytest.fixture -def trigger_cog(bot): - from cogs.utils.database import init_database - init_database() - from cogs.trigger import Trigger - cog = Trigger(bot) - return cog - - -@pytest.mark.slow -@pytest.mark.asyncio -async def test_trigger_response_flow(trigger_cog): - """Test trigger creation and response in a simulated message flow.""" - cog = trigger_cog - - ctx = MagicMock() - ctx.author = MagicMock() - ctx.author.id = 123 - ctx.guild = MagicMock() - ctx.guild.id = 456 - ctx.respond = AsyncMock() - - # Create a trigger using the create command - await cog.create.callback(cog, ctx, name="test_trigger") - - # Add a keyword and response - await cog.add.callback(cog, ctx, name="test_trigger", trigger="hello", response="world") - - # Verify trigger was created - check DB - from cogs.utils.database import get_connection - with get_connection() as conn: - c = conn.cursor() - c.execute("SELECT id FROM triggers WHERE name=?", ("test_trigger",)) - result = c.fetchone() - assert result is not None - - # Simulate a message that should trigger - message = MagicMock() - message.author = ctx.author - message.author.bot = False - message.guild = ctx.guild - message.content = "say hello to me" - message.channel.send = AsyncMock() # Make send awaitable - - # Check if trigger matches using the static method - await Trigger.trigger(message) - - # Verify message.channel.send was called with the response - message.channel.send.assert_called_once_with("world") diff --git a/tests/cogs/test_tts.py b/tests/cogs/test_tts.py deleted file mode 100644 index c6563e6..0000000 --- a/tests/cogs/test_tts.py +++ /dev/null @@ -1,58 +0,0 @@ -import pytest -from unittest.mock import AsyncMock, patch, MagicMock -import discord -from conftest import MockApplicationContext - - -@pytest.fixture -def tts_cog(bot): - from cogs.tts import TTS - cog = TTS(bot) - return cog - - -@pytest.mark.asyncio -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 - - "/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: - with patch('cogs.tts.get_volume', return_value=1.0): - await tts_cog.tts.callback(tts_cog, ctx, text="Hello", output="file") - mock_respond.assert_called_once() - - -@pytest.mark.asyncio -async def test_tts_voice_output_not_in_channel(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 - ctx.author.voice = None - - with patch('cogs.tts.gTTS'): - with patch('os.path.exists', return_value=True): - with patch('os.unlink'): - with patch.object(ctx, 'respond', new_callable=AsyncMock) as mock_respond: - with patch('cogs.tts.get_volume', return_value=1.0): - await tts_cog.tts.callback(tts_cog, ctx, text="Hello", output="vc") - - -@pytest.mark.asyncio -async def test_tts_error_handling(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 - - 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) diff --git a/tests/cogs/test_uploader.py b/tests/cogs/test_uploader.py deleted file mode 100644 index 0777126..0000000 --- a/tests/cogs/test_uploader.py +++ /dev/null @@ -1,226 +0,0 @@ -import pytest -from unittest.mock import AsyncMock, patch, MagicMock -import os -import discord -from conftest import MockApplicationContext, MockMessage, MockUser - - -@pytest.fixture -def uploader_cog(bot): - with patch('cogs.utils.temp.get_temp_dir', return_value='/tmp/test'): - from cogs.uploader import Uploader - cog = Uploader(bot) - return cog - - -@pytest.mark.asyncio -async def test_file_autocomplete(uploader_cog): - mock_autocomplete_ctx = MagicMock() - mock_autocomplete_ctx.value = "test" - mock_interaction = MagicMock() - mock_user = MockUser(id=12345) - mock_interaction.user = mock_user - mock_autocomplete_ctx.interaction = mock_interaction - - with patch('cogs.utils.file_search.UniversalSearcher.search_copyparty_autocomplete', new_callable=AsyncMock) as mock_search: - mock_search.return_value = [ - "https://copyparty.local/testfile1.mp3", - "https://copyparty.local/testfile2.mp3" - ] - result = await uploader_cog._file_autocomplete(mock_autocomplete_ctx) - assert len(result) == 2 - assert result[0].name == "testfile1.mp3" - - -@pytest.mark.asyncio -async def test_file_autocomplete_empty_query(uploader_cog): - mock_autocomplete_ctx = MagicMock() - mock_autocomplete_ctx.value = "" - mock_interaction = MagicMock() - mock_interaction.user = MockUser(id=12345) - mock_autocomplete_ctx.interaction = mock_interaction - - with patch('cogs.utils.file_search.UniversalSearcher.search_copyparty_autocomplete', new_callable=AsyncMock) as mock_search: - result = await uploader_cog._file_autocomplete(mock_autocomplete_ctx) - mock_search.assert_called_once_with("", max_results=25) - - -@pytest.mark.asyncio -async def test_download_from_url_success(uploader_cog): - with patch('requests.get') as mock_get: - mock_response = MagicMock() - mock_response.status_code = 200 - mock_response.content = b"test file content" - mock_get.return_value = mock_response - - mock_file = MagicMock() - mock_file.write = AsyncMock() - - mock_cm = AsyncMock() - mock_cm.__aenter__ = AsyncMock(return_value=mock_file) - mock_cm.__aexit__ = AsyncMock(return_value=None) - - with patch('cogs.uploader.aiofiles.open', return_value=mock_cm): - result = await uploader_cog._download_from_url("https://copyparty.local/file.txt") - - assert result is not None - assert "file.txt" in result - mock_file.write.assert_called_once_with(b"test file content") - - -@pytest.mark.asyncio -async def test_download_from_url_failure(uploader_cog): - with patch('requests.get') as mock_get: - mock_response = MagicMock() - mock_response.status_code = 404 - mock_get.return_value = mock_response - - result = await uploader_cog._download_from_url("https://copyparty.local/notfound.txt") - - assert result is None - - -@pytest.mark.asyncio -async def test_upload_to_copyparty_success(uploader_cog): - mock_file = MagicMock() - mock_file.read = AsyncMock(return_value=b"test content") - - mock_cm = AsyncMock() - mock_cm.__aenter__ = AsyncMock(return_value=mock_file) - mock_cm.__aexit__ = AsyncMock(return_value=None) - - with patch('cogs.uploader.aiofiles.open', return_value=mock_cm): - with patch('requests.post') as mock_post: - mock_response = MagicMock() - mock_response.status_code = 200 - mock_response.json.return_value = {"fileurl": "https://copyparty.local/uploaded.txt"} - mock_post.return_value = mock_response - - with patch.dict(os.environ, {"COPYPARTY_PASSWORD": "testpass"}): - result = await uploader_cog._upload_to_copyparty("/tmp/testfile.txt") - - assert result == "https://copyparty.local/uploaded.txt" - - -@pytest.mark.asyncio -async def test_upload_to_copyparty_failure(uploader_cog): - mock_file = MagicMock() - mock_file.read = AsyncMock(return_value=b"test content") - - mock_cm = AsyncMock() - mock_cm.__aenter__ = AsyncMock(return_value=mock_file) - mock_cm.__aexit__ = AsyncMock(return_value=None) - - with patch('cogs.uploader.aiofiles.open', return_value=mock_cm): - with patch('requests.post') as mock_post: - mock_response = MagicMock() - mock_response.status_code = 500 - mock_post.return_value = mock_response - - result = await uploader_cog._upload_to_copyparty("/tmp/testfile.txt") - - assert result is None - - -@pytest.mark.asyncio -async def test_upload_file_no_url(uploader_cog): - uploader_cog._uploadurl = None - - result = await uploader_cog._upload_file("/tmp/test.txt") - - assert result is None - - -@pytest.mark.asyncio -async def test_message_upload_no_attachments(uploader_cog, mock_channel, mock_guild, bot): - ctx = MockApplicationContext(bot=bot, channel=mock_channel, guild=mock_guild) - - mock_message = MagicMock() - mock_message.attachments = [] - - with patch.object(ctx, 'respond', new_callable=AsyncMock) as mock_respond: - await uploader_cog.message_upload.callback(uploader_cog, ctx, message=mock_message) - mock_respond.assert_called_once_with("Brak załączników w wiadomości", ephemeral=True) - - -@pytest.mark.asyncio -async def test_message_upload_success(uploader_cog, mock_channel, mock_guild, bot): - ctx = MockApplicationContext(bot=bot, channel=mock_channel, guild=mock_guild) - - mock_attachment = MagicMock() - mock_attachment.filename = "test.txt" - mock_attachment.save = AsyncMock() - - mock_message = MagicMock() - mock_message.attachments = [mock_attachment] - - with patch.object(uploader_cog, '_upload_file', new_callable=AsyncMock) as mock_upload: - mock_upload.return_value = "https://copyparty.local/uploaded.txt" - - with patch('os.path.exists', return_value=True): - with patch('os.remove'): - with patch.object(ctx, 'defer', new_callable=AsyncMock): - with patch.object(ctx, 'respond', new_callable=AsyncMock) as mock_respond: - await uploader_cog.message_upload.callback(uploader_cog, ctx, message=mock_message) - mock_respond.assert_called_once() - assert "Wysłano" in str(mock_respond.call_args) - - -@pytest.mark.asyncio -async def test_message_upload_all_failed(uploader_cog, mock_channel, mock_guild, bot): - ctx = MockApplicationContext(bot=bot, channel=mock_channel, guild=mock_guild) - - mock_attachment = MagicMock() - mock_attachment.filename = "test.txt" - mock_attachment.save = AsyncMock() - - mock_message = MagicMock() - mock_message.attachments = [mock_attachment] - - with patch.object(uploader_cog, '_upload_file', new_callable=AsyncMock) as mock_upload: - mock_upload.return_value = None - - with patch('os.path.exists', return_value=True): - with patch('os.remove'): - with patch.object(ctx, 'defer', new_callable=AsyncMock): - with patch.object(ctx, 'respond', new_callable=AsyncMock) as mock_respond: - await uploader_cog.message_upload.callback(uploader_cog, ctx, message=mock_message) - mock_respond.assert_called_once_with("Nie udało się wysłać żadnych plików", ephemeral=True) - - -@pytest.mark.asyncio -async def test_upload_slash_command_success(uploader_cog, mock_channel, mock_guild, bot): - ctx = MockApplicationContext(bot=bot, channel=mock_channel, guild=mock_guild) - - mock_attachment = MagicMock() - mock_attachment.filename = "test.txt" - mock_attachment.save = AsyncMock() - - with patch.object(uploader_cog, '_upload_file', new_callable=AsyncMock) as mock_upload: - mock_upload.return_value = "https://copyparty.local/uploaded.txt" - - with patch('os.path.exists', return_value=True): - with patch('os.remove'): - with patch.object(ctx, 'defer', new_callable=AsyncMock): - with patch.object(ctx, 'respond', new_callable=AsyncMock) as mock_respond: - await uploader_cog.upload.callback(uploader_cog, ctx, zalacznik=mock_attachment) - mock_respond.assert_called_once_with("https://copyparty.local/uploaded.txt") - - -@pytest.mark.asyncio -async def test_upload_slash_command_failure(uploader_cog, mock_channel, mock_guild, bot): - ctx = MockApplicationContext(bot=bot, channel=mock_channel, guild=mock_guild) - - mock_attachment = MagicMock() - mock_attachment.filename = "test.txt" - mock_attachment.save = AsyncMock() - - with patch.object(uploader_cog, '_upload_file', new_callable=AsyncMock) as mock_upload: - mock_upload.return_value = None - - with patch('os.path.exists', return_value=True): - with patch('os.remove'): - with patch.object(ctx, 'defer', new_callable=AsyncMock): - with patch.object(ctx, 'respond', new_callable=AsyncMock) as mock_respond: - await uploader_cog.upload.callback(uploader_cog, ctx, zalacznik=mock_attachment) - mock_respond.assert_called_once_with("Nie udało się wysłać pliku", ephemeral=True) \ No newline at end of file diff --git a/tests/cogs/test_vclogs.py b/tests/cogs/test_vclogs.py deleted file mode 100644 index 17ff839..0000000 --- a/tests/cogs/test_vclogs.py +++ /dev/null @@ -1,88 +0,0 @@ -import pytest -from unittest.mock import AsyncMock, patch, MagicMock -from 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" - - -def test_load_activity_data(): - with patch("cogs.vclogs.get_connection") as mock_conn: - mock_cursor = MagicMock() - mock_conn.return_value.cursor.return_value = mock_cursor - mock_conn.return_value.close.return_value = None - mock_cursor.fetchall.return_value = [] - - from cogs.vclogs import load_activity_data - data = load_activity_data() - assert isinstance(data, dict) - - -def test_save_activity_data(): - with patch("cogs.vclogs.get_connection") as mock_conn: - mock_cursor = MagicMock() - mock_conn.return_value.cursor.return_value = mock_cursor - mock_conn.return_value.commit.return_value = None - mock_conn.return_value.close.return_value = None - - from cogs.vclogs import save_activity_data - save_activity_data({"123": {"active": True}}) - - -@pytest.fixture -def vclogs_cog(bot): - with patch('cogs.vclogs.get_voice_manager'): - with patch('cogs.vclogs.get_volume', return_value=1.0): - with patch('cogs.vclogs.save_settings'): - from cogs.vclogs import VcLogs - cog = VcLogs(bot) - return cog - - -@pytest.mark.asyncio -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 - - -@pytest.mark.asyncio -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 - - -@pytest.mark.asyncio -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 - - -@pytest.mark.asyncio -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 diff --git a/tests/cogs/test_vclogs_integration.py b/tests/cogs/test_vclogs_integration.py deleted file mode 100644 index 9391876..0000000 --- a/tests/cogs/test_vclogs_integration.py +++ /dev/null @@ -1,86 +0,0 @@ -import pytest -import asyncio -from unittest.mock import MagicMock, AsyncMock, patch - - -@pytest.fixture -def vclogs_cog(bot): - from cogs.vclogs import VcLogs - cog = VcLogs(bot) - return cog - - -@pytest.mark.slow -@pytest.mark.asyncio -async def test_full_voice_session_tracking(vclogs_cog, monkeypatch): - """Test complete voice session with AFK transitions using real time sleeps.""" - cog = vclogs_cog - - # Set up environment - monkeypatch.setenv("STATUS_CHANNEL_ID", "123456") - - member = MagicMock() - member.id = 123 - member.guild.id = 456 - member.bot = False - member.display_name = "TestUser" - member.guild.get_member.return_value = member - - # Create a mock log channel - log_channel = MagicMock() - log_channel.send = AsyncMock(return_value=MagicMock()) - - # Mock bot.get_channel to return our log channel - with patch.object(vclogs_cog.bot, 'get_channel', return_value=log_channel): - # Join voice - before = MagicMock() - before.channel = None - after_join = MagicMock() - after_join.channel = MagicMock() - after_join.channel.id = 789 - after_join.channel.name = "Test Voice" - after_join.self_deaf = False - after_join.self_mute = False - after_join.deaf = False - after_join.mute = False - await cog.on_voice_state_update(member, before, after_join) - - await asyncio.sleep(2) # Simulate 2s active - - # Go AFK (self_deaf) - before_afk = after_join - after_afk = MagicMock() - after_afk.channel = before_afk.channel - after_afk.self_deaf = True - after_afk.self_mute = False - after_afk.deaf = True - after_afk.mute = False - await cog.on_voice_state_update(member, before_afk, after_afk) - - await asyncio.sleep(3) # Simulate 3s AFK - - # Return from AFK - before_back = after_afk - after_back = MagicMock() - after_back.channel = before_back.channel - after_back.self_deaf = False - after_back.self_mute = False - after_back.deaf = False - after_back.mute = False - await cog.on_voice_state_update(member, before_back, after_back) - - await asyncio.sleep(1) # Simulate 1s active - - # Leave voice - before_leave = after_back - after_leave = MagicMock() - after_leave.channel = None - after_leave.self_deaf = False - after_leave.self_mute = False - await cog.on_voice_state_update(member, before_leave, after_leave) - - # Verify activity was saved (check DB) - from cogs.vclogs import load_activity_data - activity_data = load_activity_data() - # After leaving, data should be deleted, so check the log channel was called - assert log_channel.send.called diff --git a/tests/cogs/test_voice.py b/tests/cogs/test_voice.py deleted file mode 100644 index 6eb226b..0000000 --- a/tests/cogs/test_voice.py +++ /dev/null @@ -1,79 +0,0 @@ -import pytest -from unittest.mock import AsyncMock, patch, MagicMock -import asyncio -from 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 - - -@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_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 - - -@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_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() diff --git a/tests/cogs/test_web.py b/tests/cogs/test_web.py deleted file mode 100644 index 4de2e8b..0000000 --- a/tests/cogs/test_web.py +++ /dev/null @@ -1,57 +0,0 @@ -import pytest -from unittest.mock import AsyncMock, patch, MagicMock -from cogs.web import Web -from conftest import MockApplicationContext - - -@pytest.fixture -def web_cog(bot): - cog = Web(bot) - return cog - - -@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 = ''' - - Test Result - 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") - mock_get.assert_called_once() - mock_respond.assert_called_once() - - -@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") - mock_respond.assert_called_once_with(content="No results found.", ephemeral=True) - - -@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) diff --git a/tests/conftest.py b/tests/conftest.py deleted file mode 100644 index 6b7c3bc..0000000 --- a/tests/conftest.py +++ /dev/null @@ -1,228 +0,0 @@ -import asyncio -import os -import sys -import tempfile -from unittest.mock import AsyncMock, MagicMock -import pytest - -import discord -from discord.ext import commands - -sys.path.insert(0, os.path.join(os.path.dirname(__file__), "..")) - - -@pytest.fixture(autouse=True, scope="function") -def setup_test_env(monkeypatch): - test_db = os.path.join(tempfile.gettempdir(), "test_senator.db") - if os.path.exists(test_db): - os.remove(test_db) - monkeypatch.setenv("SENATOR_DB_PATH", test_db) - reload_database() - yield - if os.path.exists(test_db): - os.remove(test_db) - - -def reload_database(): - import cogs.utils.database as db_module - db_module._initialized = False - - -class MockUser: - def __init__(self, id=12345, name="testuser", discriminator="0001"): - self.id = id - self.name = name - self.discriminator = discriminator - self.mention = f"@{name}" - self.display_name = name - self.avatar = None - self.bot = False - self.guild = None - self._state = MagicMock() - - def __str__(self): - return f"{self.name}#{self.discriminator}" - - -class MockChannel: - def __init__(self, id=11111, name="test-channel", type=discord.ChannelType.text): - self.id = id - self.name = name - self.type = type - self.mention = f"#{name}" - self.guild = None - self.category = None - self._state = MagicMock() - - def send(self, *args, **kwargs): - return MagicMock() - - -class MockTextChannel(MockChannel): - def __init__(self, id=11111, name="test-channel"): - super().__init__(id, name, discord.ChannelType.text) - - -class MockVoiceChannel(MockChannel): - def __init__(self, id=11112, name="test-voice"): - super().__init__(id, name, discord.ChannelType.voice) - self.voice_states = {} - - -class MockGuild: - def __init__(self, id=99999, name="Test Server"): - self.id = id - self.name = name - self.channels = [] - self.roles = [] - self.emojis = [] - self.me = MockUser(id=111111, name="Sen Bot") - self._state = MagicMock() - self._default_role = None - - def get_channel(self, channel_id): - for ch in self.channels: - if ch.id == channel_id: - return ch - return None - - def get_role(self, role_id): - for role in self.roles: - if role.id == role_id: - return role - return None - - def get_member(self, member_id): - return None - - -class MockMessage: - def __init__(self, id=22222, content="test message", author=None, channel=None, guild=None): - self.id = id - self.content = content - self.author = author or MockUser() - self.channel = channel or MockChannel() - self.guild = guild - self.attachments = [] - self.embeds = [] - self.jump_url = "https://discord.com/channels/..." - self.created_at = None - - async def reply(self, *args, **kwargs): - return MagicMock() - # Stub for reply - kept async to match Discord interface signature - - -class MockInteraction: - def __init__(self, user=None, channel=None, guild=None): - self.user = user or MockUser() - self.channel = channel or MockChannel() - self.guild = guild or MockGuild() - self.message = None - self.response = AsyncMock() - self.followup = AsyncMock() - self.client = None - self.id = 33333 - self.token = "test_token" - self._state = MagicMock() - - async def defer(self, *args, **kwargs): - pass - - async def respond(self, *args, **kwargs): - pass - - async def delete_original_response(self, *args, **kwargs): - pass - - async def send(self, *args, **kwargs): - return MagicMock() - - -# Stub for Discord interaction - test implementation only -class MockApplicationContext: - def __init__(self, bot=None, interaction=None, user=None, channel=None, guild=None): - self.bot = bot - self.interaction = interaction or MockInteraction(user=user, channel=channel, guild=guild) - self.user = user or MockUser() - self.channel = channel or MockChannel() - self.guild = guild or MockGuild() - self.message = None - self.response = AsyncMock() - self.followup = AsyncMock() - self.client = self.bot - self.id = 33333 - self.token = "test_token" - self._state = self.interaction._state - self.author = self.user - - async def defer(self, *args, **kwargs): - pass - # Stub for defer - tests don't verify interaction state - - async def respond(self, *args, **kwargs): - pass - # Stub for respond - tests mock the response - - async def delete_original_response(self, *args, **kwargs): - pass - # Stub for delete_original_response - not used in tests - - async def send(self, *args, **kwargs): - return MagicMock() - # Stub for send - not used in tests - - async def reply(self, *args, **kwargs): - return MagicMock() - # Stub for reply - not used in tests - - async def send_followup(self, *args, **kwargs): - return MagicMock() - # Stub for send_followup - not used in tests - - -@pytest.fixture -def mock_guild(): - return MockGuild() - - -@pytest.fixture -def mock_channel(mock_guild): - channel = MockTextChannel() - channel.guild = mock_guild - return channel - - -@pytest.fixture -def mock_voice_channel(mock_guild): - channel = MockVoiceChannel() - channel.guild = mock_guild - return channel - - -@pytest.fixture -def mock_user(): - return MockUser() - - -@pytest.fixture -def mock_member(mock_guild): - member = MockUser() - member.guild = mock_guild - return member - - -@pytest.fixture -def mock_message(mock_channel, mock_user, mock_guild): - return MockMessage(channel=mock_channel, author=mock_user, guild=mock_guild) - - -@pytest.fixture -def mock_interaction(mock_channel, mock_user, mock_guild): - return MockInteraction(user=mock_user, channel=mock_channel, guild=mock_guild) - - -@pytest.fixture -def bot(): - intents = discord.Intents.all() - return commands.Bot(intents=intents, command_prefix="!", loop=asyncio.new_event_loop()) -- cgit v1.2.3