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 = AsyncMock() mock_response.status = 200 mock_response.text = AsyncMock(return_value="") mock_response.json = AsyncMock(return_value={"fileurl": "https://example.com/file.mp3"}) mock_response.__aenter__ = AsyncMock(return_value=mock_response) mock_response.__aexit__ = AsyncMock() mock_session_context = AsyncMock() mock_session_context.__aenter__ = AsyncMock(return_value=mock_session_context) mock_session_context.__aexit__ = AsyncMock() mock_session_context.post = MagicMock(return_value=mock_response) with patch('aiohttp.ClientSession', return_value=mock_session_context): await play_commands_cog._upload_to_copyparty_async(temp_mp3_file) mock_session_context.post.assert_called_once()