You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
tasks/app/src/test/java/org/tasks/caldav/iCalendarMergeTest.kt

659 lines
19 KiB
Kotlin

@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)
}
}