diff options
Diffstat (limited to 'desktop/island/calendar/test_calctl.py')
| -rw-r--r-- | desktop/island/calendar/test_calctl.py | 101 |
1 files changed, 90 insertions, 11 deletions
diff --git a/desktop/island/calendar/test_calctl.py b/desktop/island/calendar/test_calctl.py index 98973ee..91ad384 100644 --- a/desktop/island/calendar/test_calctl.py +++ b/desktop/island/calendar/test_calctl.py @@ -117,7 +117,7 @@ END:VALARM END:VEVENT END:VCALENDAR """) -w = run("get", "weird-1") +w = run("get", "weird-1", "home") assert w["repeat"] == "custom" and w["alarm"] == "custom" and w["title"] == "Standup", w assert w["start"] == "2026-10-05T09:00", w occ = [e["start"] for e in run("list", "2026-10-01", "2026-11-01") if e["uid"] == "weird-1"] @@ -128,7 +128,7 @@ assert len(occ) == 8 and occ[0] == "2026-10-05T09:00" and "2026-10-26T09:00" in assert run("list", "2026-10-01", "2026-11-01") # Unknown uid and bad usage: the error envelope, exit 1. -assert "no event" in run("get", "nope", ok=False) +assert "no event" in run("get", "nope", "home", ok=False) assert "usage" in run("frobnicate", ok=False) def ev(**kw): @@ -156,7 +156,7 @@ assert len(mine) == 1, mine assert mine[0]["start"] == "2026-10-15T14:30" and mine[0]["end"] == "2026-10-15T15:30" assert mine[0]["alarm"] == "1h" and mine[0]["repeat"] == "none" and mine[0]["color"] == "green" assert mine[0]["override"] is False -assert run("get", uid)["title"] == "Dentist" +assert run("get", uid, "home")["title"] == "Dentist" # all-day, multi-day: exclusive DTEND on disk, inclusive end in JSON. trip = run("new", ev(title="Trip", allDay=True, start="2026-10-30", end="2026-11-02", alarm="none"))["uid"] @@ -171,11 +171,19 @@ assert not [e for e in run("list", "2026-10-01", "2026-10-30") if e["uid"] == tr gym = run("new", ev(title="Gym", repeat="weekly", until="2026-10-29"))["uid"] occ = [e["start"] for e in run("list", "2026-10-01", "2026-12-01") if e["uid"] == gym] assert occ == ["2026-10-15T14:30", "2026-10-22T14:30", "2026-10-29T14:30"], occ -assert run("get", gym)["until"] == "2026-10-29" +assert os.stat(tmp / "a" / f"{gym}.ics").st_mode & 0o777 == 0o644 + +# A late-evening series keeps its last occurrence: UNTIL is UTC on disk and +# read back in local time. +late = run("new", ev(title="Late", start="2026-10-05T22:30", end="2026-10-05T23:00", + repeat="weekly", until="2026-10-19"))["uid"] +occ = [e["start"] for e in run("list", "2026-10-01", "2026-11-01") if e["uid"] == late] +assert occ == ["2026-10-05T22:30", "2026-10-12T22:30", "2026-10-19T22:30"], occ +assert run("get", gym, "home")["until"] == "2026-10-29" # edit keeping custom: the rich rule, both alarms and an unknown property # survive; SEQUENCE goes up. -run("edit", "weird-1", ev(title="Standup v2", start="2026-10-05T09:30", +run("edit", "weird-1", "home", ev(title="Standup v2", start="2026-10-05T09:30", end="2026-10-05T10:00", repeat="custom", alarm="custom")) t = (tmp / "a" / "weird.ics").read_text() assert "BYDAY=MO,WE" in t and t.count("BEGIN:VALARM") == 2 and "X-FOO:bar" in t, t @@ -183,24 +191,95 @@ assert "SUMMARY:Standup v2" in t and "SEQUENCE:1" in t, t no_temp() # edit to presets: the rule goes, the alarms become one. -run("edit", "weird-1", ev(title="Standup v2", start="2026-10-05T09:30", +run("edit", "weird-1", "home", ev(title="Standup v2", start="2026-10-05T09:30", end="2026-10-05T10:00", repeat="none", alarm="10m")) t = (tmp / "a" / "weird.ics").read_text() assert "RRULE" not in t and t.count("BEGIN:VALARM") == 1 and "TRIGGER:-PT10M" in t, t +# a custom rule cannot have its date moved: its BY* parts would stay on the +# old day. +put(tmp / "a" / "weird2.ics", """ +BEGIN:VCALENDAR +VERSION:2.0 +PRODID:-//test//EN +BEGIN:VEVENT +UID:weird-2 +DTSTAMP:20260101T000000Z +DTSTART;TZID=Europe/Rome:20261005T090000 +DTEND;TZID=Europe/Rome:20261005T100000 +RRULE:FREQ=WEEKLY;BYDAY=MO +SUMMARY:Standup +END:VEVENT +END:VCALENDAR +""") +assert "rule" in run("edit", "weird-2", "home", ev(title="Standup", start="2026-10-07T09:00", + end="2026-10-07T10:00", repeat="custom", + alarm="none"), ok=False) + +# an edit that changes nothing leaves the event's own encoding alone: zone, +# DURATION, the alarm's ACTION and extras, SUMMARY's parameter. +put(tmp / "a" / "foreign.ics", """ +BEGIN:VCALENDAR +VERSION:2.0 +PRODID:-//test//EN +BEGIN:VEVENT +UID:foreign-1 +DTSTAMP:20260101T000000Z +DTSTART;TZID=America/New_York:20261005T100000 +DURATION:PT1H +SUMMARY;LANGUAGE=it:Chiamata +BEGIN:VALARM +ACTION:AUDIO +TRIGGER:-PT1H +ACKNOWLEDGED:20261001T080000Z +END:VALARM +END:VEVENT +END:VCALENDAR +""") +g = run("get", "foreign-1", "home") +same = {k: g[k] for k in ("calendar", "title", "allDay", "start", "end", "repeat", "until", + "alarm", "location", "notes")} +run("edit", "foreign-1", "home", json.dumps(same)) +t = (tmp / "a" / "foreign.ics").read_text() +for kept in ("DTSTART;TZID=America/New_York:20261005T100000", "DURATION:PT1H", "ACTION:AUDIO", + "ACKNOWLEDGED:20261001T080000Z", "SUMMARY;LANGUAGE=it:Chiamata"): + assert kept in t, (kept, t) +# Changing only the title rewrites the title, nothing else. +run("edit", "foreign-1", "home", json.dumps(dict(same, title="Call"))) +t = (tmp / "a" / "foreign.ics").read_text() +assert "SUMMARY:Call" in t and "TZID=America/New_York" in t and "ACTION:AUDIO" in t, t + +# the same UID in two calendars: each command acts on the copy it names. +for d in ("a", "b"): + put(tmp / d / "dup.ics", f""" +BEGIN:VCALENDAR +VERSION:2.0 +PRODID:-//test//EN +BEGIN:VEVENT +UID:dup-1 +DTSTAMP:20260101T000000Z +DTSTART;VALUE=DATE:20261020 +SUMMARY:copy {d} +END:VEVENT +END:VCALENDAR +""") +assert run("get", "dup-1", "birthdays")["title"] == "copy b" +run("delete", "dup-1", "home") +assert not (tmp / "a" / "dup.ics").exists() and (tmp / "b" / "dup.ics").exists() + # a calendar change moves the file. -run("edit", uid, ev(calendar="birthdays")) +run("edit", uid, "home", ev(calendar="birthdays")) assert not f.exists() and (tmp / "b" / f.name).exists() -assert run("get", uid)["calendar"] == "birthdays" +assert run("get", uid, "birthdays")["calendar"] == "birthdays" # cal-notif's per-event override is reported. (tmp / "overrides.toml").write_text(f'"{uid}" = ["10m"]\n') -assert run("get", uid)["override"] is True +assert run("get", uid, "birthdays")["override"] is True # delete. -assert run("delete", uid) == {} +assert run("delete", uid, "birthdays") == {} assert not (tmp / "b" / f.name).exists() -assert "no event" in run("get", uid, ok=False) +assert "no event" in run("get", uid, "birthdays", ok=False) # validation: the error envelope, exit 1, nothing written. before = sorted(p.name for p in tmp.rglob("*.ics")) |
