@file:Suppress("ClassName") package org.tasks.caldav import com.natpryce.makeiteasy.MakeItEasy.with import com.todoroo.astrid.data.Task.Companion.URGENCY_SPECIFIC_DAY import com.todoroo.astrid.data.Task.Companion.createDueDate import com.todoroo.astrid.data.Task.Priority.Companion.HIGH import com.todoroo.astrid.data.Task.Priority.Companion.LOW import com.todoroo.astrid.data.Task.Priority.Companion.MEDIUM import net.fortuna.ical4j.model.property.Status import org.junit.Assert.* import org.junit.Test import org.tasks.date.DateTimeUtils.newDateTime import org.tasks.makers.CaldavTaskMaker.REMOTE_PARENT import org.tasks.makers.CaldavTaskMaker.newCaldavTask import org.tasks.makers.TaskMaker import org.tasks.makers.TaskMaker.COMPLETION_TIME import org.tasks.makers.TaskMaker.CREATION_TIME import org.tasks.makers.TaskMaker.newTask import org.tasks.makers.iCalMaker import org.tasks.makers.iCalMaker.COLLAPSED import org.tasks.makers.iCalMaker.COMPLETED_AT import org.tasks.makers.iCalMaker.CREATED_AT import org.tasks.makers.iCalMaker.DESCRIPTION import org.tasks.makers.iCalMaker.DUE_DATE import org.tasks.makers.iCalMaker.PARENT import org.tasks.makers.iCalMaker.PRIORITY import org.tasks.makers.iCalMaker.RRULE import org.tasks.makers.iCalMaker.START_DATE import org.tasks.makers.iCalMaker.STATUS import org.tasks.makers.iCalMaker.TITLE import org.tasks.makers.iCalMaker.newIcal import org.tasks.time.DateTime class iCalendarMergeTest { @Test fun applyTitleNewTask() = newTask() .applyRemote( remote = newIcal(with(TITLE, "Title")), local = null ) .let { assertEquals("Title", it.title) } @Test fun remoteUpdatedTitle() = newTask(with(TaskMaker.TITLE, "Title")) .applyRemote( remote = newIcal(with(TITLE, "Title2")), local = newIcal(with(TITLE, "Title")), ) .let { assertEquals("Title2", it.title) } @Test fun localBeatsRemoteTitle() = newTask(with(TaskMaker.TITLE, "Title3")) .applyRemote( remote = newIcal(with(TITLE, "Title2")), local = newIcal(with(TITLE, "Title")), ) .let { assertEquals("Title3", it.title) } @Test fun remoteRemovesTitle() = newTask(with(TaskMaker.TITLE, "Title")) .applyRemote( remote = newIcal(with(TITLE, null as String?)), local = newIcal(with(TITLE, "Title")), ) .let { assertNull(it.title) } @Test fun localRemovesTitle() = newTask(with(TaskMaker.TITLE, null as String?)) .applyRemote( remote = newIcal(with(TITLE, "Title")), local = newIcal(with(TITLE, "Title")) ) .let { assertNull(it.title) } @Test fun applyNewDescription() = newTask() .applyRemote( remote = newIcal(with(DESCRIPTION, "Description")), local = null ) .let { assertEquals("Description", it.notes) } @Test fun localBeatsRemoteDescription() = newTask(with(TaskMaker.DESCRIPTION, "Description3")) .applyRemote( remote = newIcal(with(DESCRIPTION, "Description2")), local = newIcal(with(DESCRIPTION, "Description")) ) .let { assertEquals("Description3", it.notes) } @Test fun remoteUpdatesDescription() { newTask(with(TaskMaker.DESCRIPTION, "Description")) .applyRemote( remote = newIcal(with(DESCRIPTION, "Description2")), local = newIcal(with(DESCRIPTION, "Description")) ) .let { assertEquals("Description2", it.notes) } } @Test fun localRemovedDescription() = newTask(with(TaskMaker.DESCRIPTION, null as String?)) .applyRemote( remote = newIcal(with(DESCRIPTION, "Description")), local = newIcal(with(DESCRIPTION, "Description")) ) .let { assertNull(it.notes) } @Test fun remoteRemovedDescription() = newTask(with(TaskMaker.DESCRIPTION, "Description")) .applyRemote( remote = newIcal(with(DESCRIPTION, null as String?)), local = newIcal(with(DESCRIPTION, "Description")) ) .let { assertNull(it.notes) } @Test fun applyPriorityNewTask() = newTask(with(TaskMaker.PRIORITY, HIGH)) .applyRemote( remote = newIcal(with(PRIORITY, 5)), local = null ) .let { assertEquals(MEDIUM, it.priority) } @Test fun localUpdatedPriority() = newTask(with(TaskMaker.PRIORITY, LOW)) .applyRemote( remote = newIcal(with(PRIORITY, 5)), local = newIcal(with(PRIORITY, 5)) ) .let { assertEquals(LOW, it.priority) } @Test fun remoteUpdatedPriority() = newTask(with(TaskMaker.PRIORITY, MEDIUM)) .applyRemote( remote = newIcal(with(PRIORITY, 1)), local = newIcal(with(PRIORITY, 5)) ) .let { assertEquals(HIGH, it.priority) } @Test fun localBeatsRemotePriority() = newTask(with(TaskMaker.PRIORITY, HIGH)) .applyRemote( remote = newIcal(with(PRIORITY, 1)), local = newIcal(with(PRIORITY, 5)) ) .let { assertEquals(HIGH, it.priority) } @Test fun dueDateNewTask() { val due = newDateTime() newTask() .applyRemote( remote = newIcal(with(DUE_DATE, due)), local = null ) .let { assertEquals(due.allDay(), it.dueDate) } } @Test fun remoteAddsDueDate() { val due = newDateTime() newTask() .applyRemote( remote = newIcal(with(DUE_DATE, due)), local = newIcal() ) .let { assertEquals(due.allDay(), it.dueDate) } } @Test fun remoteUpdatesDueDate() { val due = newDateTime() newTask(with(TaskMaker.DUE_DATE, due)) .applyRemote( remote = newIcal(with(DUE_DATE, due.plusDays(1))), local = newIcal(with(DUE_DATE, due)) ) .let { assertEquals(due.plusDays(1).allDay(), it.dueDate) } } @Test fun remoteRemovesDueDate() { val due = newDateTime() newTask(with(TaskMaker.DUE_DATE, due)) .applyRemote( remote = newIcal(), local = newIcal(with(DUE_DATE, due)) ) .let { assertEquals(0, it.dueDate) } } @Test fun localRemovesDueDate() { val due = newDateTime() newTask() .applyRemote( remote = newIcal(with(DUE_DATE, due)), local = newIcal(with(DUE_DATE, due)) ) .let { assertEquals(0, it.dueDate) } } @Test fun localBeatsRemoteDueDate() { val due = newDateTime() newTask(with(TaskMaker.DUE_DATE, due.plusDays(2))) .applyRemote( remote = newIcal(with(DUE_DATE, due.plusDays(1))), local = newIcal(with(DUE_DATE, due)) ) .let { assertEquals(due.plusDays(2).allDay(), it.dueDate) } } @Test fun startDateNewTask() { val start = newDateTime() newTask() .applyRemote( remote = newIcal(with(START_DATE, start)), local = null ) .let { assertEquals(start.startOfDay().millis, it.hideUntil) } } @Test fun remoteAddsStartDate() { val start = newDateTime() newTask() .applyRemote( remote = newIcal(with(START_DATE, start)), local = newIcal() ) .let { assertEquals(start.startOfDay().millis, it.hideUntil) } } @Test fun remoteUpdatesStartDate() { val start = newDateTime() newTask(with(TaskMaker.START_DATE, start)) .applyRemote( remote = newIcal(with(START_DATE, start.plusDays(1))), local = newIcal(with(START_DATE, start)) ) .let { assertEquals(start.plusDays(1).startOfDay().millis, it.hideUntil) } } @Test fun remoteRemovesStartDate() { val start = newDateTime() newTask(with(TaskMaker.START_DATE, start)) .applyRemote( remote = newIcal(), local = newIcal(with(START_DATE, start)) ) .let { assertEquals(0, it.hideUntil) } } @Test fun localRemovesStartDate() { val start = newDateTime() newTask() .applyRemote( remote = newIcal(with(START_DATE, start)), local = newIcal(with(START_DATE, start)) ) .let { assertEquals(0, it.hideUntil) } } @Test fun localBeatsRemoteStartDate() { val start = newDateTime() newTask(with(TaskMaker.START_DATE, start.plusDays(2))) .applyRemote( remote = newIcal(with(START_DATE, start.plusDays(1))), local = newIcal(with(START_DATE, start)) ) .let { assertEquals(start.plusDays(2).startOfDay().millis, it.hideUntil) } } @Test fun remoteAddsCreationDate() { val created = newDateTime() newTask(with(CREATION_TIME, created.minusMinutes(1))) .applyRemote( remote = newIcal(with(CREATED_AT, created.toUTC())), local = null ) .let { assertEquals(created.millis, it.creationDate) } } @Test fun remoteSetsRecurrence() = newTask() .applyRemote( remote = newIcal(with(RRULE, "FREQ=DAILY")), local = null ) .let { assertEquals("FREQ=DAILY", it.recurrence) } @Test fun remoteUpdatesRecurrence() = newTask(with(TaskMaker.RECUR, "FREQ=DAILY")) .applyRemote( remote = newIcal(with(RRULE, "FREQ=MONTHLY")), local = newIcal(with(RRULE, "FREQ=DAILY")) ) .let { assertEquals("FREQ=MONTHLY", it.recurrence) } @Test fun remoteRemovesRecurrence() = newTask(with(TaskMaker.RECUR, "FREQ=DAILY")) .applyRemote( remote = newIcal(), local = newIcal(with(RRULE, "FREQ=DAILY")) ) .let { assertNull(it.recurrence) } @Test fun localRemovesRecurrence() = newTask() .applyRemote( remote = newIcal(with(RRULE, "FREQ=DAILY")), local = newIcal(with(RRULE, "FREQ=DAILY")) ) .let { assertNull(it.recurrence) } @Test fun localBeatsRemoteRecurrence() = newTask(with(TaskMaker.RECUR, "FREQ=WEEKLY")) .applyRemote( remote = newIcal(with(RRULE, "FREQ=MONTHLY")), local = newIcal(with(RRULE, "FREQ=DAILY")) ) .let { assertEquals("FREQ=WEEKLY", it.recurrence) } @Test fun remoteSetsCompletedStatus() = newTask() .applyRemote( remote = newIcal(with(STATUS, Status.VTODO_COMPLETED)), local = null ) .let { assertTrue(it.isCompleted) } @Test fun remoteUpdatesCompletedStatus() = newTask() .applyRemote( remote = newIcal(with(STATUS, Status.VTODO_COMPLETED)), local = newIcal(with(STATUS, Status.VTODO_IN_PROCESS)) ) .let { assertTrue(it.isCompleted) } @Test fun remoteRemovesCompletedStatus() { val now = newDateTime() newTask(with(COMPLETION_TIME, now)) .applyRemote( remote = newIcal(), local = newIcal( with(STATUS, Status.VTODO_COMPLETED), with(COMPLETED_AT, now) ) ) .let { assertFalse(it.isCompleted) } } @Test fun remoteSetsCompletedAt() { val now = newDateTime() newTask() .applyRemote( remote = newIcal(with(COMPLETED_AT, now.toUTC())), local = null ) .let { assertEquals(now.startOfSecond().millis, it.completionDate) } } @Test fun remoteUpdatesCompletedAt() { val now = newDateTime() newTask(with(COMPLETION_TIME, now)) .applyRemote( remote = newIcal(with(COMPLETED_AT, now.plusMinutes(5).toUTC())), local = newIcal( with(COMPLETED_AT, now.toUTC()), with(STATUS, Status.VTODO_COMPLETED) ) ) .let { assertEquals(now.plusMinutes(5).startOfSecond().millis, it.completionDate) } } @Test fun remoteRemovesCompletedAt() { val now = newDateTime() newTask(with(COMPLETION_TIME, now)) .applyRemote( remote = newIcal(), local = newIcal( with(COMPLETED_AT, now.toUTC()), with(STATUS, Status.VTODO_COMPLETED) ) ) .let { assertFalse(it.isCompleted) } } @Test fun localRemovesCompletedAt() { val now = newDateTime() newTask() .applyRemote( remote = newIcal(with(COMPLETED_AT, now.toUTC())), local = newIcal( with(COMPLETED_AT, now.toUTC()), with(STATUS, Status.VTODO_COMPLETED) ) ) .let { assertFalse(it.isCompleted) } } @Test fun localBeatsRemoteCompletedAt() { val now = newDateTime() newTask(with(COMPLETION_TIME, now.plusMinutes(2))) .applyRemote( remote = newIcal(with(COMPLETED_AT, now.plusMinutes(1).toUTC())), local = newIcal( with(COMPLETED_AT, now.toUTC()), with(STATUS, Status.VTODO_COMPLETED) ) ) .let { assertEquals(now.plusMinutes(2).millis, it.completionDate) } } @Test fun remoteSetsCollapsed() { newTask() .applyRemote( remote = newIcal(with(COLLAPSED, true)), local = null ) .let { assertTrue(it.isCollapsed) } } @Test fun remoteRemovesCollapsed() { newTask(with(TaskMaker.COLLAPSED, true)) .applyRemote( remote = newIcal(), local = newIcal(with(COLLAPSED, true)) ) .let { assertFalse(it.isCollapsed) } } @Test fun localBeatsRemoteCollapsed() { newTask(with(TaskMaker.COLLAPSED, true)) .applyRemote( remote = newIcal(with(COLLAPSED, false)), local = newIcal(with(COLLAPSED, false)) ) .let { assertTrue(it.isCollapsed) } } @Test fun remoteSetsOrder() = newTask() .applyRemote( remote = newIcal(with(iCalMaker.ORDER, 1234)), local = null ) .let { assertEquals(1234L, it.order) } @Test fun remoteRemovesOrder() = newTask(with(TaskMaker.ORDER, 1234)) .applyRemote( remote = newIcal(), local = newIcal(with(iCalMaker.ORDER, 1234)) ) .let { assertNull(it.order) } @Test fun localRemovesOrder() = newTask() .applyRemote( remote = newIcal(with(iCalMaker.ORDER, 1234)), local = newIcal(with(iCalMaker.ORDER, 1234)) ) .let { assertNull(it.order) } @Test fun localBeatsRemoteOrder() = newTask(with(TaskMaker.ORDER, 789L)) .applyRemote( remote = newIcal(with(iCalMaker.ORDER, 456L)), local = newIcal(with(iCalMaker.ORDER, 123)) ) .let { assertEquals(789L, it.order) } @Test fun remoteSetsParent() = newCaldavTask() .applyRemote( remote = newIcal(with(PARENT, "1234")), local = null ) .let { assertEquals("1234", it.remoteParent) } @Test fun remoteRemovesParent() = newCaldavTask(with(REMOTE_PARENT, "1234")) .applyRemote( remote = newIcal(), local = newIcal(with(PARENT, "1234")) ) .let { assertNull(it.remoteParent) } @Test fun localRemovesParent() = newCaldavTask() .applyRemote( remote = newIcal(with(PARENT, "1234")), local = newIcal(with(PARENT, "1234")) ) .let { assertNull(it.remoteParent) } @Test fun localBeatsRemoteParent() = newCaldavTask(with(REMOTE_PARENT, "789")) .applyRemote( remote = newIcal(with(PARENT, "456")), local = newIcal(with(PARENT, "123")) ) .let { assertEquals("789", it.remoteParent) } companion object { private fun DateTime.allDay() = createDueDate(URGENCY_SPECIFIC_DAY, millis) } }