diff --git a/lib/src/main/kotlin/at/bitfire/synctools/mapping/tasks/DmfsTaskProcessor.kt b/lib/src/main/kotlin/at/bitfire/synctools/mapping/tasks/DmfsTaskProcessor.kt index 424facc3..4d200bd1 100644 --- a/lib/src/main/kotlin/at/bitfire/synctools/mapping/tasks/DmfsTaskProcessor.kt +++ b/lib/src/main/kotlin/at/bitfire/synctools/mapping/tasks/DmfsTaskProcessor.kt @@ -10,7 +10,9 @@ import android.content.ContentValues import at.bitfire.ical4android.Task import at.bitfire.ical4android.UnknownProperty import at.bitfire.synctools.mapping.tasks.handler.AlarmsHandler +import at.bitfire.synctools.mapping.tasks.handler.ClassificationHandler import at.bitfire.synctools.mapping.tasks.handler.ColorHandler +import at.bitfire.synctools.mapping.tasks.handler.CompletedHandler import at.bitfire.synctools.mapping.tasks.handler.DescriptionHandler import at.bitfire.synctools.mapping.tasks.handler.DmfsTaskFieldHandler import at.bitfire.synctools.mapping.tasks.handler.DmfsTaskPropertyHandler @@ -19,8 +21,11 @@ import at.bitfire.synctools.mapping.tasks.handler.DurationHandler import at.bitfire.synctools.mapping.tasks.handler.GeoHandler import at.bitfire.synctools.mapping.tasks.handler.LocationHandler import at.bitfire.synctools.mapping.tasks.handler.OrganizerHandler +import at.bitfire.synctools.mapping.tasks.handler.PercentCompleteHandler +import at.bitfire.synctools.mapping.tasks.handler.PriorityHandler import at.bitfire.synctools.mapping.tasks.handler.SequenceHandler import at.bitfire.synctools.mapping.tasks.handler.StartTimeHandler +import at.bitfire.synctools.mapping.tasks.handler.StatusHandler import at.bitfire.synctools.mapping.tasks.handler.TitleHandler import at.bitfire.synctools.mapping.tasks.handler.UidHandler import at.bitfire.synctools.mapping.tasks.handler.UrlHandler @@ -28,20 +33,16 @@ import at.bitfire.synctools.storage.tasks.DmfsTask.Companion.UNKNOWN_PROPERTY_DA import at.bitfire.synctools.storage.tasks.DmfsTaskList import at.bitfire.synctools.util.AndroidTimeUtils import net.fortuna.ical4j.model.parameter.RelType -import net.fortuna.ical4j.model.property.Clazz -import net.fortuna.ical4j.model.property.Completed import net.fortuna.ical4j.model.property.ExDate import net.fortuna.ical4j.model.property.RDate import net.fortuna.ical4j.model.property.RRule import net.fortuna.ical4j.model.property.RelatedTo -import net.fortuna.ical4j.model.property.Status import org.dmfs.tasks.contract.TaskContract.Properties import org.dmfs.tasks.contract.TaskContract.Property.Alarm import org.dmfs.tasks.contract.TaskContract.Property.Category import org.dmfs.tasks.contract.TaskContract.Property.Comment import org.dmfs.tasks.contract.TaskContract.Property.Relation import org.dmfs.tasks.contract.TaskContract.Tasks -import java.time.Instant import java.time.temporal.Temporal import java.util.logging.Level import java.util.logging.Logger @@ -67,6 +68,11 @@ class DmfsTaskProcessor( ColorHandler(), UrlHandler(), OrganizerHandler(), + PriorityHandler(), + ClassificationHandler(), + StatusHandler(), + CompletedHandler(), + PercentCompleteHandler(), ) private val propertyHandlers: Map = mapOf( @@ -82,27 +88,8 @@ class DmfsTaskProcessor( to.userAgents += taskList.providerName.packageName - values.getAsInteger(Tasks.PRIORITY)?.let { to.priority = it } - // Note: big method – maybe split? Depends on how we want to proceed with refactoring. - to.classification = when (values.getAsInteger(Tasks.CLASSIFICATION)) { - Tasks.CLASSIFICATION_PUBLIC -> Clazz(Clazz.VALUE_PUBLIC) - Tasks.CLASSIFICATION_PRIVATE -> Clazz(Clazz.VALUE_PRIVATE) - Tasks.CLASSIFICATION_CONFIDENTIAL -> Clazz(Clazz.VALUE_CONFIDENTIAL) - else -> null - } - - values.getAsLong(Tasks.COMPLETED)?.let { to.completedAt = Completed(Instant.ofEpochMilli(it)) } - values.getAsInteger(Tasks.PERCENT_COMPLETE)?.let { to.percentComplete = it } - - to.status = when (values.getAsInteger(Tasks.STATUS)) { - Tasks.STATUS_IN_PROCESS -> Status(Status.VALUE_IN_PROCESS) - Tasks.STATUS_COMPLETED -> Status(Status.VALUE_COMPLETED) - Tasks.STATUS_CANCELLED -> Status(Status.VALUE_CANCELLED) - else -> Status(Status.VALUE_NEEDS_ACTION) - } - val allDay = (values.getAsInteger(Tasks.IS_ALLDAY) ?: 0) != 0 values.getAsLong(Tasks.CREATED)?.let { to.createdAt = it } diff --git a/lib/src/main/kotlin/at/bitfire/synctools/mapping/tasks/handler/ClassificationHandler.kt b/lib/src/main/kotlin/at/bitfire/synctools/mapping/tasks/handler/ClassificationHandler.kt new file mode 100644 index 00000000..a9c6c720 --- /dev/null +++ b/lib/src/main/kotlin/at/bitfire/synctools/mapping/tasks/handler/ClassificationHandler.kt @@ -0,0 +1,25 @@ +/* + * This file is part of bitfireAT/synctools which is released under GPLv3. + * Copyright © All Contributors. See the LICENSE and AUTHOR files in the root directory for details. + * SPDX-License-Identifier: GPL-3.0-or-later + */ + +package at.bitfire.synctools.mapping.tasks.handler + +import android.content.ContentValues +import at.bitfire.ical4android.Task +import net.fortuna.ical4j.model.property.Clazz +import org.dmfs.tasks.contract.TaskContract.Tasks + +class ClassificationHandler : DmfsTaskFieldHandler { + + override fun process(from: ContentValues, to: Task) { + to.classification = when (from.getAsInteger(Tasks.CLASSIFICATION)) { + Tasks.CLASSIFICATION_PUBLIC -> Clazz(Clazz.VALUE_PUBLIC) + Tasks.CLASSIFICATION_PRIVATE -> Clazz(Clazz.VALUE_PRIVATE) + Tasks.CLASSIFICATION_CONFIDENTIAL -> Clazz(Clazz.VALUE_CONFIDENTIAL) + else -> null + } + } + +} diff --git a/lib/src/main/kotlin/at/bitfire/synctools/mapping/tasks/handler/CompletedHandler.kt b/lib/src/main/kotlin/at/bitfire/synctools/mapping/tasks/handler/CompletedHandler.kt new file mode 100644 index 00000000..e7e0e1a4 --- /dev/null +++ b/lib/src/main/kotlin/at/bitfire/synctools/mapping/tasks/handler/CompletedHandler.kt @@ -0,0 +1,23 @@ +/* + * This file is part of bitfireAT/synctools which is released under GPLv3. + * Copyright © All Contributors. See the LICENSE and AUTHOR files in the root directory for details. + * SPDX-License-Identifier: GPL-3.0-or-later + */ + +package at.bitfire.synctools.mapping.tasks.handler + +import android.content.ContentValues +import at.bitfire.ical4android.Task +import net.fortuna.ical4j.model.property.Completed +import org.dmfs.tasks.contract.TaskContract.Tasks +import java.time.Instant + +class CompletedHandler : DmfsTaskFieldHandler { + + override fun process(from: ContentValues, to: Task) { + from.getAsLong(Tasks.COMPLETED)?.let { epochMillis -> + to.completedAt = Completed(Instant.ofEpochMilli(epochMillis)) + } + } + +} diff --git a/lib/src/main/kotlin/at/bitfire/synctools/mapping/tasks/handler/PercentCompleteHandler.kt b/lib/src/main/kotlin/at/bitfire/synctools/mapping/tasks/handler/PercentCompleteHandler.kt new file mode 100644 index 00000000..d6b09887 --- /dev/null +++ b/lib/src/main/kotlin/at/bitfire/synctools/mapping/tasks/handler/PercentCompleteHandler.kt @@ -0,0 +1,21 @@ +/* + * This file is part of bitfireAT/synctools which is released under GPLv3. + * Copyright © All Contributors. See the LICENSE and AUTHOR files in the root directory for details. + * SPDX-License-Identifier: GPL-3.0-or-later + */ + +package at.bitfire.synctools.mapping.tasks.handler + +import android.content.ContentValues +import at.bitfire.ical4android.Task +import org.dmfs.tasks.contract.TaskContract.Tasks + +class PercentCompleteHandler : DmfsTaskFieldHandler { + + override fun process(from: ContentValues, to: Task) { + from.getAsInteger(Tasks.PERCENT_COMPLETE)?.let { percent -> + to.percentComplete = percent + } + } + +} diff --git a/lib/src/main/kotlin/at/bitfire/synctools/mapping/tasks/handler/PriorityHandler.kt b/lib/src/main/kotlin/at/bitfire/synctools/mapping/tasks/handler/PriorityHandler.kt new file mode 100644 index 00000000..68905cc2 --- /dev/null +++ b/lib/src/main/kotlin/at/bitfire/synctools/mapping/tasks/handler/PriorityHandler.kt @@ -0,0 +1,19 @@ +/* + * This file is part of bitfireAT/synctools which is released under GPLv3. + * Copyright © All Contributors. See the LICENSE and AUTHOR files in the root directory for details. + * SPDX-License-Identifier: GPL-3.0-or-later + */ + +package at.bitfire.synctools.mapping.tasks.handler + +import android.content.ContentValues +import at.bitfire.ical4android.Task +import org.dmfs.tasks.contract.TaskContract.Tasks + +class PriorityHandler : DmfsTaskFieldHandler { + + override fun process(from: ContentValues, to: Task) { + from.getAsInteger(Tasks.PRIORITY)?.let { to.priority = it } + } + +} diff --git a/lib/src/main/kotlin/at/bitfire/synctools/mapping/tasks/handler/StatusHandler.kt b/lib/src/main/kotlin/at/bitfire/synctools/mapping/tasks/handler/StatusHandler.kt new file mode 100644 index 00000000..6df65f5e --- /dev/null +++ b/lib/src/main/kotlin/at/bitfire/synctools/mapping/tasks/handler/StatusHandler.kt @@ -0,0 +1,25 @@ +/* + * This file is part of bitfireAT/synctools which is released under GPLv3. + * Copyright © All Contributors. See the LICENSE and AUTHOR files in the root directory for details. + * SPDX-License-Identifier: GPL-3.0-or-later + */ + +package at.bitfire.synctools.mapping.tasks.handler + +import android.content.ContentValues +import at.bitfire.ical4android.Task +import net.fortuna.ical4j.model.property.Status +import org.dmfs.tasks.contract.TaskContract.Tasks + +class StatusHandler : DmfsTaskFieldHandler { + + override fun process(from: ContentValues, to: Task) { + to.status = when (from.getAsInteger(Tasks.STATUS)) { + Tasks.STATUS_IN_PROCESS -> Status(Status.VALUE_IN_PROCESS) + Tasks.STATUS_COMPLETED -> Status(Status.VALUE_COMPLETED) + Tasks.STATUS_CANCELLED -> Status(Status.VALUE_CANCELLED) + else -> Status(Status.VALUE_NEEDS_ACTION) + } + } + +} diff --git a/lib/src/test/kotlin/at/bitfire/synctools/mapping/tasks/handler/ClassificationHandlerTest.kt b/lib/src/test/kotlin/at/bitfire/synctools/mapping/tasks/handler/ClassificationHandlerTest.kt new file mode 100644 index 00000000..83fc4f0a --- /dev/null +++ b/lib/src/test/kotlin/at/bitfire/synctools/mapping/tasks/handler/ClassificationHandlerTest.kt @@ -0,0 +1,60 @@ +/* + * This file is part of bitfireAT/synctools which is released under GPLv3. + * Copyright © All Contributors. See the LICENSE and AUTHOR files in the root directory for details. + * SPDX-License-Identifier: GPL-3.0-or-later + */ + +package at.bitfire.synctools.mapping.tasks.handler + +import android.content.ContentValues +import androidx.core.content.contentValuesOf +import at.bitfire.ical4android.Task +import net.fortuna.ical4j.model.property.Clazz +import org.dmfs.tasks.contract.TaskContract.Tasks +import org.junit.Assert.assertEquals +import org.junit.Assert.assertNull +import org.junit.Test +import org.junit.runner.RunWith +import org.robolectric.RobolectricTestRunner + +@RunWith(RobolectricTestRunner::class) +class ClassificationHandlerTest { + + private val handler = ClassificationHandler() + + @Test + fun `No CLASSIFICATION`() { + val task = Task() + handler.process(ContentValues(), task) + assertNull(task.classification) + } + + @Test + fun `CLASSIFICATION_PUBLIC maps to CLASS PUBLIC`() { + val task = Task() + handler.process(contentValuesOf(Tasks.CLASSIFICATION to Tasks.CLASSIFICATION_PUBLIC), task) + assertEquals(Clazz(Clazz.VALUE_PUBLIC), task.classification) + } + + @Test + fun `CLASSIFICATION_PRIVATE maps to CLASS PRIVATE`() { + val task = Task() + handler.process(contentValuesOf(Tasks.CLASSIFICATION to Tasks.CLASSIFICATION_PRIVATE), task) + assertEquals(Clazz(Clazz.VALUE_PRIVATE), task.classification) + } + + @Test + fun `CLASSIFICATION_CONFIDENTIAL maps to CLASS CONFIDENTIAL`() { + val task = Task() + handler.process(contentValuesOf(Tasks.CLASSIFICATION to Tasks.CLASSIFICATION_CONFIDENTIAL), task) + assertEquals(Clazz(Clazz.VALUE_CONFIDENTIAL), task.classification) + } + + @Test + fun `Unknown CLASSIFICATION maps to null`() { + val task = Task() + handler.process(contentValuesOf(Tasks.CLASSIFICATION to 99), task) + assertNull(task.classification) + } + +} diff --git a/lib/src/test/kotlin/at/bitfire/synctools/mapping/tasks/handler/CompletedHandlerTest.kt b/lib/src/test/kotlin/at/bitfire/synctools/mapping/tasks/handler/CompletedHandlerTest.kt new file mode 100644 index 00000000..a9dcdfb6 --- /dev/null +++ b/lib/src/test/kotlin/at/bitfire/synctools/mapping/tasks/handler/CompletedHandlerTest.kt @@ -0,0 +1,41 @@ +/* + * This file is part of bitfireAT/synctools which is released under GPLv3. + * Copyright © All Contributors. See the LICENSE and AUTHOR files in the root directory for details. + * SPDX-License-Identifier: GPL-3.0-or-later + */ + +package at.bitfire.synctools.mapping.tasks.handler + +import android.content.ContentValues +import androidx.core.content.contentValuesOf +import at.bitfire.ical4android.Task +import net.fortuna.ical4j.model.property.Completed +import org.dmfs.tasks.contract.TaskContract.Tasks +import org.junit.Assert.assertEquals +import org.junit.Assert.assertNull +import org.junit.Test +import org.junit.runner.RunWith +import org.robolectric.RobolectricTestRunner +import java.time.Instant + +@RunWith(RobolectricTestRunner::class) +class CompletedHandlerTest { + + private val handler = CompletedHandler() + + @Test + fun `No COMPLETED leaves completedAt null`() { + val task = Task() + handler.process(ContentValues(), task) + assertNull(task.completedAt) + } + + @Test + fun `COMPLETED epoch millis is mapped correctly`() { + val task = Task() + val epochMillis = 1_700_000_000_000L + handler.process(contentValuesOf(Tasks.COMPLETED to epochMillis), task) + assertEquals(Completed(Instant.ofEpochMilli(epochMillis)), task.completedAt) + } + +} diff --git a/lib/src/test/kotlin/at/bitfire/synctools/mapping/tasks/handler/PercentCompleteHandlerTest.kt b/lib/src/test/kotlin/at/bitfire/synctools/mapping/tasks/handler/PercentCompleteHandlerTest.kt new file mode 100644 index 00000000..ff7600dd --- /dev/null +++ b/lib/src/test/kotlin/at/bitfire/synctools/mapping/tasks/handler/PercentCompleteHandlerTest.kt @@ -0,0 +1,45 @@ +/* + * This file is part of bitfireAT/synctools which is released under GPLv3. + * Copyright © All Contributors. See the LICENSE and AUTHOR files in the root directory for details. + * SPDX-License-Identifier: GPL-3.0-or-later + */ + +package at.bitfire.synctools.mapping.tasks.handler + +import android.content.ContentValues +import androidx.core.content.contentValuesOf +import at.bitfire.ical4android.Task +import org.dmfs.tasks.contract.TaskContract.Tasks +import org.junit.Assert.assertEquals +import org.junit.Assert.assertNull +import org.junit.Test +import org.junit.runner.RunWith +import org.robolectric.RobolectricTestRunner + +@RunWith(RobolectricTestRunner::class) +class PercentCompleteHandlerTest { + + private val handler = PercentCompleteHandler() + + @Test + fun `No PERCENT_COMPLETE leaves percentComplete null`() { + val task = Task() + handler.process(ContentValues(), task) + assertNull(task.percentComplete) + } + + @Test + fun `PERCENT_COMPLETE 0 is mapped correctly`() { + val task = Task() + handler.process(contentValuesOf(Tasks.PERCENT_COMPLETE to 0), task) + assertEquals(0, task.percentComplete) + } + + @Test + fun `PERCENT_COMPLETE 100 is mapped correctly`() { + val task = Task() + handler.process(contentValuesOf(Tasks.PERCENT_COMPLETE to 100), task) + assertEquals(100, task.percentComplete) + } + +} diff --git a/lib/src/test/kotlin/at/bitfire/synctools/mapping/tasks/handler/PriorityHandlerTest.kt b/lib/src/test/kotlin/at/bitfire/synctools/mapping/tasks/handler/PriorityHandlerTest.kt new file mode 100644 index 00000000..d317cfa1 --- /dev/null +++ b/lib/src/test/kotlin/at/bitfire/synctools/mapping/tasks/handler/PriorityHandlerTest.kt @@ -0,0 +1,58 @@ +/* + * This file is part of bitfireAT/synctools which is released under GPLv3. + * Copyright © All Contributors. See the LICENSE and AUTHOR files in the root directory for details. + * SPDX-License-Identifier: GPL-3.0-or-later + */ + +package at.bitfire.synctools.mapping.tasks.handler + +import android.content.ContentValues +import androidx.core.content.contentValuesOf +import at.bitfire.ical4android.Task +import org.dmfs.tasks.contract.TaskContract.Tasks +import org.junit.Assert.assertEquals +import org.junit.Test +import org.junit.runner.RunWith +import org.robolectric.RobolectricTestRunner + +@RunWith(RobolectricTestRunner::class) +class PriorityHandlerTest { + + private val handler = PriorityHandler() + + @Test + fun `No PRIORITY leaves priority at default (0)`() { + val task = Task() + handler.process(ContentValues(), task) + assertEquals(0, task.priority) + } + + @Test + fun `PRIORITY is 0 (undefined)`() { + val task = Task() + handler.process(contentValuesOf(Tasks.PRIORITY to 0), task) + assertEquals(0, task.priority) + } + + @Test + fun `PRIORITY is 1 (high)`() { + val task = Task() + handler.process(contentValuesOf(Tasks.PRIORITY to 1), task) + assertEquals(1, task.priority) + } + + @Test + fun `PRIORITY is 5 (medium)`() { + val task = Task() + handler.process(contentValuesOf(Tasks.PRIORITY to 5), task) + assertEquals(5, task.priority) + } + + @Test + fun `PRIORITY is 9 (low)`() { + val task = Task() + handler.process(contentValuesOf(Tasks.PRIORITY to 9), task) + assertEquals(9, task.priority) + } + +} diff --git a/lib/src/test/kotlin/at/bitfire/synctools/mapping/tasks/handler/StatusHandlerTest.kt b/lib/src/test/kotlin/at/bitfire/synctools/mapping/tasks/handler/StatusHandlerTest.kt new file mode 100644 index 00000000..b52eae17 --- /dev/null +++ b/lib/src/test/kotlin/at/bitfire/synctools/mapping/tasks/handler/StatusHandlerTest.kt @@ -0,0 +1,66 @@ +/* + * This file is part of bitfireAT/synctools which is released under GPLv3. + * Copyright © All Contributors. See the LICENSE and AUTHOR files in the root directory for details. + * SPDX-License-Identifier: GPL-3.0-or-later + */ + +package at.bitfire.synctools.mapping.tasks.handler + +import android.content.ContentValues +import androidx.core.content.contentValuesOf +import at.bitfire.ical4android.Task +import net.fortuna.ical4j.model.property.Status +import org.dmfs.tasks.contract.TaskContract.Tasks +import org.junit.Assert.assertEquals +import org.junit.Test +import org.junit.runner.RunWith +import org.robolectric.RobolectricTestRunner + +@RunWith(RobolectricTestRunner::class) +class StatusHandlerTest { + + private val handler = StatusHandler() + + @Test + fun `No STATUS defaults to NEEDS-ACTION`() { + val task = Task() + handler.process(ContentValues(), task) + assertEquals(Status(Status.VALUE_NEEDS_ACTION), task.status) + } + + @Test + fun `STATUS_NEEDS_ACTION maps to NEEDS-ACTION`() { + val task = Task() + handler.process(contentValuesOf(Tasks.STATUS to Tasks.STATUS_NEEDS_ACTION), task) + assertEquals(Status(Status.VALUE_NEEDS_ACTION), task.status) + } + + @Test + fun `STATUS_IN_PROCESS maps to IN-PROCESS`() { + val task = Task() + handler.process(contentValuesOf(Tasks.STATUS to Tasks.STATUS_IN_PROCESS), task) + assertEquals(Status(Status.VALUE_IN_PROCESS), task.status) + } + + @Test + fun `STATUS_COMPLETED maps to COMPLETED`() { + val task = Task() + handler.process(contentValuesOf(Tasks.STATUS to Tasks.STATUS_COMPLETED), task) + assertEquals(Status(Status.VALUE_COMPLETED), task.status) + } + + @Test + fun `STATUS_CANCELLED maps to CANCELLED`() { + val task = Task() + handler.process(contentValuesOf(Tasks.STATUS to Tasks.STATUS_CANCELLED), task) + assertEquals(Status(Status.VALUE_CANCELLED), task.status) + } + + @Test + fun `Unknown STATUS defaults to NEEDS-ACTION`() { + val task = Task() + handler.process(contentValuesOf(Tasks.STATUS to 99), task) + assertEquals(Status(Status.VALUE_NEEDS_ACTION), task.status) + } + +}