Add catchingExceptions method to replace runCatching (#4797)

- Add `runCatchingExceptions` and `mapCatchingExceptions` to replace `runCatching` and `mapCatching`.
- Make `tryOrNull { ... }` catch only exceptions too.
- Apply the changes to the whole project.
- Add new Rust fakes for tests to handle the code that's now unblocked - previously it just threw an `UnsatisfiedLinkError` which we ignored.
- Add a new `detekt-rules` project with a `RunCatchingRule` to prevent `runCatching` and `mapCatching` usages.
This commit is contained in:
Jorge Martin Espinosa 2025-06-04 09:02:26 +02:00 committed by GitHub
parent 7816529fd7
commit efdc10e60a
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
144 changed files with 716 additions and 375 deletions

View file

@ -15,6 +15,7 @@ android {
dependencies {
api(projects.libraries.di)
api(projects.libraries.core)
api(libs.dagger)
api(libs.appyx.core)
api(libs.androidx.lifecycle.runtime)

View file

@ -9,6 +9,7 @@ package io.element.android.libraries.architecture
import androidx.compose.runtime.MutableState
import androidx.compose.runtime.Stable
import io.element.android.libraries.core.extensions.runCatchingExceptions
import kotlin.contracts.ExperimentalContracts
import kotlin.contracts.InvocationKind
import kotlin.contracts.contract
@ -90,7 +91,7 @@ suspend inline fun <T> MutableState<AsyncAction<T>>.runCatchingUpdatingState(
state = this,
errorTransform = errorTransform,
resultBlock = {
runCatching {
runCatchingExceptions {
block()
}
},
@ -103,7 +104,7 @@ suspend inline fun <T> (suspend () -> T).runCatchingUpdatingState(
state = state,
errorTransform = errorTransform,
resultBlock = {
runCatching {
runCatchingExceptions {
this()
}
},

View file

@ -9,6 +9,7 @@ package io.element.android.libraries.architecture
import androidx.compose.runtime.MutableState
import androidx.compose.runtime.Stable
import io.element.android.libraries.core.extensions.runCatchingExceptions
import kotlin.contracts.ExperimentalContracts
import kotlin.contracts.InvocationKind
import kotlin.contracts.contract
@ -93,7 +94,7 @@ suspend inline fun <T> MutableState<AsyncData<T>>.runCatchingUpdatingState(
state = this,
errorTransform = errorTransform,
resultBlock = {
runCatching {
runCatchingExceptions {
block()
}
},
@ -106,7 +107,7 @@ suspend inline fun <T> (suspend () -> T).runCatchingUpdatingState(
state = state,
errorTransform = errorTransform,
resultBlock = {
runCatching {
runCatchingExceptions {
this()
}
},

View file

@ -38,15 +38,15 @@ class AsyncDataKtTest {
val result = runUpdatingState(state) {
delay(1)
Result.failure(MyThrowable("hello"))
Result.failure(MyException("hello"))
}
assertThat(result.isFailure).isTrue()
assertThat(result.exceptionOrNull()).isEqualTo(MyThrowable("hello"))
assertThat(result.exceptionOrNull()).isEqualTo(MyException("hello"))
assertThat(state.popFirst()).isEqualTo(AsyncData.Uninitialized)
assertThat(state.popFirst()).isEqualTo(AsyncData.Loading(null))
assertThat(state.popFirst()).isEqualTo(AsyncData.Failure<Int>(MyThrowable("hello")))
assertThat(state.popFirst()).isEqualTo(AsyncData.Failure<Int>(MyException("hello")))
state.assertNoMoreValues()
}
@ -54,17 +54,17 @@ class AsyncDataKtTest {
fun `updates state when block returns failure transforming the error`() = runTest {
val state = TestableMutableState<AsyncData<Int>>(AsyncData.Uninitialized)
val result = runUpdatingState(state, { MyThrowable(it.message + " world") }) {
val result = runUpdatingState(state, { MyException(it.message + " world") }) {
delay(1)
Result.failure(MyThrowable("hello"))
Result.failure(MyException("hello"))
}
assertThat(result.isFailure).isTrue()
assertThat(result.exceptionOrNull()).isEqualTo(MyThrowable("hello world"))
assertThat(result.exceptionOrNull()).isEqualTo(MyException("hello world"))
assertThat(state.popFirst()).isEqualTo(AsyncData.Uninitialized)
assertThat(state.popFirst()).isEqualTo(AsyncData.Loading(null))
assertThat(state.popFirst()).isEqualTo(AsyncData.Failure<Int>(MyThrowable("hello world")))
assertThat(state.popFirst()).isEqualTo(AsyncData.Failure<Int>(MyException("hello world")))
state.assertNoMoreValues()
}
}
@ -101,4 +101,4 @@ private class TestableMutableState<T>(
/**
* An exception that is also a data class so we can compare it using equals.
*/
private data class MyThrowable(val myMessage: String) : Throwable(myMessage)
private data class MyException(val myMessage: String) : Exception(myMessage)