From 1219fafe0cc00d05a2ebcc932f85e4d1d2b6f0f3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Robson=20Al=C3=A9cio=20Somera?= Date: Wed, 27 Mar 2024 10:18:10 -0300 Subject: [PATCH 1/4] adding new assertFailureWith --- .../src/commonMain/kotlin/assertk/assert.kt | 14 ++++++++ .../kotlin/assertk/assertions/throwable.kt | 13 ++++++- .../kotlin/test/assertk/AssertFailureTest.kt | 35 +++++++++++++++---- 3 files changed, 55 insertions(+), 7 deletions(-) diff --git a/assertk/src/commonMain/kotlin/assertk/assert.kt b/assertk/src/commonMain/kotlin/assertk/assert.kt index 548938ae..d028b13c 100644 --- a/assertk/src/commonMain/kotlin/assertk/assert.kt +++ b/assertk/src/commonMain/kotlin/assertk/assert.kt @@ -190,3 +190,17 @@ inline fun assertFailure(f: () -> Unit): Assert { } 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 assertFailureWith(f: () -> Unit): Assert { + @Suppress("TooGenericExceptionCaught") // Intentionally capturing all exceptions. + try { + f() + } catch (t: Throwable) { + if (t !is T) fail("2expected failure to be type of ${T::class}") + return assertThat(t) + } + fail("expected failure but lambda completed successfully") +} \ No newline at end of file diff --git a/assertk/src/commonMain/kotlin/assertk/assertions/throwable.kt b/assertk/src/commonMain/kotlin/assertk/assertions/throwable.kt index 036d437f..fbc37c92 100644 --- a/assertk/src/commonMain/kotlin/assertk/assertions/throwable.kt +++ b/assertk/src/commonMain/kotlin/assertk/assertions/throwable.kt @@ -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. @@ -62,5 +62,16 @@ fun Assert.hasRootCause(cause: Throwable) { } } +/** + * Asserts the throwable with a specific type have the expected properties for it. + */ +fun Assert.hasProperties(vararg pairs: Pair, Any>) { + all { + pairs.forEach { + prop(it.first).isEqualTo(it.second) + } + } +} + private fun Throwable.rootCause(): Throwable = this.cause?.rootCause() ?: this diff --git a/assertk/src/commonTest/kotlin/test/assertk/AssertFailureTest.kt b/assertk/src/commonTest/kotlin/test/assertk/AssertFailureTest.kt index 48882746..a38a8fd7 100644 --- a/assertk/src/commonTest/kotlin/test/assertk/AssertFailureTest.kt +++ b/assertk/src/commonTest/kotlin/test/assertk/AssertFailureTest.kt @@ -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 @@ -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 { @@ -24,6 +21,30 @@ class AssertFailureTest { assertSame(expected, assertFailure { throw expected }.valueOrFail) } + @Test + fun failure_with_expected_type_and_additional_properties() { + assertFailureWith { + throw DummyException(12, "night") + }.hasProperties( + DummyException::value to 12, + DummyException::tag to "night" + ) + } + + @Test + fun failure_with_wrong_type() { + val t = assertFailsWith { + assertFailureWith { + 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 { @@ -60,4 +81,6 @@ class AssertFailureTest { } t.isInstanceOf() } + + class DummyException(val value: Int, val tag: String) : Exception("My value broken is $value") } From 1294689727dd1885c1531aad13dbef251da5ee43 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Robson=20Al=C3=A9cio=20Somera?= Date: Wed, 27 Mar 2024 10:24:07 -0300 Subject: [PATCH 2/4] fix message of expected exception type --- assertk/src/commonMain/kotlin/assertk/assert.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/assertk/src/commonMain/kotlin/assertk/assert.kt b/assertk/src/commonMain/kotlin/assertk/assert.kt index d028b13c..10796699 100644 --- a/assertk/src/commonMain/kotlin/assertk/assert.kt +++ b/assertk/src/commonMain/kotlin/assertk/assert.kt @@ -199,7 +199,7 @@ inline fun assertFailureWith(f: () -> Unit): Assert { try { f() } catch (t: Throwable) { - if (t !is T) fail("2expected failure to be type of ${T::class}") + if (t !is T) fail("expected failure to be type of ${T::class}") return assertThat(t) } fail("expected failure but lambda completed successfully") From 481e1e5d8e8fce31f30cf773adfc616aeb52a65d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Robson=20Al=C3=A9cio=20Somera?= Date: Wed, 27 Mar 2024 10:35:52 -0300 Subject: [PATCH 3/4] accept check exception type --- assertk/src/commonMain/kotlin/assertk/assert.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/assertk/src/commonMain/kotlin/assertk/assert.kt b/assertk/src/commonMain/kotlin/assertk/assert.kt index 10796699..b01e2aba 100644 --- a/assertk/src/commonMain/kotlin/assertk/assert.kt +++ b/assertk/src/commonMain/kotlin/assertk/assert.kt @@ -195,7 +195,7 @@ inline fun assertFailure(f: () -> Unit): Assert { * Asserts that the given block will throw an exception with expected type rather than complete successfully. */ inline fun assertFailureWith(f: () -> Unit): Assert { - @Suppress("TooGenericExceptionCaught") // Intentionally capturing all exceptions. + @Suppress("TooGenericExceptionCaught", "InstanceOfCheckForException") // Intentionally capturing all exceptions. try { f() } catch (t: Throwable) { From ef4a075967356d606637095876b4d47a6429f3cc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Robson=20Al=C3=A9cio=20Somera?= Date: Thu, 28 Mar 2024 12:06:05 -0300 Subject: [PATCH 4/4] use assertFailure and improving test --- .../src/commonMain/kotlin/assertk/assert.kt | 13 +++--- .../kotlin/test/assertk/AssertFailureTest.kt | 24 +++++------ .../test/assertk/assertions/ThrowableTest.kt | 43 +++++++++++++++++-- 3 files changed, 55 insertions(+), 25 deletions(-) diff --git a/assertk/src/commonMain/kotlin/assertk/assert.kt b/assertk/src/commonMain/kotlin/assertk/assert.kt index b01e2aba..e6cdb633 100644 --- a/assertk/src/commonMain/kotlin/assertk/assert.kt +++ b/assertk/src/commonMain/kotlin/assertk/assert.kt @@ -1,5 +1,6 @@ package assertk +import assertk.assertions.isInstanceOf import assertk.assertions.support.display import assertk.assertions.support.show import kotlin.reflect.KProperty0 @@ -195,12 +196,8 @@ inline fun assertFailure(f: () -> Unit): Assert { * Asserts that the given block will throw an exception with expected type rather than complete successfully. */ inline fun assertFailureWith(f: () -> Unit): Assert { - @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") + val assertFailure = assertFailure(f) + assertFailure.isInstanceOf(T::class) + @Suppress("UNCHECKED_CAST") + return assertFailure as Assert } \ No newline at end of file diff --git a/assertk/src/commonTest/kotlin/test/assertk/AssertFailureTest.kt b/assertk/src/commonTest/kotlin/test/assertk/AssertFailureTest.kt index a38a8fd7..fbd422af 100644 --- a/assertk/src/commonTest/kotlin/test/assertk/AssertFailureTest.kt +++ b/assertk/src/commonTest/kotlin/test/assertk/AssertFailureTest.kt @@ -2,7 +2,6 @@ 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 @@ -22,27 +21,26 @@ class AssertFailureTest { } @Test - fun failure_with_expected_type_and_additional_properties() { - assertFailureWith { - throw DummyException(12, "night") - }.hasProperties( - DummyException::value to 12, - DummyException::tag to "night" - ) + fun failure_with_expected_type() { + val expected = IllegalArgumentException() + val actual = assertFailureWith { throw expected } + assertSame(expected, actual.valueOrFail) } @Test fun failure_with_wrong_type() { val t = assertFailsWith { - assertFailureWith { - throw RuntimeException() + assertFailureWith { + throw IllegalStateException() } } val message = t.message ?: fail("should have a message") - assertTrue("expected failure to be type of class" in message) - assertTrue("DummyException" in message) + assertTrue("expected to be instance of" in message) + assertTrue("IllegalArgumentException" in message) + assertTrue("but had class" in message) + assertTrue("IllegalStateException" in message) } @Test @@ -81,6 +79,4 @@ class AssertFailureTest { } t.isInstanceOf() } - - class DummyException(val value: Int, val tag: String) : Exception("My value broken is $value") } diff --git a/assertk/src/commonTest/kotlin/test/assertk/assertions/ThrowableTest.kt b/assertk/src/commonTest/kotlin/test/assertk/assertions/ThrowableTest.kt index 008cc9bd..b66c1baa 100644 --- a/assertk/src/commonTest/kotlin/test/assertk/assertions/ThrowableTest.kt +++ b/assertk/src/commonTest/kotlin/test/assertk/assertions/ThrowableTest.kt @@ -1,16 +1,19 @@ package test.assertk.assertions +import assertk.assertFailureWith import assertk.assertThat import assertk.assertions.* import test.assertk.exceptionPackageName import kotlin.test.Test import kotlin.test.assertEquals import kotlin.test.assertFailsWith +import kotlin.test.assertTrue +import kotlin.test.fail class ThrowableTest { - val rootCause = Exception("rootCause") - val cause = Exception("cause", rootCause) - val subject = Exception("test", cause) + private val rootCause = Exception("rootCause") + private val cause = Exception("cause", rootCause) + private val subject = Exception("test", cause) @Test fun extracts_message() { @@ -147,4 +150,38 @@ class ThrowableTest { ) } //endregion + + //region hasProperties + @Test + fun hasProperties_single_fail() { + val exception = DummyException(1116, 12.5) + val error = assertFailsWith { + assertFailureWith { throw exception }.hasProperties( + DummyException::index to 1118, + DummyException::rate to 12.5 + ) + } + assertEquals( + "expected [index]:<111[8]> but was:<111[6]> ($exception)", + error.message + ) + } + + @Test + fun hasProperties_multiple_fails() { + val exception = DummyException(1116, 12.5) + val error = assertFailsWith { + assertFailureWith { throw exception }.hasProperties( + DummyException::index to 1118, + DummyException::rate to 15.3 + ) + } + val message = error.message ?: fail("should have a message") + assertTrue("The following assertions failed (2 failures)" in message) + assertTrue("expected [index]:<111[8]> but was:<111[6]> ($exception)" in message) + assertTrue("expected [rate]:<1[5.3]> but was:<1[2.5]> ($exception)" in message) + } + + class DummyException(val index: Int, val rate: Double): Exception("bad value: $index -> $rate") + //endregion }