diff --git a/lib/src/main/kotlin/at/bitfire/synctools/mapping/calendar/AndroidEventHandler.kt b/lib/src/main/kotlin/at/bitfire/synctools/mapping/calendar/AndroidEventHandler.kt index 492d6da7..945ad3c9 100644 --- a/lib/src/main/kotlin/at/bitfire/synctools/mapping/calendar/AndroidEventHandler.kt +++ b/lib/src/main/kotlin/at/bitfire/synctools/mapping/calendar/AndroidEventHandler.kt @@ -42,6 +42,7 @@ import net.fortuna.ical4j.model.ParameterList import net.fortuna.ical4j.model.Property import net.fortuna.ical4j.model.component.VEvent import net.fortuna.ical4j.model.parameter.TzId +import net.fortuna.ical4j.model.parameter.Value import net.fortuna.ical4j.model.property.ExDate import net.fortuna.ical4j.model.property.ProdId import net.fortuna.ical4j.model.property.RDate @@ -166,7 +167,7 @@ class AndroidEventHandler( // Return ExDate return if (originalAllDay) { // .. as date, without time - ExDate(DateList(LocalDate.from(date))) + ExDate(ParameterList(listOf(Value.DATE)), DateList(LocalDate.from(date))) } else if (date is Instant) { ExDate(DateList(date)) } else { diff --git a/lib/src/test/kotlin/at/bitfire/synctools/mapping/calendar/AndroidEventHandlerTest.kt b/lib/src/test/kotlin/at/bitfire/synctools/mapping/calendar/AndroidEventHandlerTest.kt index 1ee5ec89..04e54161 100644 --- a/lib/src/test/kotlin/at/bitfire/synctools/mapping/calendar/AndroidEventHandlerTest.kt +++ b/lib/src/test/kotlin/at/bitfire/synctools/mapping/calendar/AndroidEventHandlerTest.kt @@ -11,13 +11,15 @@ import android.provider.CalendarContract.Events import android.provider.CalendarContract.ExtendedProperties import androidx.core.content.contentValuesOf import at.bitfire.dateTimeValue +import at.bitfire.dateValue import at.bitfire.synctools.icalendar.dtStart import at.bitfire.synctools.icalendar.recurrenceId import at.bitfire.synctools.storage.calendar.EventAndExceptions import at.bitfire.synctools.storage.calendar.EventsContract -import at.bitfire.synctools.util.AndroidTimeUtils +import net.fortuna.ical4j.model.Parameter import net.fortuna.ical4j.model.Property import net.fortuna.ical4j.model.TimeZoneRegistryFactory +import net.fortuna.ical4j.model.parameter.Value import net.fortuna.ical4j.model.property.DtStart import net.fortuna.ical4j.model.property.ExDate import net.fortuna.ical4j.model.property.ProdId @@ -148,6 +150,43 @@ class AndroidEventHandlerTest { assertTrue(result.exceptions.isEmpty()) } + @Test + fun `mapToVEvents rewrites cancelled all-day exception to EXDATE with VALUE=DATE`() { + val result = handler.mapToVEvents( + eventAndExceptions = EventAndExceptions( + main = Entity(contentValuesOf( + Events.TITLE to "Recurring all-day event with cancelled all-day exception", + Events.DTSTART to 1594056600000L, + Events.EVENT_TIMEZONE to "UTC", + Events.ALL_DAY to 1, // main event is all-day + Events.RRULE to "FREQ=DAILY;COUNT=10" + )), + exceptions = listOf( + Entity(contentValuesOf( + Events.ORIGINAL_INSTANCE_TIME to 1594143000000L, + Events.ORIGINAL_ALL_DAY to 1, // exception is all-day + Events.DTSTART to 1594143000000L, + Events.ALL_DAY to 1, + Events.EVENT_TIMEZONE to "UTC", + Events.STATUS to Events.STATUS_CANCELED + )) + ) + ) + ).associatedEvents + val main = result.main!! + assertEquals("Recurring all-day event with cancelled all-day exception", main.summary.value) + assertEquals("FREQ=DAILY;COUNT=10", main.getProperty>(Property.RRULE).get().value) + + // Check that EXDATE has VALUE=DATE + val exDate = main.getProperty>(Property.EXDATE).get() + assertEquals(Value.DATE, exDate.getParameter(Parameter.VALUE).get()) + assertEquals( + dateValue("20200707"), + main.getProperty>(Property.EXDATE)?.getOrNull()?.dates?.first() + ) + assertTrue(result.exceptions.isEmpty()) + } + @Test fun `mapToVEvents rewrites cancelled exception using UTC to EXDATE`() { val result = handler.mapToVEvents( diff --git a/lib/src/test/kotlin/at/bitfire/synctools/mapping/calendar/handler/RecurrenceFieldHandlerTest.kt b/lib/src/test/kotlin/at/bitfire/synctools/mapping/calendar/handler/RecurrenceFieldHandlerTest.kt index e638b324..f2b4a4ba 100644 --- a/lib/src/test/kotlin/at/bitfire/synctools/mapping/calendar/handler/RecurrenceFieldHandlerTest.kt +++ b/lib/src/test/kotlin/at/bitfire/synctools/mapping/calendar/handler/RecurrenceFieldHandlerTest.kt @@ -15,6 +15,7 @@ import at.bitfire.dateValue import io.mockk.mockk import junit.framework.TestCase.assertEquals import net.fortuna.ical4j.model.DateList +import net.fortuna.ical4j.model.Parameter import net.fortuna.ical4j.model.ParameterList import net.fortuna.ical4j.model.Property import net.fortuna.ical4j.model.Recur @@ -132,10 +133,10 @@ class RecurrenceFieldHandlerTest { "FREQ=WEEKLY;COUNT=1", result.getProperties>(Property.EXRULE).joinToString { it.value } ) - assertEquals( - "20260201", - result.getProperties>(Property.EXDATE).joinToString { it.value } - ) + // All-day EXDATE must have VALUE=DATE + val exDates = result.getProperties>(Property.EXDATE) + assertEquals(Value.DATE, exDates.first().getParameter(Parameter.VALUE).get()) + assertEquals("20260201", exDates.joinToString { it.value }) } @Test