Skip to content

Commit a127dce

Browse files
committed
Feat: Add Channel.readsOf() extension function
Adds a `readsOf(message: Message)` extension function to the `Channel` class. This function returns a list of `ChannelUserRead` objects for users who have read the given message, excluding the message sender. Also includes: - Adding corresponding unit tests for the new function. - Renaming `ChannelExtensionsTests.kt` to `ChannelExtensionTest.kt`. - Migrating existing tests from `kluent` to `JUnit Jupiter` assertions.
1 parent 2ea5eaf commit a127dce

File tree

3 files changed

+74
-16
lines changed

3 files changed

+74
-16
lines changed

stream-chat-android-client/api/stream-chat-android-client.api

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2664,6 +2664,7 @@ public final class io/getstream/chat/android/client/extensions/ChannelExtensionK
26642664
public static final fun isArchive (Lio/getstream/chat/android/models/Channel;)Z
26652665
public static final fun isMutedFor (Lio/getstream/chat/android/models/Channel;Lio/getstream/chat/android/models/User;)Z
26662666
public static final fun isPinned (Lio/getstream/chat/android/models/Channel;)Z
2667+
public static final fun readsOf (Lio/getstream/chat/android/models/Channel;Lio/getstream/chat/android/models/Message;)Ljava/util/List;
26672668
public static final fun syncUnreadCountWithReads (Lio/getstream/chat/android/models/Channel;Ljava/lang/String;)Lio/getstream/chat/android/models/Channel;
26682669
public static synthetic fun syncUnreadCountWithReads$default (Lio/getstream/chat/android/models/Channel;Ljava/lang/String;ILjava/lang/Object;)Lio/getstream/chat/android/models/Channel;
26692670
public static final fun userRead (Lio/getstream/chat/android/models/Channel;Ljava/lang/String;)Lio/getstream/chat/android/models/ChannelUserRead;

