Fix small issues, improve Result.flatMap

This commit is contained in:
Jorge Martín
2023-05-29 13:58:29 +02:00
parent 0b741621c6
commit 268447fd8c
7 changed files with 97 additions and 16 deletions

View File

@@ -357,5 +357,11 @@ internal fun MessagesViewDarkPreview(@PreviewParameter(MessagesStateProvider::cl
@Composable
private fun ContentToPreview(state: MessagesState) {
MessagesView(state, {}, {}, {}, {})
MessagesView(
state = state,
onBackPressed = {},
onRoomDetailsClicked = {},
onEventClicked = {},
onPreviewAttachments = {}
)
}

View File

@@ -23,14 +23,12 @@ interface LocalMediaFactory {
/**
* This method will create a [LocalMedia] with the given [MediaFile] and [mimeType].
*
*/
fun createFromMediaFile(mediaFile: MediaFile, mimeType: String?): LocalMedia
/**
* This method will create a [LocalMedia] with the given [uri] and [mimeType]
* If the [mimeType] is null, it'll try to read it from the content.
*
*/
fun createFromUri(uri: Uri, mimeType: String?): LocalMedia
}

View File

@@ -26,10 +26,10 @@ import io.element.android.features.messages.impl.MessagesEvents
import io.element.android.features.messages.impl.MessagesPresenter
import io.element.android.features.messages.impl.actionlist.ActionListPresenter
import io.element.android.features.messages.impl.actionlist.model.TimelineItemAction
import io.element.android.features.messages.media.FakeLocalMediaFactory
import io.element.android.features.messages.impl.messagecomposer.MessageComposerPresenter
import io.element.android.features.messages.impl.timeline.TimelinePresenter
import io.element.android.features.messages.impl.timeline.groups.TimelineItemGrouper
import io.element.android.features.messages.media.FakeLocalMediaFactory
import io.element.android.features.networkmonitor.test.FakeNetworkMonitor
import io.element.android.libraries.designsystem.utils.SnackbarDispatcher
import io.element.android.libraries.featureflag.test.FakeFeatureFlagService
@@ -156,4 +156,3 @@ class MessagesPresenterTest {
)
}
}

View File

@@ -51,7 +51,7 @@ class MediaViewerPresenterTest {
assertThat(initialState.name).isEqualTo(TESTED_MEDIA_NAME)
val loadingState = awaitItem()
assertThat(loadingState.downloadedMedia).isInstanceOf(Async.Loading::class.java)
testScheduler.advanceTimeBy(FAKE_DELAY_IN_MS)
testScheduler.advanceTimeBy(FAKE_DELAY_IN_MS + 1)
val successState = awaitItem()
val successData = successState.downloadedMedia.dataOrNull()
assertThat(successState.downloadedMedia).isInstanceOf(Async.Success::class.java)

View File

@@ -27,14 +27,23 @@ inline fun <R, T : R> Result<T>.mapFailure(transform: (exception: Throwable) ->
}
/**
* Can be used to transform some Throwable into some other.
* Can be used to apply a [transform] that returns a [Result] to a base [Result] and get another [Result].
* @return The result of the transform as a [Result].
*/
inline fun <R, T> Result<R>.flatMap(transform: (R) -> Result<T>): Result<T> {
return when (val exception = exceptionOrNull()) {
null -> mapCatching(transform).fold(
onSuccess = { it },
onFailure = { Result.failure(it) }
)
else -> Result.failure(exception)
}
inline fun <R, T> Result<T>.flatMap(transform: (T) -> Result<R>): Result<R> {
return map(transform).fold(
onSuccess = { it },
onFailure = { Result.failure(it) }
)
}
/**
* Can be used to apply a [transform] that returns a [Result] to a base [Result] and get another [Result], catching any exception.
* @return The result of the transform or a caught exception wrapped in a [Result].
*/
inline fun <R, T> Result<T>.flatMapCatching(transform: (T) -> Result<R>): Result<R> {
return mapCatching(transform).fold(
onSuccess = { it },
onFailure = { Result.failure(it) }
)
}

View File

@@ -0,0 +1,69 @@
/*
* 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.core.extensions
import com.google.common.truth.Truth.assertThat
import org.junit.Test
class ResultTests {
@Test
fun testFlatMap() {
val initial = Result.success("initial")
val otherResult = initial.flatMap { Result.success("other") }
val errorResult = initial.flatMap { Result.failure<String>(IllegalStateException("error")) }
assertThat(otherResult.getOrNull()).isEqualTo("other")
assertThat(errorResult.exceptionOrNull()?.message).isEqualTo("error")
try {
initial.flatMap<String, String> { error("caught error") }
} catch (e: IllegalStateException) {
assertThat(e.message).isEqualTo("caught error")
}
val initialError = Result.failure<String>(IllegalStateException("initial error"))
val mapErrorToSuccess = initialError.flatMap { Result.success("other") }
val mapErrorToError = initialError.flatMap { Result.failure<String>(IllegalStateException("error")) }
val mapErrorAndCatch: Result<String> = initialError.flatMap { error("error") }
assertThat(mapErrorToSuccess.exceptionOrNull()?.message).isEqualTo("initial error")
assertThat(mapErrorToError.exceptionOrNull()?.message).isEqualTo("initial error")
assertThat(mapErrorAndCatch.exceptionOrNull()?.message).isEqualTo("initial error")
}
@Test
fun testFlatMapCatching() {
val initial = Result.success("initial")
val otherResult = initial.flatMapCatching { Result.success("other") }
val errorResult = initial.flatMapCatching { Result.failure<String>(IllegalStateException("error")) }
val caughtExceptionResult: Result<String> = initial.flatMapCatching { error("caught error") }
assertThat(otherResult.getOrNull()).isEqualTo("other")
assertThat(errorResult.exceptionOrNull()?.message).isEqualTo("error")
assertThat(caughtExceptionResult.exceptionOrNull()?.message).isEqualTo("caught error")
val initialError = Result.failure<String>(IllegalStateException("initial error"))
val mapErrorToSuccess = initialError.flatMapCatching { Result.success("other") }
val mapErrorToError = initialError.flatMapCatching { Result.failure<String>(IllegalStateException("error")) }
val mapErrorAndCatch: Result<String> = initialError.flatMapCatching { error("error") }
assertThat(mapErrorToSuccess.exceptionOrNull()?.message).isEqualTo("initial error")
assertThat(mapErrorToError.exceptionOrNull()?.message).isEqualTo("initial error")
assertThat(mapErrorAndCatch.exceptionOrNull()?.message).isEqualTo("initial error")
}
}

View File

@@ -54,7 +54,7 @@ class MediaSender @Inject constructor(
is MediaUploadInfo.AnyFile -> {
sendFile(info.file, info.info)
}
else -> error("Unexpected MediaUploadInfo format: $info")
else -> Result.failure(IllegalStateException("Unexpected MediaUploadInfo format: $info"))
}
}
}