🧪 Add unit tests for ChatViewModel attachment manipulation (#511)
* Add unit tests for ChatViewModel attachment manipulation Adds tests covering addAttachment, removeAttachment (valid/invalid indices), and clearAttachments in ChatViewModelTest. This ensures the attachment state management logic works as expected. * test(#511): add mixed valid/invalid remove sequence + DRY attachment setup Folds in both Sourcery review notes: - New testRemoveAttachment_mixedValidAndInvalidSequence asserts list stays consistent across a valid remove, out-of-bounds + negative no-ops, then another valid remove on the shifted list. - addDummyAttachments() helper removes repeated VM/advance/add boilerplate. Verified: ktlintCheck clean + ChatViewModelTest 37/37 pass locally.
This commit is contained in:
1 file changed
+121
@@ -666,6 +666,127 @@ class ChatViewModelTest {
|
||||
}
|
||||
}
|
||||
|
||||
// ── Attachments ──────────────────────────────────────────────────────────
|
||||
|
||||
/** Add [count] dummy attachments so a test starts with a populated list. */
|
||||
private fun TestScope.addDummyAttachments(
|
||||
viewModel: ChatViewModel,
|
||||
count: Int,
|
||||
) {
|
||||
repeat(count) { i ->
|
||||
viewModel.addAttachment("uri$i", "file$i.txt", "text/plain", (i + 1) * 100L)
|
||||
}
|
||||
advanceUntilIdle()
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testAddAttachment() =
|
||||
runTest {
|
||||
val viewModel = createViewModel()
|
||||
advanceUntilIdle()
|
||||
|
||||
viewModel.addAttachment(
|
||||
uri = "content://dummy/1",
|
||||
name = "dummy.txt",
|
||||
mimeType = "text/plain",
|
||||
size = 1024L,
|
||||
)
|
||||
advanceUntilIdle()
|
||||
|
||||
val pending = viewModel.uiState.value.pendingAttachments
|
||||
assertEquals(1, pending.size)
|
||||
assertEquals("content://dummy/1", pending[0].uri)
|
||||
assertEquals("dummy.txt", pending[0].name)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testRemoveAttachment_validIndex() =
|
||||
runTest {
|
||||
val viewModel = createViewModel()
|
||||
advanceUntilIdle()
|
||||
|
||||
viewModel.addAttachment("uri1", "file1.txt", "text/plain", 100)
|
||||
viewModel.addAttachment("uri2", "file2.txt", "text/plain", 200)
|
||||
advanceUntilIdle()
|
||||
|
||||
assertEquals(2, viewModel.uiState.value.pendingAttachments.size)
|
||||
|
||||
viewModel.removeAttachment(0)
|
||||
advanceUntilIdle()
|
||||
|
||||
val pending = viewModel.uiState.value.pendingAttachments
|
||||
assertEquals(1, pending.size)
|
||||
assertEquals("uri2", pending[0].uri)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testRemoveAttachment_invalidIndex() =
|
||||
runTest {
|
||||
val viewModel = createViewModel()
|
||||
advanceUntilIdle()
|
||||
|
||||
viewModel.addAttachment("uri1", "file1.txt", "text/plain", 100)
|
||||
advanceUntilIdle()
|
||||
|
||||
assertEquals(1, viewModel.uiState.value.pendingAttachments.size)
|
||||
|
||||
// Out of bounds index should not crash or change list
|
||||
viewModel.removeAttachment(5)
|
||||
viewModel.removeAttachment(-1)
|
||||
advanceUntilIdle()
|
||||
|
||||
val pending = viewModel.uiState.value.pendingAttachments
|
||||
assertEquals(1, pending.size)
|
||||
assertEquals("uri1", pending[0].uri)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testRemoveAttachment_mixedValidAndInvalidSequence() =
|
||||
runTest {
|
||||
val viewModel = createViewModel()
|
||||
advanceUntilIdle()
|
||||
addDummyAttachments(viewModel, 3) // [uri0, uri1, uri2]
|
||||
|
||||
// 1. Remove a valid index (the middle item) → list shrinks correctly.
|
||||
viewModel.removeAttachment(1)
|
||||
advanceUntilIdle()
|
||||
assertEquals(2, viewModel.uiState.value.pendingAttachments.size)
|
||||
assertEquals("uri0", viewModel.uiState.value.pendingAttachments[0].uri)
|
||||
assertEquals("uri2", viewModel.uiState.value.pendingAttachments[1].uri)
|
||||
|
||||
// 2. Fire invalid removals (out of bounds + negative) — must be no-ops.
|
||||
viewModel.removeAttachment(99)
|
||||
viewModel.removeAttachment(-1)
|
||||
advanceUntilIdle()
|
||||
assertEquals(2, viewModel.uiState.value.pendingAttachments.size)
|
||||
|
||||
// 3. Another valid removal on the shifted list → still consistent.
|
||||
viewModel.removeAttachment(1)
|
||||
advanceUntilIdle()
|
||||
val pending = viewModel.uiState.value.pendingAttachments
|
||||
assertEquals(1, pending.size)
|
||||
assertEquals("uri0", pending[0].uri)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testClearAttachments() =
|
||||
runTest {
|
||||
val viewModel = createViewModel()
|
||||
advanceUntilIdle()
|
||||
|
||||
viewModel.addAttachment("uri1", "file1.txt", "text/plain", 100)
|
||||
viewModel.addAttachment("uri2", "file2.txt", "text/plain", 200)
|
||||
advanceUntilIdle()
|
||||
|
||||
assertEquals(2, viewModel.uiState.value.pendingAttachments.size)
|
||||
|
||||
viewModel.clearAttachments()
|
||||
advanceUntilIdle()
|
||||
|
||||
val pending = viewModel.uiState.value.pendingAttachments
|
||||
assertTrue(pending.isEmpty())
|
||||
}
|
||||
|
||||
// ── Send message ─────────────────────────────────────────────────────────
|
||||
|
||||
@Test
|
||||
|
||||
Reference in new issue
Block a user