Skip to content

Commit

Permalink
Validate event rrules always have a start date (#283)
Browse files Browse the repository at this point in the history
  • Loading branch information
allenporter authored Feb 3, 2024
1 parent ceb347e commit 368ba48
Show file tree
Hide file tree
Showing 2 changed files with 36 additions and 9 deletions.
3 changes: 3 additions & 0 deletions ical/event.py
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@
from .alarm import Alarm
from .component import ComponentModel, validate_until_dtstart, validate_recurrence_dates
from .iter import RulesetIterable
from .exceptions import CalendarParseError
from .parsing.property import ParsedProperty
from .timespan import Timespan
from .types import (
Expand Down Expand Up @@ -363,6 +364,8 @@ def as_rrule(self) -> Iterable[datetime.datetime | datetime.date] | None:
"""
if not self.rrule and not self.rdate:
return None
if not self.start:
raise CalendarParseError("Event must have a start date to be recurring")
return RulesetIterable(
self.start,
[self.rrule.as_rrule(self.start)] if self.rrule else [],
Expand Down
42 changes: 33 additions & 9 deletions tests/test_event.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,18 +2,21 @@

from __future__ import annotations

import zoneinfo
from typing import Any
from datetime import date, datetime, timedelta, timezone
from unittest.mock import patch
import zoneinfo

import pytest

try:
from pydantic.v1 import ValidationError
except ImportError:
from pydantic import ValidationError

from ical.event import Event
from ical.exceptions import CalendarParseError
from ical.types.recur import Recur

SUMMARY = "test summary"
LOS_ANGELES = zoneinfo.ZoneInfo("America/Los_Angeles")
Expand Down Expand Up @@ -179,18 +182,12 @@ def test_start_end_same_type() -> None:
def test_no_end_time_or_dur() -> None:
"""Verify that events with no end time or duration will use correct defaults."""

day_event = Event(
summary=SUMMARY,
dtstart=date(2022, 9, 9)
)
day_event = Event(summary=SUMMARY, dtstart=date(2022, 9, 9))
assert day_event.end == date(2022, 9, 10)
assert day_event.duration is None
assert day_event.computed_duration == timedelta(days=1)

time_event = Event(
summary=SUMMARY,
dtstart=datetime(2022, 9, 9, 10, 0, 0)
)
time_event = Event(summary=SUMMARY, dtstart=datetime(2022, 9, 9, 10, 0, 0))
assert time_event.end == datetime(2022, 9, 9, 10, 0, 0)
assert time_event.duration is None
assert time_event.computed_duration == timedelta()
Expand Down Expand Up @@ -432,3 +429,30 @@ def test_validate_assignment() -> None:
# But updates that are valid are OK
event.dtstart = date(2022, 9, 5)
event.dtend = date(2022, 9, 10)


@pytest.mark.parametrize(
("params"),
[
({}),
(
{
"end": datetime(2022, 9, 6, 6, 0, 0),
}
),
(
{
"duration": timedelta(hours=1),
}
),
],
)
def test_validate_rrule_required_fields(params: dict[str, Any]) -> None:
"""Test that an event with an rrule requires a dtstart."""
event = Event(
summary="Event 1",
rrule=Recur.from_rrule("FREQ=WEEKLY;BYDAY=WE,MO,TU,TH,FR;COUNT=3"),
**params,
)
with pytest.raises(CalendarParseError):
event.as_rrule()

0 comments on commit 368ba48

Please sign in to comment.