import pytest from datetime import datetime from unittest.mock import MagicMock, patch from cogs.cron import Cron @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, tmp_path): with patch.object(Cron, "__init__", lambda self, bot: None): with patch("cogs.cron.init_database"): mock_conn = MagicMock() mock_cursor = MagicMock() mock_cursor.fetchall.return_value = [] mock_conn.cursor.return_value = mock_cursor mock_conn.close.return_value = None with patch("cogs.cron.get_connection", return_value=mock_conn): with patch("cogs.utils.database.get_db_path", return_value=":memory:"): 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, tmp_path): 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 mock_conn.close.return_value = None with patch("cogs.cron.get_connection", return_value=mock_conn): 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, tmp_path): cog = create_cog(mock_bot, tmp_path) cog.scheduled_tasks = [{"id": 1, "cron_expression": "* * * * *", "type": "audio", "channel_id": 123, "active": True}] cog.save_tasks() assert len(cog.scheduled_tasks) == 1 class TestShouldRunTask: def test_should_run_task_invalid_cron(self, mock_bot, tmp_path): cog = create_cog(mock_bot, tmp_path) 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, tmp_path): cog = create_cog(mock_bot, tmp_path) 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, tmp_path): 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, tmp_path): cog = create_cog(mock_bot, tmp_path) 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, tmp_path): cog = create_cog(mock_bot, tmp_path) 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, tmp_path): cog = create_cog(mock_bot, tmp_path) 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, tmp_path): cog = create_cog(mock_bot, tmp_path) 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, tmp_path): 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, tmp_path): message_types = ("wyślij_wiadomość", "send_message") for task_type in message_types: assert task_type in ("wyślij_wiadomość", "send_message")