Repository: allenporter/gcal_sync (language: python)

Issue:
Coerce invalid all day events to have a valid duration
Update invalid events parsed from the response to have valid durations. Google calendar may return an all day event with a zero duration, which is not expected.


Discussion / hints:

Fix patch:
diff --git a/gcal_sync/model.py b/gcal_sync/model.py
index d78841f..db18b94 100644
--- a/gcal_sync/model.py
+++ b/gcal_sync/model.py
@@ -539,17 +539,17 @@ def _validate_recur(cls, values: dict[str, Any]) -> dict[str, Any]:
     @root_validator
     def _adjust_duration(cls, values: dict[str, Any]) -> dict[str, Any]:
         """Fix events with invalid durations."""
-        _LOGGER.debug("_adjust_duration")
         if (
             (dtstart := values.get("start"))
             and (dtend := values.get("end"))
-            and dtstart.date
-            and dtend.date
-            and ((dtend.date - dtstart.date) <= datetime.timedelta(days=0))
+            and (dtend.value - dtstart.value) <= datetime.timedelta(seconds=0)
         ):
-            # Duration is zero or negative. Default to 1 day
-            dtend.date = dtstart.date + datetime.timedelta(days=1)
-            values["end"] = dtend
+            if dtstart.date and dtend.date:
+                dtend.date = dtstart.date + datetime.timedelta(days=1)
+                values["end"] = dtend
+            if dtstart.date_time and dtend.date_time:
+                dtend.date_time = dtstart.date_time + datetime.timedelta(minutes=30)
+                values["end"] = dtend
         return values
 
     @root_validator


Test patch:
diff --git a/tests/test_model.py b/tests/test_model.py
index 53e3aad..362820e 100644
--- a/tests/test_model.py
+++ b/tests/test_model.py
@@ -750,7 +750,7 @@ def test_event_timezone_with_offset() -> None:
     assert event.start.value.isoformat() == "2022-11-24T19:45:00+01:00"
 
 
-def test_all_day_event() -> None:
+def test_invalid_all_day_event_duration() -> None:
     """Verify that all day events with invalid durations are fixed."""
 
     event = Event.parse_obj(
@@ -770,3 +770,41 @@ def test_all_day_event() -> None:
     assert event.start.value.isoformat() == "2022-11-24"
     assert event.end.date == datetime.date(2022, 11, 25)
     assert event.end.value.isoformat() == "2022-11-25"
+
+
+def test_invalid_event_duration() -> None:
+    """Verify that all day events with invalid durations are fixed."""
+
+    event = Event.parse_obj(
+        {
+            "id": "some-event-id",
+            "summary": "Event #1",
+            "start": {
+                "dateTime": "2022-04-12T16:30:00-08:00",
+            },
+            "end": {
+                "dateTime": "2022-04-12T16:30:00-08:00",  # Invalid end date
+            },
+        }
+    )
+    assert event.id == "some-event-id"
+    tzinfo = datetime.timezone(datetime.timedelta(hours=-8))
+
+    assert event.start
+    assert event.start.date is None
+    assert event.start.date_time
+    assert event.start.date_time == datetime.datetime(
+        2022, 4, 12, 16, 30, 0, tzinfo=tzinfo
+    )
+    assert event.start.timezone is None
+    assert event.start.value == datetime.datetime(2022, 4, 12, 16, 30, 0, tzinfo=tzinfo)
+
+    assert event.end
+    assert event.end.date is None
+    assert event.end.date_time == datetime.datetime(
+        2022, 4, 12, 17, 0, 0, tzinfo=tzinfo
+    )
+    assert event.end.timezone is None
+    assert event.end.value == datetime.datetime(2022, 4, 12, 17, 0, 0, tzinfo=tzinfo)
+
+    assert event.timespan.duration == datetime.timedelta(minutes=30)