Add multi-platform support

Converts the unit tests to use kotlin-test, allowing them to target both
the jvm and js platforms.
This commit is contained in:
Michael Bull 2017-12-16 19:30:54 +00:00
parent 416c0950b2
commit 9ddac98e0c
14 changed files with 754 additions and 500 deletions

View File

@ -7,15 +7,16 @@ buildscript {
dependencies { dependencies {
classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlinVersion" classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlinVersion"
classpath "org.jetbrains.dokka:dokka-gradle-plugin:$dokkaVersion" classpath "org.jetbrains.dokka:dokka-gradle-plugin:$dokkaVersion"
classpath "org.junit.platform:junit-platform-gradle-plugin:$junitPlatformVersion"
classpath "net.researchgate:gradle-release:$gradleReleaseVersion" classpath "net.researchgate:gradle-release:$gradleReleaseVersion"
} }
} }
apply plugin: 'kotlin' plugins {
id 'com.github.ben-manes.versions' version '0.17.0'
}
apply plugin: 'kotlin-platform-common'
apply plugin: 'maven-publish' apply plugin: 'maven-publish'
apply plugin: 'org.jetbrains.dokka'
apply plugin: 'org.junit.platform.gradle.plugin'
apply plugin: 'net.researchgate.release' apply plugin: 'net.researchgate.release'
description = 'A Result monad for modelling success or failure operations.' description = 'A Result monad for modelling success or failure operations.'
@ -25,31 +26,9 @@ repositories {
} }
dependencies { dependencies {
compile "org.jetbrains.kotlin:kotlin-stdlib-jre8:$kotlinVersion" compile "org.jetbrains.kotlin:kotlin-stdlib-common:$kotlinVersion"
testCompile "com.natpryce:hamkrest:$hamkrestVersion" testCompile "org.jetbrains.kotlin:kotlin-test-annotations-common:$kotlinVersion"
testCompile "org.junit.jupiter:junit-jupiter-params:$junitVersion" testCompile "org.jetbrains.kotlin:kotlin-test-common:$kotlinVersion"
testCompile "org.junit.jupiter:junit-jupiter-api:$junitVersion"
testRuntime "org.junit.jupiter:junit-jupiter-engine:$junitVersion"
}
compileKotlin {
kotlinOptions.jvmTarget = "1.8"
}
compileTestKotlin {
kotlinOptions.jvmTarget = "1.8"
}
dokka {
outputFormat = 'javadoc'
outputDirectory = "$buildDir/docs"
}
task javadocJar(type: Jar, dependsOn: dokka) {
group = LifecycleBasePlugin.BUILD_GROUP
description = 'Assembles a jar archive containing the Javadoc API documentation.'
classifier = 'javadoc'
from dokka.outputDirectory
} }
task sourcesJar(type: Jar) { task sourcesJar(type: Jar) {
@ -62,8 +41,6 @@ task sourcesJar(type: Jar) {
publishing { publishing {
publications { publications {
mavenJava(MavenPublication) { mavenJava(MavenPublication) {
from components.java
artifact javadocJar
artifact sourcesJar artifact sourcesJar
} }
} }

View File

@ -4,6 +4,5 @@ version=1.0.3-SNAPSHOT
dokkaVersion=0.9.15 dokkaVersion=0.9.15
gradleReleaseVersion=2.6.0 gradleReleaseVersion=2.6.0
hamkrestVersion=1.4.2.0 hamkrestVersion=1.4.2.0
junitVersion=5.0.1 junitVersion=4.12
junitPlatformVersion=1.0.0
kotlinVersion=1.2.10 kotlinVersion=1.2.10

11
js/build.gradle Normal file
View File

@ -0,0 +1,11 @@
apply plugin: 'kotlin-platform-js'
repositories {
mavenCentral()
}
dependencies {
compile "org.jetbrains.kotlin:kotlin-stdlib-js:$kotlinVersion"
expectedBy project(":")
testCompile "org.jetbrains.kotlin:kotlin-test-js:$kotlinVersion"
}

35
jvm/build.gradle Normal file
View File

@ -0,0 +1,35 @@
apply plugin: 'kotlin-platform-jvm'
apply plugin: 'org.jetbrains.dokka'
repositories {
mavenCentral()
}
dependencies {
compile "org.jetbrains.kotlin:kotlin-stdlib:$kotlinVersion"
expectedBy project(":")
testCompile "junit:junit:$junitVersion"
testCompile "org.jetbrains.kotlin:kotlin-test-junit:$kotlinVersion"
testCompile "org.jetbrains.kotlin:kotlin-test:$kotlinVersion"
}
dokka {
outputFormat = 'javadoc'
outputDirectory = "$buildDir/docs"
}
task javadocJar(type: Jar, dependsOn: dokka) {
group = LifecycleBasePlugin.BUILD_GROUP
description = 'Assembles a jar archive containing the Javadoc API documentation.'
classifier = 'javadoc'
from dokka.outputDirectory
}
publishing {
publications {
mavenJava(MavenPublication) {
from components.java
artifact javadocJar
}
}
}

View File

@ -1,2 +1,3 @@
rootProject.name = 'kotlin-result' rootProject.name = 'kotlin-result'
include 'js', 'jvm'

View File

@ -1,34 +1,45 @@
package com.github.michaelbull.result package com.github.michaelbull.result
import com.natpryce.hamkrest.assertion.assertThat import kotlin.test.Test
import com.natpryce.hamkrest.equalTo import kotlin.test.assertEquals
import com.natpryce.hamkrest.sameInstance import kotlin.test.assertSame
import org.junit.jupiter.api.Test
internal class AndTest { internal class AndTest {
private object AndError private object AndError
@Test internal class `and` {
internal fun `and should return the result value if ok`() { @Test
val value = Ok(230).and(Ok(500)).get() internal fun returnsValueIfOk() {
assertThat(value, equalTo(500)) assertEquals(
expected = 500,
actual = Ok(230).and(Ok(500)).get()
)
}
@Test
internal fun returnsValueIfErr() {
assertEquals(
expected = "hello world",
actual = Ok(300).and(Err("hello world")).getError()
)
}
} }
@Test internal class `andThen` {
internal fun `and should return the result value if not ok`() { @Test
val error = Ok(300).and(Err("hello world")).getError() internal fun returnsTransformedValueIfOk() {
assertThat(error, equalTo("hello world")) assertEquals(
} expected = 12,
actual = Ok(5).andThen { Ok(it + 7) }.get()
)
}
@Test @Test
internal fun `andThen should return the transformed result value if ok`() { internal fun returnsErrorIfErr() {
val value = Ok(5).andThen { Ok(it + 7) }.get() assertSame(
assertThat(value, equalTo(12)) expected = AndError,
} actual = Ok(20).andThen { Ok(it + 43) }.andThen { Err(AndError) }.getError()!!
)
@Test }
internal fun `andThen should return the result error if not ok`() {
val error = Ok(20).andThen { Ok(it + 43) }.andThen { Err(AndError) }.getError()!!
assertThat(error, sameInstance(AndError))
} }
} }

View File

@ -1,79 +1,109 @@
package com.github.michaelbull.result package com.github.michaelbull.result
import com.natpryce.hamkrest.assertion.assertThat import kotlin.test.Test
import com.natpryce.hamkrest.equalTo import kotlin.test.assertEquals
import org.junit.jupiter.api.Test import kotlin.test.assertNull
internal class GetTest { internal class GetTest {
@Test internal class `get` {
internal fun `get should return the result value if ok`() { @Test
val value = Ok(12).get() internal fun returnsValueIfOk() {
assertThat(value, equalTo(12)) assertEquals(
expected = 12,
actual = Ok(12).get()
)
}
@Test
internal fun returnsNullIfErr() {
assertNull(Err("error").get())
}
} }
@Test internal class `getError` {
internal fun `get should return null if not ok`() { @Test
val value = Err("error").get() internal fun returnsNullIfOk() {
assertThat(value, equalTo(null)) assertNull(Ok("example").getError())
}
@Test
internal fun returnsErrorIfErr() {
assertEquals(
expected = "example",
actual = Err("example").getError()
)
}
} }
@Test internal class `getOr` {
internal fun `getError should return null if ok`() { @Test
val error = Ok("example").getError() internal fun returnsValueIfOk() {
assertThat(error, equalTo(null)) assertEquals(
expected = "hello",
actual = Ok("hello").getOr("world")
)
}
@Test
internal fun returnsDefaultValueIfErr() {
assertEquals(
expected = "default",
actual = Err("error").getOr("default")
)
}
} }
@Test internal class `getErrorOr` {
internal fun `getError should return the result error if not ok`() { @Test
val error = Err("example").getError() internal fun returnsDefaultValueIfOk() {
assertThat(error, equalTo("example")) assertEquals(
expected = "world",
actual = Ok("hello").getErrorOr("world")
)
}
@Test
internal fun returnsErrorIfErr() {
assertEquals(
expected = "hello",
actual = Err("hello").getErrorOr("world")
)
}
} }
@Test internal class `getOrElse` {
internal fun `getOr should return the result value if ok`() { @Test
val value = Ok("hello").getOr("world") internal fun returnsValueIfOk() {
assertThat(value, equalTo("hello")) assertEquals(
expected = "hello",
actual = Ok("hello").getOrElse { "world" }
)
}
@Test
internal fun returnsTransformedErrorIfErr() {
assertEquals(
expected = "world",
actual = Err("hello").getOrElse { "world" }
)
}
} }
@Test internal class `getErrorOrElse` {
internal fun `getOr should return default value if not ok`() { @Test
val value = Err("error").getOr("default") internal fun returnsTransformedValueIfOk() {
assertThat(value, equalTo("default")) assertEquals(
} expected = "world",
actual = Ok("hello").getErrorOrElse { "world" }
)
}
@Test @Test
internal fun `getErrorOr should return the default value if ok`() { internal fun returnsErrorIfErr() {
val error = Ok("hello").getErrorOr("world") assertEquals(
assertThat(error, equalTo("world")) expected = "hello",
} actual = Err("hello").getErrorOrElse { "world" }
)
@Test }
internal fun `getErrorOr should return the result error if not ok`() {
val error = Err("hello").getErrorOr("world")
assertThat(error, equalTo("hello"))
}
@Test
internal fun `getOrElse should return the result value if ok`() {
val value = Ok("hello").getOrElse { "world" }
assertThat(value, equalTo("hello"))
}
@Test
internal fun `getOrElse should return the transformed result error if ok`() {
val value = Err("hello").getOrElse { "world" }
assertThat(value, equalTo("world"))
}
@Test
internal fun `getErrorOrElse should return the transformed result value if ok`() {
val error = Ok("hello").getErrorOrElse { "world" }
assertThat(error, equalTo("world"))
}
@Test
internal fun `getErrorOrElse should return the result error if not ok`() {
val error = Err("hello").getErrorOrElse { "world" }
assertThat(error, equalTo("hello"))
} }
} }

View File

@ -1,10 +1,8 @@
package com.github.michaelbull.result package com.github.michaelbull.result
import com.natpryce.hamkrest.Matcher import kotlin.test.Test
import com.natpryce.hamkrest.assertion.assertThat import kotlin.test.assertEquals
import com.natpryce.hamkrest.equalTo import kotlin.test.assertSame
import com.natpryce.hamkrest.sameInstance
import org.junit.jupiter.api.Test
internal class IterableTest { internal class IterableTest {
private sealed class IterableError { private sealed class IterableError {
@ -12,168 +10,291 @@ internal class IterableTest {
object IterableError2 : IterableError() object IterableError2 : IterableError()
} }
private fun sameError(error: IterableError): Matcher<IterableError> { internal class `fold` {
return sameInstance(error) @Test
} internal fun returnAccumulatedValueIfOk() {
val result = listOf(20, 30, 40, 50).fold(
initial = 10,
operation = { a, b -> Ok(a + b) }
)
@Test result as Ok
internal fun `fold should return the accumulated value if ok`() {
val result = listOf(20, 30, 40, 50).fold(
initial = 10,
operation = { a, b -> Ok(a + b) }
)
result as Ok assertEquals(
expected = 150,
actual = result.value
)
}
assertThat(result.value, equalTo(150)) @Test
} internal fun returnsFirstErrorIfErr() {
val result: Result<Int, IterableError> = listOf(5, 10, 15, 20, 25).fold(
@Test initial = 1,
internal fun `fold should return the first error if not ok`() { operation = { a, b ->
val result: Result<Int, IterableError> = listOf(5, 10, 15, 20, 25).fold( when (b) {
initial = 1, (5 + 10) -> Err(IterableError.IterableError1)
operation = { a, b -> (5 + 10 + 15 + 20) -> Err(IterableError.IterableError2)
when (b) { else -> Ok(a * b)
(5 + 10) -> Err(IterableError.IterableError1) }
(5 + 10 + 15 + 20) -> Err(IterableError.IterableError2)
else -> Ok(a * b)
} }
} )
)
result as Err result as Err
val matcher: Matcher<IterableError> = sameInstance(IterableError.IterableError1) assertSame(
assertThat(result.error, matcher) expected = IterableError.IterableError1,
actual = result.error
)
}
} }
@Test internal class `foldRight` {
internal fun `foldRight should return the accumulated value if ok`() { @Test
val result = listOf(2, 5, 10, 20).foldRight( internal fun returnsAccumulatedValueIfOk() {
initial = 100, val result = listOf(2, 5, 10, 20).foldRight(
operation = { a, b -> Ok(b - a) } initial = 100,
) operation = { a, b -> Ok(b - a) }
)
result as Ok result as Ok
assertThat(result.value, equalTo(63)) assertEquals(
} expected = 63,
actual = result.value
)
}
@Test @Test
internal fun `foldRight should return the last error if not ok`() { internal fun returnsLastErrorIfErr() {
val result = listOf(2, 5, 10, 20, 40).foldRight( val result = listOf(2, 5, 10, 20, 40).foldRight(
initial = 38500, initial = 38500,
operation = { a, b -> operation = { a, b ->
when (b) { when (b) {
(((38500 / 40) / 20) / 10) -> Err(IterableError.IterableError1) (((38500 / 40) / 20) / 10) -> Err(IterableError.IterableError1)
((38500 / 40) / 20) -> Err(IterableError.IterableError2) ((38500 / 40) / 20) -> Err(IterableError.IterableError2)
else -> Ok(b / a) else -> Ok(b / a)
}
} }
} )
)
result as Err result as Err
assertThat(result.error, sameError(IterableError.IterableError2)) assertSame(
expected = IterableError.IterableError2,
actual = result.error
)
}
} }
@Test internal class `combine` {
internal fun `combine should return the combined list of values if results are ok`() { @Test
val values = combine( internal fun returnsValuesIfAllOk() {
Ok(10), val values = combine(
Ok(20), Ok(10),
Ok(30) Ok(20),
).get()!! Ok(30)
).get()!!
assertThat(values.size, equalTo(3)) assertEquals(
assertThat(values[0], equalTo(10)) expected = 3,
assertThat(values[1], equalTo(20)) actual = values.size
assertThat(values[2], equalTo(30)) )
assertEquals(
expected = 10,
actual = values[0]
)
assertEquals(
expected = 20,
actual = values[1]
)
assertEquals(
expected = 30,
actual = values[2]
)
}
@Test
internal fun returnsFirstErrorIfErr() {
val result = combine(
Ok(20),
Ok(40),
Err(IterableError.IterableError1),
Ok(60),
Err(IterableError.IterableError2),
Ok(80)
)
result as Err
assertSame(
expected = IterableError.IterableError1,
actual = result.error
)
}
} }
@Test internal class `getAll` {
internal fun `combine should return the first error if results are not ok`() { @Test
val result = combine( internal fun returnsAllValues() {
Ok(20), val values = getAll(
Ok(40), Ok("hello"),
Err(IterableError.IterableError1), Ok("big"),
Ok(60), Err(IterableError.IterableError2),
Err(IterableError.IterableError2), Ok("wide"),
Ok(80) Err(IterableError.IterableError1),
) Ok("world")
)
result as Err assertEquals(
expected = 4,
actual = values.size
)
assertThat(result.error, sameError(IterableError.IterableError1)) assertEquals(
expected = "hello",
actual = values[0]
)
assertEquals(
expected = "big",
actual = values[1]
)
assertEquals(
expected = "wide",
actual = values[2]
)
assertEquals(
expected = "world",
actual = values[3]
)
}
} }
@Test internal class `getAllErrors` {
internal fun `getAll should return all of the result values`() { @Test
val values = getAll( internal fun returnsAllErrors() {
Ok("hello"), val errors = getAllErrors(
Ok("big"), Err(IterableError.IterableError2),
Err(IterableError.IterableError2), Ok("haskell"),
Ok("wide"), Err(IterableError.IterableError2),
Err(IterableError.IterableError1), Ok("f#"),
Ok("world") Err(IterableError.IterableError1),
) Ok("elm"),
Err(IterableError.IterableError1),
Ok("clojure"),
Err(IterableError.IterableError2)
)
assertThat(values.size, equalTo(4)) assertEquals(
assertThat(values[0], equalTo("hello")) expected = 5,
assertThat(values[1], equalTo("big")) actual = errors.size
assertThat(values[2], equalTo("wide")) )
assertThat(values[3], equalTo("world"))
assertSame(
expected = IterableError.IterableError2,
actual = errors[0]
)
assertSame(
expected = IterableError.IterableError2,
actual = errors[1]
)
assertSame(
expected = IterableError.IterableError1,
actual = errors[2]
)
assertSame(
expected = IterableError.IterableError1,
actual = errors[3]
)
assertSame(
expected = IterableError.IterableError2,
actual = errors[4]
)
}
} }
@Test internal class `partition` {
internal fun `getAllErrors should return all of the result errors`() { @Test
val errors = getAllErrors( internal fun returnsPairOfValuesAndErrors() {
Err(IterableError.IterableError2), val pairs = partition(
Ok("haskell"), Err(IterableError.IterableError2),
Err(IterableError.IterableError2), Ok("haskell"),
Ok("f#"), Err(IterableError.IterableError2),
Err(IterableError.IterableError1), Ok("f#"),
Ok("elm"), Err(IterableError.IterableError1),
Err(IterableError.IterableError1), Ok("elm"),
Ok("clojure"), Err(IterableError.IterableError1),
Err(IterableError.IterableError2) Ok("clojure"),
) Err(IterableError.IterableError2)
)
assertThat(errors.size, equalTo(5)) val values = pairs.first
assertThat(errors[0], sameError(IterableError.IterableError2))
assertThat(errors[1], sameError(IterableError.IterableError2))
assertThat(errors[2], sameError(IterableError.IterableError1))
assertThat(errors[3], sameError(IterableError.IterableError1))
assertThat(errors[4], sameError(IterableError.IterableError2))
}
@Test assertEquals(
internal fun `partition should return a pair of all the result values and errors`() { expected = 4,
val pairs = partition( actual = values.size
Err(IterableError.IterableError2), )
Ok("haskell"),
Err(IterableError.IterableError2),
Ok("f#"),
Err(IterableError.IterableError1),
Ok("elm"),
Err(IterableError.IterableError1),
Ok("clojure"),
Err(IterableError.IterableError2)
)
val values = pairs.first assertEquals(
assertThat(values.size, equalTo(4)) expected = "haskell",
assertThat(values[0], equalTo("haskell")) actual = values[0]
assertThat(values[1], equalTo("f#")) )
assertThat(values[2], equalTo("elm"))
assertThat(values[3], equalTo("clojure"))
val errors = pairs.second assertEquals(
assertThat(errors.size, equalTo(5)) expected = "f#",
assertThat(errors[0], sameError(IterableError.IterableError2)) actual = values[1]
assertThat(errors[1], sameError(IterableError.IterableError2)) )
assertThat(errors[2], sameError(IterableError.IterableError1))
assertThat(errors[3], sameError(IterableError.IterableError1)) assertEquals(
assertThat(errors[4], sameError(IterableError.IterableError2)) expected = "elm",
actual = values[2]
)
assertEquals(
expected = "clojure",
actual = values[3]
)
val errors = pairs.second
assertEquals(
expected = 5,
actual = errors.size
)
assertSame(
expected = IterableError.IterableError2,
actual = errors[0]
)
assertSame(
expected = IterableError.IterableError2,
actual = errors[1]
)
assertSame(
expected = IterableError.IterableError1,
actual = errors[2]
)
assertSame(
expected = IterableError.IterableError1,
actual = errors[3]
)
assertSame(
expected = IterableError.IterableError2,
actual = errors[4]
)
}
} }
} }

View File

@ -1,10 +1,8 @@
package com.github.michaelbull.result package com.github.michaelbull.result
import com.natpryce.hamkrest.Matcher import kotlin.test.Test
import com.natpryce.hamkrest.assertion.assertThat import kotlin.test.assertEquals
import com.natpryce.hamkrest.equalTo import kotlin.test.assertSame
import com.natpryce.hamkrest.sameInstance
import org.junit.jupiter.api.Test
internal class MapTest { internal class MapTest {
private sealed class MapError(val reason: String) { private sealed class MapError(val reason: String) {
@ -13,93 +11,121 @@ internal class MapTest {
class CustomError(reason: String) : MapError(reason) class CustomError(reason: String) : MapError(reason)
} }
private fun sameError(error: MapError): Matcher<MapError> { internal class `map` {
return sameInstance(error) @Test
internal fun returnsTransformedValueIfOk() {
assertEquals(
expected = 30,
actual = Ok(10).map { it + 20 }.get()
)
}
@Test
@Suppress("UNREACHABLE_CODE")
internal fun returnsErrorIfErr() {
val result = Err(MapError.HelloError).map { "hello $it" }
result as Err
assertSame(
expected = MapError.HelloError,
actual = result.error
)
}
} }
@Test internal class `mapError` {
internal fun `map should return the transformed result value if ok`() { @Test
val value = Ok(10).map { it + 20 }.get() internal fun returnsValueIfOk() {
assertThat(value, equalTo(30)) val value = Ok(55).map { it + 15 }.mapError { MapError.WorldError }.get()
}
@Test assertEquals(
@Suppress("UNREACHABLE_CODE") expected = 70,
internal fun `map should return the result error if not ok`() { actual = value
val result = Err(MapError.HelloError).map { "hello $it" } )
}
result as Err @Test
internal fun returnsErrorIfErr() {
assertThat(result.error, sameError(MapError.HelloError)) val result: Result<String, MapError> = Ok("let")
} .map { "$it me" }
.andThen {
@Test when (it) {
internal fun `mapError should return the result value if ok`() { "let me" -> Err(MapError.CustomError("$it $it"))
val value = Ok(55).map { it + 15 }.mapError { MapError.WorldError }.get() else -> Ok("$it get")
assertThat(value, equalTo(70)) }
}
@Test
internal fun `mapError should return the transformed result error if not ok`() {
val result: Result<String, MapError> = Ok("let")
.map { "$it me" }
.andThen {
when (it) {
"let me" -> Err(MapError.CustomError("$it $it"))
else -> Ok("$it get")
} }
} .mapError { MapError.CustomError("${it.reason} get what i want") }
.mapError { MapError.CustomError("${it.reason} get what i want") }
result as Err result as Err
assertThat(result.error.reason, equalTo("let me let me get what i want")) assertEquals(
expected = "let me let me get what i want",
actual = result.error.reason
)
}
} }
@Test internal class `mapBoth` {
@Suppress("UNREACHABLE_CODE") @Test
internal fun `mapBoth should return the transformed result value if ok`() { @Suppress("UNREACHABLE_CODE")
val value = Ok("there is").mapBoth( internal fun returnsTransformedValueIfOk() {
success = { "$it a light" }, val value = Ok("there is").mapBoth(
failure = { "$it that never" } success = { "$it a light" },
) failure = { "$it that never" }
)
assertThat(value, equalTo("there is a light")) assertEquals(
expected = "there is a light",
actual = value
)
}
@Test
@Suppress("UNREACHABLE_CODE")
internal fun returnsTransformedErrorIfErr() {
val error = Err(MapError.CustomError("this")).mapBoth(
success = { "$it charming" },
failure = { "${it.reason} man" }
)
assertEquals(
expected = "this man",
actual = error
)
}
} }
@Test internal class `mapEither` {
@Suppress("UNREACHABLE_CODE") @Test
internal fun `mapBoth should return the transformed result error if not ok`() { @Suppress("UNREACHABLE_CODE")
val error = Err(MapError.CustomError("this")).mapBoth( internal fun returnsTransformedValueIfOk() {
success = { "$it charming" }, val result = Ok(500).mapEither(
failure = { "${it.reason} man" } success = { it + 500 },
) failure = { MapError.CustomError("$it") }
)
assertThat(error, equalTo("this man")) result as Ok
}
@Test assertEquals(
@Suppress("UNREACHABLE_CODE") expected = 1000,
internal fun `mapEither should return the transformed result value if ok`() { actual = result.value
val result = Ok(500).mapEither( )
success = { it + 500 }, }
failure = { MapError.CustomError("$it") }
)
result as Ok @Test
internal fun returnsTransformedErrorIfErr() {
val result = Err("the reckless").mapEither(
success = { "the wild youth" },
failure = { MapError.CustomError("the truth") }
)
assertThat(result.value, equalTo(1000)) result as Err
}
@Test assertEquals(
internal fun `mapEither should return the transformed result error if not ok`() { expected = "the truth",
val result = Err("the reckless").mapEither( actual = result.error.reason
success = { "the wild youth" }, )
failure = { MapError.CustomError("the truth") } }
)
result as Err
assertThat(result.error.reason, equalTo("the truth"))
} }
} }

View File

@ -1,38 +1,61 @@
package com.github.michaelbull.result package com.github.michaelbull.result
import com.natpryce.hamkrest.assertion.assertThat import kotlin.test.Test
import com.natpryce.hamkrest.equalTo import kotlin.test.assertEquals
import org.junit.jupiter.api.Test
internal class OnTest { internal class OnTest {
object CounterError object CounterError
class Counter(var count: Int) class Counter(var count: Int)
@Test internal class `onSuccess` {
internal fun `onSuccess should invoke the callback when result is ok`() { @Test
val counter = Counter(50) internal fun invokesCallbackIfOk() {
Ok(counter).onSuccess { it.count += 50 } val counter = Counter(50)
assertThat(counter.count, equalTo(100))
Ok(counter).onSuccess { it.count += 50 }
assertEquals(
expected = 100,
actual = counter.count
)
}
@Test
internal fun invokesNothingIfErr() {
val counter = Counter(200)
Err(CounterError).onSuccess { counter.count -= 50 }
assertEquals(
expected = 200,
actual = counter.count
)
}
} }
@Test internal class `onFailure` {
internal fun `onSuccess should not invoke the callback when result is not ok`() { @Test
val counter = Counter(200) internal fun invokesCallbackIfErr() {
Err(CounterError).onSuccess { counter.count -= 50 } val counter = Counter(555)
assertThat(counter.count, equalTo(200))
}
@Test Err(CounterError).onFailure { counter.count += 100 }
internal fun `onFailure should invoke the callback when result is not ok`() {
val counter = Counter(555)
Err(CounterError).onFailure { counter.count += 100 }
assertThat(counter.count, equalTo(655))
}
@Test assertEquals(
internal fun `onFailure should not invoke the callback when result is ok`() { expected = 655,
val counter = Counter(1020) actual = counter.count
Ok("hello").onFailure { counter.count = 1030 } )
assertThat(counter.count, equalTo(1020)) }
@Test
internal fun invokesNothingIfOk() {
val counter = Counter(1020)
Ok("hello").onFailure { counter.count = 1030 }
assertEquals(
expected = 1020,
actual = counter.count
)
}
} }
} }

View File

@ -1,33 +1,44 @@
package com.github.michaelbull.result package com.github.michaelbull.result
import com.natpryce.hamkrest.assertion.assertThat import kotlin.test.Test
import com.natpryce.hamkrest.equalTo import kotlin.test.assertEquals
import org.junit.jupiter.api.Test
internal class OrTest { internal class OrTest {
private object OrError private object OrError
@Test internal class `or` {
internal fun `or should return the result value if ok`() { @Test
val value = Ok(500).or(Ok(1000)).get() internal fun returnsValueIfOk() {
assertThat(value, equalTo(500)) assertEquals(
expected = 500,
actual = Ok(500).or(Ok(1000)).get()
)
}
@Test
internal fun returnsDefaultValueIfErr() {
assertEquals(
expected = 5000,
actual = Err(OrError).or(Ok(5000)).get()
)
}
} }
@Test internal class `orElse` {
internal fun `or should return the default value if not ok`() { @Test
val value = Err(OrError).or(Ok(5000)).get() internal fun returnsValueIfOk() {
assertThat(value, equalTo(5000)) assertEquals(
} expected = 3000,
actual = Ok(3000).orElse { Ok(4000) }.get()
)
}
@Test @Test
internal fun `orElse should return the result value if ok`() { internal fun returnsTransformedValueIfErr() {
val value = Ok(3000).orElse { Ok(4000) }.get() assertEquals(
assertThat(value, equalTo(3000)) expected = 2000,
} actual = Err(4000).orElse { Ok(2000) }.get()
)
@Test }
internal fun `orElse should return the transformed value if not ok`() {
val value = Err(4000).orElse { Ok(2000) }.get()
assertThat(value, equalTo(2000))
} }
} }

View File

@ -1,69 +1,65 @@
package com.github.michaelbull.result package com.github.michaelbull.result
import com.natpryce.hamkrest.assertion.assertThat import kotlin.test.*
import com.natpryce.hamkrest.equalTo
import org.junit.jupiter.api.Assertions.assertThrows
import org.junit.jupiter.api.Test
internal class ResultIteratorTest { internal class ResultIteratorTest {
@Test internal class `hasNext` {
internal fun `hasNext should return true if unyielded and result is ok`() { @Test
val iterator = Ok("hello").iterator() internal fun returnsTrueIfUnyieldedAndOk() {
assertThat(iterator.hasNext(), equalTo(true)) val iterator = Ok("hello").iterator()
} assertTrue { iterator.hasNext() }
}
@Test @Test
internal fun `hasNext should return false if result is not ok`() { internal fun returnsFalseIfErr() {
val iterator = Err("hello").iterator() val iterator = Err("hello").iterator()
assertThat(iterator.hasNext(), equalTo(false)) assertFalse { iterator.hasNext() }
} }
@Test @Test
internal fun `hasNext should return false if yielded`() { internal fun returnsFalseIfYielded() {
val iterator = Ok("hello").iterator() val iterator = Ok("hello").iterator()
iterator.next()
assertThat(iterator.hasNext(), equalTo(false))
}
@Test
internal fun `next should return the result value if unyielded and result is ok`() {
val value = Ok("hello").iterator().next()
assertThat(value, equalTo("hello"))
}
@Test
internal fun `next should throw NoSuchElementException if unyielded and result is not ok`() {
val iterator = Err("hello").iterator()
assertThrows(NoSuchElementException::class.java) {
iterator.next() iterator.next()
assertFalse { iterator.hasNext() }
} }
} }
@Test internal class `next` {
internal fun `next should throw NoSuchElementException if yielded and result is ok`() { @Test
val iterator = Ok("hello").iterator() internal fun returnsValueIfUnyieldedAndOk() {
iterator.next() assertEquals(
expected = "hello",
actual = Ok("hello").iterator().next()
)
}
assertThrows(NoSuchElementException::class.java) { @Test
internal fun throwsExceptionIfUnyieldedAndErr() {
val iterator = Err("hello").iterator()
assertFailsWith<NoSuchElementException> { iterator.next() }
}
@Test
internal fun throwsExceptionIfYieldedAndOk() {
val iterator = Ok("hello").iterator()
iterator.next() iterator.next()
assertFailsWith<NoSuchElementException> { iterator.next() }
} }
} }
@Test internal class `remove` {
internal fun `remove should make hasNext return false`() { @Test
val iterator = Ok("hello").mutableIterator() internal fun makesHasNextReturnFalse() {
iterator.remove() val iterator = Ok("hello").mutableIterator()
assertThat(iterator.hasNext(), equalTo(false)) iterator.remove()
} assertFalse { iterator.hasNext() }
}
@Test @Test
internal fun `remove should make next throw NoSuchElementException`() { internal fun makesNextThrowException() {
val iterator = Ok("hello").mutableIterator() val iterator = Ok("hello").mutableIterator()
iterator.remove() iterator.remove()
assertFailsWith<NoSuchElementException> { iterator.next() }
assertThrows(NoSuchElementException::class.java) {
iterator.next()
} }
} }
} }

View File

@ -1,25 +1,31 @@
package com.github.michaelbull.result package com.github.michaelbull.result
import com.natpryce.hamkrest.Matcher import kotlin.test.Test
import com.natpryce.hamkrest.assertion.assertThat import kotlin.test.assertEquals
import com.natpryce.hamkrest.equalTo import kotlin.test.assertSame
import com.natpryce.hamkrest.sameInstance
import org.junit.jupiter.api.Test
internal class ResultTest { internal class ResultTest {
@Test internal class `of` {
internal fun `of should return ok if invocation did not throw anything`() { @Test
val callback = { "example" } internal fun returnsOkIfInvocationSuccessful() {
val value = Result.of(callback).get() val callback = { "example" }
assertThat(value, equalTo("example"))
}
@Test assertEquals(
internal fun `of should return error if invocation threw something`() { expected = "example",
val throwable = IllegalArgumentException("throw me") actual = Result.of(callback).get()
val callback = { throw throwable } )
val error = Result.of(callback).getError()!! }
val matcher: Matcher<Throwable> = sameInstance(throwable)
assertThat(error, matcher) @Test
internal fun returnsErrIfInvocationFails() {
val throwable = IllegalArgumentException("throw me")
val callback = { throw throwable }
val error = Result.of(callback).getError()!!
assertSame(
expected = throwable,
actual = error
)
}
} }
} }

View File

@ -1,76 +1,83 @@
package com.github.michaelbull.result package com.github.michaelbull.result
import com.natpryce.hamkrest.assertion.assertThat import kotlin.test.Test
import com.natpryce.hamkrest.equalTo import kotlin.test.assertEquals
import org.junit.jupiter.api.Assertions.assertThrows import kotlin.test.assertFailsWith
import org.junit.jupiter.api.Test
internal class UnwrapTest { internal class UnwrapTest {
@Test internal class `unwrap` {
internal fun `unwrap should return the result value if ok`() { @Test
val value = Ok(5000).unwrap() internal fun returnsValueIfOk() {
assertThat(value, equalTo(5000)) assertEquals(
} expected = 5000,
actual = Ok(5000).unwrap()
@Test )
internal fun `unwrap should throw an UnwrapException if not ok`() {
val throwable = assertThrows(UnwrapException::class.java) {
Err(5000).unwrap()
} }
assertThat(throwable.message, equalTo("called Result.wrap on an Err value 5000")) @Test
internal fun throwsExceptionIfErr() {
assertFailsWith<UnwrapException>("called Result.wrap on an Err value 5000") {
Err(5000).unwrap()
}
}
} }
@Test internal class `expect` {
internal fun `expect should return the result value if ok`() { @Test
val value = Ok(1994).expect { "the year should be" } internal fun returnsValueIfOk() {
assertThat(value, equalTo(1994)) assertEquals(
} expected = 1994,
actual = Ok(1994).expect { "the year should be" }
@Test )
internal fun `expect should throw an UnwrapException with a specified message if not ok`() {
val message = object {
override fun toString() = "the year should be"
} }
val throwable = assertThrows(UnwrapException::class.java) { @Test
Err(1994).expect { message } internal fun throwsExceptionIfErr() {
} val message = object {
override fun toString() = "the year should be"
}
assertThat(throwable.message, equalTo("the year should be 1994")) assertFailsWith<UnwrapException>("the year should be 1994") {
Err(1994).expect { message }
}
}
} }
@Test internal class `unwrapError` {
internal fun `unwrapError should throw an UnwrapException if ok`() { @Test
val throwable = assertThrows(UnwrapException::class.java) { internal fun throwsExceptionIfOk() {
Ok("example").unwrapError() assertFailsWith<UnwrapException>("called Result.unwrapError on an Ok value example") {
Ok("example").unwrapError()
}
} }
assertThat(throwable.message, equalTo("called Result.unwrapError on an Ok value example")) @Test
internal fun returnsErrorIfErr() {
assertEquals(
expected = "example",
actual = Err("example").unwrapError()
)
}
} }
@Test internal class `expectError` {
internal fun `unwrapError should return the result error if not ok`() { @Test
val error = Err("example").unwrapError() internal fun throwsExceptionIfOk() {
assertThat(error, equalTo("example")) val message = object {
} override fun toString() = "the year should be"
}
@Test assertFailsWith<UnwrapException>("the year should be 2010") {
internal fun `expectError should throw an UnwrapException with a specified message if ok`() { Ok(2010).expectError { message }
val message = object { }
override fun toString() = "the year should be"
} }
val throwable = assertThrows(UnwrapException::class.java) { @Test
Ok(2010).expectError { message } internal fun returnsErrorIfErr() {
assertEquals(
expected = 2010,
actual = Err(2010).expectError { "the year should be" }
)
} }
assertThat(throwable.message, equalTo("the year should be 2010"))
}
@Test
internal fun `expectError should return the result error if not ok`() {
val error = Err(2010).expectError { "the year should be" }
assertThat(error, equalTo(2010))
} }
} }