Skip to content

Commit 621a9b7

Browse files
committed
feat(60): Added the function RaiseAssert.assertThatRaisedBy and its tests
1 parent 29d6c9d commit 621a9b7

File tree

5 files changed

+77
-2
lines changed

5 files changed

+77
-2
lines changed

src/main/kotlin/in/rcard/assertj/arrowcore/RaiseAssert.kt

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,9 +4,12 @@ package `in`.rcard.assertj.arrowcore
44

55
import arrow.core.raise.Raise
66
import arrow.core.raise.fold
7+
import `in`.rcard.assertj.arrowcore.errors.RaiseShouldFailButSucceeds.Companion.shouldFailButSucceedsWith
78
import `in`.rcard.assertj.arrowcore.errors.RaiseShouldThrowAnException.Companion.shouldThrowAnException
9+
import org.assertj.core.api.AbstractObjectAssert
810
import org.assertj.core.api.AbstractThrowableAssert
911
import org.assertj.core.api.Assertions
12+
import org.assertj.core.api.Fail
1013
import org.assertj.core.internal.Failures
1114
import kotlin.experimental.ExperimentalTypeInference
1215

@@ -57,5 +60,21 @@ class RaiseAssert<ERROR : Any, VALUE : Any>(
5760
.instance()
5861
.failure(Assertions.assertThat(throwable).writableAssertionInfo, shouldThrowAnException())
5962
}
63+
64+
inline fun <ERROR : Any, VALUE : Any> assertThatRaisedBy(
65+
@BuilderInference shouldRaiseError: Raise<ERROR>.() -> VALUE,
66+
): AbstractObjectAssert<*, out ERROR> {
67+
val error =
68+
fold(
69+
block = shouldRaiseError,
70+
recover = { error -> error },
71+
transform = { value ->
72+
Fail.fail(
73+
shouldFailButSucceedsWith(value).create(),
74+
)
75+
},
76+
)
77+
return Assertions.assertThat(error)
78+
}
6079
}
6180
}

src/main/kotlin/in/rcard/assertj/arrowcore/errors/RaiseShouldFailButSucceeds.kt

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ private const val SHOULD_FAIL_BUT_SUCCEEDS_WITH_MESSAGE: String =
1414
* @author Riccardo Cardin
1515
* @since 0.2.0
1616
*/
17-
internal class RaiseShouldFailButSucceeds private constructor(
17+
class RaiseShouldFailButSucceeds private constructor(
1818
expectedError: Any,
1919
actualSucceededValue: Any,
2020
message: String,
@@ -26,7 +26,7 @@ internal class RaiseShouldFailButSucceeds private constructor(
2626
): RaiseShouldFailButSucceeds =
2727
RaiseShouldFailButSucceeds(expectedError, actualSucceededValue, SHOULD_FAIL_WITH_BUT_SUCCEEDS_WITH_MESSAGE)
2828

29-
internal fun shouldFailButSucceedsWith(actualSucceededValue: Any): RaiseShouldFailButSucceeds =
29+
fun shouldFailButSucceedsWith(actualSucceededValue: Any): RaiseShouldFailButSucceeds =
3030
RaiseShouldFailButSucceeds("", actualSucceededValue, SHOULD_FAIL_BUT_SUCCEEDS_WITH_MESSAGE)
3131
}
3232
}

src/test/kotlin/in/rcard/assertj/arrowcore/Dummy.kt

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,4 +12,6 @@ internal object Dummy {
1212
suspend fun Raise<String>.aSuspendFunctionWithContext(input: Int): Int = input
1313

1414
suspend fun Raise<String>.aSuspendFunctionThatThrowsAnException(): Int = throw RuntimeException("AN EXCEPTION")
15+
16+
suspend fun Raise<String>.aSuspendFunctionThatRaisesAnError(): Int = raise("LOGICAL ERROR")
1517
}
Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
package `in`.rcard.assertj.arrowcore
2+
3+
import `in`.rcard.assertj.arrowcore.Dummy.aFunctionThatRaisesAnError
4+
import `in`.rcard.assertj.arrowcore.Dummy.aFunctionThatThrowsAnException
5+
import `in`.rcard.assertj.arrowcore.Dummy.aFunctionWithContext
6+
import `in`.rcard.assertj.arrowcore.Dummy.aSuspendFunctionThatRaisesAnError
7+
import `in`.rcard.assertj.arrowcore.RaiseAssert.Companion.assertThatRaisedBy
8+
import `in`.rcard.assertj.arrowcore.errors.RaiseShouldFailButSucceeds.Companion.shouldFailButSucceedsWith
9+
import kotlinx.coroutines.test.runTest
10+
import org.assertj.core.api.Assertions
11+
import org.junit.jupiter.api.Test
12+
13+
class RaiseAssert_assertThatRaisedBy_Test {
14+
@Test
15+
internal fun `should return a valid Object Assert if the Raise raises an error`() {
16+
assertThatRaisedBy { aFunctionThatRaisesAnError() }.isEqualTo("LOGICAL ERROR")
17+
}
18+
19+
@Test
20+
fun `should work with suspended functions`() =
21+
runTest {
22+
assertThatRaisedBy { aSuspendFunctionThatRaisesAnError() }.isEqualTo("LOGICAL ERROR")
23+
}
24+
25+
@Test
26+
internal fun `should fails if the Raise returns a value`() {
27+
Assertions
28+
.assertThatThrownBy { assertThatRaisedBy { aFunctionWithContext(42) } }
29+
.isInstanceOf(AssertionError::class.java)
30+
.hasMessage(shouldFailButSucceedsWith(42).create())
31+
}
32+
33+
@Test
34+
internal fun `should rethrow the inner exception`() {
35+
Assertions
36+
.assertThatThrownBy { assertThatRaisedBy { aFunctionThatThrowsAnException() } }
37+
.isInstanceOf(RuntimeException::class.java)
38+
.hasMessage("AN EXCEPTION")
39+
}
40+
}

src/test/kotlin/in/rcard/assertj/arrowcore/RaiseAssert_result_Test.kt

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
package `in`.rcard.assertj.arrowcore
22

3+
import arrow.core.raise.Raise
34
import `in`.rcard.assertj.arrowcore.Dummy.aFunctionThatRaisesAnError
45
import `in`.rcard.assertj.arrowcore.Dummy.aFunctionThatThrowsAnException
56
import `in`.rcard.assertj.arrowcore.Dummy.aFunctionWithContext
@@ -29,4 +30,17 @@ internal class RaiseAssert_result_Test {
2930
.isInstanceOf(RuntimeException::class.java)
3031
.hasMessage("AN EXCEPTION")
3132
}
33+
34+
@Test
35+
fun lordOfTheRings() {
36+
val hobbits: Raise<String>.() -> List<String> = { listOf("Frodo", "Samwise", "Peregrin", "Meriadoc") }
37+
assertThat(hobbits).succeedsWith(listOf("Frodo", "Samwise", "Peregrin", "Meriadoc"))
38+
39+
assertThat(hobbits).result().satisfies({
40+
Assertions.assertThat(it).hasSize(4)
41+
})
42+
43+
val dwarves: Raise<String>.() -> List<String> = { raise("No dwarves here!") }
44+
assertThat(dwarves).error().isEqualTo("No dwarves here!")
45+
}
3246
}

0 commit comments

Comments
 (0)