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
internal class `and` {
@Test @Test
internal fun `and should return the result value if ok`() { internal fun returnsValueIfOk() {
val value = Ok(230).and(Ok(500)).get() assertEquals(
assertThat(value, equalTo(500)) expected = 500,
actual = Ok(230).and(Ok(500)).get()
)
} }
@Test @Test
internal fun `and should return the result value if not ok`() { internal fun returnsValueIfErr() {
val error = Ok(300).and(Err("hello world")).getError() assertEquals(
assertThat(error, equalTo("hello world")) expected = "hello world",
actual = Ok(300).and(Err("hello world")).getError()
)
}
}
internal class `andThen` {
@Test
internal fun returnsTransformedValueIfOk() {
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 {
internal class `get` {
@Test @Test
internal fun `get should return the result value if ok`() { internal fun returnsValueIfOk() {
val value = Ok(12).get() assertEquals(
assertThat(value, equalTo(12)) expected = 12,
actual = Ok(12).get()
)
} }
@Test @Test
internal fun `get should return null if not ok`() { internal fun returnsNullIfErr() {
val value = Err("error").get() assertNull(Err("error").get())
assertThat(value, equalTo(null)) }
}
internal class `getError` {
@Test
internal fun returnsNullIfOk() {
assertNull(Ok("example").getError())
} }
@Test @Test
internal fun `getError should return null if ok`() { internal fun returnsErrorIfErr() {
val error = Ok("example").getError() assertEquals(
assertThat(error, equalTo(null)) expected = "example",
actual = Err("example").getError()
)
}
}
internal class `getOr` {
@Test
internal fun returnsValueIfOk() {
assertEquals(
expected = "hello",
actual = Ok("hello").getOr("world")
)
} }
@Test @Test
internal fun `getError should return the result error if not ok`() { internal fun returnsDefaultValueIfErr() {
val error = Err("example").getError() assertEquals(
assertThat(error, equalTo("example")) expected = "default",
actual = Err("error").getOr("default")
)
}
}
internal class `getErrorOr` {
@Test
internal fun returnsDefaultValueIfOk() {
assertEquals(
expected = "world",
actual = Ok("hello").getErrorOr("world")
)
} }
@Test @Test
internal fun `getOr should return the result value if ok`() { internal fun returnsErrorIfErr() {
val value = Ok("hello").getOr("world") assertEquals(
assertThat(value, equalTo("hello")) expected = "hello",
actual = Err("hello").getErrorOr("world")
)
}
}
internal class `getOrElse` {
@Test
internal fun returnsValueIfOk() {
assertEquals(
expected = "hello",
actual = Ok("hello").getOrElse { "world" }
)
} }
@Test @Test
internal fun `getOr should return default value if not ok`() { internal fun returnsTransformedErrorIfErr() {
val value = Err("error").getOr("default") assertEquals(
assertThat(value, equalTo("default")) expected = "world",
actual = Err("hello").getOrElse { "world" }
)
}
}
internal class `getErrorOrElse` {
@Test
internal fun returnsTransformedValueIfOk() {
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,12 +10,9 @@ internal class IterableTest {
object IterableError2 : IterableError() object IterableError2 : IterableError()
} }
private fun sameError(error: IterableError): Matcher<IterableError> { internal class `fold` {
return sameInstance(error)
}
@Test @Test
internal fun `fold should return the accumulated value if ok`() { internal fun returnAccumulatedValueIfOk() {
val result = listOf(20, 30, 40, 50).fold( val result = listOf(20, 30, 40, 50).fold(
initial = 10, initial = 10,
operation = { a, b -> Ok(a + b) } operation = { a, b -> Ok(a + b) }
@ -25,11 +20,14 @@ internal class IterableTest {
result as Ok result as Ok
assertThat(result.value, equalTo(150)) assertEquals(
expected = 150,
actual = result.value
)
} }
@Test @Test
internal fun `fold should return the first error if not ok`() { internal fun returnsFirstErrorIfErr() {
val result: Result<Int, IterableError> = listOf(5, 10, 15, 20, 25).fold( val result: Result<Int, IterableError> = listOf(5, 10, 15, 20, 25).fold(
initial = 1, initial = 1,
operation = { a, b -> operation = { a, b ->
@ -43,12 +41,16 @@ internal class IterableTest {
result as Err result as Err
val matcher: Matcher<IterableError> = sameInstance(IterableError.IterableError1) assertSame(
assertThat(result.error, matcher) expected = IterableError.IterableError1,
actual = result.error
)
}
} }
internal class `foldRight` {
@Test @Test
internal fun `foldRight should return the accumulated value if ok`() { internal fun returnsAccumulatedValueIfOk() {
val result = listOf(2, 5, 10, 20).foldRight( val result = listOf(2, 5, 10, 20).foldRight(
initial = 100, initial = 100,
operation = { a, b -> Ok(b - a) } operation = { a, b -> Ok(b - a) }
@ -56,11 +58,14 @@ internal class IterableTest {
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 ->
@ -74,25 +79,45 @@ internal class IterableTest {
result as Err result as Err
assertThat(result.error, sameError(IterableError.IterableError2)) assertSame(
expected = IterableError.IterableError2,
actual = result.error
)
}
} }
internal class `combine` {
@Test @Test
internal fun `combine should return the combined list of values if results are ok`() { internal fun returnsValuesIfAllOk() {
val values = combine( val values = combine(
Ok(10), Ok(10),
Ok(20), Ok(20),
Ok(30) Ok(30)
).get()!! ).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 @Test
internal fun `combine should return the first error if results are not ok`() { internal fun returnsFirstErrorIfErr() {
val result = combine( val result = combine(
Ok(20), Ok(20),
Ok(40), Ok(40),
@ -104,11 +129,16 @@ internal class IterableTest {
result as Err result as Err
assertThat(result.error, sameError(IterableError.IterableError1)) assertSame(
expected = IterableError.IterableError1,
actual = result.error
)
}
} }
internal class `getAll` {
@Test @Test
internal fun `getAll should return all of the result values`() { internal fun returnsAllValues() {
val values = getAll( val values = getAll(
Ok("hello"), Ok("hello"),
Ok("big"), Ok("big"),
@ -118,15 +148,36 @@ internal class IterableTest {
Ok("world") Ok("world")
) )
assertThat(values.size, equalTo(4)) assertEquals(
assertThat(values[0], equalTo("hello")) expected = 4,
assertThat(values[1], equalTo("big")) actual = values.size
assertThat(values[2], equalTo("wide")) )
assertThat(values[3], equalTo("world"))
assertEquals(
expected = "hello",
actual = values[0]
)
assertEquals(
expected = "big",
actual = values[1]
)
assertEquals(
expected = "wide",
actual = values[2]
)
assertEquals(
expected = "world",
actual = values[3]
)
}
} }
internal class `getAllErrors` {
@Test @Test
internal fun `getAllErrors should return all of the result errors`() { internal fun returnsAllErrors() {
val errors = getAllErrors( val errors = getAllErrors(
Err(IterableError.IterableError2), Err(IterableError.IterableError2),
Ok("haskell"), Ok("haskell"),
@ -139,16 +190,41 @@ internal class IterableTest {
Err(IterableError.IterableError2) Err(IterableError.IterableError2)
) )
assertThat(errors.size, equalTo(5)) assertEquals(
assertThat(errors[0], sameError(IterableError.IterableError2)) expected = 5,
assertThat(errors[1], sameError(IterableError.IterableError2)) actual = errors.size
assertThat(errors[2], sameError(IterableError.IterableError1)) )
assertThat(errors[3], sameError(IterableError.IterableError1))
assertThat(errors[4], sameError(IterableError.IterableError2)) 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]
)
}
} }
internal class `partition` {
@Test @Test
internal fun `partition should return a pair of all the result values and errors`() { internal fun returnsPairOfValuesAndErrors() {
val pairs = partition( val pairs = partition(
Err(IterableError.IterableError2), Err(IterableError.IterableError2),
Ok("haskell"), Ok("haskell"),
@ -162,18 +238,63 @@ internal class IterableTest {
) )
val values = pairs.first val values = pairs.first
assertThat(values.size, equalTo(4))
assertThat(values[0], equalTo("haskell")) assertEquals(
assertThat(values[1], equalTo("f#")) expected = 4,
assertThat(values[2], equalTo("elm")) actual = values.size
assertThat(values[3], equalTo("clojure")) )
assertEquals(
expected = "haskell",
actual = values[0]
)
assertEquals(
expected = "f#",
actual = values[1]
)
assertEquals(
expected = "elm",
actual = values[2]
)
assertEquals(
expected = "clojure",
actual = values[3]
)
val errors = pairs.second val errors = pairs.second
assertThat(errors.size, equalTo(5))
assertThat(errors[0], sameError(IterableError.IterableError2)) assertEquals(
assertThat(errors[1], sameError(IterableError.IterableError2)) expected = 5,
assertThat(errors[2], sameError(IterableError.IterableError1)) actual = errors.size
assertThat(errors[3], sameError(IterableError.IterableError1)) )
assertThat(errors[4], sameError(IterableError.IterableError2))
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,34 +11,42 @@ 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 @Test
internal fun `map should return the transformed result value if ok`() { internal fun returnsTransformedValueIfOk() {
val value = Ok(10).map { it + 20 }.get() assertEquals(
assertThat(value, equalTo(30)) expected = 30,
actual = Ok(10).map { it + 20 }.get()
)
} }
@Test @Test
@Suppress("UNREACHABLE_CODE") @Suppress("UNREACHABLE_CODE")
internal fun `map should return the result error if not ok`() { internal fun returnsErrorIfErr() {
val result = Err(MapError.HelloError).map { "hello $it" } val result = Err(MapError.HelloError).map { "hello $it" }
result as Err result as Err
assertThat(result.error, sameError(MapError.HelloError)) assertSame(
expected = MapError.HelloError,
actual = result.error
)
}
} }
internal class `mapError` {
@Test @Test
internal fun `mapError should return the result value if ok`() { internal fun returnsValueIfOk() {
val value = Ok(55).map { it + 15 }.mapError { MapError.WorldError }.get() val value = Ok(55).map { it + 15 }.mapError { MapError.WorldError }.get()
assertThat(value, equalTo(70))
assertEquals(
expected = 70,
actual = value
)
} }
@Test @Test
internal fun `mapError should return the transformed result error if not ok`() { internal fun returnsErrorIfErr() {
val result: Result<String, MapError> = Ok("let") val result: Result<String, MapError> = Ok("let")
.map { "$it me" } .map { "$it me" }
.andThen { .andThen {
@ -53,34 +59,47 @@ internal class MapTest {
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
)
}
} }
internal class `mapBoth` {
@Test @Test
@Suppress("UNREACHABLE_CODE") @Suppress("UNREACHABLE_CODE")
internal fun `mapBoth should return the transformed result value if ok`() { internal fun returnsTransformedValueIfOk() {
val value = Ok("there is").mapBoth( val value = Ok("there is").mapBoth(
success = { "$it a light" }, success = { "$it a light" },
failure = { "$it that never" } failure = { "$it that never" }
) )
assertThat(value, equalTo("there is a light")) assertEquals(
expected = "there is a light",
actual = value
)
} }
@Test @Test
@Suppress("UNREACHABLE_CODE") @Suppress("UNREACHABLE_CODE")
internal fun `mapBoth should return the transformed result error if not ok`() { internal fun returnsTransformedErrorIfErr() {
val error = Err(MapError.CustomError("this")).mapBoth( val error = Err(MapError.CustomError("this")).mapBoth(
success = { "$it charming" }, success = { "$it charming" },
failure = { "${it.reason} man" } failure = { "${it.reason} man" }
) )
assertThat(error, equalTo("this man")) assertEquals(
expected = "this man",
actual = error
)
}
} }
internal class `mapEither` {
@Test @Test
@Suppress("UNREACHABLE_CODE") @Suppress("UNREACHABLE_CODE")
internal fun `mapEither should return the transformed result value if ok`() { internal fun returnsTransformedValueIfOk() {
val result = Ok(500).mapEither( val result = Ok(500).mapEither(
success = { it + 500 }, success = { it + 500 },
failure = { MapError.CustomError("$it") } failure = { MapError.CustomError("$it") }
@ -88,11 +107,14 @@ internal class MapTest {
result as Ok result as Ok
assertThat(result.value, equalTo(1000)) assertEquals(
expected = 1000,
actual = result.value
)
} }
@Test @Test
internal fun `mapEither should return the transformed result error if not ok`() { internal fun returnsTransformedErrorIfErr() {
val result = Err("the reckless").mapEither( val result = Err("the reckless").mapEither(
success = { "the wild youth" }, success = { "the wild youth" },
failure = { MapError.CustomError("the truth") } failure = { MapError.CustomError("the truth") }
@ -100,6 +122,10 @@ internal class MapTest {
result as Err result as Err
assertThat(result.error.reason, equalTo("the truth")) assertEquals(
expected = "the truth",
actual = result.error.reason
)
}
} }
} }

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)
internal class `onSuccess` {
@Test @Test
internal fun `onSuccess should invoke the callback when result is ok`() { internal fun invokesCallbackIfOk() {
val counter = Counter(50) val counter = Counter(50)
Ok(counter).onSuccess { it.count += 50 } Ok(counter).onSuccess { it.count += 50 }
assertThat(counter.count, equalTo(100))
assertEquals(
expected = 100,
actual = counter.count
)
} }
@Test @Test
internal fun `onSuccess should not invoke the callback when result is not ok`() { internal fun invokesNothingIfErr() {
val counter = Counter(200) val counter = Counter(200)
Err(CounterError).onSuccess { counter.count -= 50 } Err(CounterError).onSuccess { counter.count -= 50 }
assertThat(counter.count, equalTo(200))
assertEquals(
expected = 200,
actual = counter.count
)
}
} }
internal class `onFailure` {
@Test @Test
internal fun `onFailure should invoke the callback when result is not ok`() { internal fun invokesCallbackIfErr() {
val counter = Counter(555) val counter = Counter(555)
Err(CounterError).onFailure { counter.count += 100 } Err(CounterError).onFailure { counter.count += 100 }
assertThat(counter.count, equalTo(655))
assertEquals(
expected = 655,
actual = counter.count
)
} }
@Test @Test
internal fun `onFailure should not invoke the callback when result is ok`() { internal fun invokesNothingIfOk() {
val counter = Counter(1020) val counter = Counter(1020)
Ok("hello").onFailure { counter.count = 1030 } Ok("hello").onFailure { counter.count = 1030 }
assertThat(counter.count, equalTo(1020))
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
internal class `or` {
@Test @Test
internal fun `or should return the result value if ok`() { internal fun returnsValueIfOk() {
val value = Ok(500).or(Ok(1000)).get() assertEquals(
assertThat(value, equalTo(500)) expected = 500,
actual = Ok(500).or(Ok(1000)).get()
)
} }
@Test @Test
internal fun `or should return the default value if not ok`() { internal fun returnsDefaultValueIfErr() {
val value = Err(OrError).or(Ok(5000)).get() assertEquals(
assertThat(value, equalTo(5000)) expected = 5000,
actual = Err(OrError).or(Ok(5000)).get()
)
}
}
internal class `orElse` {
@Test
internal fun returnsValueIfOk() {
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 {
internal class `hasNext` {
@Test @Test
internal fun `hasNext should return true if unyielded and result is ok`() { internal fun returnsTrueIfUnyieldedAndOk() {
val iterator = Ok("hello").iterator() val iterator = Ok("hello").iterator()
assertThat(iterator.hasNext(), equalTo(true)) 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() iterator.next()
assertThat(iterator.hasNext(), equalTo(false)) assertFalse { iterator.hasNext() }
}
}
internal class `next` {
@Test
internal fun returnsValueIfUnyieldedAndOk() {
assertEquals(
expected = "hello",
actual = Ok("hello").iterator().next()
)
} }
@Test @Test
internal fun `next should return the result value if unyielded and result is ok`() { internal fun throwsExceptionIfUnyieldedAndErr() {
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() val iterator = Err("hello").iterator()
assertFailsWith<NoSuchElementException> { iterator.next() }
assertThrows(NoSuchElementException::class.java) {
iterator.next()
}
} }
@Test @Test
internal fun `next should throw NoSuchElementException if yielded and result is ok`() { internal fun throwsExceptionIfYieldedAndOk() {
val iterator = Ok("hello").iterator() val iterator = Ok("hello").iterator()
iterator.next() iterator.next()
assertFailsWith<NoSuchElementException> { iterator.next() }
assertThrows(NoSuchElementException::class.java) {
iterator.next()
} }
} }
internal class `remove` {
@Test @Test
internal fun `remove should make hasNext return false`() { internal fun makesHasNextReturnFalse() {
val iterator = Ok("hello").mutableIterator() val iterator = Ok("hello").mutableIterator()
iterator.remove() iterator.remove()
assertThat(iterator.hasNext(), equalTo(false)) 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 {
internal class `of` {
@Test @Test
internal fun `of should return ok if invocation did not throw anything`() { internal fun returnsOkIfInvocationSuccessful() {
val callback = { "example" } val callback = { "example" }
val value = Result.of(callback).get()
assertThat(value, equalTo("example")) assertEquals(
expected = "example",
actual = Result.of(callback).get()
)
} }
@Test @Test
internal fun `of should return error if invocation threw something`() { internal fun returnsErrIfInvocationFails() {
val throwable = IllegalArgumentException("throw me") val throwable = IllegalArgumentException("throw me")
val callback = { throw throwable } val callback = { throw throwable }
val error = Result.of(callback).getError()!! val error = Result.of(callback).getError()!!
val matcher: Matcher<Throwable> = sameInstance(throwable)
assertThat(error, matcher) 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 {
internal class `unwrap` {
@Test @Test
internal fun `unwrap should return the result value if ok`() { internal fun returnsValueIfOk() {
val value = Ok(5000).unwrap() assertEquals(
assertThat(value, equalTo(5000)) expected = 5000,
actual = Ok(5000).unwrap()
)
} }
@Test @Test
internal fun `unwrap should throw an UnwrapException if not ok`() { internal fun throwsExceptionIfErr() {
val throwable = assertThrows(UnwrapException::class.java) { assertFailsWith<UnwrapException>("called Result.wrap on an Err value 5000") {
Err(5000).unwrap() Err(5000).unwrap()
} }
}
}
assertThat(throwable.message, equalTo("called Result.wrap on an Err value 5000")) internal class `expect` {
@Test
internal fun returnsValueIfOk() {
assertEquals(
expected = 1994,
actual = Ok(1994).expect { "the year should be" }
)
} }
@Test @Test
internal fun `expect should return the result value if ok`() { internal fun throwsExceptionIfErr() {
val value = Ok(1994).expect { "the year should be" }
assertThat(value, equalTo(1994))
}
@Test
internal fun `expect should throw an UnwrapException with a specified message if not ok`() {
val message = object { val message = object {
override fun toString() = "the year should be" override fun toString() = "the year should be"
} }
val throwable = assertThrows(UnwrapException::class.java) { assertFailsWith<UnwrapException>("the year should be 1994") {
Err(1994).expect { message } Err(1994).expect { message }
} }
}
assertThat(throwable.message, equalTo("the year should be 1994"))
} }
internal class `unwrapError` {
@Test @Test
internal fun `unwrapError should throw an UnwrapException if ok`() { internal fun throwsExceptionIfOk() {
val throwable = assertThrows(UnwrapException::class.java) { assertFailsWith<UnwrapException>("called Result.unwrapError on an Ok value example") {
Ok("example").unwrapError() Ok("example").unwrapError()
} }
assertThat(throwable.message, equalTo("called Result.unwrapError on an Ok value example"))
} }
@Test @Test
internal fun `unwrapError should return the result error if not ok`() { internal fun returnsErrorIfErr() {
val error = Err("example").unwrapError() assertEquals(
assertThat(error, equalTo("example")) expected = "example",
actual = Err("example").unwrapError()
)
}
} }
internal class `expectError` {
@Test @Test
internal fun `expectError should throw an UnwrapException with a specified message if ok`() { internal fun throwsExceptionIfOk() {
val message = object { val message = object {
override fun toString() = "the year should be" override fun toString() = "the year should be"
} }
val throwable = assertThrows(UnwrapException::class.java) { assertFailsWith<UnwrapException>("the year should be 2010") {
Ok(2010).expectError { message } Ok(2010).expectError { message }
} }
assertThat(throwable.message, equalTo("the year should be 2010"))
} }
@Test @Test
internal fun `expectError should return the result error if not ok`() { internal fun returnsErrorIfErr() {
val error = Err(2010).expectError { "the year should be" } assertEquals(
assertThat(error, equalTo(2010)) expected = 2010,
actual = Err(2010).expectError { "the year should be" }
)
}
} }
} }