diff --git a/CHANGELOG.md b/CHANGELOG.md index a47343b9..a4f2b2e1 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -14,6 +14,10 @@ and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0. - signature of `isIn` and `isNotIn` has been changed to ensure at least two items are supplied. - added assertions `isIn(Iterable)` and `isNotIn(Iterable)` +### Added +- Added `doesNotExist` assertions to `Path` +- Added `havingInstancesOf` and `notHavingInstancesOf` for `Iterable` and `Array` + ## [0.28.1] 2024-04-17 ### Added diff --git a/assertk/src/commonMain/kotlin/assertk/assertions/array.kt b/assertk/src/commonMain/kotlin/assertk/assertions/array.kt index db67357b..74f430d4 100644 --- a/assertk/src/commonMain/kotlin/assertk/assertions/array.kt +++ b/assertk/src/commonMain/kotlin/assertk/assertions/array.kt @@ -178,6 +178,34 @@ fun Assert>.containsExactly(vararg elements: Any?) = given { actual -> expectedListDiff(elements.asList(), actual.asList()) } +/** + * Asserts the collection contains at least one instance of a given type. + * + * ``` + * assertThat(arrayOf("one", "two", 1)).havingInstanceOf().each { + * it.hasLength(3) + * } + * ``` + */ +inline fun Assert>.havingInstancesOf(): Assert> { + return transform("contains instances of ${T::class}") { actual -> + actual.filterIsInstance().also { + if (it.isEmpty()) expected("to contain at least one instance of ${T::class} but was ${actual.asList()}") + } + } +} + +/** + * Asserts the collection does not contain an instance of a given type. + * + * ``` + * assertThat(arrayOf("one", "two", 1)).havingInstancesOf() + * ``` + */ +inline fun Assert>.notHavingInstancesOf() = given { actual -> + if (actual.any { it is T }) expected("to not contain instances of ${T::class} but was ${actual.asList()}") +} + /** * Asserts on each item in the array. The given lambda will be run for each item. * diff --git a/assertk/src/commonMain/kotlin/assertk/assertions/iterable.kt b/assertk/src/commonMain/kotlin/assertk/assertions/iterable.kt index 65861d3d..ba5d43a0 100644 --- a/assertk/src/commonMain/kotlin/assertk/assertions/iterable.kt +++ b/assertk/src/commonMain/kotlin/assertk/assertions/iterable.kt @@ -131,6 +131,34 @@ internal fun MutableList<*>.removeFirst(value: Any?) { if (index > -1) removeAt(index) } +/** + * Asserts the collection contains at least one instance of a given type. + * + * ``` + * assertThat(listOf("one", "two", 1)).havingInstanceOf().each { + * it.hasLength(3) + * } + * ``` + */ +inline fun Assert>.havingInstancesOf(): Assert> { + return transform("contains instance of ${T::class}") { actual -> + actual.filterIsInstance().also { + if (it.isEmpty()) expected("to contain at least one instance of ${T::class} but was $actual") + } + } +} + +/** + * Asserts the collection does not contain an instance of a given type. + * + * ``` + * assertThat(listOf("one", "two", 1)).doesNotContainInstanceOf() + * ``` + */ +inline fun Assert>.notHavingInstancesOf() = given { actual -> + if (actual.any { it is T }) expected("to not contain instances of ${T::class} but was $actual") +} + /** * Asserts on each item in the iterable. The given lambda will be run for each item. * diff --git a/assertk/src/commonTest/kotlin/test/assertk/assertions/ArrayTest.kt b/assertk/src/commonTest/kotlin/test/assertk/assertions/ArrayTest.kt index 23b096e4..4581a1b0 100644 --- a/assertk/src/commonTest/kotlin/test/assertk/assertions/ArrayTest.kt +++ b/assertk/src/commonTest/kotlin/test/assertk/assertions/ArrayTest.kt @@ -322,6 +322,32 @@ class ArrayTest { } //endregion + //region containsInstanceOf + @Test fun containsInstanceOf_element_present_passes() { + assertThat(arrayOf(1, "two")).havingInstancesOf().single().isEqualTo("two") + } + + @Test fun containsInstanceOf_element_missing_fails() { + val error = assertFailsWith { + assertThat(arrayOf(1, "two")).havingInstancesOf() + } + assertEquals("expected to contain at least one instance of class kotlin.Double but was [1, two]", error.message) + } + //endregion + + //region doesNotContainInstanceOf + @Test fun doesNotContainInstanceOf_element_present_fails() { + val error = assertFailsWith() { + assertThat(arrayOf(1, "two")).notHavingInstancesOf() + } + assertEquals("expected to not contain instances of class kotlin.String but was [1, two]", error.message) + } + + @Test fun doesNotContainInstanceOf_element_missing_passes() { + assertThat(arrayOf(1, "two")).notHavingInstancesOf() + } + //endregion + //region each @Test fun each_empty_list_passes() { diff --git a/assertk/src/commonTest/kotlin/test/assertk/assertions/IterableTest.kt b/assertk/src/commonTest/kotlin/test/assertk/assertions/IterableTest.kt index 79ed523b..ca6d00ea 100644 --- a/assertk/src/commonTest/kotlin/test/assertk/assertions/IterableTest.kt +++ b/assertk/src/commonTest/kotlin/test/assertk/assertions/IterableTest.kt @@ -9,9 +9,11 @@ import assertk.assertions.contains import assertk.assertions.containsAtLeast import assertk.assertions.containsExactly import assertk.assertions.containsExactlyInAnyOrder +import assertk.assertions.havingInstancesOf import assertk.assertions.containsNone import assertk.assertions.containsOnly import assertk.assertions.doesNotContain +import assertk.assertions.notHavingInstancesOf import assertk.assertions.each import assertk.assertions.exactly import assertk.assertions.extracting @@ -229,6 +231,32 @@ class IterableTest { } //endregion + //region containsInstanceOf + @Test fun containsInstanceOf_element_present_passes() { + assertThat(iterableOf(1, "two")).havingInstancesOf().single().isEqualTo("two") + } + + @Test fun containsInstanceOf_element_missing_fails() { + val error = assertFailsWith { + assertThat(iterableOf(1, "two")).havingInstancesOf() + } + assertEquals("expected to contain at least one instance of class kotlin.Double but was [1, two]", error.message) + } + //endregion + + //region doesNotContainInstanceOf + @Test fun doesNotContainInstanceOf_element_present_fails() { + val error = assertFailsWith() { + assertThat(iterableOf(1, "two")).notHavingInstancesOf() + } + assertEquals("expected to not contain instances of class kotlin.String but was [1, two]", error.message) + } + + @Test fun doesNotContainInstanceOf_element_missing_passes() { + assertThat(iterableOf(1, "two")).notHavingInstancesOf() + } + //endregion + //region each @Test fun each_empty_list_passes() {