From 3b87373b238df613605cee0a82ee1e0def879507 Mon Sep 17 00:00:00 2001 From: Joseph Cooper Date: Tue, 26 Oct 2021 15:54:28 +0100 Subject: [PATCH] Add Result#{throwIf,throwUnless} Closes #64, #66 --- .../com/github/michaelbull/result/Or.kt | 42 ++++++++++++++ .../com/github/michaelbull/result/OrTest.kt | 58 +++++++++++++++++++ 2 files changed, 100 insertions(+) diff --git a/kotlin-result/src/commonMain/kotlin/com/github/michaelbull/result/Or.kt b/kotlin-result/src/commonMain/kotlin/com/github/michaelbull/result/Or.kt index b82325a..619be28 100644 --- a/kotlin-result/src/commonMain/kotlin/com/github/michaelbull/result/Or.kt +++ b/kotlin-result/src/commonMain/kotlin/com/github/michaelbull/result/Or.kt @@ -105,3 +105,45 @@ public inline fun Result.recoverUnless(predicate: (E) -> Boolean, t } } } + +/** + * Throws the [error][Err.error] if this [Result] is an [Err] + * and satisfies the given [predicate], otherwise this [Result]. + * + * @see [takeIf] + */ +public inline fun Result.throwIf(predicate: (E) -> Boolean): Result { + contract { + callsInPlace(predicate, InvocationKind.AT_MOST_ONCE) + } + + return when (this) { + is Ok -> this + is Err -> if (predicate(error)) { + throw error + } else { + this + } + } +} + +/** + * Throws the [error][Err.error] if this [Result] is an [Err] + * and _does not_ satisfy the given [predicate], otherwise this [Result]. + * + * @see [takeUnless] + */ +public inline fun Result.throwUnless(predicate: (E) -> Boolean): Result { + contract { + callsInPlace(predicate, InvocationKind.AT_MOST_ONCE) + } + + return when (this) { + is Ok -> this + is Err -> if (!predicate(error)) { + throw error + } else { + this + } + } +} diff --git a/kotlin-result/src/commonTest/kotlin/com/github/michaelbull/result/OrTest.kt b/kotlin-result/src/commonTest/kotlin/com/github/michaelbull/result/OrTest.kt index a948537..6abb300 100644 --- a/kotlin-result/src/commonTest/kotlin/com/github/michaelbull/result/OrTest.kt +++ b/kotlin-result/src/commonTest/kotlin/com/github/michaelbull/result/OrTest.kt @@ -181,4 +181,62 @@ class OrTest { ) } } + + class ThrowIf { + @Test + fun returnsValueIfOk() { + assertEquals( + expected = Ok(200), + actual = Ok(200).throwIf { true } + ) + } + + @Test + fun returnsErrIfPredicateDoesNotMatch() { + val error = RuntimeException("throw if") + + assertEquals( + expected = Err(error), + actual = Err(error).throwIf { false } + ) + } + + @Test + fun throwsErrIfPredicateMatches() { + val error = RuntimeException("throw if") + + assertFailsWith(error.message) { + Err(error).throwIf { true } + } + } + } + + class ThrowUnless { + @Test + fun returnsValueIfOk() { + assertEquals( + expected = Ok(500), + actual = Ok(500).throwUnless { false } + ) + } + + @Test + fun returnsErrIfPredicateMatches() { + val error = RuntimeException("example") + + assertEquals( + expected = Err(error), + actual = Err(error).throwUnless { true } + ) + } + + @Test + fun throwsErrIfPredicateDoesNotMatch() { + val error = RuntimeException("throw unless") + + assertFailsWith(error.message) { + Err(error).throwUnless { false } + } + } + } }