import json import os import sqlite3 import sys from pathlib import Path import pytest SCRIPTS = Path(__file__).parent.parent / "scripts" sys.path.insert(0, str(SCRIPTS)) from db import get_db, init_db import remind_edit def _run(db_path, argv): """Run remind_edit main with a temporary DB path.""" original_db_path = remind_edit.DB_PATH try: remind_edit.DB_PATH = db_path # Patch the module-level DB_PATH used by functions sys.argv = ["remind_edit.py"] + argv return remind_edit.main() finally: remind_edit.DB_PATH = original_db_path def test_add_list(tmp_path, capsys): db_path = tmp_path / "test.sqlite" init_db(db_path) ret = _run(db_path, ["add", "--text", "drink water", "--cron", "0 9 * * *"]) captured = capsys.readouterr() assert ret == 0 data = json.loads(captured.out) assert data["added"]["text"] == "drink water" assert len(data["added"]["cron"]) == 1 ret = _run(db_path, ["list"]) captured = capsys.readouterr() assert ret == 0 assert "drink water" in captured.out assert "cron: 0 9 * * *" in captured.out def test_add_at_validation(tmp_path, capsys): db_path = tmp_path / "test.sqlite" init_db(db_path) ret = _run(db_path, ["add", "--text", "x", "--at", "not-a-date"]) captured = capsys.readouterr() assert ret == 1 assert "invalid --at datetime" in captured.err def test_add_cron_validation(tmp_path, capsys): db_path = tmp_path / "test.sqlite" init_db(db_path) ret = _run(db_path, ["add", "--text", "x", "--cron", "bad"]) captured = capsys.readouterr() assert ret == 1 assert "invalid cron expression" in captured.err def test_remove(tmp_path, capsys): db_path = tmp_path / "test.sqlite" init_db(db_path) _run(db_path, ["add", "--text", "stretch", "--cron", "0 10 * * *"]) capsys.readouterr() # clear setup output ret = _run(db_path, ["remove", "--keyword", "stretch"]) captured = capsys.readouterr() assert ret == 0 data = json.loads(captured.out) assert data["removed"]["text"] == "stretch" ret = _run(db_path, ["list"]) captured = capsys.readouterr() assert captured.out.strip() == "" def test_remove_no_match(tmp_path, capsys): db_path = tmp_path / "test.sqlite" init_db(db_path) ret = _run(db_path, ["remove", "--keyword", "nonexistent"]) captured = capsys.readouterr() assert ret == 1 assert "no match" in captured.err def test_remove_ambiguous(tmp_path, capsys): db_path = tmp_path / "test.sqlite" init_db(db_path) _run(db_path, ["add", "--text", "drink water", "--cron", "0 9 * * *"]) _run(db_path, ["add", "--text", "drink tea", "--cron", "0 10 * * *"]) ret = _run(db_path, ["remove", "--keyword", "drink"]) captured = capsys.readouterr() assert ret == 1 assert "ambiguous" in captured.err def test_edit_text(tmp_path, capsys): db_path = tmp_path / "test.sqlite" init_db(db_path) _run(db_path, ["add", "--text", "old text", "--cron", "0 9 * * *"]) capsys.readouterr() # clear setup output ret = _run(db_path, ["edit", "--keyword", "old", "--text", "new text"]) captured = capsys.readouterr() assert ret == 0 data = json.loads(captured.out) assert data["edited"]["text"] == "new text" def test_edit_replace_schedules(tmp_path, capsys): db_path = tmp_path / "test.sqlite" init_db(db_path) _run(db_path, ["add", "--text", "task", "--cron", "0 9 * * *"]) capsys.readouterr() # clear setup output ret = _run(db_path, ["edit", "--keyword", "task", "--replace-schedules", "--at", "2026-06-15T10:00:00"]) captured = capsys.readouterr() assert ret == 0 data = json.loads(captured.out) assert len(data["edited"]["cron"]) == 0 assert len(data["edited"]["at"]) == 1 def test_enable_disable(tmp_path, capsys): db_path = tmp_path / "test.sqlite" init_db(db_path) _run(db_path, ["add", "--text", "toggle me", "--cron", "0 9 * * *"]) capsys.readouterr() # clear setup output ret = _run(db_path, ["disable", "--keyword", "toggle"]) captured = capsys.readouterr() assert ret == 0 data = json.loads(captured.out) assert data["disabled"]["enabled"] == 0 ret = _run(db_path, ["enable", "--keyword", "toggle"]) captured = capsys.readouterr() assert ret == 0 data = json.loads(captured.out) assert data["enabled"]["enabled"] == 1 def test_add_combined_schedules(tmp_path, capsys): db_path = tmp_path / "test.sqlite" init_db(db_path) ret = _run(db_path, [ "add", "--text", "multi", "--at", "2026-06-15T10:00:00", "--cron", "0 9 * * *", "--random-times-per-day", "2", "--random-window", "08:00-20:00", ]) captured = capsys.readouterr() assert ret == 0 data = json.loads(captured.out) assert len(data["added"]["at"]) == 1 assert len(data["added"]["cron"]) == 1 assert len(data["added"]["random"]) == 1 def test_add_random_validation(tmp_path, capsys): db_path = tmp_path / "test.sqlite" init_db(db_path) ret = _run(db_path, [ "add", "--text", "bad", "--random-times-per-day", "2", "--random-window", "08:00-08:01", ]) captured = capsys.readouterr() assert ret == 1 assert "window" in captured.err.lower() or "gap" in captured.err.lower()