Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Adding new assertFailureWith #525

Open
wants to merge 4 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 3 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 14 additions & 0 deletions assertk/src/commonMain/kotlin/assertk/assert.kt
Original file line number Diff line number Diff line change
Expand Up @@ -190,3 +190,17 @@ inline fun assertFailure(f: () -> Unit): Assert<Throwable> {
}
fail("expected failure but lambda completed successfully")
}

/**
* Asserts that the given block will throw an exception with expected type rather than complete successfully.
*/
inline fun <reified T: Throwable> assertFailureWith(f: () -> Unit): Assert<T> {
@Suppress("TooGenericExceptionCaught", "InstanceOfCheckForException") // Intentionally capturing all exceptions.
try {
f()
} catch (t: Throwable) {
if (t !is T) fail("expected failure to be type of ${T::class}")
return assertThat(t)
}
fail("expected failure but lambda completed successfully")
}
13 changes: 12 additions & 1 deletion assertk/src/commonMain/kotlin/assertk/assertions/throwable.kt
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
package assertk.assertions

import assertk.Assert
import assertk.ValueAssert
import assertk.all
import kotlin.reflect.KProperty1

/**
* Returns an assert on the throwable's message.
Expand Down Expand Up @@ -62,5 +62,16 @@ fun Assert<Throwable>.hasRootCause(cause: Throwable) {
}
}

/**
* Asserts the throwable with a specific type have the expected properties for it.
*/
fun <T: Throwable> Assert<T>.hasProperties(vararg pairs: Pair<KProperty1<T, Any>, Any>) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is unrelated to assertFailsWith. It's not clear why it's type parameter is bound to Throwable subtypes since it's a general-purpose utility. I would separate it into its own PR, or even start with an issue discussing the use case and why regular .all { } in insufficient.

all {
pairs.forEach {
prop(it.first).isEqualTo(it.second)
}
}
}

private fun Throwable.rootCause(): Throwable = this.cause?.rootCause() ?: this

35 changes: 29 additions & 6 deletions assertk/src/commonTest/kotlin/test/assertk/AssertFailureTest.kt
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
package test.assertk

import assertk.assertFailure
import assertk.assertFailureWith
import assertk.assertions.hasProperties
import assertk.assertions.isEqualTo
import assertk.assertions.isInstanceOf
import assertk.assertions.message
Expand All @@ -9,12 +11,7 @@ import test.assertk.assertions.valueOrFail
import kotlin.coroutines.resume
import kotlin.coroutines.resumeWithException
import kotlin.coroutines.suspendCoroutine
import kotlin.test.Test
import kotlin.test.assertEquals
import kotlin.test.assertFailsWith
import kotlin.test.assertFalse
import kotlin.test.assertSame
import kotlin.test.assertTrue
import kotlin.test.*

class AssertFailureTest {

Expand All @@ -24,6 +21,30 @@ class AssertFailureTest {
assertSame(expected, assertFailure { throw expected }.valueOrFail)
}

@Test
fun failure_with_expected_type_and_additional_properties() {
assertFailureWith<DummyException> {
throw DummyException(12, "night")
}.hasProperties(
DummyException::value to 12,
DummyException::tag to "night"
)
}

@Test
fun failure_with_wrong_type() {
val t = assertFailsWith<AssertionFailedError> {
assertFailureWith<DummyException> {
throw RuntimeException()
}
}

val message = t.message ?: fail("should have a message")

assertTrue("expected failure to be type of class" in message)
assertTrue("DummyException" in message)
}

@Test
fun failure_originating_subject_not_wrapped_in_result() {
val t = assertFailsWith<AssertionFailedError> {
Expand Down Expand Up @@ -60,4 +81,6 @@ class AssertFailureTest {
}
t.isInstanceOf<IllegalArgumentException>()
}

class DummyException(val value: Int, val tag: String) : Exception("My value broken is $value")
}