test: characterize getTasksForResidence filter contract
Locks down the contract that becomes the primary path for residence detail in Phase 3: - filters _allTasks by residenceId - returns empty shell for residence with no tasks (vs null for cache miss) - returns null when _allTasks itself is null (caller must hit API)
This commit is contained in:
@@ -88,6 +88,53 @@ class DataManagerTaskCacheTest {
|
||||
assertEquals("v2", inProgress.tasks.first { it.id == 5 }.title)
|
||||
}
|
||||
|
||||
/// Characterization: getTasksForResidence filters _allTasks by
|
||||
/// residence id. This is the helper that becomes the primary path
|
||||
/// for residence-detail in Phase 3 (collapse the dual cache).
|
||||
@Test
|
||||
fun getTasksForResidence_filtersAllTasksByResidenceId() {
|
||||
// Seed _allTasks with tasks across two residences via the upsert path.
|
||||
DataManager.updateTask(sampleTask(id = 1, residenceId = 100, column = "upcoming_tasks"))
|
||||
DataManager.updateTask(sampleTask(id = 2, residenceId = 100, column = "overdue_tasks"))
|
||||
DataManager.updateTask(sampleTask(id = 3, residenceId = 200, column = "upcoming_tasks"))
|
||||
|
||||
val r100 = DataManager.getTasksForResidence(100)
|
||||
assertNotNull(r100)
|
||||
val r100Ids = r100.columns.flatMap { it.tasks }.map { it.id }.toSet()
|
||||
assertEquals(setOf(1, 2), r100Ids)
|
||||
|
||||
val r200 = DataManager.getTasksForResidence(200)
|
||||
assertNotNull(r200)
|
||||
val r200Ids = r200.columns.flatMap { it.tasks }.map { it.id }.toSet()
|
||||
assertEquals(setOf(3), r200Ids)
|
||||
|
||||
// Counts on each column must match the filtered task lists.
|
||||
for (column in r100.columns) {
|
||||
assertEquals(column.tasks.size, column.count, "column ${column.name} count mismatch")
|
||||
}
|
||||
}
|
||||
|
||||
/// Characterization: residenceId with no tasks returns a non-null
|
||||
/// shell so the residence-detail screen can distinguish "loading"
|
||||
/// (null) from "loaded, no tasks" (non-null with empty columns).
|
||||
@Test
|
||||
fun getTasksForResidence_returnsEmptyShellForResidenceWithNoTasks() {
|
||||
DataManager.updateTask(sampleTask(id = 1, residenceId = 100, column = "upcoming_tasks"))
|
||||
|
||||
val r999 = DataManager.getTasksForResidence(999)
|
||||
assertNotNull(r999, "residence with no tasks must return an empty shell, not null")
|
||||
assertEquals(0, r999.columns.sumOf { it.tasks.size })
|
||||
}
|
||||
|
||||
/// Characterization: when _allTasks is null entirely (cache never
|
||||
/// populated), getTasksForResidence returns null — caller must call
|
||||
/// the API path. Phase 3's getTasksByResidence relies on this.
|
||||
@Test
|
||||
fun getTasksForResidence_returnsNullWhenAllTasksIsNull() {
|
||||
DataManager.clear()
|
||||
assertEquals(null, DataManager.getTasksForResidence(100))
|
||||
}
|
||||
|
||||
/// Lockdown: updateTask must NOT touch `_tasksByResidence`. That cache
|
||||
/// is being deleted in Phase 3; until then, updateTask must leave it
|
||||
/// alone. If a future commit re-introduces the conditional write
|
||||
|
||||
Reference in New Issue
Block a user