Prevent setting parent to self

pull/1061/head
Alex Baker 4 years ago
parent 97cb202f22
commit 1178b8f3e6

@ -37,13 +37,12 @@ class RecursiveLoopTest : InjectingTestCase() {
@Test @Test
@Ignore("infinite loop") @Ignore("infinite loop")
fun handleSelfLoop() = runBlocking { fun handleSelfLoop() = runBlocking {
val id = addTask(with(DUE_DATE, newDateTime())) addTask(with(DUE_DATE, newDateTime()), with(PARENT, 1L))
taskDao.setParent(id, listOf(id))
val tasks = getTasks() val tasks = getTasks()
assertEquals(1, tasks.size) assertEquals(1, tasks.size)
assertEquals(id, tasks[0].id) assertEquals(1L, tasks[0].id)
} }
@Test @Test

@ -12,11 +12,11 @@ import com.todoroo.astrid.service.TaskDeleter
import dagger.hilt.android.testing.HiltAndroidTest import dagger.hilt.android.testing.HiltAndroidTest
import dagger.hilt.android.testing.UninstallModules import dagger.hilt.android.testing.UninstallModules
import kotlinx.coroutines.runBlocking import kotlinx.coroutines.runBlocking
import org.junit.Assert.* import org.junit.Assert.assertEquals
import org.junit.Assert.assertNull
import org.junit.Test import org.junit.Test
import org.tasks.injection.InjectingTestCase import org.tasks.injection.InjectingTestCase
import org.tasks.injection.ProductionModule import org.tasks.injection.ProductionModule
import org.tasks.makers.TaskMaker.ID
import org.tasks.makers.TaskMaker.PARENT import org.tasks.makers.TaskMaker.PARENT
import org.tasks.makers.TaskMaker.newTask import org.tasks.makers.TaskMaker.newTask
import javax.inject.Inject import javax.inject.Inject
@ -99,24 +99,37 @@ class TaskDaoTests : InjectingTestCase() {
@Test @Test
fun findChildrenInList() = runBlocking { fun findChildrenInList() = runBlocking {
taskDao.createNew(newTask(with(ID, 1L))) val parent = taskDao.createNew(newTask())
taskDao.createNew(newTask(with(ID, 2L), with(PARENT, 1L))) val child = taskDao.createNew(newTask(with(PARENT, parent)))
assertEquals(listOf(2L), taskDao.getChildren(listOf(1L, 2L))) assertEquals(listOf(child), taskDao.getChildren(listOf(parent, child)))
} }
@Test @Test
fun findRecursiveChildrenInList() = runBlocking { fun findRecursiveChildrenInList() = runBlocking {
taskDao.createNew(newTask(with(ID, 1L))) val parent = taskDao.createNew(newTask())
taskDao.createNew(newTask(with(ID, 2L), with(PARENT, 1L))) val child = taskDao.createNew(newTask(with(PARENT, parent)))
taskDao.createNew(newTask(with(ID, 3L), with(PARENT, 2L))) val grandchild = taskDao.createNew(newTask(with(PARENT, child)))
assertEquals(listOf(2L, 3L, 3L), taskDao.getChildren(listOf(1L, 2L, 3L))) assertEquals(
listOf(child, grandchild, grandchild),
taskDao.getChildren(listOf(parent, child, grandchild)))
} }
@Test @Test
fun findRecursiveChildrenInListAfterSkippingParent() = runBlocking { fun findRecursiveChildrenInListAfterSkippingParent() = runBlocking {
taskDao.createNew(newTask(with(ID, 1L))) val parent = taskDao.createNew(newTask())
taskDao.createNew(newTask(with(ID, 2L), with(PARENT, 1L))) val child = taskDao.createNew(newTask(with(PARENT, parent)))
taskDao.createNew(newTask(with(ID, 3L), with(PARENT, 2L))) val grandchild = taskDao.createNew(newTask(with(PARENT, child)))
assertEquals(listOf(2L, 3L), taskDao.getChildren(listOf(1L, 3L))) assertEquals(listOf(child, grandchild), taskDao.getChildren(listOf(parent, grandchild)))
}
@Test
fun dontSetParentToSelf() = runBlocking {
val parent = taskDao.createNew(newTask())
val child = taskDao.createNew(newTask())
taskDao.setParent(parent, listOf(parent, child))
assertEquals(0, taskDao.fetch(parent)!!.parent)
assertEquals(parent, taskDao.fetch(child)!!.parent)
} }
} }

