import json import os 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): cog = Cron.__new__(Cron) cog.bot = mock_bot cog.scheduled_tasks = [] cog.cron_file = str(tmp_path / "cron_jobs.json") cog.task = MagicMock() return cog class TestLoadTasks: def test_load_tasks_file_not_exists(self, mock_bot, tmp_path): cog = create_cog(mock_bot, tmp_path) cog.cron_file = str(tmp_path / "nonexistent.json") cog.load_tasks() assert cog.scheduled_tasks == [] def test_load_tasks_empty_file(self, mock_bot, tmp_path): cron_file = tmp_path / "empty.json" cron_file.write_text("") cog = create_cog(mock_bot, tmp_path) cog.cron_file = str(cron_file) cog.load_tasks() assert cog.scheduled_tasks == [] def test_load_tasks_valid_file(self, mock_bot, tmp_path): cron_file = tmp_path / "valid.json" tasks = [{"id": 1, "cron_expression": "* * * * *", "type": "audio", "channel_id": 123, "active": True}] cron_file.write_text(json.dumps(tasks)) cog = create_cog(mock_bot, tmp_path) cog.cron_file = str(cron_file) cog.load_tasks() assert len(cog.scheduled_tasks) == 1 assert cog.scheduled_tasks[0]["id"] == 1 def test_load_tasks_io_error(self, mock_bot, tmp_path): cog = create_cog(mock_bot, tmp_path) with patch("builtins.open", side_effect=IOError("test error")): cog.load_tasks() assert cog.scheduled_tasks == [] class TestSaveTasks: def test_save_tasks_with_real_file(self, mock_bot, tmp_path): cron_file = tmp_path / "cron_jobs.json" cog = create_cog(mock_bot, tmp_path) cog.cron_file = str(cron_file) cog.scheduled_tasks = [{"id": 1, "cron_expression": "* * * * *"}] cog.save_tasks() assert os.path.exists(cron_file) with open(cron_file) as f: loaded = json.load(f) assert len(loaded) == 1 def test_save_tasks_creates_directory_structure(self, mock_bot, tmp_path): cog = create_cog(mock_bot, tmp_path) new_dir = tmp_path / "new_dir" cron_file = new_dir / "cron_jobs.json" cog.cron_file = str(cron_file) cog.scheduled_tasks = [{"id": 1}] cog.save_tasks() assert os.path.exists(new_dir) 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")