parent
a40dcdf688
commit
bd7e1244b3
@ -91,6 +91,7 @@ kotlin {
|
|||||||
dependencies {
|
dependencies {
|
||||||
implementation(kotlin("test-common"))
|
implementation(kotlin("test-common"))
|
||||||
implementation(kotlin("test-annotations-common"))
|
implementation(kotlin("test-annotations-common"))
|
||||||
|
implementation("org.jetbrains.kotlinx:kotlinx-coroutines-core-native:1.3.7")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -0,0 +1,26 @@
|
|||||||
|
package com.github.michaelbull.result.coroutines
|
||||||
|
|
||||||
|
import com.github.michaelbull.result.BindException
|
||||||
|
import com.github.michaelbull.result.Ok
|
||||||
|
import com.github.michaelbull.result.Result
|
||||||
|
import com.github.michaelbull.result.ResultBinding
|
||||||
|
import com.github.michaelbull.result.ResultBindingImpl
|
||||||
|
import kotlin.contracts.InvocationKind
|
||||||
|
import kotlin.contracts.contract
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Suspending variant of [binding][com.github.michaelbull.result.binding].
|
||||||
|
*/
|
||||||
|
suspend inline fun <V, E> binding(crossinline block: suspend ResultBinding<E>.() -> V): Result<V, E> {
|
||||||
|
contract {
|
||||||
|
callsInPlace(block, InvocationKind.EXACTLY_ONCE)
|
||||||
|
}
|
||||||
|
|
||||||
|
val receiver = ResultBindingImpl<E>()
|
||||||
|
|
||||||
|
return try {
|
||||||
|
with(receiver) { Ok(block()) }
|
||||||
|
} catch (ex: BindException) {
|
||||||
|
receiver.error
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,9 @@
|
|||||||
|
package com.github.michaelbull.result
|
||||||
|
|
||||||
|
import kotlinx.coroutines.CoroutineScope
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Workaround to use suspending functions in unit tests for multiplatform/native projects.
|
||||||
|
* Solution was found here: https://github.com/Kotlin/kotlinx.coroutines/issues/885#issuecomment-446586161
|
||||||
|
*/
|
||||||
|
expect fun runBlockingTest(block: suspend (scope : CoroutineScope) -> Unit)
|
@ -0,0 +1,135 @@
|
|||||||
|
package com.github.michaelbull.result.coroutines
|
||||||
|
|
||||||
|
import com.github.michaelbull.result.Err
|
||||||
|
import com.github.michaelbull.result.Ok
|
||||||
|
import com.github.michaelbull.result.Result
|
||||||
|
import com.github.michaelbull.result.runBlockingTest
|
||||||
|
import kotlinx.coroutines.delay
|
||||||
|
import kotlin.test.Test
|
||||||
|
import kotlin.test.assertEquals
|
||||||
|
import kotlin.test.assertTrue
|
||||||
|
|
||||||
|
class SuspendableBindingTest {
|
||||||
|
|
||||||
|
private object BindingError
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun returnsOkIfAllBindsSuccessful() {
|
||||||
|
suspend fun provideX(): Result<Int, BindingError> {
|
||||||
|
delay(1)
|
||||||
|
return Ok(1)
|
||||||
|
}
|
||||||
|
|
||||||
|
suspend fun provideY(): Result<Int, BindingError> {
|
||||||
|
delay(1)
|
||||||
|
return Ok(2)
|
||||||
|
}
|
||||||
|
|
||||||
|
runBlockingTest {
|
||||||
|
val result = binding<Int, BindingError> {
|
||||||
|
val x = provideX().bind()
|
||||||
|
val y = provideY().bind()
|
||||||
|
x + y
|
||||||
|
}
|
||||||
|
|
||||||
|
assertTrue(result is Ok)
|
||||||
|
assertEquals(
|
||||||
|
expected = 3,
|
||||||
|
actual = result.value
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun returnsOkIfAllBindsOfDifferentTypeAreSuccessful() {
|
||||||
|
suspend fun provideX(): Result<String, BindingError> {
|
||||||
|
delay(1)
|
||||||
|
return Ok("1")
|
||||||
|
}
|
||||||
|
|
||||||
|
suspend fun provideY(x: Int): Result<Int, BindingError> {
|
||||||
|
delay(1)
|
||||||
|
return Ok(x + 2)
|
||||||
|
}
|
||||||
|
|
||||||
|
runBlockingTest {
|
||||||
|
val result = binding<Int, BindingError> {
|
||||||
|
val x = provideX().bind()
|
||||||
|
val y = provideY(x.toInt()).bind()
|
||||||
|
y
|
||||||
|
}
|
||||||
|
|
||||||
|
assertTrue(result is Ok)
|
||||||
|
assertEquals(
|
||||||
|
expected = 3,
|
||||||
|
actual = result.value
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun returnsFirstErrIfBindingFailed() {
|
||||||
|
suspend fun provideX(): Result<Int, BindingError> {
|
||||||
|
delay(1)
|
||||||
|
return Ok(1)
|
||||||
|
}
|
||||||
|
|
||||||
|
suspend fun provideY(): Result<Int, BindingError> {
|
||||||
|
delay(1)
|
||||||
|
return Err(BindingError)
|
||||||
|
}
|
||||||
|
|
||||||
|
suspend fun provideZ(): Result<Int, BindingError> {
|
||||||
|
delay(1)
|
||||||
|
return Ok(2)
|
||||||
|
}
|
||||||
|
|
||||||
|
runBlockingTest {
|
||||||
|
val result = binding<Int, BindingError> {
|
||||||
|
val x = provideX().bind()
|
||||||
|
val y = provideY().bind()
|
||||||
|
val z = provideZ().bind()
|
||||||
|
x + y + z
|
||||||
|
}
|
||||||
|
|
||||||
|
assertTrue(result is Err)
|
||||||
|
assertEquals(
|
||||||
|
expected = BindingError,
|
||||||
|
actual = result.error
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun returnsFirstErrIfBindingsOfDifferentTypesFailed() {
|
||||||
|
suspend fun provideX(): Result<Int, BindingError> {
|
||||||
|
delay(1)
|
||||||
|
return Ok(1)
|
||||||
|
}
|
||||||
|
|
||||||
|
suspend fun provideY(): Result<String, BindingError> {
|
||||||
|
delay(1)
|
||||||
|
return Err(BindingError)
|
||||||
|
}
|
||||||
|
|
||||||
|
suspend fun provideZ(): Result<Int, BindingError> {
|
||||||
|
delay(1)
|
||||||
|
return Ok(2)
|
||||||
|
}
|
||||||
|
|
||||||
|
runBlockingTest {
|
||||||
|
val result = binding<Int, BindingError> {
|
||||||
|
val x = provideX().bind()
|
||||||
|
val y = provideY().bind()
|
||||||
|
val z = provideZ().bind()
|
||||||
|
x + y.toInt() + z
|
||||||
|
}
|
||||||
|
|
||||||
|
assertTrue(result is Err)
|
||||||
|
assertEquals(
|
||||||
|
expected = BindingError,
|
||||||
|
actual = result.error
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,6 @@
|
|||||||
|
package com.github.michaelbull.result
|
||||||
|
|
||||||
|
import kotlinx.coroutines.CoroutineScope
|
||||||
|
import kotlinx.coroutines.runBlocking
|
||||||
|
|
||||||
|
actual fun runBlockingTest(block: suspend (scope : CoroutineScope) -> Unit) = runBlocking { block(this) }
|
Loading…
Reference in New Issue
Block a user