From 36942ab2964dca67a897cb64b513fa6cb34bc5ab Mon Sep 17 00:00:00 2001 From: Andrew Haisting <142518658+ahaisting-livefront@users.noreply.github.com> Date: Mon, 18 Sep 2023 14:34:25 -0500 Subject: [PATCH] Add flatMap for Result type (#51) --- .../data/platform/util/ResultExtensions.kt | 10 ++++ .../data/platform/util/ResultTest.kt | 52 +++++++++++++++++++ 2 files changed, 62 insertions(+) create mode 100644 app/src/main/java/com/x8bit/bitwarden/data/platform/util/ResultExtensions.kt create mode 100644 app/src/test/java/com/x8bit/bitwarden/data/platform/util/ResultTest.kt diff --git a/app/src/main/java/com/x8bit/bitwarden/data/platform/util/ResultExtensions.kt b/app/src/main/java/com/x8bit/bitwarden/data/platform/util/ResultExtensions.kt new file mode 100644 index 000000000..72337c27a --- /dev/null +++ b/app/src/main/java/com/x8bit/bitwarden/data/platform/util/ResultExtensions.kt @@ -0,0 +1,10 @@ +package com.x8bit.bitwarden.data.platform.util + +/** + * Flat maps a successful [Result] with the given [transform] to another [Result], and leaves + * failures untouched. + */ +inline fun Result.flatMap(transform: (T) -> Result): Result = + this.exceptionOrNull() + ?.let { Result.failure(it) } + ?: transform(this.getOrThrow()) diff --git a/app/src/test/java/com/x8bit/bitwarden/data/platform/util/ResultTest.kt b/app/src/test/java/com/x8bit/bitwarden/data/platform/util/ResultTest.kt new file mode 100644 index 000000000..25a4db865 --- /dev/null +++ b/app/src/test/java/com/x8bit/bitwarden/data/platform/util/ResultTest.kt @@ -0,0 +1,52 @@ +package com.x8bit.bitwarden.data.platform.util + +import org.junit.jupiter.api.Assertions.assertEquals +import org.junit.jupiter.api.Assertions.assertTrue +import org.junit.jupiter.api.Test + +class ResultTest { + + @Test + fun `flatMap where receiver is success and argument is success should be argument success`() { + val intResult = Result.success(1) + val stringResult = intResult.flatMap { + Result.success(it.toString()) + } + assertTrue(stringResult.isSuccess) + assertEquals("1", stringResult.getOrNull()) + } + + @Test + fun `flatMap where receiver is success and argument is failure should be argument failure`() { + val expectedException = IllegalStateException("Exception in transform") + val intResult = Result.success(1) + val stringResult = intResult.flatMap { + Result.failure(expectedException) + } + assertTrue(stringResult.isFailure) + assertEquals(expectedException, stringResult.exceptionOrNull()) + } + + @Test + @Suppress("TooGenericExceptionThrown") + fun `flatMap where receiver is failure and argument is failure should be receiver failure`() { + val expectedException = RuntimeException("Exception on int result.") + val intResult = Result.failure(expectedException) + val stringResult = intResult.flatMap { + throw RuntimeException("transform function should not be called for failed Results") + } + assertTrue(stringResult.isFailure) + assertEquals(expectedException, stringResult.exceptionOrNull()) + } + + @Test + fun `flatMap where receiver is failure and argument is success should be receiver failure`() { + val expectedException = RuntimeException("Exception on int result.") + val intResult = Result.failure(expectedException) + val stringResult = intResult.flatMap { + Result.success("1") + } + assertTrue(stringResult.isFailure) + assertEquals(expectedException, stringResult.exceptionOrNull()) + } +}