Skip to content

Commit

Permalink
Merge pull request #59 from FineCinnamon/ab/Katz-58_try_tests
Browse files Browse the repository at this point in the history
Added test for Try.
  • Loading branch information
aballano authored Apr 6, 2017
2 parents 14b72fb + 6820695 commit dc9093c
Show file tree
Hide file tree
Showing 2 changed files with 123 additions and 22 deletions.
41 changes: 19 additions & 22 deletions katz/src/main/kotlin/katz/data/Try.kt
Original file line number Diff line number Diff line change
Expand Up @@ -27,19 +27,13 @@ sealed class Try<out A> {
companion object {

inline operator fun <A> invoke(f: () -> A): Try<A> =
try { Success(f()) } catch (e: Throwable) { Failure(e) }
try {
Success(f())
} catch (e: Throwable) {
Failure(e)
}
}

/**
* Returns `true` if the `Try` is a `Failure`, `false` otherwise.
*/
abstract val isFailure: Boolean

/**
* Returns `true` if the `Try` is a `Success`, `false` otherwise.
*/
abstract val isSuccess: Boolean

/**
* Returns the given function applied to the value from this `Success` or returns this if this is a `Failure`.
*/
Expand All @@ -55,7 +49,7 @@ sealed class Try<out A> {
*/
inline fun filter(crossinline p: (A) -> Boolean): Try<A> = fold(
{ Failure(it) },
{ if (p(it)) Success(it) else Failure(NoSuchElementException("Predicate does not hold for " + it)) }
{ if (p(it)) Success(it) else Failure(TryException.PredicateException("Predicate does not hold for $it")) }
)

/**
Expand All @@ -64,7 +58,7 @@ sealed class Try<out A> {
*/
fun failed(): Try<Throwable> = fold(
{ Success(it) },
{ Failure(UnsupportedOperationException("Success.failed")) }
{ Failure(TryException.UnsupportedOperationException("Success.failed")) }
)

/**
Expand All @@ -74,24 +68,27 @@ sealed class Try<out A> {
*/
fun <B> fold(fa: (Throwable) -> B, fb: (A) -> B): B = when (this) {
is Failure -> fa(exception)
is Success -> try { fb(value) } catch (e: Throwable) { fa(e) }
is Success -> try {
fb(value)
} catch (e: Throwable) {
fa(e)
}
}

/**
* The `Failure` type represents a computation that result in an exception.
*/
class Failure<out A>(val exception: Throwable) : Try<A>() {
override val isFailure: Boolean = false
override val isSuccess: Boolean = true
}
data class Failure<out A>(val exception: Throwable) : Try<A>()

/**
* The `Success` type represents a computation that return a successfully computed value.
*/
class Success<out A>(val value: A) : Try<A>() {
override val isFailure: Boolean = true
override val isSuccess: Boolean = false
}
data class Success<out A>(val value: A) : Try<A>()
}

sealed class TryException(override val message: String) : kotlin.Exception(message) {
data class PredicateException(override val message: String) : TryException(message)
data class UnsupportedOperationException(override val message: String) : TryException(message)
}

/**
Expand Down
104 changes: 104 additions & 0 deletions katz/src/test/kotlin/katz/data/TryTest.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,104 @@
/*
* Copyright (C) 2017 The Katz Authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

package katz

import io.kotlintest.KTestJUnitRunner
import io.kotlintest.matchers.shouldBe
import katz.Try.*
import org.junit.runner.RunWith

@RunWith(KTestJUnitRunner::class)
class TryTest : UnitSpec() {
init {
"invoke of any should be success" {
Try.invoke { 1 } shouldBe Success(1)
}

"invoke of exception should be failure" {
val ex = Exception()
Try.invoke { throw ex } shouldBe Failure<Any>(ex)
}

"flatMap should modify entity" {
val failure: Try<Int> = Failure(Exception())

Success(1).flatMap { failure } shouldBe failure
Success(1).flatMap { Success(2) } shouldBe Success(2)
failure.flatMap { Success(2) } shouldBe failure
}

"map should modify value" {
val failure: Try<Int> = Failure(Exception())

Success(1).map { 2 } shouldBe Success(2)
failure.map { 2 } shouldBe failure
}

"filter evaluates predicate" {
val failure: Try<Int> = Failure(Exception())

Success(1).filter { true } shouldBe Success(1)
Success(1).filter { false } shouldBe Failure<Int>(TryException.PredicateException("Predicate does not hold for 1"))
failure.filter { true } shouldBe failure
failure.filter { false } shouldBe failure
}

"failed tries to swap" {
val ex = Exception()
val failure: Try<Int> = Failure(ex)

Success(1).failed() shouldBe Failure<Int>(TryException.UnsupportedOperationException("Success.failed"))
failure.failed() shouldBe Success(ex)
}

"fold should call left function on Failure" {
Failure<Int>(Exception()).fold({ 2 }, { 3 }) shouldBe 2
}

"fold should call right function on Success" {
Success(1).fold({ 2 }, { 3 }) shouldBe 3
}

"fold should call left function on Success with exception" {
Success(1).fold({ 2 }, { throw Exception() }) shouldBe 2
}

"getOrElse returns default if Failure" {
Success(1).getOrElse { 2 } shouldBe 1
Failure<Int>(Exception()).getOrElse { 2 } shouldBe 2
}

"recoverWith should modify Failure entity" {
Success(1).recoverWith { Failure<Int>(Exception()) } shouldBe Success(1)
Success(1).recoverWith { Success(2) } shouldBe Success(1)
Failure<Int>(Exception()).recoverWith { Success(2) } shouldBe Success(2)
}

"recover should modify Failure value" {
Success(1).recover { 2 } shouldBe Success(1)
Failure<Int>(Exception()).recover { 2 } shouldBe Success(2)
}

"transform applies left function for Success" {
Success(1).transform({ Success(2) }, { Success(3) }) shouldBe Success(2)
}

"transform applies right function for Failure" {
Failure<Int>(Exception()).transform({ Success(2) }, { Success(3) }) shouldBe Success(3)
}
}
}

0 comments on commit dc9093c

Please sign in to comment.