Poll history : add tests and fix others
This commit is contained in:
parent
6020bf7b44
commit
055eb43708
17 changed files with 831 additions and 529 deletions
|
|
@ -97,6 +97,8 @@ dependencies {
|
||||||
testImplementation(libs.test.mockk)
|
testImplementation(libs.test.mockk)
|
||||||
testImplementation(libs.test.junitext)
|
testImplementation(libs.test.junitext)
|
||||||
testImplementation(libs.test.robolectric)
|
testImplementation(libs.test.robolectric)
|
||||||
|
testImplementation(projects.features.poll.test)
|
||||||
|
testImplementation(projects.features.poll.impl)
|
||||||
|
|
||||||
ksp(libs.showkase.processor)
|
ksp(libs.showkase.processor)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -47,6 +47,8 @@ import io.element.android.features.messages.impl.voicemessages.composer.VoiceMes
|
||||||
import io.element.android.features.messages.impl.voicemessages.timeline.FakeRedactedVoiceMessageManager
|
import io.element.android.features.messages.impl.voicemessages.timeline.FakeRedactedVoiceMessageManager
|
||||||
import io.element.android.features.messages.test.FakeMessageComposerContext
|
import io.element.android.features.messages.test.FakeMessageComposerContext
|
||||||
import io.element.android.features.networkmonitor.test.FakeNetworkMonitor
|
import io.element.android.features.networkmonitor.test.FakeNetworkMonitor
|
||||||
|
import io.element.android.features.poll.test.actions.FakeEndPollAction
|
||||||
|
import io.element.android.features.poll.test.actions.FakeSendPollResponseAction
|
||||||
import io.element.android.libraries.androidutils.clipboard.FakeClipboardHelper
|
import io.element.android.libraries.androidutils.clipboard.FakeClipboardHelper
|
||||||
import io.element.android.libraries.architecture.Async
|
import io.element.android.libraries.architecture.Async
|
||||||
import io.element.android.libraries.core.coroutine.CoroutineDispatchers
|
import io.element.android.libraries.core.coroutine.CoroutineDispatchers
|
||||||
|
|
@ -705,11 +707,12 @@ class MessagesPresenterTest {
|
||||||
dispatchers = coroutineDispatchers,
|
dispatchers = coroutineDispatchers,
|
||||||
appScope = this,
|
appScope = this,
|
||||||
navigator = navigator,
|
navigator = navigator,
|
||||||
analyticsService = analyticsService,
|
|
||||||
encryptionService = FakeEncryptionService(),
|
encryptionService = FakeEncryptionService(),
|
||||||
verificationService = FakeSessionVerificationService(),
|
verificationService = FakeSessionVerificationService(),
|
||||||
featureFlagService = FakeFeatureFlagService(),
|
featureFlagService = FakeFeatureFlagService(),
|
||||||
redactedVoiceMessageManager = FakeRedactedVoiceMessageManager(),
|
redactedVoiceMessageManager = FakeRedactedVoiceMessageManager(),
|
||||||
|
endPollAction = FakeEndPollAction(),
|
||||||
|
sendPollResponseAction = FakeSendPollResponseAction(),
|
||||||
)
|
)
|
||||||
val timelinePresenterFactory = object: TimelinePresenter.Factory {
|
val timelinePresenterFactory = object: TimelinePresenter.Factory {
|
||||||
override fun create(navigator: MessagesNavigator): TimelinePresenter {
|
override fun create(navigator: MessagesNavigator): TimelinePresenter {
|
||||||
|
|
|
||||||
|
|
@ -32,6 +32,7 @@ import io.element.android.features.messages.impl.timeline.factories.event.Timeli
|
||||||
import io.element.android.features.messages.impl.timeline.factories.virtual.TimelineItemDaySeparatorFactory
|
import io.element.android.features.messages.impl.timeline.factories.virtual.TimelineItemDaySeparatorFactory
|
||||||
import io.element.android.features.messages.impl.timeline.factories.virtual.TimelineItemVirtualFactory
|
import io.element.android.features.messages.impl.timeline.factories.virtual.TimelineItemVirtualFactory
|
||||||
import io.element.android.features.messages.impl.timeline.groups.TimelineItemGrouper
|
import io.element.android.features.messages.impl.timeline.groups.TimelineItemGrouper
|
||||||
|
import io.element.android.features.poll.test.pollcontent.FakePollContentStateFactory
|
||||||
import io.element.android.libraries.androidutils.filesize.FakeFileSizeFormatter
|
import io.element.android.libraries.androidutils.filesize.FakeFileSizeFormatter
|
||||||
import io.element.android.libraries.dateformatter.test.FakeDaySeparatorFormatter
|
import io.element.android.libraries.dateformatter.test.FakeDaySeparatorFormatter
|
||||||
import io.element.android.libraries.dateformatter.test.FakeLastMessageTimestampFormatter
|
import io.element.android.libraries.dateformatter.test.FakeLastMessageTimestampFormatter
|
||||||
|
|
@ -57,7 +58,7 @@ internal fun TestScope.aTimelineItemsFactory(): TimelineItemsFactory {
|
||||||
),
|
),
|
||||||
redactedMessageFactory = TimelineItemContentRedactedFactory(),
|
redactedMessageFactory = TimelineItemContentRedactedFactory(),
|
||||||
stickerFactory = TimelineItemContentStickerFactory(),
|
stickerFactory = TimelineItemContentStickerFactory(),
|
||||||
pollFactory = TimelineItemContentPollFactory(matrixClient, FakeFeatureFlagService()),
|
pollFactory = TimelineItemContentPollFactory(FakeFeatureFlagService(), FakePollContentStateFactory()),
|
||||||
utdFactory = TimelineItemContentUTDFactory(),
|
utdFactory = TimelineItemContentUTDFactory(),
|
||||||
roomMembershipFactory = TimelineItemContentRoomMembershipFactory(timelineEventFormatter),
|
roomMembershipFactory = TimelineItemContentRoomMembershipFactory(timelineEventFormatter),
|
||||||
profileChangeFactory = TimelineItemContentProfileChangeFactory(timelineEventFormatter),
|
profileChangeFactory = TimelineItemContentProfileChangeFactory(timelineEventFormatter),
|
||||||
|
|
|
||||||
|
|
@ -20,10 +20,7 @@ import app.cash.molecule.RecompositionMode
|
||||||
import app.cash.molecule.moleculeFlow
|
import app.cash.molecule.moleculeFlow
|
||||||
import app.cash.turbine.test
|
import app.cash.turbine.test
|
||||||
import com.google.common.truth.Truth.assertThat
|
import com.google.common.truth.Truth.assertThat
|
||||||
import im.vector.app.features.analytics.plan.PollEnd
|
|
||||||
import im.vector.app.features.analytics.plan.PollVote
|
|
||||||
import io.element.android.features.messages.impl.FakeMessagesNavigator
|
import io.element.android.features.messages.impl.FakeMessagesNavigator
|
||||||
import io.element.android.features.messages.impl.fixtures.aMessageEvent
|
|
||||||
import io.element.android.features.messages.impl.fixtures.aTimelineItemsFactory
|
import io.element.android.features.messages.impl.fixtures.aTimelineItemsFactory
|
||||||
import io.element.android.features.messages.impl.timeline.factories.TimelineItemsFactory
|
import io.element.android.features.messages.impl.timeline.factories.TimelineItemsFactory
|
||||||
import io.element.android.features.messages.impl.timeline.model.NewEventState
|
import io.element.android.features.messages.impl.timeline.model.NewEventState
|
||||||
|
|
@ -32,8 +29,11 @@ import io.element.android.features.messages.impl.timeline.session.SessionState
|
||||||
import io.element.android.features.messages.impl.voicemessages.timeline.FakeRedactedVoiceMessageManager
|
import io.element.android.features.messages.impl.voicemessages.timeline.FakeRedactedVoiceMessageManager
|
||||||
import io.element.android.features.messages.impl.voicemessages.timeline.RedactedVoiceMessageManager
|
import io.element.android.features.messages.impl.voicemessages.timeline.RedactedVoiceMessageManager
|
||||||
import io.element.android.features.messages.impl.voicemessages.timeline.aRedactedMatrixTimeline
|
import io.element.android.features.messages.impl.voicemessages.timeline.aRedactedMatrixTimeline
|
||||||
|
import io.element.android.features.poll.api.actions.EndPollAction
|
||||||
|
import io.element.android.features.poll.api.actions.SendPollResponseAction
|
||||||
|
import io.element.android.features.poll.test.actions.FakeEndPollAction
|
||||||
|
import io.element.android.features.poll.test.actions.FakeSendPollResponseAction
|
||||||
import io.element.android.libraries.featureflag.test.FakeFeatureFlagService
|
import io.element.android.libraries.featureflag.test.FakeFeatureFlagService
|
||||||
import io.element.android.libraries.matrix.api.room.MatrixRoom
|
|
||||||
import io.element.android.libraries.matrix.api.timeline.MatrixTimeline
|
import io.element.android.libraries.matrix.api.timeline.MatrixTimeline
|
||||||
import io.element.android.libraries.matrix.api.timeline.MatrixTimelineItem
|
import io.element.android.libraries.matrix.api.timeline.MatrixTimelineItem
|
||||||
import io.element.android.libraries.matrix.api.timeline.item.event.EventReaction
|
import io.element.android.libraries.matrix.api.timeline.item.event.EventReaction
|
||||||
|
|
@ -48,13 +48,11 @@ import io.element.android.libraries.matrix.test.room.anEventTimelineItem
|
||||||
import io.element.android.libraries.matrix.test.timeline.FakeMatrixTimeline
|
import io.element.android.libraries.matrix.test.timeline.FakeMatrixTimeline
|
||||||
import io.element.android.libraries.matrix.test.verification.FakeSessionVerificationService
|
import io.element.android.libraries.matrix.test.verification.FakeSessionVerificationService
|
||||||
import io.element.android.libraries.matrix.ui.components.aMatrixUserList
|
import io.element.android.libraries.matrix.ui.components.aMatrixUserList
|
||||||
import io.element.android.services.analytics.test.FakeAnalyticsService
|
|
||||||
import io.element.android.tests.testutils.WarmUpRule
|
import io.element.android.tests.testutils.WarmUpRule
|
||||||
import io.element.android.tests.testutils.awaitLastSequentialItem
|
import io.element.android.tests.testutils.awaitLastSequentialItem
|
||||||
import io.element.android.tests.testutils.awaitWithLatch
|
import io.element.android.tests.testutils.awaitWithLatch
|
||||||
import io.element.android.tests.testutils.consumeItemsUntilPredicate
|
import io.element.android.tests.testutils.consumeItemsUntilPredicate
|
||||||
import io.element.android.tests.testutils.testCoroutineDispatchers
|
import io.element.android.tests.testutils.testCoroutineDispatchers
|
||||||
import io.element.android.tests.testutils.waitForPredicate
|
|
||||||
import kotlinx.collections.immutable.persistentListOf
|
import kotlinx.collections.immutable.persistentListOf
|
||||||
import kotlinx.coroutines.delay
|
import kotlinx.coroutines.delay
|
||||||
import kotlinx.coroutines.test.TestScope
|
import kotlinx.coroutines.test.TestScope
|
||||||
|
|
@ -295,12 +293,10 @@ class TimelinePresenterTest {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun `present - PollAnswerSelected event calls into rust room api and analytics`() = runTest {
|
fun `present - PollAnswerSelected event`() = runTest {
|
||||||
val room = FakeMatrixRoom()
|
val sendPollResponseAction = FakeSendPollResponseAction()
|
||||||
val analyticsService = FakeAnalyticsService()
|
|
||||||
val presenter = createTimelinePresenter(
|
val presenter = createTimelinePresenter(
|
||||||
room = room,
|
sendPollResponseAction = sendPollResponseAction,
|
||||||
analyticsService = analyticsService,
|
|
||||||
)
|
)
|
||||||
moleculeFlow(RecompositionMode.Immediate) {
|
moleculeFlow(RecompositionMode.Immediate) {
|
||||||
presenter.present()
|
presenter.present()
|
||||||
|
|
@ -309,34 +305,23 @@ class TimelinePresenterTest {
|
||||||
initialState.eventSink.invoke(TimelineEvents.PollAnswerSelected(AN_EVENT_ID, "anAnswerId"))
|
initialState.eventSink.invoke(TimelineEvents.PollAnswerSelected(AN_EVENT_ID, "anAnswerId"))
|
||||||
}
|
}
|
||||||
delay(1)
|
delay(1)
|
||||||
assertThat(room.sendPollResponseInvocations.size).isEqualTo(1)
|
sendPollResponseAction.verifyExecutionCount(1)
|
||||||
assertThat(room.sendPollResponseInvocations.first().answers).isEqualTo(listOf("anAnswerId"))
|
|
||||||
assertThat(room.sendPollResponseInvocations.first().pollStartId).isEqualTo(AN_EVENT_ID)
|
|
||||||
assertThat(analyticsService.capturedEvents.size).isEqualTo(1)
|
|
||||||
assertThat(analyticsService.capturedEvents.last()).isEqualTo(PollVote())
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun `present - PollEndClicked event calls into rust room api and analytics`() = runTest {
|
fun `present - PollEndClicked event`() = runTest {
|
||||||
val room = FakeMatrixRoom()
|
val endPollAction = FakeEndPollAction()
|
||||||
val analyticsService = FakeAnalyticsService()
|
|
||||||
val presenter = createTimelinePresenter(
|
val presenter = createTimelinePresenter(
|
||||||
room = room,
|
endPollAction = endPollAction,
|
||||||
analyticsService = analyticsService,
|
|
||||||
)
|
)
|
||||||
moleculeFlow(RecompositionMode.Immediate) {
|
moleculeFlow(RecompositionMode.Immediate) {
|
||||||
presenter.present()
|
presenter.present()
|
||||||
}.test {
|
}.test {
|
||||||
val initialState = awaitItem()
|
val initialState = awaitItem()
|
||||||
initialState.eventSink(TimelineEvents.PollEndClicked(aMessageEvent().eventId!!))
|
initialState.eventSink.invoke(TimelineEvents.PollEndClicked(AN_EVENT_ID))
|
||||||
waitForPredicate { room.endPollInvocations.size == 1 }
|
|
||||||
cancelAndIgnoreRemainingEvents()
|
|
||||||
assertThat(room.endPollInvocations.size).isEqualTo(1)
|
|
||||||
assertThat(room.endPollInvocations.first().pollStartId).isEqualTo(AN_EVENT_ID)
|
|
||||||
assertThat(room.endPollInvocations.first().text).isEqualTo("The poll with event id: \$anEventId has ended.")
|
|
||||||
assertThat(analyticsService.capturedEvents.size).isEqualTo(1)
|
|
||||||
assertThat(analyticsService.capturedEvents.last()).isEqualTo(PollEnd())
|
|
||||||
}
|
}
|
||||||
|
delay(1)
|
||||||
|
endPollAction.verifyExecutionCount(1)
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
|
|
@ -379,36 +364,21 @@ class TimelinePresenterTest {
|
||||||
timelineItemsFactory: TimelineItemsFactory = aTimelineItemsFactory(),
|
timelineItemsFactory: TimelineItemsFactory = aTimelineItemsFactory(),
|
||||||
redactedVoiceMessageManager: RedactedVoiceMessageManager = FakeRedactedVoiceMessageManager(),
|
redactedVoiceMessageManager: RedactedVoiceMessageManager = FakeRedactedVoiceMessageManager(),
|
||||||
messagesNavigator: FakeMessagesNavigator = FakeMessagesNavigator(),
|
messagesNavigator: FakeMessagesNavigator = FakeMessagesNavigator(),
|
||||||
): TimelinePresenter {
|
endPollAction: EndPollAction = FakeEndPollAction(),
|
||||||
|
sendPollResponseAction: SendPollResponseAction = FakeSendPollResponseAction(),
|
||||||
|
): TimelinePresenter {
|
||||||
return TimelinePresenter(
|
return TimelinePresenter(
|
||||||
timelineItemsFactory = timelineItemsFactory,
|
timelineItemsFactory = timelineItemsFactory,
|
||||||
room = FakeMatrixRoom(matrixTimeline = timeline),
|
room = FakeMatrixRoom(matrixTimeline = timeline),
|
||||||
dispatchers = testCoroutineDispatchers(),
|
dispatchers = testCoroutineDispatchers(),
|
||||||
appScope = this,
|
appScope = this,
|
||||||
navigator = messagesNavigator,
|
navigator = messagesNavigator,
|
||||||
analyticsService = FakeAnalyticsService(),
|
|
||||||
encryptionService = FakeEncryptionService(),
|
encryptionService = FakeEncryptionService(),
|
||||||
verificationService = FakeSessionVerificationService(),
|
verificationService = FakeSessionVerificationService(),
|
||||||
featureFlagService = FakeFeatureFlagService(),
|
featureFlagService = FakeFeatureFlagService(),
|
||||||
redactedVoiceMessageManager = redactedVoiceMessageManager,
|
redactedVoiceMessageManager = redactedVoiceMessageManager,
|
||||||
)
|
endPollAction = endPollAction,
|
||||||
}
|
sendPollResponseAction = sendPollResponseAction,
|
||||||
|
|
||||||
private fun TestScope.createTimelinePresenter(
|
|
||||||
room: MatrixRoom,
|
|
||||||
analyticsService: FakeAnalyticsService = FakeAnalyticsService(),
|
|
||||||
): TimelinePresenter {
|
|
||||||
return TimelinePresenter(
|
|
||||||
timelineItemsFactory = aTimelineItemsFactory(),
|
|
||||||
room = room,
|
|
||||||
dispatchers = testCoroutineDispatchers(),
|
|
||||||
appScope = this,
|
|
||||||
navigator = FakeMessagesNavigator(),
|
|
||||||
analyticsService = analyticsService,
|
|
||||||
encryptionService = FakeEncryptionService(),
|
|
||||||
verificationService = FakeSessionVerificationService(),
|
|
||||||
featureFlagService = FakeFeatureFlagService(),
|
|
||||||
redactedVoiceMessageManager = FakeRedactedVoiceMessageManager(),
|
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,328 +0,0 @@
|
||||||
/*
|
|
||||||
* Copyright (c) 2023 New Vector Ltd
|
|
||||||
*
|
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
* you may not use this file except in compliance with the License.
|
|
||||||
* You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
* See the License for the specific language governing permissions and
|
|
||||||
* limitations under the License.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package io.element.android.features.messages.impl.timeline.factories.event
|
|
||||||
|
|
||||||
import com.google.common.truth.Truth
|
|
||||||
import io.element.android.features.messages.impl.timeline.model.event.TimelineItemPollContent
|
|
||||||
import io.element.android.features.poll.api.pollcontent.PollAnswerItem
|
|
||||||
import io.element.android.libraries.featureflag.api.FeatureFlags
|
|
||||||
import io.element.android.libraries.featureflag.test.FakeFeatureFlagService
|
|
||||||
import io.element.android.libraries.matrix.api.core.EventId
|
|
||||||
import io.element.android.libraries.matrix.api.core.UserId
|
|
||||||
import io.element.android.libraries.matrix.api.poll.PollAnswer
|
|
||||||
import io.element.android.libraries.matrix.api.poll.PollKind
|
|
||||||
import io.element.android.libraries.matrix.api.timeline.item.event.PollContent
|
|
||||||
import io.element.android.libraries.matrix.test.AN_EVENT_ID
|
|
||||||
import io.element.android.libraries.matrix.test.A_USER_ID
|
|
||||||
import io.element.android.libraries.matrix.test.A_USER_ID_10
|
|
||||||
import io.element.android.libraries.matrix.test.A_USER_ID_2
|
|
||||||
import io.element.android.libraries.matrix.test.A_USER_ID_3
|
|
||||||
import io.element.android.libraries.matrix.test.A_USER_ID_4
|
|
||||||
import io.element.android.libraries.matrix.test.A_USER_ID_5
|
|
||||||
import io.element.android.libraries.matrix.test.A_USER_ID_6
|
|
||||||
import io.element.android.libraries.matrix.test.A_USER_ID_7
|
|
||||||
import io.element.android.libraries.matrix.test.A_USER_ID_8
|
|
||||||
import io.element.android.libraries.matrix.test.A_USER_ID_9
|
|
||||||
import io.element.android.libraries.matrix.test.FakeMatrixClient
|
|
||||||
import kotlinx.collections.immutable.ImmutableList
|
|
||||||
import kotlinx.collections.immutable.ImmutableMap
|
|
||||||
import kotlinx.collections.immutable.persistentListOf
|
|
||||||
import kotlinx.collections.immutable.persistentMapOf
|
|
||||||
import kotlinx.collections.immutable.toImmutableMap
|
|
||||||
import kotlinx.coroutines.test.runTest
|
|
||||||
import org.junit.Test
|
|
||||||
|
|
||||||
internal class TimelineItemContentPollFactoryTest {
|
|
||||||
|
|
||||||
private val factory = TimelineItemContentPollFactory(
|
|
||||||
matrixClient = FakeMatrixClient(),
|
|
||||||
featureFlagService = FakeFeatureFlagService(mapOf(FeatureFlags.Polls.key to true)),
|
|
||||||
)
|
|
||||||
|
|
||||||
@Test
|
|
||||||
fun `Disclosed poll - not ended, no votes`() = runTest {
|
|
||||||
Truth.assertThat(factory.create(aPollContent(), eventId = null, eventTimelineItem.isOwn)).isEqualTo(aTimelineItemPollContent())
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
fun `Disclosed poll - not ended, some votes, including one from current user`() = runTest {
|
|
||||||
val votes = MY_USER_WINNING_VOTES.mapKeys { it.key.id }.toImmutableMap()
|
|
||||||
Truth.assertThat(
|
|
||||||
factory.create(aPollContent(votes = votes), eventId = null, eventTimelineItem.isOwn)
|
|
||||||
)
|
|
||||||
.isEqualTo(
|
|
||||||
aTimelineItemPollContent(
|
|
||||||
answerItems = listOf(
|
|
||||||
aPollAnswerItem(answer = A_POLL_ANSWER_1, votesCount = 3, percentage = 0.3f),
|
|
||||||
aPollAnswerItem(answer = A_POLL_ANSWER_2, isSelected = true, votesCount = 6, percentage = 0.6f),
|
|
||||||
aPollAnswerItem(answer = A_POLL_ANSWER_3),
|
|
||||||
aPollAnswerItem(answer = A_POLL_ANSWER_4, votesCount = 1, percentage = 0.1f),
|
|
||||||
),
|
|
||||||
)
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
fun `Disclosed poll - ended, no votes, no winner`() = runTest {
|
|
||||||
Truth.assertThat(
|
|
||||||
factory.create(aPollContent(endTime = 1UL), eventId = null, eventTimelineItem.isOwn)
|
|
||||||
).isEqualTo(
|
|
||||||
aTimelineItemPollContent().let {
|
|
||||||
it.copy(
|
|
||||||
answerItems = it.answerItems.map { answerItem -> answerItem.copy(isEnabled = false) },
|
|
||||||
isEnded = true,
|
|
||||||
)
|
|
||||||
}
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
fun `Disclosed poll - ended, some votes, including one from current user (winner)`() = runTest {
|
|
||||||
val votes = MY_USER_WINNING_VOTES.mapKeys { it.key.id }.toImmutableMap()
|
|
||||||
Truth.assertThat(
|
|
||||||
factory.create(
|
|
||||||
aPollContent(votes = votes, endTime = 1UL),
|
|
||||||
eventId = null,
|
|
||||||
eventTimelineItem.isOwn
|
|
||||||
)
|
|
||||||
)
|
|
||||||
.isEqualTo(
|
|
||||||
aTimelineItemPollContent(
|
|
||||||
answerItems = listOf(
|
|
||||||
aPollAnswerItem(answer = A_POLL_ANSWER_1, isEnabled = false, votesCount = 3, percentage = 0.3f),
|
|
||||||
aPollAnswerItem(answer = A_POLL_ANSWER_2, isSelected = true, isEnabled = false, isWinner = true, votesCount = 6, percentage = 0.6f),
|
|
||||||
aPollAnswerItem(answer = A_POLL_ANSWER_3, isEnabled = false),
|
|
||||||
aPollAnswerItem(answer = A_POLL_ANSWER_4, isEnabled = false, votesCount = 1, percentage = 0.1f),
|
|
||||||
),
|
|
||||||
isEnded = true,
|
|
||||||
)
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
fun `Disclosed poll - ended, some votes, including one from current user (not winner) and two winning votes`() = runTest {
|
|
||||||
val votes = OTHER_WINNING_VOTES.mapKeys { it.key.id }.toImmutableMap()
|
|
||||||
Truth.assertThat(
|
|
||||||
factory.create(
|
|
||||||
aPollContent(votes = votes, endTime = 1UL),
|
|
||||||
eventId = null,
|
|
||||||
eventTimelineItem.isOwn
|
|
||||||
)
|
|
||||||
)
|
|
||||||
.isEqualTo(
|
|
||||||
aTimelineItemPollContent(
|
|
||||||
answerItems = listOf(
|
|
||||||
aPollAnswerItem(answer = A_POLL_ANSWER_1, isEnabled = false, isWinner = true, votesCount = 4, percentage = 0.4f),
|
|
||||||
aPollAnswerItem(answer = A_POLL_ANSWER_2, isSelected = true, isEnabled = false, votesCount = 2, percentage = 0.2f),
|
|
||||||
aPollAnswerItem(answer = A_POLL_ANSWER_3, isEnabled = false),
|
|
||||||
aPollAnswerItem(answer = A_POLL_ANSWER_4, isEnabled = false, isWinner = true, votesCount = 4, percentage = 0.4f),
|
|
||||||
),
|
|
||||||
isEnded = true,
|
|
||||||
)
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
fun `Undisclosed poll - not ended, no votes`() = runTest {
|
|
||||||
Truth.assertThat(
|
|
||||||
factory.create(
|
|
||||||
aPollContent(PollKind.Undisclosed).copy(),
|
|
||||||
eventId = null,
|
|
||||||
eventTimelineItem.isOwn
|
|
||||||
)
|
|
||||||
).isEqualTo(
|
|
||||||
aTimelineItemPollContent(pollKind = PollKind.Undisclosed).let {
|
|
||||||
it.copy(answerItems = it.answerItems.map { answerItem -> answerItem.copy(isDisclosed = false) })
|
|
||||||
}
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
fun `Undisclosed poll - not ended, some votes, including one from current user`() = runTest {
|
|
||||||
val votes = MY_USER_WINNING_VOTES.mapKeys { it.key.id }.toImmutableMap()
|
|
||||||
Truth.assertThat(
|
|
||||||
factory.create(
|
|
||||||
aPollContent(pollKind = PollKind.Undisclosed, votes = votes),
|
|
||||||
eventId = null,
|
|
||||||
eventTimelineItem.isOwn
|
|
||||||
)
|
|
||||||
)
|
|
||||||
.isEqualTo(
|
|
||||||
aTimelineItemPollContent(
|
|
||||||
pollKind = PollKind.Undisclosed,
|
|
||||||
answerItems = listOf(
|
|
||||||
aPollAnswerItem(answer = A_POLL_ANSWER_1, isDisclosed = false, votesCount = 3, percentage = 0.3f),
|
|
||||||
aPollAnswerItem(answer = A_POLL_ANSWER_2, isDisclosed = false, isSelected = true, votesCount = 6, percentage = 0.6f),
|
|
||||||
aPollAnswerItem(answer = A_POLL_ANSWER_3, isDisclosed = false),
|
|
||||||
aPollAnswerItem(answer = A_POLL_ANSWER_4, isDisclosed = false, votesCount = 1, percentage = 0.1f),
|
|
||||||
),
|
|
||||||
)
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
fun `Undisclosed poll - ended, no votes, no winner`() = runTest {
|
|
||||||
Truth.assertThat(
|
|
||||||
factory.create(
|
|
||||||
aPollContent(pollKind = PollKind.Undisclosed, endTime = 1UL),
|
|
||||||
eventId = null,
|
|
||||||
eventTimelineItem.isOwn
|
|
||||||
)
|
|
||||||
).isEqualTo(
|
|
||||||
aTimelineItemPollContent().let {
|
|
||||||
it.copy(
|
|
||||||
pollKind = PollKind.Undisclosed,
|
|
||||||
answerItems = it.answerItems.map { answerItem ->
|
|
||||||
answerItem.copy(isDisclosed = true, isEnabled = false, isWinner = false)
|
|
||||||
},
|
|
||||||
isEnded = true,
|
|
||||||
)
|
|
||||||
}
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
fun `Undisclosed poll - ended, some votes, including one from current user (winner)`() = runTest {
|
|
||||||
val votes = MY_USER_WINNING_VOTES.mapKeys { it.key.id }.toImmutableMap()
|
|
||||||
Truth.assertThat(
|
|
||||||
factory.create(
|
|
||||||
aPollContent(pollKind = PollKind.Undisclosed, votes = votes, endTime = 1UL),
|
|
||||||
eventId = null,
|
|
||||||
eventTimelineItem.isOwn
|
|
||||||
)
|
|
||||||
)
|
|
||||||
.isEqualTo(
|
|
||||||
aTimelineItemPollContent(
|
|
||||||
pollKind = PollKind.Undisclosed,
|
|
||||||
answerItems = listOf(
|
|
||||||
aPollAnswerItem(answer = A_POLL_ANSWER_1, isEnabled = false, votesCount = 3, percentage = 0.3f),
|
|
||||||
aPollAnswerItem(answer = A_POLL_ANSWER_2, isSelected = true, isEnabled = false, isWinner = true, votesCount = 6, percentage = 0.6f),
|
|
||||||
aPollAnswerItem(answer = A_POLL_ANSWER_3, isEnabled = false),
|
|
||||||
aPollAnswerItem(answer = A_POLL_ANSWER_4, isEnabled = false, votesCount = 1, percentage = 0.1f),
|
|
||||||
),
|
|
||||||
isEnded = true,
|
|
||||||
)
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
fun `Undisclosed poll - ended, some votes, including one from current user (not winner) and two winning votes`() = runTest {
|
|
||||||
val votes = OTHER_WINNING_VOTES.mapKeys { it.key.id }.toImmutableMap()
|
|
||||||
Truth.assertThat(
|
|
||||||
factory.create(
|
|
||||||
aPollContent(PollKind.Undisclosed).copy(votes = votes, endTime = 1UL),
|
|
||||||
eventId = null,
|
|
||||||
eventTimelineItem.isOwn
|
|
||||||
)
|
|
||||||
)
|
|
||||||
.isEqualTo(
|
|
||||||
aTimelineItemPollContent(
|
|
||||||
pollKind = PollKind.Undisclosed,
|
|
||||||
answerItems = listOf(
|
|
||||||
aPollAnswerItem(A_POLL_ANSWER_1, isEnabled = false, isWinner = true, votesCount = 4, percentage = 0.4f),
|
|
||||||
aPollAnswerItem(A_POLL_ANSWER_2, isSelected = true, isEnabled = false, votesCount = 2, percentage = 0.2f),
|
|
||||||
aPollAnswerItem(A_POLL_ANSWER_3, isEnabled = false),
|
|
||||||
aPollAnswerItem(A_POLL_ANSWER_4, isEnabled = false, isWinner = true, votesCount = 4, percentage = 0.4f),
|
|
||||||
),
|
|
||||||
isEnded = true,
|
|
||||||
)
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
fun `eventId is populated`() = runTest {
|
|
||||||
Truth.assertThat(factory.create(aPollContent(), eventId = null, eventTimelineItem.isOwn))
|
|
||||||
.isEqualTo(aTimelineItemPollContent(eventId = null))
|
|
||||||
|
|
||||||
Truth.assertThat(factory.create(
|
|
||||||
aPollContent(),
|
|
||||||
eventId = AN_EVENT_ID,
|
|
||||||
eventTimelineItem.isOwn
|
|
||||||
))
|
|
||||||
.isEqualTo(aTimelineItemPollContent(eventId = AN_EVENT_ID))
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun aPollContent(
|
|
||||||
pollKind: PollKind = PollKind.Disclosed,
|
|
||||||
votes: ImmutableMap<String, ImmutableList<UserId>> = persistentMapOf(),
|
|
||||||
endTime: ULong? = null,
|
|
||||||
): PollContent = PollContent(
|
|
||||||
question = A_POLL_QUESTION,
|
|
||||||
kind = pollKind,
|
|
||||||
maxSelections = 1UL,
|
|
||||||
answers = persistentListOf(A_POLL_ANSWER_1, A_POLL_ANSWER_2, A_POLL_ANSWER_3, A_POLL_ANSWER_4),
|
|
||||||
votes = votes,
|
|
||||||
endTime = endTime,
|
|
||||||
)
|
|
||||||
|
|
||||||
private fun aTimelineItemPollContent(
|
|
||||||
eventId: EventId? = null,
|
|
||||||
pollKind: PollKind = PollKind.Disclosed,
|
|
||||||
answerItems: List<PollAnswerItem> = listOf(
|
|
||||||
aPollAnswerItem(A_POLL_ANSWER_1),
|
|
||||||
aPollAnswerItem(A_POLL_ANSWER_2),
|
|
||||||
aPollAnswerItem(A_POLL_ANSWER_3),
|
|
||||||
aPollAnswerItem(A_POLL_ANSWER_4),
|
|
||||||
),
|
|
||||||
isEnded: Boolean = false,
|
|
||||||
) = TimelineItemPollContent(
|
|
||||||
eventId = eventId,
|
|
||||||
question = A_POLL_QUESTION,
|
|
||||||
answerItems = answerItems,
|
|
||||||
pollKind = pollKind,
|
|
||||||
isEnded = isEnded,
|
|
||||||
)
|
|
||||||
|
|
||||||
private fun aPollAnswerItem(
|
|
||||||
answer: PollAnswer,
|
|
||||||
isSelected: Boolean = false,
|
|
||||||
isEnabled: Boolean = true,
|
|
||||||
isWinner: Boolean = false,
|
|
||||||
isDisclosed: Boolean = true,
|
|
||||||
votesCount: Int = 0,
|
|
||||||
percentage: Float = 0f,
|
|
||||||
) = PollAnswerItem(
|
|
||||||
answer = answer,
|
|
||||||
isSelected = isSelected,
|
|
||||||
isEnabled = isEnabled,
|
|
||||||
isWinner = isWinner,
|
|
||||||
isDisclosed = isDisclosed,
|
|
||||||
votesCount = votesCount,
|
|
||||||
percentage = percentage,
|
|
||||||
)
|
|
||||||
|
|
||||||
private companion object TestData {
|
|
||||||
private const val A_POLL_QUESTION = "What is your favorite food?"
|
|
||||||
private val A_POLL_ANSWER_1 = PollAnswer("id_1", "Pizza")
|
|
||||||
private val A_POLL_ANSWER_2 = PollAnswer("id_2", "Pasta")
|
|
||||||
private val A_POLL_ANSWER_3 = PollAnswer("id_3", "French Fries")
|
|
||||||
private val A_POLL_ANSWER_4 = PollAnswer("id_4", "Hamburger")
|
|
||||||
|
|
||||||
private val MY_USER_WINNING_VOTES = persistentMapOf(
|
|
||||||
A_POLL_ANSWER_1 to persistentListOf(A_USER_ID_2, A_USER_ID_3, A_USER_ID_4),
|
|
||||||
A_POLL_ANSWER_2 to persistentListOf(A_USER_ID /* my vote */, A_USER_ID_5, A_USER_ID_6, A_USER_ID_7, A_USER_ID_8, A_USER_ID_9), // winner
|
|
||||||
A_POLL_ANSWER_3 to persistentListOf(),
|
|
||||||
A_POLL_ANSWER_4 to persistentListOf(A_USER_ID_10),
|
|
||||||
)
|
|
||||||
private val OTHER_WINNING_VOTES = persistentMapOf(
|
|
||||||
A_POLL_ANSWER_1 to persistentListOf(A_USER_ID_2, A_USER_ID_3, A_USER_ID_4, A_USER_ID_5), // winner
|
|
||||||
A_POLL_ANSWER_2 to persistentListOf(A_USER_ID /* my vote */, A_USER_ID_6),
|
|
||||||
A_POLL_ANSWER_3 to persistentListOf(),
|
|
||||||
A_POLL_ANSWER_4 to persistentListOf(A_USER_ID_7, A_USER_ID_8, A_USER_ID_9, A_USER_ID_10), // winner
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -52,6 +52,8 @@ dependencies {
|
||||||
testImplementation(projects.services.analytics.test)
|
testImplementation(projects.services.analytics.test)
|
||||||
testImplementation(projects.features.messages.test)
|
testImplementation(projects.features.messages.test)
|
||||||
testImplementation(projects.tests.testutils)
|
testImplementation(projects.tests.testutils)
|
||||||
|
testImplementation(projects.libraries.dateformatter.test)
|
||||||
|
testImplementation(projects.features.poll.test)
|
||||||
|
|
||||||
ksp(libs.showkase.processor)
|
ksp(libs.showkase.processor)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,55 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2023 New Vector Ltd
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package io.element.android.features.poll.impl
|
||||||
|
|
||||||
|
import io.element.android.libraries.matrix.api.core.EventId
|
||||||
|
import io.element.android.libraries.matrix.api.poll.PollAnswer
|
||||||
|
import io.element.android.libraries.matrix.api.timeline.MatrixTimelineItem
|
||||||
|
import io.element.android.libraries.matrix.api.timeline.item.event.PollContent
|
||||||
|
import io.element.android.libraries.matrix.test.timeline.FakeMatrixTimeline
|
||||||
|
import io.element.android.libraries.matrix.test.timeline.aPollContent
|
||||||
|
import io.element.android.libraries.matrix.test.timeline.anEventTimelineItem
|
||||||
|
import kotlinx.collections.immutable.persistentListOf
|
||||||
|
|
||||||
|
fun aPollTimeline(
|
||||||
|
polls: Map<EventId, PollContent> = emptyMap(),
|
||||||
|
): FakeMatrixTimeline {
|
||||||
|
return FakeMatrixTimeline(
|
||||||
|
initialTimelineItems = polls.map { entry ->
|
||||||
|
MatrixTimelineItem.Event(
|
||||||
|
entry.key.hashCode().toLong(),
|
||||||
|
anEventTimelineItem(
|
||||||
|
eventId = entry.key,
|
||||||
|
content = entry.value,
|
||||||
|
)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun anOngoingPollContent() = aPollContent(
|
||||||
|
question = "Do you like polls?",
|
||||||
|
answers = persistentListOf(
|
||||||
|
PollAnswer("1", "Yes"),
|
||||||
|
PollAnswer("2", "No"),
|
||||||
|
PollAnswer("2", "Maybe"),
|
||||||
|
),
|
||||||
|
)
|
||||||
|
|
||||||
|
fun anEndedPollContent() = anOngoingPollContent().copy(
|
||||||
|
endTime = 1702400215U
|
||||||
|
)
|
||||||
|
|
@ -25,21 +25,17 @@ import im.vector.app.features.analytics.plan.Composer
|
||||||
import im.vector.app.features.analytics.plan.PollCreation
|
import im.vector.app.features.analytics.plan.PollCreation
|
||||||
import io.element.android.features.messages.test.FakeMessageComposerContext
|
import io.element.android.features.messages.test.FakeMessageComposerContext
|
||||||
import io.element.android.features.poll.api.create.CreatePollMode
|
import io.element.android.features.poll.api.create.CreatePollMode
|
||||||
|
import io.element.android.features.poll.impl.aPollTimeline
|
||||||
|
import io.element.android.features.poll.impl.anOngoingPollContent
|
||||||
import io.element.android.features.poll.impl.data.PollRepository
|
import io.element.android.features.poll.impl.data.PollRepository
|
||||||
import io.element.android.libraries.matrix.api.poll.PollAnswer
|
|
||||||
import io.element.android.libraries.matrix.api.poll.PollKind
|
import io.element.android.libraries.matrix.api.poll.PollKind
|
||||||
import io.element.android.libraries.matrix.api.room.MatrixRoom
|
import io.element.android.libraries.matrix.api.room.MatrixRoom
|
||||||
import io.element.android.libraries.matrix.api.timeline.MatrixTimelineItem
|
|
||||||
import io.element.android.libraries.matrix.api.timeline.item.event.PollContent
|
import io.element.android.libraries.matrix.api.timeline.item.event.PollContent
|
||||||
import io.element.android.libraries.matrix.test.AN_EVENT_ID
|
import io.element.android.libraries.matrix.test.AN_EVENT_ID
|
||||||
import io.element.android.libraries.matrix.test.room.SavePollInvocation
|
|
||||||
import io.element.android.libraries.matrix.test.room.FakeMatrixRoom
|
import io.element.android.libraries.matrix.test.room.FakeMatrixRoom
|
||||||
import io.element.android.libraries.matrix.test.room.aPollContent
|
import io.element.android.libraries.matrix.test.room.SavePollInvocation
|
||||||
import io.element.android.libraries.matrix.test.room.anEventTimelineItem
|
|
||||||
import io.element.android.libraries.matrix.test.timeline.FakeMatrixTimeline
|
|
||||||
import io.element.android.services.analytics.test.FakeAnalyticsService
|
import io.element.android.services.analytics.test.FakeAnalyticsService
|
||||||
import io.element.android.tests.testutils.WarmUpRule
|
import io.element.android.tests.testutils.WarmUpRule
|
||||||
import kotlinx.collections.immutable.persistentListOf
|
|
||||||
import kotlinx.coroutines.delay
|
import kotlinx.coroutines.delay
|
||||||
import kotlinx.coroutines.test.runTest
|
import kotlinx.coroutines.test.runTest
|
||||||
import org.junit.Rule
|
import org.junit.Rule
|
||||||
|
|
@ -52,8 +48,12 @@ class CreatePollPresenterTest {
|
||||||
|
|
||||||
private val pollEventId = AN_EVENT_ID
|
private val pollEventId = AN_EVENT_ID
|
||||||
private var navUpInvocationsCount = 0
|
private var navUpInvocationsCount = 0
|
||||||
private val existingPoll = anExistingPoll()
|
private val existingPoll = anOngoingPollContent()
|
||||||
private val fakeMatrixRoom = createFakeMatrixRoom(existingPoll)
|
private val fakeMatrixRoom = FakeMatrixRoom(
|
||||||
|
matrixTimeline = aPollTimeline(
|
||||||
|
mapOf(pollEventId to existingPoll)
|
||||||
|
)
|
||||||
|
)
|
||||||
private val fakeAnalyticsService = FakeAnalyticsService()
|
private val fakeAnalyticsService = FakeAnalyticsService()
|
||||||
private val fakeMessageComposerContext = FakeMessageComposerContext()
|
private val fakeMessageComposerContext = FakeMessageComposerContext()
|
||||||
|
|
||||||
|
|
@ -80,7 +80,9 @@ class CreatePollPresenterTest {
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun `in edit mode, if poll doesn't exist, error is tracked and screen is closed`() = runTest {
|
fun `in edit mode, if poll doesn't exist, error is tracked and screen is closed`() = runTest {
|
||||||
val room = createFakeMatrixRoom(existingPoll = null)
|
val room = FakeMatrixRoom(
|
||||||
|
matrixTimeline = aPollTimeline()
|
||||||
|
)
|
||||||
val presenter = createCreatePollPresenter(mode = CreatePollMode.EditPoll(AN_EVENT_ID), room = room)
|
val presenter = createCreatePollPresenter(mode = CreatePollMode.EditPoll(AN_EVENT_ID), room = room)
|
||||||
moleculeFlow(RecompositionMode.Immediate) {
|
moleculeFlow(RecompositionMode.Immediate) {
|
||||||
presenter.present()
|
presenter.present()
|
||||||
|
|
@ -475,7 +477,6 @@ class CreatePollPresenterTest {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
private suspend fun TurbineTestContext<CreatePollState>.awaitDefaultItem() =
|
private suspend fun TurbineTestContext<CreatePollState>.awaitDefaultItem() =
|
||||||
awaitItem().apply {
|
awaitItem().apply {
|
||||||
Truth.assertThat(canSave).isFalse()
|
Truth.assertThat(canSave).isFalse()
|
||||||
|
|
@ -518,35 +519,8 @@ class CreatePollPresenterTest {
|
||||||
navigateUp = { navUpInvocationsCount++ },
|
navigateUp = { navUpInvocationsCount++ },
|
||||||
mode = mode,
|
mode = mode,
|
||||||
)
|
)
|
||||||
|
|
||||||
private fun createFakeMatrixRoom(
|
|
||||||
existingPoll: PollContent? = anExistingPoll(),
|
|
||||||
) = FakeMatrixRoom(
|
|
||||||
matrixTimeline = FakeMatrixTimeline(
|
|
||||||
initialTimelineItems = existingPoll?.let {
|
|
||||||
listOf(
|
|
||||||
MatrixTimelineItem.Event(
|
|
||||||
0,
|
|
||||||
anEventTimelineItem(
|
|
||||||
eventId = pollEventId,
|
|
||||||
content = it,
|
|
||||||
)
|
|
||||||
)
|
|
||||||
)
|
|
||||||
}.orEmpty()
|
|
||||||
)
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun anExistingPoll() = aPollContent(
|
|
||||||
question = "Do you like polls?",
|
|
||||||
answers = persistentListOf(
|
|
||||||
PollAnswer("1", "Yes"),
|
|
||||||
PollAnswer("2", "No"),
|
|
||||||
PollAnswer("2", "Maybe"),
|
|
||||||
),
|
|
||||||
)
|
|
||||||
|
|
||||||
private fun PollContent.expectedAnswersState() = answers.map { answer ->
|
private fun PollContent.expectedAnswersState() = answers.map { answer ->
|
||||||
Answer(
|
Answer(
|
||||||
text = answer.text,
|
text = answer.text,
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,169 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2023 New Vector Ltd
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package io.element.android.features.poll.impl.history
|
||||||
|
|
||||||
|
import app.cash.molecule.RecompositionMode
|
||||||
|
import app.cash.molecule.moleculeFlow
|
||||||
|
import app.cash.turbine.test
|
||||||
|
import com.google.common.truth.Truth.assertThat
|
||||||
|
import io.element.android.features.poll.api.actions.EndPollAction
|
||||||
|
import io.element.android.features.poll.api.actions.SendPollResponseAction
|
||||||
|
import io.element.android.features.poll.impl.aPollTimeline
|
||||||
|
import io.element.android.features.poll.impl.anEndedPollContent
|
||||||
|
import io.element.android.features.poll.impl.anOngoingPollContent
|
||||||
|
import io.element.android.features.poll.impl.history.model.PollHistoryFilter
|
||||||
|
import io.element.android.features.poll.impl.history.model.PollHistoryItemsFactory
|
||||||
|
import io.element.android.features.poll.impl.model.DefaultPollContentStateFactory
|
||||||
|
import io.element.android.features.poll.test.actions.FakeEndPollAction
|
||||||
|
import io.element.android.features.poll.test.actions.FakeSendPollResponseAction
|
||||||
|
import io.element.android.libraries.dateformatter.test.FakeDaySeparatorFormatter
|
||||||
|
import io.element.android.libraries.matrix.api.room.MatrixRoom
|
||||||
|
import io.element.android.libraries.matrix.test.AN_EVENT_ID
|
||||||
|
import io.element.android.libraries.matrix.test.AN_EVENT_ID_2
|
||||||
|
import io.element.android.libraries.matrix.test.FakeMatrixClient
|
||||||
|
import io.element.android.libraries.matrix.test.room.FakeMatrixRoom
|
||||||
|
import io.element.android.tests.testutils.WarmUpRule
|
||||||
|
import io.element.android.tests.testutils.consumeItemsUntilPredicate
|
||||||
|
import io.element.android.tests.testutils.testCoroutineDispatchers
|
||||||
|
import kotlinx.coroutines.CoroutineScope
|
||||||
|
import kotlinx.coroutines.ExperimentalCoroutinesApi
|
||||||
|
import kotlinx.coroutines.test.TestScope
|
||||||
|
import kotlinx.coroutines.test.runCurrent
|
||||||
|
import kotlinx.coroutines.test.runTest
|
||||||
|
import org.junit.Rule
|
||||||
|
import org.junit.Test
|
||||||
|
|
||||||
|
class PollHistoryPresenterTest {
|
||||||
|
|
||||||
|
@get:Rule
|
||||||
|
val warmUpRule = WarmUpRule()
|
||||||
|
|
||||||
|
private val room = FakeMatrixRoom(
|
||||||
|
matrixTimeline = aPollTimeline(
|
||||||
|
polls = mapOf(
|
||||||
|
AN_EVENT_ID to anOngoingPollContent(),
|
||||||
|
AN_EVENT_ID_2 to anEndedPollContent()
|
||||||
|
)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun `present - initial states`() = runTest {
|
||||||
|
val presenter = createPollHistoryPresenter(room = room)
|
||||||
|
moleculeFlow(RecompositionMode.Immediate) {
|
||||||
|
presenter.present()
|
||||||
|
}.test {
|
||||||
|
awaitItem().also { state ->
|
||||||
|
assertThat(state.activeFilter).isEqualTo(PollHistoryFilter.ONGOING)
|
||||||
|
assertThat(state.pollHistoryItems.size).isEqualTo(0)
|
||||||
|
assertThat(state.isLoading).isTrue()
|
||||||
|
assertThat(state.hasMoreToLoad).isTrue()
|
||||||
|
}
|
||||||
|
consumeItemsUntilPredicate {
|
||||||
|
it.pollHistoryItems.size == 2
|
||||||
|
}.last().also { state ->
|
||||||
|
assertThat(state.pollHistoryItems.size).isEqualTo(2)
|
||||||
|
assertThat(state.pollHistoryItems.ongoing).hasSize(1)
|
||||||
|
assertThat(state.pollHistoryItems.past).hasSize(1)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun `present - change filter scenario`() = runTest {
|
||||||
|
val presenter = createPollHistoryPresenter(room = room)
|
||||||
|
moleculeFlow(RecompositionMode.Immediate) {
|
||||||
|
presenter.present()
|
||||||
|
}.test {
|
||||||
|
awaitItem().also { state ->
|
||||||
|
assertThat(state.activeFilter).isEqualTo(PollHistoryFilter.ONGOING)
|
||||||
|
state.eventSink(PollHistoryEvents.OnFilterSelected(PollHistoryFilter.PAST))
|
||||||
|
}
|
||||||
|
consumeItemsUntilPredicate {
|
||||||
|
it.activeFilter == PollHistoryFilter.PAST
|
||||||
|
}.last().also { state ->
|
||||||
|
state.eventSink(PollHistoryEvents.OnFilterSelected(PollHistoryFilter.ONGOING))
|
||||||
|
}
|
||||||
|
consumeItemsUntilPredicate {
|
||||||
|
it.activeFilter == PollHistoryFilter.ONGOING
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@OptIn(ExperimentalCoroutinesApi::class)
|
||||||
|
@Test
|
||||||
|
fun `present - poll actions scenario`() = runTest {
|
||||||
|
val sendPollResponseAction = FakeSendPollResponseAction()
|
||||||
|
val endPollAction = FakeEndPollAction()
|
||||||
|
val presenter = createPollHistoryPresenter(
|
||||||
|
sendPollResponseAction = sendPollResponseAction,
|
||||||
|
endPollAction = endPollAction
|
||||||
|
)
|
||||||
|
moleculeFlow(RecompositionMode.Immediate) {
|
||||||
|
presenter.present()
|
||||||
|
}.test {
|
||||||
|
val state = awaitItem()
|
||||||
|
state.eventSink(PollHistoryEvents.PollEndClicked(AN_EVENT_ID))
|
||||||
|
runCurrent()
|
||||||
|
endPollAction.verifyExecutionCount(1)
|
||||||
|
state.eventSink(PollHistoryEvents.PollAnswerSelected(AN_EVENT_ID, "answer"))
|
||||||
|
runCurrent()
|
||||||
|
sendPollResponseAction.verifyExecutionCount(1)
|
||||||
|
cancelAndConsumeRemainingEvents()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun `present - load more scenario`() = runTest {
|
||||||
|
val presenter = createPollHistoryPresenter(room = room)
|
||||||
|
moleculeFlow(RecompositionMode.Immediate) {
|
||||||
|
presenter.present()
|
||||||
|
}.test {
|
||||||
|
consumeItemsUntilPredicate {
|
||||||
|
it.pollHistoryItems.size == 2 && !it.isLoading
|
||||||
|
}.last().also { state ->
|
||||||
|
state.eventSink(PollHistoryEvents.LoadMore)
|
||||||
|
}
|
||||||
|
consumeItemsUntilPredicate {
|
||||||
|
it.isLoading
|
||||||
|
}
|
||||||
|
consumeItemsUntilPredicate {
|
||||||
|
!it.isLoading
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun TestScope.createPollHistoryPresenter(
|
||||||
|
room: MatrixRoom = FakeMatrixRoom(),
|
||||||
|
appCoroutineScope: CoroutineScope = this,
|
||||||
|
endPollAction: EndPollAction = FakeEndPollAction(),
|
||||||
|
sendPollResponseAction: SendPollResponseAction = FakeSendPollResponseAction(),
|
||||||
|
pollHistoryItemFactory: PollHistoryItemsFactory = PollHistoryItemsFactory(
|
||||||
|
pollContentStateFactory = DefaultPollContentStateFactory(FakeMatrixClient()),
|
||||||
|
daySeparatorFormatter = FakeDaySeparatorFormatter(),
|
||||||
|
dispatchers = testCoroutineDispatchers(),
|
||||||
|
),
|
||||||
|
): PollHistoryPresenter {
|
||||||
|
return PollHistoryPresenter(
|
||||||
|
room = room,
|
||||||
|
appCoroutineScope = appCoroutineScope,
|
||||||
|
sendPollResponseAction = sendPollResponseAction,
|
||||||
|
endPollAction = endPollAction,
|
||||||
|
pollHistoryItemFactory = pollHistoryItemFactory,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,288 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2023 New Vector Ltd
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package io.element.android.features.poll.impl.pollcontent
|
||||||
|
|
||||||
|
import com.google.common.truth.Truth.assertThat
|
||||||
|
import io.element.android.features.poll.api.pollcontent.PollAnswerItem
|
||||||
|
import io.element.android.features.poll.api.pollcontent.PollContentState
|
||||||
|
import io.element.android.features.poll.impl.model.DefaultPollContentStateFactory
|
||||||
|
import io.element.android.libraries.matrix.api.core.EventId
|
||||||
|
import io.element.android.libraries.matrix.api.core.UserId
|
||||||
|
import io.element.android.libraries.matrix.api.poll.PollAnswer
|
||||||
|
import io.element.android.libraries.matrix.api.poll.PollKind
|
||||||
|
import io.element.android.libraries.matrix.api.timeline.item.event.PollContent
|
||||||
|
import io.element.android.libraries.matrix.test.AN_EVENT_ID
|
||||||
|
import io.element.android.libraries.matrix.test.A_USER_ID
|
||||||
|
import io.element.android.libraries.matrix.test.A_USER_ID_10
|
||||||
|
import io.element.android.libraries.matrix.test.A_USER_ID_2
|
||||||
|
import io.element.android.libraries.matrix.test.A_USER_ID_3
|
||||||
|
import io.element.android.libraries.matrix.test.A_USER_ID_4
|
||||||
|
import io.element.android.libraries.matrix.test.A_USER_ID_5
|
||||||
|
import io.element.android.libraries.matrix.test.A_USER_ID_6
|
||||||
|
import io.element.android.libraries.matrix.test.A_USER_ID_7
|
||||||
|
import io.element.android.libraries.matrix.test.A_USER_ID_8
|
||||||
|
import io.element.android.libraries.matrix.test.A_USER_ID_9
|
||||||
|
import io.element.android.libraries.matrix.test.FakeMatrixClient
|
||||||
|
import io.element.android.libraries.matrix.test.timeline.anEventTimelineItem
|
||||||
|
import kotlinx.collections.immutable.ImmutableList
|
||||||
|
import kotlinx.collections.immutable.ImmutableMap
|
||||||
|
import kotlinx.collections.immutable.persistentListOf
|
||||||
|
import kotlinx.collections.immutable.persistentMapOf
|
||||||
|
import kotlinx.collections.immutable.toImmutableList
|
||||||
|
import kotlinx.collections.immutable.toImmutableMap
|
||||||
|
import kotlinx.coroutines.test.runTest
|
||||||
|
import org.junit.Test
|
||||||
|
|
||||||
|
class PollContentStateFactoryTest {
|
||||||
|
|
||||||
|
private val factory = DefaultPollContentStateFactory(FakeMatrixClient())
|
||||||
|
private val eventTimelineItem = anEventTimelineItem()
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun `Disclosed poll - not ended, no votes`() = runTest {
|
||||||
|
val state = factory.create(eventTimelineItem, aPollContent())
|
||||||
|
val expectedState = aPollContentState()
|
||||||
|
assertThat(state).isEqualTo(expectedState)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun `Disclosed poll - not ended, some votes, including one from current user`() = runTest {
|
||||||
|
val votes = MY_USER_WINNING_VOTES.mapKeys { it.key.id }.toImmutableMap()
|
||||||
|
val state = factory.create(
|
||||||
|
eventTimelineItem, aPollContent(votes = votes)
|
||||||
|
)
|
||||||
|
val expectedState = aPollContentState(
|
||||||
|
answerItems = listOf(
|
||||||
|
aPollAnswerItem(answer = A_POLL_ANSWER_1, votesCount = 3, percentage = 0.3f),
|
||||||
|
aPollAnswerItem(answer = A_POLL_ANSWER_2, isSelected = true, votesCount = 6, percentage = 0.6f),
|
||||||
|
aPollAnswerItem(answer = A_POLL_ANSWER_3),
|
||||||
|
aPollAnswerItem(answer = A_POLL_ANSWER_4, votesCount = 1, percentage = 0.1f),
|
||||||
|
)
|
||||||
|
)
|
||||||
|
assertThat(state).isEqualTo(expectedState)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun `Disclosed poll - ended, no votes, no winner`() = runTest {
|
||||||
|
val state = factory.create(eventTimelineItem, aPollContent(endTime = 1UL))
|
||||||
|
val expectedState = aPollContentState().let {
|
||||||
|
it.copy(
|
||||||
|
answerItems = it.answerItems.map { answerItem -> answerItem.copy(isEnabled = false) }.toImmutableList(),
|
||||||
|
isPollEnded = true,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
assertThat(state).isEqualTo(expectedState)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun `Disclosed poll - ended, some votes, including one from current user (winner)`() = runTest {
|
||||||
|
val votes = MY_USER_WINNING_VOTES.mapKeys { it.key.id }.toImmutableMap()
|
||||||
|
val state = factory.create(
|
||||||
|
eventTimelineItem, aPollContent(votes = votes, endTime = 1UL)
|
||||||
|
)
|
||||||
|
val expectedState = aPollContentState(
|
||||||
|
answerItems = listOf(
|
||||||
|
aPollAnswerItem(answer = A_POLL_ANSWER_1, isEnabled = false, votesCount = 3, percentage = 0.3f),
|
||||||
|
aPollAnswerItem(answer = A_POLL_ANSWER_2, isSelected = true, isEnabled = false, isWinner = true, votesCount = 6, percentage = 0.6f),
|
||||||
|
aPollAnswerItem(answer = A_POLL_ANSWER_3, isEnabled = false),
|
||||||
|
aPollAnswerItem(answer = A_POLL_ANSWER_4, isEnabled = false, votesCount = 1, percentage = 0.1f),
|
||||||
|
),
|
||||||
|
isEnded = true,
|
||||||
|
)
|
||||||
|
assertThat(state).isEqualTo(expectedState)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun `Disclosed poll - ended, some votes, including one from current user (not winner) and two winning votes`() = runTest {
|
||||||
|
val votes = OTHER_WINNING_VOTES.mapKeys { it.key.id }.toImmutableMap()
|
||||||
|
val state = factory.create(
|
||||||
|
eventTimelineItem, aPollContent(votes = votes, endTime = 1UL)
|
||||||
|
)
|
||||||
|
val expectedState = aPollContentState(
|
||||||
|
answerItems = listOf(
|
||||||
|
aPollAnswerItem(answer = A_POLL_ANSWER_1, isEnabled = false, isWinner = true, votesCount = 4, percentage = 0.4f),
|
||||||
|
aPollAnswerItem(answer = A_POLL_ANSWER_2, isSelected = true, isEnabled = false, votesCount = 2, percentage = 0.2f),
|
||||||
|
aPollAnswerItem(answer = A_POLL_ANSWER_3, isEnabled = false),
|
||||||
|
aPollAnswerItem(answer = A_POLL_ANSWER_4, isEnabled = false, isWinner = true, votesCount = 4, percentage = 0.4f),
|
||||||
|
),
|
||||||
|
isEnded = true,
|
||||||
|
)
|
||||||
|
assertThat(state).isEqualTo(expectedState)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun `Undisclosed poll - not ended, no votes`() = runTest {
|
||||||
|
val state = factory.create(eventTimelineItem, aPollContent(PollKind.Undisclosed))
|
||||||
|
val expectedState = aPollContentState(pollKind = PollKind.Undisclosed).let {
|
||||||
|
it.copy(
|
||||||
|
answerItems = it.answerItems.map { answerItem -> answerItem.copy(isDisclosed = false) }.toImmutableList()
|
||||||
|
)
|
||||||
|
}
|
||||||
|
assertThat(state).isEqualTo(expectedState)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun `Undisclosed poll - not ended, some votes, including one from current user`() = runTest {
|
||||||
|
val votes = MY_USER_WINNING_VOTES.mapKeys { it.key.id }.toImmutableMap()
|
||||||
|
val state = factory.create(
|
||||||
|
eventTimelineItem, aPollContent(PollKind.Undisclosed, votes = votes)
|
||||||
|
)
|
||||||
|
val expectedState = aPollContentState(
|
||||||
|
pollKind = PollKind.Undisclosed,
|
||||||
|
answerItems = listOf(
|
||||||
|
aPollAnswerItem(answer = A_POLL_ANSWER_1, isDisclosed = false, votesCount = 3, percentage = 0.3f),
|
||||||
|
aPollAnswerItem(answer = A_POLL_ANSWER_2, isDisclosed = false, isSelected = true, votesCount = 6, percentage = 0.6f),
|
||||||
|
aPollAnswerItem(answer = A_POLL_ANSWER_3, isDisclosed = false),
|
||||||
|
aPollAnswerItem(answer = A_POLL_ANSWER_4, isDisclosed = false, votesCount = 1, percentage = 0.1f),
|
||||||
|
),
|
||||||
|
)
|
||||||
|
assertThat(state).isEqualTo(expectedState)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun `Undisclosed poll - ended, no votes, no winner`() = runTest {
|
||||||
|
val state = factory.create(eventTimelineItem, aPollContent(PollKind.Undisclosed, endTime = 1UL))
|
||||||
|
val expectedState = aPollContentState(
|
||||||
|
isEnded = true,
|
||||||
|
pollKind = PollKind.Undisclosed
|
||||||
|
).let {
|
||||||
|
it.copy(
|
||||||
|
answerItems = it.answerItems.map { answerItem -> answerItem.copy(isDisclosed = true, isEnabled = false) }.toImmutableList(),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
assertThat(state).isEqualTo(expectedState)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun `Undisclosed poll - ended, some votes, including one from current user (winner)`() = runTest {
|
||||||
|
val votes = MY_USER_WINNING_VOTES.mapKeys { it.key.id }.toImmutableMap()
|
||||||
|
val state = factory.create(
|
||||||
|
eventTimelineItem, aPollContent(PollKind.Undisclosed, votes = votes, endTime = 1UL)
|
||||||
|
)
|
||||||
|
val expectedState = aPollContentState(
|
||||||
|
pollKind = PollKind.Undisclosed,
|
||||||
|
answerItems = listOf(
|
||||||
|
aPollAnswerItem(answer = A_POLL_ANSWER_1, isEnabled = false, votesCount = 3, percentage = 0.3f),
|
||||||
|
aPollAnswerItem(answer = A_POLL_ANSWER_2, isSelected = true, isEnabled = false, isWinner = true, votesCount = 6, percentage = 0.6f),
|
||||||
|
aPollAnswerItem(answer = A_POLL_ANSWER_3, isEnabled = false),
|
||||||
|
aPollAnswerItem(answer = A_POLL_ANSWER_4, isEnabled = false, votesCount = 1, percentage = 0.1f),
|
||||||
|
),
|
||||||
|
isEnded = true,
|
||||||
|
)
|
||||||
|
assertThat(state).isEqualTo(expectedState)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun `Undisclosed poll - ended, some votes, including one from current user (not winner) and two winning votes`() = runTest {
|
||||||
|
val votes = OTHER_WINNING_VOTES.mapKeys { it.key.id }.toImmutableMap()
|
||||||
|
val state = factory.create(
|
||||||
|
eventTimelineItem, aPollContent(PollKind.Undisclosed, votes = votes, endTime = 1UL)
|
||||||
|
)
|
||||||
|
val expectedState = aPollContentState(
|
||||||
|
pollKind = PollKind.Undisclosed,
|
||||||
|
answerItems = listOf(
|
||||||
|
aPollAnswerItem(answer = A_POLL_ANSWER_1, isEnabled = false, isWinner = true, votesCount = 4, percentage = 0.4f),
|
||||||
|
aPollAnswerItem(answer = A_POLL_ANSWER_2, isSelected = true, isEnabled = false, votesCount = 2, percentage = 0.2f),
|
||||||
|
aPollAnswerItem(answer = A_POLL_ANSWER_3, isEnabled = false),
|
||||||
|
aPollAnswerItem(answer = A_POLL_ANSWER_4, isEnabled = false, isWinner = true, votesCount = 4, percentage = 0.4f),
|
||||||
|
),
|
||||||
|
isEnded = true,
|
||||||
|
)
|
||||||
|
assertThat(state).isEqualTo(expectedState)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun `eventId is populated`() = runTest {
|
||||||
|
val state = factory.create(eventTimelineItem, aPollContent())
|
||||||
|
assertThat(state.eventId).isEqualTo(eventTimelineItem.eventId)
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun aPollContent(
|
||||||
|
pollKind: PollKind = PollKind.Disclosed,
|
||||||
|
votes: ImmutableMap<String, ImmutableList<UserId>> = persistentMapOf(),
|
||||||
|
endTime: ULong? = null,
|
||||||
|
): PollContent = PollContent(
|
||||||
|
question = A_POLL_QUESTION,
|
||||||
|
kind = pollKind,
|
||||||
|
maxSelections = 1UL,
|
||||||
|
answers = persistentListOf(A_POLL_ANSWER_1, A_POLL_ANSWER_2, A_POLL_ANSWER_3, A_POLL_ANSWER_4),
|
||||||
|
votes = votes,
|
||||||
|
endTime = endTime,
|
||||||
|
)
|
||||||
|
|
||||||
|
private fun aPollContentState(
|
||||||
|
eventId: EventId? = AN_EVENT_ID,
|
||||||
|
pollKind: PollKind = PollKind.Disclosed,
|
||||||
|
answerItems: List<PollAnswerItem> = listOf(
|
||||||
|
aPollAnswerItem(A_POLL_ANSWER_1),
|
||||||
|
aPollAnswerItem(A_POLL_ANSWER_2),
|
||||||
|
aPollAnswerItem(A_POLL_ANSWER_3),
|
||||||
|
aPollAnswerItem(A_POLL_ANSWER_4),
|
||||||
|
),
|
||||||
|
isEnded: Boolean = false,
|
||||||
|
isMine: Boolean = false,
|
||||||
|
isEditable: Boolean = false,
|
||||||
|
question: String = A_POLL_QUESTION,
|
||||||
|
) = PollContentState(
|
||||||
|
eventId = eventId,
|
||||||
|
question = question,
|
||||||
|
answerItems = answerItems.toImmutableList(),
|
||||||
|
pollKind = pollKind,
|
||||||
|
isMine = isMine,
|
||||||
|
isPollEnded = isEnded,
|
||||||
|
isPollEditable = isEditable,
|
||||||
|
)
|
||||||
|
|
||||||
|
private fun aPollAnswerItem(
|
||||||
|
answer: PollAnswer,
|
||||||
|
isSelected: Boolean = false,
|
||||||
|
isEnabled: Boolean = true,
|
||||||
|
isWinner: Boolean = false,
|
||||||
|
isDisclosed: Boolean = true,
|
||||||
|
votesCount: Int = 0,
|
||||||
|
percentage: Float = 0f,
|
||||||
|
) = PollAnswerItem(
|
||||||
|
answer = answer,
|
||||||
|
isSelected = isSelected,
|
||||||
|
isEnabled = isEnabled,
|
||||||
|
isWinner = isWinner,
|
||||||
|
isDisclosed = isDisclosed,
|
||||||
|
votesCount = votesCount,
|
||||||
|
percentage = percentage,
|
||||||
|
)
|
||||||
|
|
||||||
|
private companion object TestData {
|
||||||
|
private const val A_POLL_QUESTION = "What is your favorite food?"
|
||||||
|
private val A_POLL_ANSWER_1 = PollAnswer("id_1", "Pizza")
|
||||||
|
private val A_POLL_ANSWER_2 = PollAnswer("id_2", "Pasta")
|
||||||
|
private val A_POLL_ANSWER_3 = PollAnswer("id_3", "French Fries")
|
||||||
|
private val A_POLL_ANSWER_4 = PollAnswer("id_4", "Hamburger")
|
||||||
|
|
||||||
|
private val MY_USER_WINNING_VOTES = persistentMapOf(
|
||||||
|
A_POLL_ANSWER_1 to persistentListOf(A_USER_ID_2, A_USER_ID_3, A_USER_ID_4),
|
||||||
|
A_POLL_ANSWER_2 to persistentListOf(A_USER_ID /* my vote */, A_USER_ID_5, A_USER_ID_6, A_USER_ID_7, A_USER_ID_8, A_USER_ID_9), // winner
|
||||||
|
A_POLL_ANSWER_3 to persistentListOf(),
|
||||||
|
A_POLL_ANSWER_4 to persistentListOf(A_USER_ID_10),
|
||||||
|
)
|
||||||
|
private val OTHER_WINNING_VOTES = persistentMapOf(
|
||||||
|
A_POLL_ANSWER_1 to persistentListOf(A_USER_ID_2, A_USER_ID_3, A_USER_ID_4, A_USER_ID_5), // winner
|
||||||
|
A_POLL_ANSWER_2 to persistentListOf(A_USER_ID /* my vote */, A_USER_ID_6),
|
||||||
|
A_POLL_ANSWER_3 to persistentListOf(),
|
||||||
|
A_POLL_ANSWER_4 to persistentListOf(A_USER_ID_7, A_USER_ID_8, A_USER_ID_9, A_USER_ID_10), // winner
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
29
features/poll/test/build.gradle.kts
Normal file
29
features/poll/test/build.gradle.kts
Normal file
|
|
@ -0,0 +1,29 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2022 New Vector Ltd
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
plugins {
|
||||||
|
id("io.element.android-library")
|
||||||
|
}
|
||||||
|
|
||||||
|
android {
|
||||||
|
namespace = "io.element.android.features.poll.test"
|
||||||
|
}
|
||||||
|
|
||||||
|
dependencies {
|
||||||
|
implementation(projects.libraries.matrix.api)
|
||||||
|
api(projects.features.poll.api)
|
||||||
|
implementation(libs.kotlinx.collections.immutable)
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,34 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2023 New Vector Ltd
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package io.element.android.features.poll.test.actions
|
||||||
|
|
||||||
|
import io.element.android.features.poll.api.actions.EndPollAction
|
||||||
|
import io.element.android.libraries.matrix.api.core.EventId
|
||||||
|
|
||||||
|
class FakeEndPollAction : EndPollAction {
|
||||||
|
|
||||||
|
private var executionCount = 0
|
||||||
|
|
||||||
|
fun verifyExecutionCount(count: Int) {
|
||||||
|
assert(executionCount == count)
|
||||||
|
}
|
||||||
|
|
||||||
|
override suspend fun execute(pollStartId: EventId): Result<Unit> {
|
||||||
|
executionCount++
|
||||||
|
return Result.success(Unit)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,34 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2023 New Vector Ltd
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package io.element.android.features.poll.test.actions
|
||||||
|
|
||||||
|
import io.element.android.features.poll.api.actions.SendPollResponseAction
|
||||||
|
import io.element.android.libraries.matrix.api.core.EventId
|
||||||
|
|
||||||
|
class FakeSendPollResponseAction : SendPollResponseAction {
|
||||||
|
|
||||||
|
private var executionCount = 0
|
||||||
|
|
||||||
|
fun verifyExecutionCount(count: Int) {
|
||||||
|
assert(executionCount == count)
|
||||||
|
}
|
||||||
|
|
||||||
|
override suspend fun execute(pollStartId: EventId, answerId: String): Result<Unit> {
|
||||||
|
executionCount++
|
||||||
|
return Result.success(Unit)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,39 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2023 New Vector Ltd
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package io.element.android.features.poll.test.pollcontent
|
||||||
|
|
||||||
|
import io.element.android.features.poll.api.pollcontent.PollAnswerItem
|
||||||
|
import io.element.android.features.poll.api.pollcontent.PollContentState
|
||||||
|
import io.element.android.features.poll.api.pollcontent.PollContentStateFactory
|
||||||
|
import io.element.android.libraries.matrix.api.timeline.item.event.EventTimelineItem
|
||||||
|
import io.element.android.libraries.matrix.api.timeline.item.event.PollContent
|
||||||
|
import kotlinx.collections.immutable.toImmutableList
|
||||||
|
|
||||||
|
class FakePollContentStateFactory : PollContentStateFactory {
|
||||||
|
|
||||||
|
override suspend fun create(event: EventTimelineItem, content: PollContent): PollContentState {
|
||||||
|
return PollContentState(
|
||||||
|
eventId = event.eventId,
|
||||||
|
isMine = event.isOwn,
|
||||||
|
question = content.question,
|
||||||
|
answerItems = emptyList<PollAnswerItem>().toImmutableList(),
|
||||||
|
pollKind = content.kind,
|
||||||
|
isPollEditable = event.isEditable,
|
||||||
|
isPollEnded = content.endTime != null,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -431,7 +431,8 @@ class FakeMatrixRoom(
|
||||||
): Result<String> = generateWidgetWebViewUrlResult
|
): Result<String> = generateWidgetWebViewUrlResult
|
||||||
|
|
||||||
override fun getWidgetDriver(widgetSettings: MatrixWidgetSettings): Result<MatrixWidgetDriver> = getWidgetDriverResult
|
override fun getWidgetDriver(widgetSettings: MatrixWidgetSettings): Result<MatrixWidgetDriver> = getWidgetDriverResult
|
||||||
override suspend fun pollHistory(): MatrixTimeline {
|
|
||||||
|
override fun pollHistory(): MatrixTimeline {
|
||||||
return FakeMatrixTimeline()
|
return FakeMatrixTimeline()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -18,35 +18,17 @@ package io.element.android.libraries.matrix.test.room
|
||||||
|
|
||||||
import io.element.android.libraries.matrix.api.core.EventId
|
import io.element.android.libraries.matrix.api.core.EventId
|
||||||
import io.element.android.libraries.matrix.api.core.RoomId
|
import io.element.android.libraries.matrix.api.core.RoomId
|
||||||
import io.element.android.libraries.matrix.api.core.TransactionId
|
|
||||||
import io.element.android.libraries.matrix.api.core.UserId
|
import io.element.android.libraries.matrix.api.core.UserId
|
||||||
import io.element.android.libraries.matrix.api.poll.PollAnswer
|
|
||||||
import io.element.android.libraries.matrix.api.poll.PollKind
|
|
||||||
import io.element.android.libraries.matrix.api.room.RoomNotificationMode
|
import io.element.android.libraries.matrix.api.room.RoomNotificationMode
|
||||||
import io.element.android.libraries.matrix.api.room.message.RoomMessage
|
import io.element.android.libraries.matrix.api.room.message.RoomMessage
|
||||||
import io.element.android.libraries.matrix.api.roomlist.RoomSummary
|
import io.element.android.libraries.matrix.api.roomlist.RoomSummary
|
||||||
import io.element.android.libraries.matrix.api.roomlist.RoomSummaryDetails
|
import io.element.android.libraries.matrix.api.roomlist.RoomSummaryDetails
|
||||||
import io.element.android.libraries.matrix.api.timeline.item.TimelineItemDebugInfo
|
|
||||||
import io.element.android.libraries.matrix.api.timeline.item.event.EventContent
|
|
||||||
import io.element.android.libraries.matrix.api.timeline.item.event.EventReaction
|
|
||||||
import io.element.android.libraries.matrix.api.timeline.item.event.EventTimelineItem
|
import io.element.android.libraries.matrix.api.timeline.item.event.EventTimelineItem
|
||||||
import io.element.android.libraries.matrix.api.timeline.item.event.InReplyTo
|
|
||||||
import io.element.android.libraries.matrix.api.timeline.item.event.LocalEventSendState
|
|
||||||
import io.element.android.libraries.matrix.api.timeline.item.event.MessageContent
|
|
||||||
import io.element.android.libraries.matrix.api.timeline.item.event.MessageType
|
|
||||||
import io.element.android.libraries.matrix.api.timeline.item.event.PollContent
|
|
||||||
import io.element.android.libraries.matrix.api.timeline.item.event.ProfileChangeContent
|
|
||||||
import io.element.android.libraries.matrix.api.timeline.item.event.ProfileTimelineDetails
|
|
||||||
import io.element.android.libraries.matrix.api.timeline.item.event.Receipt
|
|
||||||
import io.element.android.libraries.matrix.api.timeline.item.event.TextMessageType
|
|
||||||
import io.element.android.libraries.matrix.test.AN_EVENT_ID
|
import io.element.android.libraries.matrix.test.AN_EVENT_ID
|
||||||
import io.element.android.libraries.matrix.test.A_ROOM_ID
|
import io.element.android.libraries.matrix.test.A_ROOM_ID
|
||||||
import io.element.android.libraries.matrix.test.A_ROOM_NAME
|
import io.element.android.libraries.matrix.test.A_ROOM_NAME
|
||||||
import io.element.android.libraries.matrix.test.A_USER_ID
|
import io.element.android.libraries.matrix.test.A_USER_ID
|
||||||
import io.element.android.libraries.matrix.test.A_USER_NAME
|
import io.element.android.libraries.matrix.test.timeline.anEventTimelineItem
|
||||||
import kotlinx.collections.immutable.ImmutableList
|
|
||||||
import kotlinx.collections.immutable.persistentListOf
|
|
||||||
import kotlinx.collections.immutable.persistentMapOf
|
|
||||||
|
|
||||||
fun aRoomSummaryFilled(
|
fun aRoomSummaryFilled(
|
||||||
roomId: RoomId = A_ROOM_ID,
|
roomId: RoomId = A_ROOM_ID,
|
||||||
|
|
@ -101,95 +83,3 @@ fun aRoomMessage(
|
||||||
sender = userId,
|
sender = userId,
|
||||||
originServerTs = timestamp,
|
originServerTs = timestamp,
|
||||||
)
|
)
|
||||||
|
|
||||||
fun anEventTimelineItem(
|
|
||||||
eventId: EventId = AN_EVENT_ID,
|
|
||||||
transactionId: TransactionId? = null,
|
|
||||||
isEditable: Boolean = false,
|
|
||||||
isLocal: Boolean = false,
|
|
||||||
isOwn: Boolean = false,
|
|
||||||
isRemote: Boolean = false,
|
|
||||||
localSendState: LocalEventSendState? = null,
|
|
||||||
reactions: ImmutableList<EventReaction> = persistentListOf(),
|
|
||||||
receipts: ImmutableList<Receipt> = persistentListOf(),
|
|
||||||
sender: UserId = A_USER_ID,
|
|
||||||
senderProfile: ProfileTimelineDetails = aProfileTimelineDetails(),
|
|
||||||
timestamp: Long = 0L,
|
|
||||||
content: EventContent = aProfileChangeMessageContent(),
|
|
||||||
debugInfo: TimelineItemDebugInfo = aTimelineItemDebugInfo(),
|
|
||||||
) = EventTimelineItem(
|
|
||||||
eventId = eventId,
|
|
||||||
transactionId = transactionId,
|
|
||||||
isEditable = isEditable,
|
|
||||||
isLocal = isLocal,
|
|
||||||
isOwn = isOwn,
|
|
||||||
isRemote = isRemote,
|
|
||||||
localSendState = localSendState,
|
|
||||||
reactions = reactions,
|
|
||||||
receipts = receipts,
|
|
||||||
sender = sender,
|
|
||||||
senderProfile = senderProfile,
|
|
||||||
timestamp = timestamp,
|
|
||||||
content = content,
|
|
||||||
debugInfo = debugInfo,
|
|
||||||
origin = null,
|
|
||||||
)
|
|
||||||
|
|
||||||
fun aProfileTimelineDetails(
|
|
||||||
displayName: String? = A_USER_NAME,
|
|
||||||
displayNameAmbiguous: Boolean = false,
|
|
||||||
avatarUrl: String? = null
|
|
||||||
): ProfileTimelineDetails = ProfileTimelineDetails.Ready(
|
|
||||||
displayName = displayName,
|
|
||||||
displayNameAmbiguous = displayNameAmbiguous,
|
|
||||||
avatarUrl = avatarUrl,
|
|
||||||
)
|
|
||||||
|
|
||||||
fun aProfileChangeMessageContent(
|
|
||||||
displayName: String? = null,
|
|
||||||
prevDisplayName: String? = null,
|
|
||||||
avatarUrl: String? = null,
|
|
||||||
prevAvatarUrl: String? = null,
|
|
||||||
) = ProfileChangeContent(
|
|
||||||
displayName = displayName,
|
|
||||||
prevDisplayName = prevDisplayName,
|
|
||||||
avatarUrl = avatarUrl,
|
|
||||||
prevAvatarUrl = prevAvatarUrl,
|
|
||||||
)
|
|
||||||
|
|
||||||
fun aMessageContent(
|
|
||||||
body: String = "body",
|
|
||||||
inReplyTo: InReplyTo? = null,
|
|
||||||
isEdited: Boolean = false,
|
|
||||||
isThreaded: Boolean = false,
|
|
||||||
messageType: MessageType = TextMessageType(
|
|
||||||
body = body,
|
|
||||||
formatted = null
|
|
||||||
)
|
|
||||||
) = MessageContent(
|
|
||||||
body = body,
|
|
||||||
inReplyTo = inReplyTo,
|
|
||||||
isEdited = isEdited,
|
|
||||||
isThreaded = isThreaded,
|
|
||||||
type = messageType
|
|
||||||
)
|
|
||||||
|
|
||||||
fun aTimelineItemDebugInfo(
|
|
||||||
model: String = "Rust(Model())",
|
|
||||||
originalJson: String? = null,
|
|
||||||
latestEditedJson: String? = null,
|
|
||||||
) = TimelineItemDebugInfo(
|
|
||||||
model, originalJson, latestEditedJson
|
|
||||||
)
|
|
||||||
|
|
||||||
fun aPollContent(
|
|
||||||
question: String = "Do you like polls?",
|
|
||||||
answers: ImmutableList<PollAnswer> = persistentListOf(PollAnswer("1", "Yes"), PollAnswer("2", "No")),
|
|
||||||
) = PollContent(
|
|
||||||
question = question,
|
|
||||||
kind = PollKind.Disclosed,
|
|
||||||
maxSelections = 1u,
|
|
||||||
answers = answers,
|
|
||||||
votes = persistentMapOf(),
|
|
||||||
endTime = null
|
|
||||||
)
|
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,139 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2023 New Vector Ltd
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package io.element.android.libraries.matrix.test.timeline
|
||||||
|
|
||||||
|
import io.element.android.libraries.matrix.api.core.EventId
|
||||||
|
import io.element.android.libraries.matrix.api.core.TransactionId
|
||||||
|
import io.element.android.libraries.matrix.api.core.UserId
|
||||||
|
import io.element.android.libraries.matrix.api.poll.PollAnswer
|
||||||
|
import io.element.android.libraries.matrix.api.poll.PollKind
|
||||||
|
import io.element.android.libraries.matrix.api.timeline.item.TimelineItemDebugInfo
|
||||||
|
import io.element.android.libraries.matrix.api.timeline.item.event.EventContent
|
||||||
|
import io.element.android.libraries.matrix.api.timeline.item.event.EventReaction
|
||||||
|
import io.element.android.libraries.matrix.api.timeline.item.event.EventTimelineItem
|
||||||
|
import io.element.android.libraries.matrix.api.timeline.item.event.InReplyTo
|
||||||
|
import io.element.android.libraries.matrix.api.timeline.item.event.LocalEventSendState
|
||||||
|
import io.element.android.libraries.matrix.api.timeline.item.event.MessageContent
|
||||||
|
import io.element.android.libraries.matrix.api.timeline.item.event.MessageType
|
||||||
|
import io.element.android.libraries.matrix.api.timeline.item.event.PollContent
|
||||||
|
import io.element.android.libraries.matrix.api.timeline.item.event.ProfileChangeContent
|
||||||
|
import io.element.android.libraries.matrix.api.timeline.item.event.ProfileTimelineDetails
|
||||||
|
import io.element.android.libraries.matrix.api.timeline.item.event.Receipt
|
||||||
|
import io.element.android.libraries.matrix.api.timeline.item.event.TextMessageType
|
||||||
|
import io.element.android.libraries.matrix.test.AN_EVENT_ID
|
||||||
|
import io.element.android.libraries.matrix.test.A_USER_ID
|
||||||
|
import io.element.android.libraries.matrix.test.A_USER_NAME
|
||||||
|
import kotlinx.collections.immutable.ImmutableList
|
||||||
|
import kotlinx.collections.immutable.ImmutableMap
|
||||||
|
import kotlinx.collections.immutable.persistentListOf
|
||||||
|
import kotlinx.collections.immutable.persistentMapOf
|
||||||
|
|
||||||
|
fun anEventTimelineItem(
|
||||||
|
eventId: EventId = AN_EVENT_ID,
|
||||||
|
transactionId: TransactionId? = null,
|
||||||
|
isEditable: Boolean = false,
|
||||||
|
isLocal: Boolean = false,
|
||||||
|
isOwn: Boolean = false,
|
||||||
|
isRemote: Boolean = false,
|
||||||
|
localSendState: LocalEventSendState? = null,
|
||||||
|
reactions: ImmutableList<EventReaction> = persistentListOf(),
|
||||||
|
receipts: ImmutableList<Receipt> = persistentListOf(),
|
||||||
|
sender: UserId = A_USER_ID,
|
||||||
|
senderProfile: ProfileTimelineDetails = aProfileTimelineDetails(),
|
||||||
|
timestamp: Long = 0L,
|
||||||
|
content: EventContent = aProfileChangeMessageContent(),
|
||||||
|
debugInfo: TimelineItemDebugInfo = aTimelineItemDebugInfo(),
|
||||||
|
) = EventTimelineItem(
|
||||||
|
eventId = eventId,
|
||||||
|
transactionId = transactionId,
|
||||||
|
isEditable = isEditable,
|
||||||
|
isLocal = isLocal,
|
||||||
|
isOwn = isOwn,
|
||||||
|
isRemote = isRemote,
|
||||||
|
localSendState = localSendState,
|
||||||
|
reactions = reactions,
|
||||||
|
receipts = receipts,
|
||||||
|
sender = sender,
|
||||||
|
senderProfile = senderProfile,
|
||||||
|
timestamp = timestamp,
|
||||||
|
content = content,
|
||||||
|
debugInfo = debugInfo,
|
||||||
|
origin = null,
|
||||||
|
)
|
||||||
|
|
||||||
|
fun aProfileTimelineDetails(
|
||||||
|
displayName: String? = A_USER_NAME,
|
||||||
|
displayNameAmbiguous: Boolean = false,
|
||||||
|
avatarUrl: String? = null
|
||||||
|
): ProfileTimelineDetails = ProfileTimelineDetails.Ready(
|
||||||
|
displayName = displayName,
|
||||||
|
displayNameAmbiguous = displayNameAmbiguous,
|
||||||
|
avatarUrl = avatarUrl,
|
||||||
|
)
|
||||||
|
|
||||||
|
fun aProfileChangeMessageContent(
|
||||||
|
displayName: String? = null,
|
||||||
|
prevDisplayName: String? = null,
|
||||||
|
avatarUrl: String? = null,
|
||||||
|
prevAvatarUrl: String? = null,
|
||||||
|
) = ProfileChangeContent(
|
||||||
|
displayName = displayName,
|
||||||
|
prevDisplayName = prevDisplayName,
|
||||||
|
avatarUrl = avatarUrl,
|
||||||
|
prevAvatarUrl = prevAvatarUrl,
|
||||||
|
)
|
||||||
|
|
||||||
|
fun aMessageContent(
|
||||||
|
body: String = "body",
|
||||||
|
inReplyTo: InReplyTo? = null,
|
||||||
|
isEdited: Boolean = false,
|
||||||
|
isThreaded: Boolean = false,
|
||||||
|
messageType: MessageType = TextMessageType(
|
||||||
|
body = body,
|
||||||
|
formatted = null
|
||||||
|
)
|
||||||
|
) = MessageContent(
|
||||||
|
body = body,
|
||||||
|
inReplyTo = inReplyTo,
|
||||||
|
isEdited = isEdited,
|
||||||
|
isThreaded = isThreaded,
|
||||||
|
type = messageType
|
||||||
|
)
|
||||||
|
|
||||||
|
fun aTimelineItemDebugInfo(
|
||||||
|
model: String = "Rust(Model())",
|
||||||
|
originalJson: String? = null,
|
||||||
|
latestEditedJson: String? = null,
|
||||||
|
) = TimelineItemDebugInfo(
|
||||||
|
model, originalJson, latestEditedJson
|
||||||
|
)
|
||||||
|
|
||||||
|
fun aPollContent(
|
||||||
|
question: String = "Do you like polls?",
|
||||||
|
answers: ImmutableList<PollAnswer> = persistentListOf(PollAnswer("1", "Yes"), PollAnswer("2", "No")),
|
||||||
|
kind: PollKind = PollKind.Disclosed,
|
||||||
|
maxSelections: ULong = 1u,
|
||||||
|
votes: ImmutableMap<String, ImmutableList<UserId>> = persistentMapOf(),
|
||||||
|
endTime: ULong? = null,
|
||||||
|
) = PollContent(
|
||||||
|
question = question,
|
||||||
|
kind = kind,
|
||||||
|
maxSelections = maxSelections,
|
||||||
|
answers = answers,
|
||||||
|
votes = votes,
|
||||||
|
endTime = endTime,
|
||||||
|
)
|
||||||
Loading…
Add table
Add a link
Reference in a new issue