Skip to content

Commit 619841f

Browse files
committed
Add unit test on MatrixTimelineDiffProcessor
1 parent 6cb4d10 commit 619841f

File tree

2 files changed

+204
-4
lines changed

2 files changed

+204
-4
lines changed

libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/timeline/MatrixTimelineDiffProcessor.kt

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ import kotlinx.coroutines.flow.MutableStateFlow
1515
import kotlinx.coroutines.sync.Mutex
1616
import kotlinx.coroutines.sync.withLock
1717
import org.matrix.rustcomponents.sdk.TimelineChange
18-
import org.matrix.rustcomponents.sdk.TimelineDiff
18+
import org.matrix.rustcomponents.sdk.TimelineDiffInterface
1919
import org.matrix.rustcomponents.sdk.TimelineItem
2020
import timber.log.Timber
2121

@@ -36,7 +36,7 @@ internal class MatrixTimelineDiffProcessor(
3636
}
3737
}
3838

39-
suspend fun postDiffs(diffs: List<TimelineDiff>) {
39+
suspend fun postDiffs(diffs: List<TimelineDiffInterface>) {
4040
updateTimelineItems {
4141
Timber.v("Update timeline items from postDiffs (with ${diffs.size} items) on ${Thread.currentThread()}")
4242
diffs.forEach { diff ->
@@ -52,7 +52,7 @@ internal class MatrixTimelineDiffProcessor(
5252
timelineItems.value = mutableTimelineItems
5353
}
5454

55-
private fun MutableList<MatrixTimelineItem>.applyDiff(diff: TimelineDiff) {
55+
private fun MutableList<MatrixTimelineItem>.applyDiff(diff: TimelineDiffInterface) {
5656
when (diff.change()) {
5757
TimelineChange.APPEND -> {
5858
val items = diff.append()?.map { it.asMatrixTimelineItem() } ?: return
@@ -100,7 +100,8 @@ internal class MatrixTimelineDiffProcessor(
100100
clear()
101101
}
102102
TimelineChange.TRUNCATE -> {
103-
// Not supported
103+
val index = diff.truncate() ?: return
104+
subList(index.toInt(), size).clear()
104105
}
105106
}
106107
}
Lines changed: 199 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,199 @@
1+
/*
2+
* Copyright 2024 New Vector Ltd.
3+
*
4+
* SPDX-License-Identifier: AGPL-3.0-only
5+
* Please see LICENSE in the repository root for full details.
6+
*/
7+
8+
package io.element.android.libraries.matrix.impl.timeline
9+
10+
import com.google.common.truth.Truth.assertThat
11+
import io.element.android.libraries.matrix.api.timeline.MatrixTimelineItem
12+
import io.element.android.libraries.matrix.impl.timeline.item.event.EventTimelineItemMapper
13+
import io.element.android.libraries.matrix.impl.timeline.item.event.TimelineEventContentMapper
14+
import io.element.android.libraries.matrix.impl.timeline.item.virtual.VirtualTimelineItemMapper
15+
import io.element.android.libraries.matrix.test.A_UNIQUE_ID
16+
import io.element.android.libraries.matrix.test.A_UNIQUE_ID_2
17+
import io.element.android.libraries.matrix.test.timeline.anEventTimelineItem
18+
import kotlinx.coroutines.flow.MutableStateFlow
19+
import kotlinx.coroutines.test.TestScope
20+
import kotlinx.coroutines.test.runTest
21+
import org.junit.Test
22+
import org.matrix.rustcomponents.sdk.EventTimelineItem
23+
import org.matrix.rustcomponents.sdk.InsertData
24+
import org.matrix.rustcomponents.sdk.NoPointer
25+
import org.matrix.rustcomponents.sdk.SetData
26+
import org.matrix.rustcomponents.sdk.TimelineChange
27+
import org.matrix.rustcomponents.sdk.TimelineDiffInterface
28+
import org.matrix.rustcomponents.sdk.TimelineItem
29+
import org.matrix.rustcomponents.sdk.VirtualTimelineItem
30+
31+
open class FakeTimelineDiff(
32+
private val change: TimelineChange,
33+
private val item: TimelineItem? = FakeTimelineItem()
34+
) : TimelineDiffInterface {
35+
override fun change() = change
36+
override fun append(): List<TimelineItem>? = item?.let { listOf(it) }
37+
override fun insert(): InsertData? = item?.let { InsertData(1u, it) }
38+
override fun pushBack(): TimelineItem? = item
39+
override fun pushFront(): TimelineItem? = item
40+
override fun remove(): UInt? = 1u
41+
override fun reset(): List<TimelineItem>? = item?.let { listOf(it) }
42+
override fun set(): SetData? = item?.let { SetData(1u, it) }
43+
override fun truncate(): UInt? = 1u
44+
}
45+
46+
class MatrixTimelineDiffProcessorTest {
47+
private val timelineItems = MutableStateFlow<List<MatrixTimelineItem>>(emptyList())
48+
49+
private val anEvent = MatrixTimelineItem.Event(A_UNIQUE_ID, anEventTimelineItem())
50+
private val anEvent2 = MatrixTimelineItem.Event(A_UNIQUE_ID_2, anEventTimelineItem())
51+
52+
@Test
53+
fun `Append adds new entries at the end of the list`() = runTest {
54+
timelineItems.value = listOf(anEvent)
55+
val processor = createProcessor()
56+
processor.postDiffs(listOf(FakeTimelineDiff(change = TimelineChange.APPEND)))
57+
assertThat(timelineItems.value.count()).isEqualTo(2)
58+
assertThat(timelineItems.value).containsExactly(
59+
anEvent,
60+
MatrixTimelineItem.Other,
61+
)
62+
}
63+
64+
@Test
65+
fun `PushBack adds a new entry at the end of the list`() = runTest {
66+
timelineItems.value = listOf(anEvent)
67+
val processor = createProcessor()
68+
processor.postDiffs(listOf(FakeTimelineDiff(change = TimelineChange.PUSH_BACK)))
69+
assertThat(timelineItems.value.count()).isEqualTo(2)
70+
assertThat(timelineItems.value).containsExactly(
71+
anEvent,
72+
MatrixTimelineItem.Other,
73+
)
74+
}
75+
76+
@Test
77+
fun `PushFront inserts a new entry at the start of the list`() = runTest {
78+
timelineItems.value = listOf(anEvent)
79+
val processor = createProcessor()
80+
processor.postDiffs(listOf(FakeTimelineDiff(change = TimelineChange.PUSH_FRONT)))
81+
assertThat(timelineItems.value.count()).isEqualTo(2)
82+
assertThat(timelineItems.value).containsExactly(
83+
MatrixTimelineItem.Other,
84+
anEvent,
85+
)
86+
}
87+
88+
@Test
89+
fun `Set replaces an entry at some index`() = runTest {
90+
timelineItems.value = listOf(anEvent, anEvent2)
91+
val processor = createProcessor()
92+
processor.postDiffs(listOf(FakeTimelineDiff(change = TimelineChange.SET)))
93+
assertThat(timelineItems.value.count()).isEqualTo(2)
94+
assertThat(timelineItems.value).containsExactly(
95+
anEvent,
96+
MatrixTimelineItem.Other
97+
)
98+
}
99+
100+
@Test
101+
fun `Insert inserts a new entry at the provided index`() = runTest {
102+
timelineItems.value = listOf(anEvent, anEvent2)
103+
val processor = createProcessor()
104+
processor.postDiffs(listOf(FakeTimelineDiff(change = TimelineChange.INSERT)))
105+
assertThat(timelineItems.value.count()).isEqualTo(3)
106+
assertThat(timelineItems.value).containsExactly(
107+
anEvent,
108+
MatrixTimelineItem.Other,
109+
anEvent2,
110+
)
111+
}
112+
113+
@Test
114+
fun `Remove removes an entry at some index`() = runTest {
115+
timelineItems.value = listOf(anEvent, MatrixTimelineItem.Other, anEvent2)
116+
val processor = createProcessor()
117+
processor.postDiffs(listOf(FakeTimelineDiff(change = TimelineChange.REMOVE)))
118+
assertThat(timelineItems.value.count()).isEqualTo(2)
119+
assertThat(timelineItems.value).containsExactly(
120+
anEvent,
121+
anEvent2,
122+
)
123+
}
124+
125+
@Test
126+
fun `PopBack removes an entry at the end of the list`() = runTest {
127+
timelineItems.value = listOf(anEvent, anEvent2)
128+
val processor = createProcessor()
129+
processor.postDiffs(listOf(FakeTimelineDiff(change = TimelineChange.POP_BACK)))
130+
assertThat(timelineItems.value.count()).isEqualTo(1)
131+
assertThat(timelineItems.value).containsExactly(
132+
anEvent,
133+
)
134+
}
135+
136+
@Test
137+
fun `PopFront removes an entry at the start of the list`() = runTest {
138+
timelineItems.value = listOf(anEvent, anEvent2)
139+
val processor = createProcessor()
140+
processor.postDiffs(listOf(FakeTimelineDiff(change = TimelineChange.POP_FRONT)))
141+
assertThat(timelineItems.value.count()).isEqualTo(1)
142+
assertThat(timelineItems.value).containsExactly(
143+
anEvent2,
144+
)
145+
}
146+
147+
@Test
148+
fun `Clear removes all the entries`() = runTest {
149+
timelineItems.value = listOf(anEvent, anEvent2)
150+
val processor = createProcessor()
151+
processor.postDiffs(listOf(FakeTimelineDiff(change = TimelineChange.CLEAR)))
152+
assertThat(timelineItems.value).isEmpty()
153+
}
154+
155+
@Test
156+
fun `Truncate removes all entries after the provided length`() = runTest {
157+
timelineItems.value = listOf(anEvent, MatrixTimelineItem.Other, anEvent2)
158+
val processor = createProcessor()
159+
processor.postDiffs(listOf(FakeTimelineDiff(change = TimelineChange.TRUNCATE)))
160+
assertThat(timelineItems.value.count()).isEqualTo(1)
161+
assertThat(timelineItems.value).containsExactly(
162+
anEvent,
163+
)
164+
}
165+
166+
@Test
167+
fun `Reset removes all entries and add the provided ones`() = runTest {
168+
timelineItems.value = listOf(anEvent, MatrixTimelineItem.Other, anEvent2)
169+
val processor = createProcessor()
170+
processor.postDiffs(listOf(FakeTimelineDiff(change = TimelineChange.RESET)))
171+
assertThat(timelineItems.value.count()).isEqualTo(1)
172+
assertThat(timelineItems.value).containsExactly(
173+
MatrixTimelineItem.Other,
174+
)
175+
}
176+
177+
private fun TestScope.createProcessor(): MatrixTimelineDiffProcessor {
178+
val timelineEventContentMapper = TimelineEventContentMapper()
179+
val timelineItemMapper = MatrixTimelineItemMapper(
180+
fetchDetailsForEvent = { _ -> Result.success(Unit) },
181+
coroutineScope = this,
182+
virtualTimelineItemMapper = VirtualTimelineItemMapper(),
183+
eventTimelineItemMapper = EventTimelineItemMapper(
184+
contentMapper = timelineEventContentMapper
185+
)
186+
)
187+
return MatrixTimelineDiffProcessor(
188+
timelineItems,
189+
timelineItemFactory = timelineItemMapper,
190+
)
191+
}
192+
}
193+
194+
class FakeTimelineItem : TimelineItem(NoPointer) {
195+
override fun asEvent(): EventTimelineItem? = null
196+
override fun asVirtual(): VirtualTimelineItem? = null
197+
override fun fmtDebug(): String = "fmtDebug"
198+
override fun uniqueId(): String = "uniqueId"
199+
}

0 commit comments

Comments
 (0)