@ -36,27 +36,29 @@ class BackupServiceTests : InjectingTestCase() {
private lateinit var temporaryDirectory: File private lateinit var temporaryDirectory: File
@Before @Before
override fun setUp() = runBlocking { override fun setUp() {
super.setUp() runBlocking {
temporaryDirectory = try { super.setUp()
File.createTempFile("backup", System.nanoTime().toString()) temporaryDirectory = try {
} catch (e: IOException) { File.createTempFile("backup", System.nanoTime().toString())
throw RuntimeException(e) } catch (e: IOException) {
} throw RuntimeException(e)
if (!temporaryDirectory.delete()) { }
throw RuntimeException( if (!temporaryDirectory.delete()) {
"Could not delete temp file: " + temporaryDirectory.absolutePath) throw RuntimeException(
} "Could not delete temp file: " + temporaryDirectory.absolutePath)
if (!temporaryDirectory.mkdir()) { }
throw RuntimeException( if (!temporaryDirectory.mkdir()) {
"Could not create temp directory: " + temporaryDirectory.absolutePath) throw RuntimeException(
} "Could not create temp directory: " + temporaryDirectory.absolutePath)
preferences.setUri(R.string.p_backup_dir, Uri.fromFile(temporaryDirectory)) }
preferences.setUri(R.string.p_backup_dir, Uri.fromFile(temporaryDirectory))
// make a temporary task // make a temporary task
val task = Task() val task = Task()
task.title = "helicopter" task.title = "helicopter"
taskDao.createNew(task) taskDao.createNew(task)
}
} }
@After @After

@ -144,7 +144,7 @@ SELECT EXISTS(SELECT 1 FROM tasks WHERE parent > 0 AND deleted = 0) AS hasSubtas
suspend fun setParent(parent: Long, tasks: List<Long>) = suspend fun setParent(parent: Long, tasks: List<Long>) =
tasks.eachChunk { setParentInternal(parent, it) } tasks.eachChunk { setParentInternal(parent, it) }
@Query("UPDATE tasks SET parent = :parent WHERE _id IN (:children)") @Query("UPDATE tasks SET parent = :parent WHERE _id IN (:children) AND _id != :parent")
internal abstract suspend fun setParentInternal(parent: Long, children: List<Long>) internal abstract suspend fun setParentInternal(parent: Long, children: List<Long>)
@Query("UPDATE tasks SET lastNotified = :timestamp WHERE _id = :id AND lastNotified != :timestamp") @Query("UPDATE tasks SET lastNotified = :timestamp WHERE _id = :id AND lastNotified != :timestamp")
@ -203,7 +203,7 @@ SELECT EXISTS(SELECT 1 FROM tasks WHERE parent > 0 AND deleted = 0) AS hasSubtas
@Update @Update
internal abstract suspend fun updateInternal(task: Task): Int internal abstract suspend fun updateInternal(task: Task): Int
suspend fun createNew(task: Task) { suspend fun createNew(task: Task): Long {
task.id = NO_ID task.id = NO_ID
if (task.creationDate == 0L) { if (task.creationDate == 0L) {
task.creationDate = DateUtilities.now() task.creationDate = DateUtilities.now()
@ -216,6 +216,7 @@ SELECT EXISTS(SELECT 1 FROM tasks WHERE parent > 0 AND deleted = 0) AS hasSubtas
} }
val insert = insert(task) val insert = insert(task)
task.id = insert task.id = insert
return task.id
} }
suspend fun count(filter: Filter): Int { suspend fun count(filter: Filter): Int {

Loading…
Cancel
Save