adding tests around the messaging echo merging

This commit is contained in:
Adam Brown 2022-03-13 12:17:49 +00:00
parent 50663f486f
commit e6c5eee948
14 changed files with 223 additions and 54 deletions

View File

@ -15,6 +15,7 @@ dependencies {
kotlinTest(it)
androidImportFixturesWorkaround(project, project(":matrix:services:sync"))
androidImportFixturesWorkaround(project, project(":matrix:services:message"))
androidImportFixturesWorkaround(project, project(":matrix:common"))
androidImportFixturesWorkaround(project, project(":core"))
androidImportFixturesWorkaround(project, project(":domains:store"))

View File

@ -6,26 +6,33 @@ import app.dapk.st.matrix.message.MessageService
import app.dapk.st.matrix.sync.MessageMeta
import app.dapk.st.matrix.sync.RoomEvent
class LocalEchoMapper {
internal class LocalEchoMapper(private val metaMapper: MetaMapper) {
fun MessageService.LocalEcho.toMessage(message: MessageService.Message.TextMessage, member: RoomMember): RoomEvent.Message {
return RoomEvent.Message(
eventId = this.eventId ?: EventId(this.localId),
content = message.content.body,
author = member,
utcTimestamp = message.timestampUtc,
meta = this.toMeta()
)
fun MessageService.LocalEcho.toMessage(member: RoomMember): RoomEvent.Message {
return when (val message = this.message) {
is MessageService.Message.TextMessage -> {
RoomEvent.Message(
eventId = this.eventId ?: EventId(this.localId),
content = message.content.body,
author = member,
utcTimestamp = message.timestampUtc,
meta = metaMapper.toMeta(this)
)
}
}
}
fun RoomEvent.mergeWith(echo: MessageService.LocalEcho) = when (this) {
is RoomEvent.Message -> this.copy(meta = echo.toMeta())
is RoomEvent.Reply -> this.copy(message = this.message.copy(meta = echo.toMeta()))
is RoomEvent.Message -> this.copy(meta = metaMapper.toMeta(echo))
is RoomEvent.Reply -> this.copy(message = this.message.copy(meta = metaMapper.toMeta(echo)))
}
}
private fun MessageService.LocalEcho.toMeta() = MessageMeta.LocalEcho(
echoId = this.localId,
state = when (val localEchoState = this.state) {
internal class MetaMapper {
fun toMeta(echo: MessageService.LocalEcho) = MessageMeta.LocalEcho(
echoId = echo.localId,
state = when (val localEchoState = echo.state) {
MessageService.LocalEcho.State.Sending -> MessageMeta.LocalEcho.State.Sending
MessageService.LocalEcho.State.Sent -> MessageMeta.LocalEcho.State.Sent
is MessageService.LocalEcho.State.Error -> MessageMeta.LocalEcho.State.Error(
@ -34,4 +41,5 @@ class LocalEchoMapper {
)
}
)
}

View File

@ -29,13 +29,7 @@ internal class MergeWithLocalEchosUseCaseImpl(
return with(localEventMapper) {
echos
.filter { echo -> echo.eventId == null || stateByEventId[echo.eventId] == null }
.map { localEcho ->
when (val message = localEcho.message) {
is MessageService.Message.TextMessage -> {
localEcho.toMessage(message, member)
}
}
}
.map { localEcho -> localEcho.toMessage(member) }
}
}

View File

@ -21,5 +21,8 @@ class MessengerModule(
return MessengerViewModel(messageService, roomService, roomStore, credentialsStore, timelineUseCase(), LocalIdFactory(), clock)
}
private fun timelineUseCase() = TimelineUseCaseImpl(syncService, messageService, roomService, MergeWithLocalEchosUseCaseImpl(LocalEchoMapper()))
private fun timelineUseCase(): TimelineUseCaseImpl {
val mergeWithLocalEchosUseCase = MergeWithLocalEchosUseCaseImpl(LocalEchoMapper(MetaMapper()))
return TimelineUseCaseImpl(syncService, messageService, roomService, mergeWithLocalEchosUseCase)
}
}

View File

@ -0,0 +1,69 @@
package app.dapk.st.messenger
import app.dapk.st.matrix.common.EventId
import app.dapk.st.matrix.message.MessageService
import app.dapk.st.matrix.sync.MessageMeta
import fixture.*
import internalfake.FakeMetaMapper
import org.amshove.kluent.shouldBeEqualTo
import org.junit.Test
private val A_META = MessageMeta.LocalEcho("echo-id", MessageMeta.LocalEcho.State.Sent)
private val AN_ECHO_CONTENT = aTextMessage(localId = "a-local-id")
private val A_ROOM_MEMBER = aRoomMember()
class LocalEchoMapperTest {
private val fakeMetaMapper = FakeMetaMapper()
private val localEchoMapper = LocalEchoMapper(fakeMetaMapper.instance)
@Test
fun `given echo with event id when mapping to message then uses event id`() = runWith(localEchoMapper) {
val echo = givenEcho(eventId = anEventId("a-known-id"))
val result = echo.toMessage(A_ROOM_MEMBER)
result shouldBeEqualTo aRoomMessageEvent(
eventId = echo.eventId!!,
content = AN_ECHO_CONTENT.content.body,
meta = A_META
)
}
@Test
fun `given echo without event id when mapping to message then uses local id`() = runWith(localEchoMapper) {
val echo = givenEcho(eventId = null, localId = "a-local-id")
val result = echo.toMessage(A_ROOM_MEMBER)
result shouldBeEqualTo aRoomMessageEvent(
eventId = anEventId(echo.localId),
content = AN_ECHO_CONTENT.content.body,
meta = A_META
)
}
@Test
fun `when merging with echo then updates meta with the echos meta`() = runWith(localEchoMapper) {
val previousMeta = MessageMeta.LocalEcho("previous", MessageMeta.LocalEcho.State.Sending)
val event = aRoomMessageEvent(meta = previousMeta)
val echo = aLocalEcho()
fakeMetaMapper.given(echo).returns(A_META)
val result = event.mergeWith(echo)
result shouldBeEqualTo aRoomMessageEvent(meta = A_META)
}
private fun givenEcho(eventId: EventId? = null, localId: String = "", meta: MessageMeta.LocalEcho = A_META): MessageService.LocalEcho {
return aLocalEcho(eventId = eventId, message = aTextMessage(localId = localId)).also {
fakeMetaMapper.given(it).returns(meta)
}
}
}
fun <T> runWith(context: T, block: T.() -> Unit) {
block(context)
}

View File

@ -3,11 +3,9 @@ package app.dapk.st.messenger
import app.dapk.st.matrix.common.EventId
import app.dapk.st.matrix.common.MessageType
import app.dapk.st.matrix.common.RoomId
import app.dapk.st.matrix.common.RoomMember
import app.dapk.st.matrix.message.MessageService
import fixture.*
import io.mockk.every
import io.mockk.mockk
import internalfake.FakeLocalEventMapper
import org.amshove.kluent.shouldBeEqualTo
import org.junit.Test
@ -34,7 +32,7 @@ class MergeWithLocalEchosUseCaseTest {
@Test
fun `given local echo with sending state, when merging then maps to room event with local echo state`() {
val second = createLocalEcho(A_LOCAL_ECHO_EVENT_ID, A_LOCAL_ECHO_BODY, state = MessageService.LocalEcho.State.Sending)
fakeLocalEchoMapper.givenMapping(second, aTextMessage(aTextContent(A_LOCAL_ECHO_BODY)), A_ROOM_MEMBER).returns(ANOTHER_ROOM_MESSAGE_EVENT)
fakeLocalEchoMapper.givenMapping(second, A_ROOM_MEMBER).returns(ANOTHER_ROOM_MESSAGE_EVENT)
val roomState = aRoomState(events = listOf(A_ROOM_MESSAGE_EVENT))
val result = mergeWithLocalEchosUseCase.invoke(roomState, A_ROOM_MEMBER, listOf(second))
@ -53,30 +51,3 @@ class MergeWithLocalEchosUseCaseTest {
state,
)
}
fun aLocalEcho(
eventId: EventId? = anEventId(),
message: MessageService.Message = aTextMessage(),
state: MessageService.LocalEcho.State = MessageService.LocalEcho.State.Sending,
) = MessageService.LocalEcho(eventId, message, state)
fun aTextMessage(
content: MessageService.Message.Content.TextContent = aTextContent(),
sendEncrypted: Boolean = false,
roomId: RoomId = aRoomId(),
localId: String = "a-local-id",
timestampUtc: Long = 0,
) = MessageService.Message.TextMessage(content, sendEncrypted, roomId, localId, timestampUtc)
fun aTextContent(
body: String = "text content body",
type: String = MessageType.TEXT.value,
) = MessageService.Message.Content.TextContent(body, type)
class FakeLocalEventMapper {
val instance = mockk<LocalEchoMapper>()
fun givenMapping(echo: MessageService.LocalEcho, event: MessageService.Message.TextMessage, roomMember: RoomMember) = every {
with(instance) { echo.toMessage(event, roomMember) }
}
}

View File

@ -11,6 +11,7 @@ import app.dapk.st.matrix.sync.RoomState
import fake.FakeCredentialsStore
import fake.FakeRoomStore
import fixture.*
import internalfake.FakeLocalIdFactory
import io.mockk.coEvery
import io.mockk.mockk
import kotlinx.coroutines.flow.flowOf

View File

@ -0,0 +1,60 @@
package app.dapk.st.messenger
import app.dapk.st.matrix.message.MessageService
import app.dapk.st.matrix.sync.MessageMeta
import fixture.aLocalEcho
import fixture.aTextMessage
import org.amshove.kluent.shouldBeEqualTo
import org.junit.Test
private const val A_LOCAL_ECHO_ID = "a-local-echo-id"
class MetaMapperTest {
private val metaMapper = MetaMapper()
@Test
fun `given echo with sending meta then maps to sending state`() {
val result = metaMapper.toMeta(
aLocalEcho(
state = MessageService.LocalEcho.State.Sending,
message = aTextMessage(localId = A_LOCAL_ECHO_ID)
)
)
result shouldBeEqualTo MessageMeta.LocalEcho(
echoId = A_LOCAL_ECHO_ID,
state = MessageMeta.LocalEcho.State.Sending
)
}
@Test
fun `given echo with sent meta then maps to sent state`() {
val result = metaMapper.toMeta(
aLocalEcho(
state = MessageService.LocalEcho.State.Sent,
message = aTextMessage(localId = A_LOCAL_ECHO_ID)
)
)
result shouldBeEqualTo MessageMeta.LocalEcho(
echoId = A_LOCAL_ECHO_ID,
state = MessageMeta.LocalEcho.State.Sent
)
}
@Test
fun `given echo with error meta then maps to error state`() {
val result = metaMapper.toMeta(
aLocalEcho(
state = MessageService.LocalEcho.State.Error("an error", MessageService.LocalEcho.State.Error.Type.UNKNOWN),
message = aTextMessage(localId = A_LOCAL_ECHO_ID)
)
)
result shouldBeEqualTo MessageMeta.LocalEcho(
echoId = A_LOCAL_ECHO_ID,
state = MessageMeta.LocalEcho.State.Error("an error", MessageMeta.LocalEcho.State.Error.Type.UNKNOWN)
)
}
}

View File

@ -0,0 +1,14 @@
package internalfake
import app.dapk.st.matrix.common.RoomMember
import app.dapk.st.matrix.message.MessageService
import app.dapk.st.messenger.LocalEchoMapper
import io.mockk.every
import io.mockk.mockk
internal class FakeLocalEventMapper {
val instance = mockk<LocalEchoMapper>()
fun givenMapping(echo: MessageService.LocalEcho, roomMember: RoomMember) = every {
with(instance) { echo.toMessage(roomMember) }
}
}

View File

@ -1,5 +1,6 @@
package app.dapk.st.messenger
package internalfake
import app.dapk.st.messenger.LocalIdFactory
import io.mockk.every
import io.mockk.mockk
import test.delegateReturn

View File

@ -0,0 +1,12 @@
package internalfake
import app.dapk.st.matrix.message.MessageService
import app.dapk.st.messenger.MetaMapper
import io.mockk.every
import io.mockk.mockk
import test.delegateReturn
internal class FakeMetaMapper {
val instance = mockk<MetaMapper>()
fun given(echo: MessageService.LocalEcho) = every { instance.toMeta(echo) }.delegateReturn()
}

View File

@ -1 +1,8 @@
plugins { id 'java-test-fixtures' }
applyMatrixServiceModule(project)
dependencies {
kotlinFixtures(it)
testFixturesImplementation(testFixtures(project(":core")))
testFixturesImplementation(testFixtures(project(":matrix:common")))
}

View File

@ -0,0 +1,10 @@
package fixture
import app.dapk.st.matrix.common.EventId
import app.dapk.st.matrix.message.MessageService
fun aLocalEcho(
eventId: EventId? = anEventId(),
message: MessageService.Message = aTextMessage(),
state: MessageService.LocalEcho.State = MessageService.LocalEcho.State.Sending,
) = MessageService.LocalEcho(eventId, message, state)

View File

@ -0,0 +1,18 @@
package fixture
import app.dapk.st.matrix.common.MessageType
import app.dapk.st.matrix.common.RoomId
import app.dapk.st.matrix.message.MessageService
fun aTextMessage(
content: MessageService.Message.Content.TextContent = aTextContent(),
sendEncrypted: Boolean = false,
roomId: RoomId = aRoomId(),
localId: String = "a-local-id",
timestampUtc: Long = 0,
) = MessageService.Message.TextMessage(content, sendEncrypted, roomId, localId, timestampUtc)
fun aTextContent(
body: String = "text content body",
type: String = MessageType.TEXT.value,
) = MessageService.Message.Content.TextContent(body, type)