Skip to content

Commit

Permalink
default Result Assertions Fix (again) (#1429)
Browse files Browse the repository at this point in the history
  • Loading branch information
JordanllHarper authored May 8, 2023
1 parent e20eafa commit 7f22d9c
Show file tree
Hide file tree
Showing 3 changed files with 127 additions and 91 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -57,69 +57,70 @@ class ResultExpectationSamples {
}
}

//TODO 1.1.0 activate once we have the workaround for #1234 implemented
// @Test
// fun toBeAFailureFeature() {
// val message = "wrong argument"
// val failure = Result.failure<Int>(IllegalArgumentException(message))
//
// expect(failure)
// .toBeAFailure<IllegalArgumentException>() // subject is now of type IllegalArgumentException
// .messageToContain("argument")
//
//
// fails { // because sub-expectation fails
// expect(failure)
// .toBeAFailure<IllegalArgumentException>()
// .messageToContain("parameter") // fails
// }
//
// fails { // because wrong Expectation type expected
// expect(failure)
// .toBeAFailure<ArithmeticException>() // fails
// .messageToContain("parameter") // not evaluated/reported because toBeAFailure already fails
// // use `toBeAFailure<...> { ... }` if you want that all expectations are evaluated
// }
//
// fails { // because it was a Success
// expect(Result.success(10))
// .toBeAFailure<IllegalArgumentException>() // fails
// .messageToContain("parameter") // not evaluated/reported because toBeAFailure already fails
// // use `toBeAFailure<...> { ... }` if you want that all expectations are evaluated
// }
// }
//
// @Test
// fun toBeAFailure() {
// val errorMessage = "can not divide by zero"
// val failure = Result.failure<Int>(ArithmeticException(errorMessage))
//
// expect(failure).toBeAFailure<ArithmeticException> { // subject within this expectation-group is of type ArithmeticException
// messageToContain("by zero")
// } // subject here is back to type Result<Int>
//
// fails { // because sub-expectation fails
// expect(failure).toBeAFailure<IllegalArgumentException> {
// messageToContain("parameter") // fails
// message.toStartWith("wrong") // still evaluated even though messageToContain already fails
// // use `.toBeAFailure.` if you want a fail fast behaviour
// }
// }
//
// fails { // because wrong Expectation type expected, but since we use an expectation-group...
// expect(failure).toBeAFailure<ArithmeticException> {
// messageToContain("parameter") // ...reporting mentions that subject's message was expected `to contain: "parameter"``
// // use `.toBeAFailure.` if you want a fail fast behaviour
// }
// }
//
// fails { // because it was a Success, but since we use a block
// expect(Result.success(10)).toBeAFailure<IllegalArgumentException> {
// messageToContain("parameter") // ...reporting mentions that subject's message was expected `to contain: "parameter"``
// // use `.toBeAFailure.` if you want a fail fast behaviour
// }
// }
// }


@Test
fun toBeAFailureFeature() {
val message = "wrong argument"
val failure = Result.failure<Int>(IllegalArgumentException(message))

expect(failure)
.toBeAFailure<IllegalArgumentException>() // subject is now of type IllegalArgumentException
.messageToContain("argument")


fails { // because sub-expectation fails
expect(failure)
.toBeAFailure<IllegalArgumentException>()
.messageToContain("parameter") // fails
}

fails { // because wrong Expectation type expected
expect(failure)
.toBeAFailure<ArithmeticException>() // fails
.messageToContain("parameter") // not evaluated/reported because toBeAFailure already fails
// use `toBeAFailure<...> { ... }` if you want that all expectations are evaluated
}

fails { // because it was a Success
expect(Result.success(10))
.toBeAFailure<IllegalArgumentException>() // fails
.messageToContain("parameter") // not evaluated/reported because toBeAFailure already fails
// use `toBeAFailure<...> { ... }` if you want that all expectations are evaluated
}
}

@Test
fun toBeAFailure() {
val errorMessage = "can not divide by zero"
val failure = Result.failure<Int>(ArithmeticException(errorMessage))

expect(failure).toBeAFailure<ArithmeticException> { // subject within this expectation-group is of type ArithmeticException
messageToContain("by zero")
} // subject here is back to type Result<Int>

fails { // because sub-expectation fails
expect(failure).toBeAFailure<IllegalArgumentException> {
messageToContain("parameter") // fails
message.toStartWith("wrong") // still evaluated even though messageToContain already fails
// use `.toBeAFailure.` if you want a fail fast behaviour
}
}

fails { // because wrong Expectation type expected, but since we use an expectation-group...
expect(failure).toBeAFailure<ArithmeticException> {
messageToContain("parameter") // ...reporting mentions that subject's message was expected `to contain: "parameter"``
// use `.toBeAFailure.` if you want a fail fast behaviour
}
}

fails { // because it was a Success, but since we use a block
expect(Result.success(10)).toBeAFailure<IllegalArgumentException> {
messageToContain("parameter") // ...reporting mentions that subject's message was expected `to contain: "parameter"``
// use `.toBeAFailure.` if you want a fail fast behaviour
}
}
}


}
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,14 @@ package ch.tutteli.atrium.logic.kotlin_1_3.impl

