Skip to content

Commit 4374e20

Browse files
committed
Added shouldContainsInstanceOf assertion to OptionAssert
1 parent 043eb83 commit 4374e20

File tree

3 files changed

+131
-2
lines changed

3 files changed

+131
-2
lines changed

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

Lines changed: 28 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ import arrow.core.Option
44
import `in`.rcard.assertj.arrowcore.errors.OptionShouldBeEmpty.Companion.shouldBeEmpty
55
import `in`.rcard.assertj.arrowcore.errors.OptionShouldBePresent.Companion.shouldBePresent
66
import `in`.rcard.assertj.arrowcore.errors.OptionShouldContain.Companion.shouldContain
7+
import `in`.rcard.assertj.arrowcore.errors.OptionShouldContainInstanceOf.Companion.shouldContainInstanceOf
78
import org.assertj.core.api.AbstractObjectAssert
89
import org.assertj.core.internal.ComparisonStrategy
910
import org.assertj.core.internal.StandardComparisonStrategy
@@ -29,8 +30,7 @@ abstract class AbstractOptionAssert<
2930
* @return this assertion object.
3031
*/
3132
fun isDefined(): SELF {
32-
isNotNull
33-
if (actual.isEmpty()) throwAssertionError(shouldBePresent())
33+
assertValueIsPresent()
3434
return myself
3535
}
3636

@@ -63,4 +63,30 @@ abstract class AbstractOptionAssert<
6363
)
6464
return myself
6565
}
66+
67+
/**
68+
* Verifies that the actual [Option] contains a value that is an instance of the argument.
69+
*
70+
* @param expectedClass the expected class of the value inside the [Option].
71+
* @return this assertion object.
72+
*/
73+
fun containsInstanceOf(expectedClass: Class<*>): SELF {
74+
assertValueIsPresent()
75+
actual.tap { value ->
76+
if (!expectedClass.isInstance(value)) {
77+
throwAssertionError(
78+
shouldContainInstanceOf(
79+
actual,
80+
expectedClass,
81+
),
82+
)
83+
}
84+
}
85+
return myself
86+
}
87+
88+
private fun assertValueIsPresent() {
89+
isNotNull
90+
if (actual.isEmpty()) throwAssertionError(shouldBePresent())
91+
}
6692
}
Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
package `in`.rcard.assertj.arrowcore.errors
2+
3+
import arrow.core.Option
4+
import org.assertj.core.error.BasicErrorMessageFactory
5+
6+
/**
7+
* Build an error message when a value should be instance of a specific class.
8+
*
9+
* @author Riccardo Cardin
10+
*/
11+
internal class OptionShouldContainInstanceOf(message: String) : BasicErrorMessageFactory(message) {
12+
13+
companion object {
14+
/**
15+
* Indicates that a value of a specific class should be present in an empty [Option].
16+
*
17+
* @param option Option to be checked.
18+
* @param clazz expected class of a value
19+
* @return an error message factory.
20+
* @throws java.lang.NullPointerException if option is null.
21+
*/
22+
internal fun <VALUE : Any> shouldContainInstanceOf(
23+
option: Option<VALUE>,
24+
clazz: Class<*>,
25+
): OptionShouldContainInstanceOf = option.fold(
26+
{
27+
OptionShouldContainInstanceOf(
28+
"%nExpecting:%n <%s>%nto contain a value that is an instance of:%n <%s>%nbut was empty".format(
29+
option,
30+
clazz.name,
31+
),
32+
)
33+
},
34+
{ value ->
35+
OptionShouldContainInstanceOf(
36+
"%nExpecting:%n <%s>%nto contain a value that is an instance of:%n <%s>%nbut did contain an instance of:%n <%s>".format(
37+
option,
38+
clazz.name,
39+
value.javaClass.name,
40+
),
41+
)
42+
},
43+
)
44+
}
45+
}
Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
package `in`.rcard.assertj.arrowcore
2+
3+
import arrow.core.None
4+
import arrow.core.Option
5+
import arrow.core.some
6+
import `in`.rcard.assertj.arrowcore.OptionAssert.Companion.assertThat
7+
import `in`.rcard.assertj.arrowcore.errors.OptionShouldBePresent.Companion.shouldBePresent
8+
import `in`.rcard.assertj.arrowcore.errors.OptionShouldContainInstanceOf.Companion.shouldContainInstanceOf
9+
import org.assertj.core.api.Assertions
10+
import org.junit.jupiter.api.Test
11+
12+
internal class OptionAssert_containsInstanceOf_Test {
13+
14+
@Test
15+
internal fun `should fail if option is empty`() {
16+
val actual: Option<Any> = None
17+
Assertions.assertThatThrownBy {
18+
assertThat(actual).containsInstanceOf(
19+
Any::class.java,
20+
)
21+
}
22+
.isInstanceOf(AssertionError::class.java)
23+
.hasMessage(shouldBePresent().create())
24+
}
25+
26+
@Test
27+
internal fun `should pass if option contains required type`() {
28+
val optionValue = "something".some()
29+
assertThat(optionValue).containsInstanceOf(String::class.java)
30+
}
31+
32+
@Test
33+
internal fun `should pass if option contains required type subclass`() {
34+
val optionValue = Child().some()
35+
assertThat(optionValue).containsInstanceOf(
36+
Parent::class.java,
37+
)
38+
}
39+
40+
@Test
41+
internal fun `should fail if option contains other type than required`() {
42+
val actual = 42.some()
43+
Assertions.assertThatThrownBy {
44+
assertThat(actual).containsInstanceOf(String::class.java)
45+
}
46+
.isInstanceOf(AssertionError::class.java)
47+
.hasMessage(
48+
shouldContainInstanceOf(
49+
actual,
50+
String::class.java,
51+
).create(),
52+
)
53+
}
54+
55+
private open class Parent
56+
57+
private class Child : Parent()
58+
}

0 commit comments

Comments
 (0)