Skip to content

Commit 745d76a

Browse files
committed
feat(31): add assertion for NonEmptyList<A> type
1 parent db8d0b9 commit 745d76a

17 files changed

+642
-1
lines changed

README.md

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -89,4 +89,19 @@ The available assertions are:
8989
| `raises` | Verifies that the function in the Raise context fails with the given error. |
9090
| `fails` | Verifies that the function in the Raise context fails, no matter the type of the logical error. |
9191
| `result` | Verifies that the actual function in the `Raise` context succeeds and returns an `Object` assertion that allows chaining (object) assertions on the returned value. |
92-
| `error` | Verifies that the actual function in the Raise context fails and returns an Object assertion that allows chaining (object) assertions on the raised error. |
92+
| `error` | Verifies that the actual function in the Raise context fails and returns an Object assertion that allows chaining (object) assertions on the raised error. |
93+
94+
### `NonEmptyList<A>`
95+
96+
Use the `in.rcard.assertj.arrowcore.NonEmptyListAssert` class as an entry point to assert `NonEmptyList<A>` instances.
97+
98+
| Assertions | Description |
99+
|-----------------------------------|---------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
100+
| `shouldContain` | Verifies that the actual `NonEmptyList` contains the expected element. |
101+
| `shouldContainAll` | Verifies that the actual `NonEmptyList` contains all the expected elements. |
102+
| `shouldContainNoNulls` | Verifies that the actual `NonEmptyList` does not contain null. |
103+
| `shouldContainOnlyNulls` | Verifies that the actual `NonEmptyList` contains only null. |
104+
| `shouldContainNull` | Verifies that the actual `NonEmptyList` contains null. |
105+
| `shouldHaveDuplicates` | Verifies that the actual `NonEmptyList` contains at least one duplicate. |
106+
| `shouldBeSingleElement` | Verifies that the actual `NonEmptyList` has a single element which is expected element. |
107+
| `shouldBeSorted` | Verifies that the actual `NonEmptyList` is sorted. |
Lines changed: 142 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,142 @@
1+
package `in`.rcard.assertj.arrowcore
2+
3+
import arrow.core.NonEmptyList
4+
import `in`.rcard.assertj.arrowcore.errors.NonEmptyListHasNoDuplicates.Companion.hasNoDuplicate
5+
import `in`.rcard.assertj.arrowcore.errors.NonEmptyListIsNotSorted.Companion.isNotSorted
6+
import org.assertj.core.api.AbstractAssert
7+
import `in`.rcard.assertj.arrowcore.errors.NonEmptyListContains.Companion.contains
8+
import `in`.rcard.assertj.arrowcore.errors.NonEmptyListDoesNotContain.Companion.doesNotContain
9+
import `in`.rcard.assertj.arrowcore.errors.NonEmptyListDoesNotContainOnly.Companion.doesNotContainOnly
10+
import `in`.rcard.assertj.arrowcore.errors.NonEmptyListDoesNotHaveSingleElementEqual.Companion.doesNotHaveSingleElementEqual
11+
import org.assertj.core.api.AbstractIterableAssert
12+
import org.assertj.core.internal.ComparisonStrategy
13+
import org.assertj.core.internal.StandardComparisonStrategy
14+
15+
/**
16+
* Assertions for [NonEmptyList].
17+
*
18+
* @param SELF the "self" type of this assertion class.
19+
* @param ELEMENT type of the element contained in the [NonEmptyList].
20+
* @param ELEMENT_ASSERT type used for navigational assertion of element contained in the [NonEmptyList].
21+
* @author Hamza Faraji
22+
*
23+
* @since 1.2.0
24+
*/
25+
abstract class AbstractNonEmptyListAssert<
26+
SELF : AbstractNonEmptyListAssert<SELF, ELEMENT, ELEMENT_ASSERT>,
27+
ELEMENT : Any?,
28+
ELEMENT_ASSERT : AbstractAssert<ELEMENT_ASSERT, ELEMENT>
29+
> internal constructor(
30+
list: NonEmptyList<ELEMENT?>?,
31+
) : AbstractIterableAssert<SELF, NonEmptyList<ELEMENT?>, ELEMENT, ELEMENT_ASSERT>(list, AbstractNonEmptyListAssert::class.java) {
32+
private val comparisonStrategy: ComparisonStrategy = StandardComparisonStrategy.instance()
33+
34+
/**
35+
* Verifies that the actual [NonEmptyList] contains the expected element
36+
*
37+
* @return the assertion object
38+
*/
39+
fun shouldContain(expectedValue: ELEMENT): SELF {
40+
isNotNull
41+
assertContains(expectedValue)
42+
return myself
43+
}
44+
45+
/**
46+
* Verifies that the actual [NonEmptyList] contains all the expected elements
47+
*
48+
* @return the assertion object
49+
*/
50+
fun shouldContainAll(vararg elements: ELEMENT): SELF {
51+
isNotNull
52+
if (!actual.containsAll(elements.toList())) {
53+
throwAssertionError(doesNotContain(actual, elements))
54+
}
55+
return myself
56+
}
57+
58+
/**
59+
* Verifies that the actual [NonEmptyList] contains null
60+
*
61+
* @return the assertion object
62+
*/
63+
fun shouldContainNull(): SELF {
64+
isNotNull
65+
assertContains(null)
66+
return myself
67+
}
68+
69+
/**
70+
* Verifies that the actual [NonEmptyList] does not contain null
71+
*
72+
* @return the assertion object
73+
*/
74+
fun shouldContainNoNulls(): SELF {
75+
isNotNull
76+
if (actual.contains(null)) {
77+
throwAssertionError(contains(actual, null))
78+
}
79+
return myself
80+
}
81+
82+
/**
83+
* Verifies that the actual [NonEmptyList] contains only null
84+
*
85+
* @return the assertion object
86+
*/
87+
fun shouldContainOnlyNulls(): SELF {
88+
isNotNull
89+
if (!actual.all { it == null }) {
90+
throwAssertionError(doesNotContainOnly(actual, null))
91+
}
92+
return myself
93+
}
94+
95+
/**
96+
* Verifies that the actual [NonEmptyList] contains at least one duplicate
97+
*
98+
* @return the assertion object
99+
*/
100+
fun shouldHaveDuplicates(): SELF {
101+
isNotNull
102+
if (!actual.groupBy { it }.any { it.value.size > 1 }) {
103+
throwAssertionError(hasNoDuplicate(actual))
104+
}
105+
return myself
106+
}
107+
108+
/**
109+
* Verifies that the actual [NonEmptyList] has a single element which is expected element
110+
*
111+
* @return the assertion object
112+
*/
113+
fun shouldBeSingleElement(expectedValue: ELEMENT): SELF {
114+
isNotNull
115+
if (actual.size != 1 || !comparisonStrategy.areEqual(actual.first(), expectedValue)) {
116+
throwAssertionError(doesNotHaveSingleElementEqual(actual, expectedValue))
117+
}
118+
return myself
119+
}
120+
121+
/**
122+
* Verifies that the actual [NonEmptyList] is sorted
123+
*
124+
* @return the assertion object
125+
*/
126+
fun shouldBeSorted(): SELF {
127+
isNotNull
128+
if (!actual.zipWithNext().all { comparisonStrategy.isLessThanOrEqualTo(it.first, it.second) }) {
129+
throwAssertionError(isNotSorted(actual))
130+
}
131+
132+
return myself
133+
}
134+
135+
private fun assertContains(expectedValue: ELEMENT?) {
136+
isNotNull
137+
if (!actual.contains(expectedValue)) {
138+
throwAssertionError(doesNotContain(actual, expectedValue))
139+
}
140+
}
141+
142+
}
Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
package `in`.rcard.assertj.arrowcore
2+
3+
import arrow.core.NonEmptyList
4+
import arrow.core.toNonEmptyListOrNull
5+
import org.assertj.core.api.ObjectAssert
6+
7+
/**
8+
* Assertions for [NonEmptyList].
9+
*
10+
* @param ELEMENT type of the element contained in the [NonEmptyList].
11+
* @author Hamza Faraji
12+
*
13+
* @since 1.2.0
14+
*/
15+
class NonEmptyListAssert<ELEMENT : Any?> private constructor(nel: NonEmptyList<ELEMENT>?) :
16+
AbstractNonEmptyListAssert<NonEmptyListAssert<ELEMENT>, ELEMENT, ObjectAssert<ELEMENT>>(nel) {
17+
companion object {
18+
fun <VALUE : Any?> assertThat(list: NonEmptyList<VALUE>?): NonEmptyListAssert<VALUE> =
19+
NonEmptyListAssert(list)
20+
}
21+
22+
override fun toAssert(value: ELEMENT, description: String?): ObjectAssert<ELEMENT> =
23+
ObjectAssert(value).`as`(description)
24+
25+
override fun newAbstractIterableAssert(iterable: MutableIterable<ELEMENT>?): NonEmptyListAssert<ELEMENT> =
26+
NonEmptyListAssert(iterable?.toNonEmptyListOrNull())
27+
}
Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
package `in`.rcard.assertj.arrowcore.errors
2+
3+
import arrow.core.NonEmptyList
4+
import org.assertj.core.error.BasicErrorMessageFactory
5+
6+
/**
7+
* Build error message when a [NonEmptyList] contains a specific value.
8+
*
9+
* @author Hamza Faraji
10+
* @since 1.2.0
11+
*/
12+
class NonEmptyListContains(message: String, actual: NonEmptyList<Any?>, expected: Any?) :
13+
BasicErrorMessageFactory(message, actual, expected) {
14+
companion object {
15+
private const val EXPECTING_NOT_TO_CONTAIN =
16+
"%nExpecting:%n <%s>%nto not contain any:%n <%s>%nbut it did."
17+
18+
internal fun <ELEMENT : Any?> contains(
19+
actual: NonEmptyList<ELEMENT>,
20+
expected: ELEMENT
21+
): NonEmptyListContains = NonEmptyListContains(
22+
EXPECTING_NOT_TO_CONTAIN,
23+
actual,
24+
expected
25+
)
26+
}
27+
}
Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
package `in`.rcard.assertj.arrowcore.errors
2+
3+
import arrow.core.NonEmptyList
4+
import org.assertj.core.error.BasicErrorMessageFactory
5+
6+
/**
7+
* Build error message when a [NonEmptyList] does not contain a specific value.
8+
*
9+
* @author Hamza Faraji
10+
* @since 1.2.0
11+
*/
12+
internal class NonEmptyListDoesNotContain private constructor(message: String, actual: NonEmptyList<Any?>, expected: Any?) :
13+
BasicErrorMessageFactory(message, actual, expected) {
14+
companion object {
15+
private const val EXPECTING_TO_CONTAIN =
16+
"%nExpecting:%n <%s>%nto contain:%n <%s>%nbut did not."
17+
18+
internal fun <ELEMENT : Any> doesNotContain(
19+
actual: NonEmptyList<ELEMENT?>,
20+
vararg expected: ELEMENT?
21+
): NonEmptyListDoesNotContain = NonEmptyListDoesNotContain(
22+
EXPECTING_TO_CONTAIN,
23+
actual,
24+
expected
25+
)
26+
}
27+
}
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
package `in`.rcard.assertj.arrowcore.errors
2+
3+
import arrow.core.NonEmptyList
4+
import org.assertj.core.error.BasicErrorMessageFactory
5+
6+
/**
7+
* Build error message when a [NonEmptyList] does not contain only a specific value.
8+
*
9+
* @author Hamza Faraji
10+
* @since 1.2.0
11+
*/
12+
class NonEmptyListDoesNotContainOnly private constructor(message: String, actual: NonEmptyList<Any?>, expected: Any?) :
13+
BasicErrorMessageFactory(message, actual, expected) {
14+
15+
companion object {
16+
private const val EXPECTING_TO_CONTAIN_ONLY =
17+
"%nExpecting:%n <%s>%nto contain only:%n <%s>%nbut did not."
18+
19+
internal fun <ELEMENT : Any> doesNotContainOnly(
20+
actual: NonEmptyList<ELEMENT?>,
21+
expected: ELEMENT?
22+
): NonEmptyListDoesNotContainOnly = NonEmptyListDoesNotContainOnly(
23+
EXPECTING_TO_CONTAIN_ONLY,
24+
actual,
25+
expected
26+
)
27+
}
28+
}
Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
package `in`.rcard.assertj.arrowcore.errors
2+
3+
import arrow.core.NonEmptyList
4+
import org.assertj.core.error.BasicErrorMessageFactory
5+
6+
/**
7+
* Build error message when a [NonEmptyList] does not have a single element equal a specific value.
8+
*
9+
* @author Hamza Faraji
10+
* @since 1.2.0
11+
*/
12+
class NonEmptyListDoesNotHaveSingleElementEqual private constructor(message: String, actual: NonEmptyList<Any?>, expected: Any?) :
13+
BasicErrorMessageFactory(message, actual, expected) {
14+
companion object {
15+
private const val EXPECTING_TO_HAVE_SINGLE_ELEMENT_EQUAL =
16+
"%nExpecting:%n <%s>%nto have single element:%n <%s>%nbut did not."
17+
18+
internal fun <ELEMENT : Any> doesNotHaveSingleElementEqual(
19+
actual: NonEmptyList<ELEMENT?>,
20+
expected: ELEMENT?
21+
): NonEmptyListDoesNotHaveSingleElementEqual = NonEmptyListDoesNotHaveSingleElementEqual(
22+
EXPECTING_TO_HAVE_SINGLE_ELEMENT_EQUAL,
23+
actual,
24+
expected
25+
)
26+
}
27+
}
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
package `in`.rcard.assertj.arrowcore.errors
2+
3+
import arrow.core.NonEmptyList
4+
import org.assertj.core.error.BasicErrorMessageFactory
5+
6+
/**
7+
* Build error message when a [NonEmptyList] has no duplicates.
8+
*
9+
* @author Hamza Faraji
10+
* @since 1.2.0
11+
*/
12+
class NonEmptyListHasNoDuplicates private constructor(message: String, actual: NonEmptyList<Any?>) :
13+
BasicErrorMessageFactory(message, actual) {
14+
companion object {
15+
private const val EXPECTING_TO_CONTAIN_DUPLICATES =
16+
"%nExpecting:%n <%s>%nto contain duplicates but did not."
17+
18+
internal fun <ELEMENT : Any> hasNoDuplicate(
19+
actual: NonEmptyList<ELEMENT?>
20+
): NonEmptyListHasNoDuplicates = NonEmptyListHasNoDuplicates(
21+
EXPECTING_TO_CONTAIN_DUPLICATES,
22+
actual
23+
)
24+
}
25+
}
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
package `in`.rcard.assertj.arrowcore.errors
2+
3+
import arrow.core.NonEmptyList
4+
import org.assertj.core.error.BasicErrorMessageFactory
5+
6+
/**
7+
* Build error message when a [NonEmptyList] is not sorted.
8+
*
9+
* @author Hamza Faraji
10+
* @since 1.2.0
11+
*/
12+
class NonEmptyListIsNotSorted private constructor(message: String, actual: NonEmptyList<Any?>) :
13+
BasicErrorMessageFactory(message, actual) {
14+
companion object {
15+
private const val EXPECTING_TO_BE_SORTED =
16+
"%nExpecting:%n <%s>%nto be sorted, but it is not."
17+
18+
internal fun <ELEMENT : Any> isNotSorted(
19+
actual: NonEmptyList<ELEMENT?>
20+
): NonEmptyListIsNotSorted = NonEmptyListIsNotSorted(
21+
EXPECTING_TO_BE_SORTED,
22+
actual
23+
)
24+
}
25+
}

0 commit comments

Comments
 (0)