stream-chat-android-client/src/main/java/io/getstream/chat/android/client/extensions/ChannelExtension.kt

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -130,6 +130,23 @@ public fun Channel.syncUnreadCountWithReads(
130130
public fun Channel.userRead(userId: UserId): ChannelUserRead? =
131131
read.firstOrNull { read -> read.user.id == userId }
132132

133+
/**
134+
* Returns a list of [ChannelUserRead] objects representing which ones have
135+
* read the given [message].
136+
*
137+
* A message is considered read by a user if:
138+
* - The user is not the sender of the message
139+
* - The user has read the message
140+
*
141+
* @param message The [Message] object for which to find read reads.
142+
* @return A list of [ChannelUserRead] objects representing users who have read the message
143+
*/
144+
public fun Channel.readsOf(message: Message): List<ChannelUserRead> =
145+
read.filter { read ->
146+
read.user.id != message.user.id &&
147+
read.lastRead > message.getCreatedAtOrThrow()
148+
}
149+
133150
/**
134151
* Returns a list of [ChannelUserRead] objects representing which ones have
135152
* delivered the given [message].
Lines changed: 56 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -26,62 +26,64 @@ import io.getstream.chat.android.randomMember
2626
import io.getstream.chat.android.randomMessage
2727
import io.getstream.chat.android.randomString
2828
import io.getstream.chat.android.randomUser
29-
import org.amshove.kluent.shouldBeEqualTo
3029
import org.junit.Test
30+
import org.junit.jupiter.api.Assertions.assertEquals
31+
import org.junit.jupiter.api.Assertions.assertFalse
32+
import org.junit.jupiter.api.Assertions.assertTrue
3133
import java.util.Date
3234

33-
internal class ChannelExtensionsTests {
35+
internal class ChannelExtensionTest {
3436

3537
@Test
3638
fun `isAnonymousChannel should return true for anonymous channel`() {
3739
val anonymousChannel = randomChannel(id = "!members-12345")
38-
anonymousChannel.isAnonymousChannel() shouldBeEqualTo true
40+
assertTrue(anonymousChannel.isAnonymousChannel())
3941
}
4042

4143
@Test
4244
fun `isAnonymousChannel should return false for non-anonymous channel`() {
4345
val channel = randomChannel(id = "messaging:12345")
44-
channel.isAnonymousChannel() shouldBeEqualTo false
46+
assertFalse(channel.isAnonymousChannel())
4547
}
4648

4749
@Test
4850
fun `isPinned should return true if channel is pinned`() {
4951
val pinnedChannel = randomChannel(membership = randomMember(pinnedAt = randomDate()))
50-
pinnedChannel.isPinned() shouldBeEqualTo true
52+
assertTrue(pinnedChannel.isPinned())
5153
}
5254

5355
@Test
5456
fun `isPinned should return false if channel is not pinned`() {
5557
val channel = randomChannel(membership = randomMember(pinnedAt = null))
56-
channel.isPinned() shouldBeEqualTo false
58+
assertFalse(channel.isPinned())
5759
}
5860

5961
@Test
6062
fun `isArchive should return true if channel is archived`() {
6163
val archivedChannel = randomChannel(membership = randomMember(archivedAt = randomDate()))
62-
archivedChannel.isArchive() shouldBeEqualTo true
64+
assertTrue(archivedChannel.isArchive())
6365
}
6466

6567
@Test
6668
fun `isArchive should return false if channel is not archived`() {
6769
val channel = randomChannel(membership = randomMember(archivedAt = null))
68-
channel.isArchive() shouldBeEqualTo false
70+
assertFalse(channel.isArchive())
6971
}
7072

7173
@Test
7274
fun `isMutedFor should return true if channel is muted for user`() {
7375
val channelId = randomCID()
7476
val channel = randomChannel(id = channelId)
7577
val mutedUser = randomUser(channelMutes = listOf(randomChannelMute(channel = channel)))
76-
channel.isMutedFor(mutedUser) shouldBeEqualTo true
78+
assertTrue(channel.isMutedFor(mutedUser))
7779
}
7880

7981
@Test
8082
fun `isMutedFor should return false if channel is not muted for user`() {
8183
val channelId = randomCID()
8284
val channel = randomChannel(id = channelId)
8385
val user = randomUser()
84-
channel.isMutedFor(user) shouldBeEqualTo false
86+
assertFalse(channel.isMutedFor(user))
8587
}
8688

8789
@Test
@@ -94,8 +96,8 @@ internal class ChannelExtensionsTests {
9496
)
9597
val channel = randomChannel(members = members)
9698
val users = channel.getUsersExcludingCurrent(currentUser)
97-
users.size shouldBeEqualTo 1
98-
users.first() shouldBeEqualTo otherUser
99+
assertEquals(1, users.size)
100+
assertEquals(otherUser, users.first())
99101
}
100102

101103
@Test
@@ -115,7 +117,7 @@ internal class ChannelExtensionsTests {
115117
),
116118
)
117119
val channel = randomChannel(messages = messages)
118-
channel.countUnreadMentionsForUser(user) shouldBeEqualTo 2
120+
assertEquals(2, channel.countUnreadMentionsForUser(user))
119121
}
120122

121123
@Test
@@ -140,7 +142,7 @@ internal class ChannelExtensionsTests {
140142
)
141143
val channelRead = randomChannelUserRead(user = user, lastRead = lastReadDate)
142144
val channel = randomChannel(messages = messages, read = listOf(channelRead))
143-
channel.countUnreadMentionsForUser(user) shouldBeEqualTo 1
145+
assertEquals(1, channel.countUnreadMentionsForUser(user))
144146
}
145147

146148
@Test
@@ -149,7 +151,7 @@ internal class ChannelExtensionsTests {
149151
val unreadMessages = positiveRandomInt()
150152
val channelRead = randomChannelUserRead(user = randomUser(id = currentUserId), unreadMessages = unreadMessages)
151153
val channel = randomChannel(read = listOf(channelRead))
152-
channel.currentUserUnreadCount(currentUserId) shouldBeEqualTo unreadMessages
154+
assertEquals(unreadMessages, channel.currentUserUnreadCount(currentUserId))
153155
}
154156

155157
@Test
@@ -158,6 +160,44 @@ internal class ChannelExtensionsTests {
158160
val unreadMessages = positiveRandomInt()
159161
val channelRead = randomChannelUserRead(user = randomUser(id = currentUserId), unreadMessages = unreadMessages)
160162
val channel = randomChannel(read = listOf(channelRead))
161-
channel.syncUnreadCountWithReads(currentUserId).unreadCount shouldBeEqualTo unreadMessages
163+
assertEquals(unreadMessages, channel.syncUnreadCountWithReads(currentUserId).unreadCount)
164+
}
165+
166+
@Test
167+
fun `readsOf should return correct list of ChannelUserRead who have read the message`() {
168+
val createdAt = randomDate()
169+
val messageUser = randomUser()
170+
val otherUser1 = randomUser()
171+
val otherUser2 = randomUser()
172+
val lastRead = Date(createdAt.time + 1000) // After message creation time
173+
val read1 = randomChannelUserRead(user = otherUser1, lastRead = lastRead)
174+
val read2 = randomChannelUserRead(user = otherUser2, lastRead = lastRead)
175+
val read3 = randomChannelUserRead(user = messageUser, lastRead = lastRead)
176+
val channel = randomChannel(read = listOf(read1, read2, read3))
177+
val message = randomMessage(user = messageUser, createdAt = createdAt)
178+
179+
val actual = channel.readsOf(message)
180+
181+
assertEquals(2, actual.size)
182+
assertEquals(listOf(read1, read2), actual)
183+
}
184+
185+
@Test
186+
fun `deliveredReadsOf should return correct list of ChannelUserRead who have delivered the message`() {
187+
val createdAt = randomDate()
188+
val messageUser = randomUser()
189+
val otherUser1 = randomUser()
190+
val otherUser2 = randomUser()
191+
val lastDelivered = Date(createdAt.time + 1000) // After message creation time
192+
val delivered1 = randomChannelUserRead(user = otherUser1, lastDeliveredAt = lastDelivered)
193+
val delivered2 = randomChannelUserRead(user = otherUser2, lastDeliveredAt = lastDelivered)
194+
val delivered3 = randomChannelUserRead(user = messageUser, lastDeliveredAt = lastDelivered)
195+
val channel = randomChannel(read = listOf(delivered1, delivered2, delivered3))
196+
val message = randomMessage(user = messageUser, createdAt = createdAt)
197+
198+
val actual = channel.deliveredReadsOf(message)
199+
200+
assertEquals(2, actual.size)
201+
assertEquals(listOf(delivered1, delivered2), actual)
162202
}
163203
}

0 commit comments

Comments
 (0)