mirror of https://github.com/tasks/tasks
Merge remote changes before pushing local changes
Only applies to native CalDAV and native EteSyncpull/1790/head
parent
39438dd8b7
commit
42e44eafdc
@ -0,0 +1,73 @@
|
||||
package org.tasks.makers
|
||||
|
||||
import at.bitfire.ical4android.Task
|
||||
import com.natpryce.makeiteasy.Instantiator
|
||||
import com.natpryce.makeiteasy.Property
|
||||
import com.natpryce.makeiteasy.Property.newProperty
|
||||
import com.natpryce.makeiteasy.PropertyLookup
|
||||
import com.natpryce.makeiteasy.PropertyValue
|
||||
import net.fortuna.ical4j.model.property.Completed
|
||||
import net.fortuna.ical4j.model.property.DtStart
|
||||
import net.fortuna.ical4j.model.property.Due
|
||||
import net.fortuna.ical4j.model.property.Priority
|
||||
import net.fortuna.ical4j.model.property.RRule
|
||||
import net.fortuna.ical4j.model.property.Status
|
||||
import org.tasks.caldav.iCalendar
|
||||
import org.tasks.caldav.iCalendar.Companion.collapsed
|
||||
import org.tasks.caldav.iCalendar.Companion.order
|
||||
import org.tasks.caldav.iCalendar.Companion.parent
|
||||
import org.tasks.time.DateTime
|
||||
import org.tasks.time.DateTimeUtils.toDate
|
||||
|
||||
@Suppress("ClassName")
|
||||
object iCalMaker {
|
||||
val TITLE: Property<Task, String?> = newProperty()
|
||||
val DESCRIPTION: Property<Task, String?> = newProperty()
|
||||
val DUE_DATE: Property<Task, DateTime?> = newProperty()
|
||||
val DUE_TIME: Property<Task, DateTime?> = newProperty()
|
||||
val START_DATE: Property<Task, DateTime?> = newProperty()
|
||||
val START_TIME: Property<Task, DateTime?> = newProperty()
|
||||
val CREATED_AT: Property<Task, DateTime?> = newProperty()
|
||||
val COMPLETED_AT: Property<Task, DateTime?> = newProperty()
|
||||
val ORDER: Property<Task, Long?> = newProperty()
|
||||
val PARENT: Property<Task, String?> = newProperty()
|
||||
val PRIORITY: Property<Task, Int> = newProperty()
|
||||
val COLLAPSED: Property<Task, Boolean> = newProperty()
|
||||
val RRULE: Property<Task, String?> = newProperty()
|
||||
val STATUS: Property<Task, Status?> = newProperty()
|
||||
|
||||
private val instantiator = Instantiator { lookup: PropertyLookup<Task> ->
|
||||
val task = Task()
|
||||
lookup.valueOf(CREATED_AT, null as DateTime?)?.let {
|
||||
task.createdAt = it.millis
|
||||
}
|
||||
lookup.valueOf(DUE_DATE, null as DateTime?)?.let {
|
||||
task.due = Due(it.millis.toDate())
|
||||
}
|
||||
lookup.valueOf(DUE_TIME, null as DateTime?)?.let {
|
||||
task.due = Due(iCalendar.getDateTime(it.millis))
|
||||
}
|
||||
lookup.valueOf(START_DATE, null as DateTime?)?.let {
|
||||
task.dtStart = DtStart(it.millis.toDate())
|
||||
}
|
||||
lookup.valueOf(START_TIME, null as DateTime?)?.let {
|
||||
task.dtStart = DtStart(iCalendar.getDateTime(it.millis))
|
||||
}
|
||||
lookup.valueOf(COMPLETED_AT, null as DateTime?)?.let {
|
||||
task.completedAt = Completed(iCalendar.getDateTime(it.millis))
|
||||
task.status = Status.VTODO_COMPLETED
|
||||
}
|
||||
task.order = lookup.valueOf(ORDER, null as Long?)
|
||||
task.summary = lookup.valueOf(TITLE, null as String?)
|
||||
task.parent = lookup.valueOf(PARENT, null as String?)
|
||||
task.description = lookup.valueOf(DESCRIPTION, null as String?)
|
||||
task.priority = lookup.valueOf(PRIORITY, Priority.UNDEFINED.level)
|
||||
task.collapsed = lookup.valueOf(COLLAPSED, false)
|
||||
task.rRule = lookup.valueOf(RRULE, null as String?)?.let { RRule(it) }
|
||||
task.status = lookup.valueOf(STATUS, null as Status?)
|
||||
task
|
||||
}
|
||||
fun newIcal(vararg properties: PropertyValue<in Task?, *>): Task {
|
||||
return Maker.make(instantiator, *properties)
|
||||
}
|
||||
}
|
@ -0,0 +1,132 @@
|
||||
package org.tasks.caldav
|
||||
|
||||
import at.bitfire.ical4android.Task
|
||||
import com.todoroo.andlib.utility.DateUtilities
|
||||
import com.todoroo.astrid.data.Task.Companion.withoutFrom
|
||||
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 com.todoroo.astrid.data.Task.Priority.Companion.NONE
|
||||
import net.fortuna.ical4j.model.property.Status
|
||||
import org.tasks.caldav.iCalendar.Companion.collapsed
|
||||
import org.tasks.caldav.iCalendar.Companion.getLocal
|
||||
import org.tasks.caldav.iCalendar.Companion.order
|
||||
import org.tasks.caldav.iCalendar.Companion.parent
|
||||
import org.tasks.caldav.iCalendar.Companion.toMillis
|
||||
import org.tasks.data.CaldavTask
|
||||
import org.tasks.date.DateTimeUtils.newDateTime
|
||||
import org.tasks.time.DateTime.UTC
|
||||
import org.tasks.time.DateTimeUtils.startOfMinute
|
||||
import org.tasks.time.DateTimeUtils.startOfSecond
|
||||
|
||||
fun com.todoroo.astrid.data.Task.applyRemote(
|
||||
remote: Task,
|
||||
local: Task?
|
||||
): com.todoroo.astrid.data.Task {
|
||||
applyCompletedAt(remote, local)
|
||||
applyCreatedAt(remote, local)
|
||||
applyTitle(remote, local)
|
||||
applyDescription(remote, local)
|
||||
applyPriority(remote, local)
|
||||
applyRecurrence(remote, local)
|
||||
applyDue(remote, local)
|
||||
applyStart(remote, local)
|
||||
applyCollapsed(remote, local)
|
||||
return this
|
||||
}
|
||||
|
||||
fun CaldavTask.applyRemote(remote: Task, local: Task?): CaldavTask {
|
||||
applyParent(remote, local)
|
||||
applyOrder(remote, local)
|
||||
return this
|
||||
}
|
||||
|
||||
private fun com.todoroo.astrid.data.Task.applyCompletedAt(remote: Task, local: Task?) {
|
||||
if (local == null ||
|
||||
(local.completedAt?.let { getLocal(it) } ?: 0) == completionDate.startOfSecond() &&
|
||||
(local.status == Status.VTODO_COMPLETED) == isCompleted
|
||||
) {
|
||||
val completedAt = remote.completedAt
|
||||
if (completedAt != null) {
|
||||
completionDate = getLocal(completedAt)
|
||||
} else if (remote.status === Status.VTODO_COMPLETED) {
|
||||
if (!isCompleted) {
|
||||
completionDate = DateUtilities.now()
|
||||
}
|
||||
} else {
|
||||
completionDate = 0L
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun com.todoroo.astrid.data.Task.applyCreatedAt(remote: Task, local: Task?) {
|
||||
val localCreated = local?.createdAt?.let { newDateTime(it, UTC) }?.toLocal()?.millis
|
||||
if (localCreated == null || localCreated == creationDate) {
|
||||
remote.createdAt?.let {
|
||||
creationDate = newDateTime(it, UTC).toLocal().millis
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun com.todoroo.astrid.data.Task.applyTitle(remote: Task, local: Task?) {
|
||||
if (local == null || local.summary == title) {
|
||||
title = remote.summary
|
||||
}
|
||||
}
|
||||
|
||||
private fun com.todoroo.astrid.data.Task.applyDescription(remote: Task, local: Task?) {
|
||||
if (local == null || local.description == notes) {
|
||||
notes = remote.description
|
||||
}
|
||||
}
|
||||
|
||||
private fun com.todoroo.astrid.data.Task.applyPriority(remote: Task, local: Task?) {
|
||||
if (local == null || local.tasksPriority == priority) {
|
||||
priority = remote.tasksPriority
|
||||
}
|
||||
}
|
||||
|
||||
private fun com.todoroo.astrid.data.Task.applyRecurrence(remote: Task, local: Task?) {
|
||||
if (local == null || local.rRule?.recur?.toString() == recurrence.withoutFrom()) {
|
||||
setRecurrence(remote.rRule?.recur)
|
||||
}
|
||||
}
|
||||
|
||||
private fun com.todoroo.astrid.data.Task.applyDue(remote: Task, local: Task?) {
|
||||
if (local == null || local.due.toMillis() == dueDate) {
|
||||
dueDate = remote.due.toMillis()
|
||||
}
|
||||
}
|
||||
|
||||
private fun com.todoroo.astrid.data.Task.applyStart(remote: Task, local: Task?) {
|
||||
if (local == null || local.dtStart.toMillis(this) == hideUntil) {
|
||||
hideUntil = remote.dtStart.toMillis(this)
|
||||
}
|
||||
}
|
||||
|
||||
private fun com.todoroo.astrid.data.Task.applyCollapsed(remote: Task, local: Task?) {
|
||||
if (local == null || isCollapsed == local.collapsed) {
|
||||
isCollapsed = remote.collapsed
|
||||
}
|
||||
}
|
||||
|
||||
private fun CaldavTask.applyOrder(remote: Task, local: Task?) {
|
||||
if (local == null || local.order == order) {
|
||||
order = remote.order
|
||||
}
|
||||
}
|
||||
|
||||
private fun CaldavTask.applyParent(remote: Task, local: Task?) {
|
||||
if (local == null || local.parent == remoteParent) {
|
||||
remoteParent = remote.parent
|
||||
}
|
||||
}
|
||||
|
||||
private val Task.tasksPriority: Int
|
||||
get() = when (this.priority) {
|
||||
// https://tools.ietf.org/html/rfc5545#section-3.8.1.9
|
||||
in 1..4 -> HIGH
|
||||
5 -> MEDIUM
|
||||
in 6..9 -> LOW
|
||||
else -> NONE
|
||||
}
|
@ -0,0 +1,660 @@
|
||||
@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_ORDER
|
||||
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.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.ORDER
|
||||
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() =
|
||||
newCaldavTask()
|
||||
.applyRemote(
|
||||
remote = newIcal(with(ORDER, 1234)),
|
||||
local = null
|
||||
)
|
||||
.let {
|
||||
assertEquals(1234L, it.order)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun remoteRemovesOrder() =
|
||||
newCaldavTask(with(REMOTE_ORDER, 1234))
|
||||
.applyRemote(
|
||||
remote = newIcal(),
|
||||
local = newIcal(with(ORDER, 1234))
|
||||
)
|
||||
.let {
|
||||
assertNull(it.order)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun localRemovesOrder() =
|
||||
newCaldavTask()
|
||||
.applyRemote(
|
||||
remote = newIcal(with(ORDER, 1234)),
|
||||
local = newIcal(with(ORDER, 1234))
|
||||
)
|
||||
.let {
|
||||
assertNull(it.order)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun localBeatsRemoteOrder() =
|
||||
newCaldavTask(with(REMOTE_ORDER, 789))
|
||||
.applyRemote(
|
||||
remote = newIcal(with(ORDER, 456)),
|
||||
local = newIcal(with(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)
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue