Skip to content

Add catchingExceptions method to replace runCatching #4797

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 14 commits into from
Jun 4, 2025

Conversation

jmartinesp
Copy link
Member

Content

  • Add catchingExceptions(block()): this method creates a Result by catching only Exception throwables, also re-throwing CancellationException so coroutines can work as expected.
  • Add also Result.mapCatchingException(block()) to replace Result.mapCatching, with the same behaviour of catching only exceptions.
  • Make tryOrNull also catch only exceptions and re-throw cancellation exceptions.
  • Replace usages of these methods in the project and thrown error/throwables so the tests pass again.
  • Create a custom detekt rules module with an specific rule to prevent runCatching and mapCatching from being used.

Motivation and context

Fixes #4778

Tests

The app builds, the tests should pass and we have Maestro for runtime.

Tested devices

  • Physical
  • Emulator
  • OS version(s): 14

Checklist

  • Changes have been tested on an Android device or Android emulator with API 24
  • UI change has been tested on both light and dark themes
  • Accessibility has been taken into account. See https://github.com/element-hq/element-x-android/blob/develop/CONTRIBUTING.md#accessibility
  • Pull request is based on the develop branch
  • Pull request title will be used in the release note, it clearly define what will change for the user
  • Pull request includes screenshots or videos if containing UI changes
  • You've made a self review of your PR

@jmartinesp jmartinesp added the PR-Misc For other changes label May 29, 2025
@ElementBot
Copy link
Collaborator

ElementBot commented May 29, 2025

Warnings
⚠️

gradle/libs.versions.toml#L41 - A newer version of io.coil-kt.coil3:coil-test than 3.1.0 is available: 3.2.0

⚠️

gradle/libs.versions.toml#L46 - A newer version of me.saket.telephoto:zoomable-image-coil than 0.15.1 is available: 0.16.0

⚠️

gradle/libs.versions.toml#L189 - A newer version of org.maplibre.gl:android-sdk than 11.8.8 is available: 11.9.0

⚠️

gradle/libs.versions.toml#L192 - The native library arm64-v8a/libopuscodec.so (from io.element.android:opusencoder:1.1.0) is not 16 KB aligned

Generated by 🚫 dangerJS against af71f9d

Copy link
Contributor

github-actions bot commented May 29, 2025

📱 Scan the QR code below to install the build (arm64 only) for this PR.
QR code
If you can't scan the QR code you can install the build via this link: https://i.diawi.com/LypGqZ

Copy link

codecov bot commented May 29, 2025

Codecov Report

Attention: Patch coverage is 25.20000% with 187 lines in your changes missing coverage. Please review.

Project coverage is 80.39%. Comparing base (7816529) to head (af71f9d).
Report is 1 commits behind head on develop.

Files with missing lines Patch % Lines
...droid/libraries/matrix/impl/room/JoinedRustRoom.kt 0.00% 29 Missing ⚠️
...android/libraries/matrix/impl/room/RustBaseRoom.kt 3.33% 29 Missing ⚠️
.../android/libraries/matrix/impl/RustMatrixClient.kt 3.84% 25 Missing ⚠️
...oid/libraries/matrix/impl/timeline/RustTimeline.kt 5.55% 17 Missing ⚠️
...es/matrix/impl/encryption/RustEncryptionService.kt 6.66% 14 Missing ⚠️
...icationsettings/RustNotificationSettingsService.kt 7.14% 13 Missing ⚠️
...atrix/impl/auth/RustMatrixAuthenticationService.kt 0.00% 8 Missing ⚠️
...ment/android/features/share/impl/SharePresenter.kt 42.85% 2 Missing and 2 partials ⚠️
...braries/matrix/impl/room/knock/RustKnockRequest.kt 0.00% 4 Missing ⚠️
.../matrix/impl/encryption/RustIdentityResetHandle.kt 0.00% 3 Missing ⚠️
... and 33 more
Additional details and impacted files
@@             Coverage Diff             @@
##           develop    #4797      +/-   ##
===========================================
- Coverage    80.39%   80.39%   -0.01%     
===========================================
  Files         2149     2149              
  Lines        56833    56838       +5     
  Branches      7131     7126       -5     