import ch.tutteli.atrium.core.ExperimentalNewExpectTypes
import ch.tutteli.atrium.core.Option
import ch.tutteli.atrium.core.getOrElse
import ch.tutteli.atrium.core.polyfills.cast
import ch.tutteli.atrium.creating.AssertionContainer
import ch.tutteli.atrium.creating.ExperimentalComponentFactoryContainer
import ch.tutteli.atrium.creating.FeatureExpect
import ch.tutteli.atrium.creating.FeatureExpectOptions
import ch.tutteli.atrium.logic.changeSubject
import ch.tutteli.atrium.logic.creating.FeatureExpectOptions
import ch.tutteli.atrium.logic.creating.transformers.FeatureExtractorBuilder
import ch.tutteli.atrium.logic.creating.transformers.SubjectChangerBuilder
import ch.tutteli.atrium.logic.creating.transformers.impl.ThrowableThrownFailureHandler
Expand All @@ -33,8 +36,42 @@ class DefaultResultAssertions : ResultAssertions {
override fun <TExpected : Throwable> isFailureOfType(
container: AssertionContainer<out Result<*>>,
expectedType: KClass<TExpected>
): SubjectChangerBuilder.ExecutionStep<Throwable?, TExpected> =
container.manualFeature(EXCEPTION) { exceptionOrNull() }.transform().let { previousExpect ->
): SubjectChangerBuilder.ExecutionStep<Throwable?, TExpected> =
container.manualFeature(EXCEPTION) {


//fix is here for bug in kotlin 1.3, 1.4, 1.5 (fixed in 1.6) => https://youtrack.jetbrains.com/issue/KT-50974
//Comments below explain the fix
val badResult = exceptionOrNull()
//mapping manually to get internal value throwable - exception or null just produced null + we lost the exception
val maybeSubjectResult = container.maybeSubject.map {
onSuccess { null }
onFailure { it.cause }
}


if (maybeSubjectResult.getOrElse { null } != null && badResult == null) {
//there is something inside first option type so unwrap
val successError = maybeSubjectResult.getOrElse { null }

if (successError == null) {

return@manualFeature exceptionOrNull()
}
//if the result is a success we have another value to check
if (successError.isSuccess) {

val valueInsideSuccess = getOrNull() as Result<*>
if (valueInsideSuccess.isFailure) {
return@manualFeature valueInsideSuccess.exceptionOrNull()
}
}

}
exceptionOrNull()


}.transform().let { previousExpect ->
FeatureExpect(
previousExpect,
FeatureExpectOptions(representationInsteadOfFeature = { it ?: IS_NOT_FAILURE })
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -44,16 +44,15 @@ abstract class ResultExpectationsSpec(
toBeASuccessNullable.forAssertionCreatorSpec("$toEqualDescr: 2") { toEqual(2) }
) {})

//TODO 1.1.0 activate once we have the workaround for #1234 implemented
// include(object : AssertionCreatorSpec<Result<Int>>(
// "$describePrefix[failure] ", Result.failure(IllegalArgumentException("oh no...")),
// assertionCreatorSpecTriple(
// toBeAFailure.name,
// "${DescriptionCharSequenceExpectation.VALUE.getDefault()}: \"oh no...\"",
// { apply { toBeAFailure.invoke(this) { messageToContain("oh no...") } } },
// { apply { toBeAFailure.invoke(this) {} } }
// )
// ) {})
include(object : AssertionCreatorSpec<Result<Int>>(
"$describePrefix[failure] ", Result.failure(IllegalArgumentException("oh no...")),
assertionCreatorSpecTriple(
toBeAFailure.name,
"${DescriptionCharSequenceExpectation.VALUE.getDefault()}: \"oh no...\"",
{ apply { toBeAFailure.invoke(this) { messageToContain("oh no...") } } },
{ apply { toBeAFailure.invoke(this) {} } }
)
) {})

fun describeFun(vararg pairs: SpecPair<*>, body: Suite.() -> Unit) =
describeFunTemplate(describePrefix, pairs.map { it.name }.toTypedArray(), body = body)
Expand Down Expand Up @@ -120,22 +119,21 @@ abstract class ResultExpectationsSpec(
}
}

//TODO 1.1.0 activate once we have the workaround for #1234 implemented
// failureFunctions.forEach { (name, toBeAFailureFun, _) ->
// it("$name - can perform sub-assertion which holds") {
// expect(resultFailure).toBeAFailureFun { messageToContain("oh no...") }
// }
// it("$name - can perform sub-assertion which fails, throws AssertionError") {
// expect {
// expect(resultFailure).toBeAFailureFun { messageToContain("oh yes...") }
// }.toThrow<AssertionError> {
// messageToContain(
// "$exceptionDescr: ${IllegalArgumentException::class.fullName}",
// DescriptionCharSequenceExpectation.TO_CONTAIN.getDefault(), "${DescriptionCharSequenceExpectation.VALUE.getDefault()}: \"oh yes...\""
// )
// }
// }
// }
failureFunctions.forEach { (name, toBeAFailureFun, _) ->
it("$name - can perform sub-assertion which holds") {
expect(resultFailure).toBeAFailureFun { messageToContain("oh no...") }
}
it("$name - can perform sub-assertion which fails, throws AssertionError") {
expect {
expect(resultFailure).toBeAFailureFun { messageToContain("oh yes...") }
}.toThrow<AssertionError> {
messageToContain(
"$exceptionDescr: ${IllegalArgumentException::class.fullName}",
DescriptionCharSequenceExpectation.TO_CONTAIN.getDefault(), "${DescriptionCharSequenceExpectation.VALUE.getDefault()}: \"oh yes...\""
)
}
}
}
}
}

Expand Down

0 comments on commit 7f22d9c

Please sign in to comment.