===========================================
+ Hits         45693    45697       +4     
+ Misses        8693     8690       -3     
- Partials      2447     2451       +4     

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

@jmartinesp jmartinesp marked this pull request as ready for review June 2, 2025 09:30
@jmartinesp jmartinesp requested a review from a team as a code owner June 2, 2025 09:30
@jmartinesp jmartinesp requested review from bmarty and removed request for a team June 2, 2025 09:30
Copy link
Member

@bmarty bmarty left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM, some small remark.

On Element Android we had an opt-in fail fast option in the developer settings, useful to avoid crash at runtime (when disabled) as much as possible. This is maybe something we want to introduce here?

*
* [Error]s are not caught by this function, as they are not meant to be caught in normal application flow.
*/
inline fun <T> catchingExceptions(
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

To be closer to runCatching, maybe rename to runCatchingExceptions?

Also I am wondering if we could still have a safe mode (for production?) where we still catch Errors. Here we take the risk to have crashes on production. Maybe we could have only this on debug build, so that we have time to fix existing problems?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't think we can, not easily 🫤 . This is in a java library module so we don't have the concept of BuildConfig to check if it's a debug or release version and we can't inject the BuildMeta here either.

*
* This is a safer version of [Result.mapCatching].
*/
inline fun <R, T> Result<T>.mapCatchingException(
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe rename to mapCatchingExceptions? It seems that this is what you wanted to do according to the description of the detekt rule you wrote :)

isSuccess -> catchingExceptions { block(getOrNull()!!) }
else -> Result.failure(exceptionOrNull()!!)
}
}
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe rewrite to

    return fold(
        onSuccess = { value -> catchingExceptions { block(value) } },
        onFailure = { exception -> Result.failure(exception) }
    )

to avoid usage of !!.

import org.matrix.rustcomponents.sdk.SessionVerificationController
import org.matrix.rustcomponents.sdk.SessionVerificationControllerDelegate

class FakeSessionVerificationController : SessionVerificationController(NoPointer) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The (not-written) convention is to name this class FakeRustSessionVerificationController so that we see that it's not a regular Fake class that we use for Unit test.
It seems that I did not follow the convention for FakeQrCodeData, my bad...

System.err.println(it)
}
exitProcess(1)
throw AssertionError(message)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The comment above can be removed I think!

jmartinesp added 13 commits June 2, 2025 12:57
This method creates a `Result` by catching only `Exception` throwables, also re-throwing `CancellationException` so coroutines can work as expected.

Add also `Result.mapCatchingException` to replace `Result.mapCatching`, with the same behaviour of catching only exceptions.
With this we make sure no `Error` will be incorrectly caught and `CancellationException`s get to follow the coroutine cancellation flow.
…terparts.

Also replace the instantiation of `Throwable` errors for tests with `RuntimeException`.
…he cancellation exceptions and re-throw them after some cleanup
…rs those threw were previously silently ignored
# This is the 1st commit message:

Rename `catchingExceptions` to `runCatchingExceptions`

# The commit message #2 will be skipped:

# fixup runcatching
@jmartinesp jmartinesp force-pushed the refactor/replace-runcatching branch from 45e2481 to b9202d2 Compare June 2, 2025 12:29
Copy link

sonarqubecloud bot commented Jun 4, 2025

@jmartinesp jmartinesp merged commit efdc10e into develop Jun 4, 2025
28 of 31 checks passed
@jmartinesp jmartinesp deleted the refactor/replace-runcatching branch June 4, 2025 07:02
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
PR-Misc For other changes
Projects
None yet
Development

Successfully merging this pull request may close these issues.

[Task] Replace usages of runCatching/mapCatching with our own versions
3 participants