From 122d5820ecad5cf8053920530a47b977e3fa9a79 Mon Sep 17 00:00:00 2001 From: Yahor Barkouski Date: Sun, 4 Jun 2023 17:16:15 +0200 Subject: [PATCH 1/3] Add containsExactlyInAnyOrder(anotherIterable) support --- .../kotlin/assertk/assertions/iterable.kt | 4 ++ .../test/assertk/assertions/IterableTest.kt | 66 +++++++++++++++++++ 2 files changed, 70 insertions(+) diff --git a/assertk/src/commonMain/kotlin/assertk/assertions/iterable.kt b/assertk/src/commonMain/kotlin/assertk/assertions/iterable.kt index 9fd4f510..0995a274 100644 --- a/assertk/src/commonMain/kotlin/assertk/assertions/iterable.kt +++ b/assertk/src/commonMain/kotlin/assertk/assertions/iterable.kt @@ -116,6 +116,10 @@ fun Assert>.containsExactlyInAnyOrder(vararg elements: Any?) = given }.toString()) } +inline fun Assert>.containsExactlyInAnyOrder(expected: Iterable) = given { actual -> + assertThat(actual).containsExactlyInAnyOrder(*expected.toList().toTypedArray()) +} + internal fun MutableList<*>.removeFirst(value: Any?) { val index = indexOf(value) if (index > -1) removeAt(index) diff --git a/assertk/src/commonTest/kotlin/test/assertk/assertions/IterableTest.kt b/assertk/src/commonTest/kotlin/test/assertk/assertions/IterableTest.kt index 390a3774..76d30796 100644 --- a/assertk/src/commonTest/kotlin/test/assertk/assertions/IterableTest.kt +++ b/assertk/src/commonTest/kotlin/test/assertk/assertions/IterableTest.kt @@ -206,6 +206,72 @@ class IterableTest { error.message ) } + + @Test fun containsExactlyInAnyOrder_only_elements_of_another_iterable_passes() { + assertThat(iterableOf(1, 2)).containsExactlyInAnyOrder(iterableOf(2, 1)) + } + + @Test fun containsExactlyInAnyOrder_only_elements_of_another_iterable_passes2() { + assertThat(iterableOf(1, 2, 1)).containsExactlyInAnyOrder(iterableOf(2, 1, 1)) + } + + @Test fun containsExactlyInAnyOrder_duplicate_elements_of_another_iterable_fails() { + val error = assertFailsWith { + assertThat(iterableOf(1, 2, 2)).containsExactlyInAnyOrder(iterableOf(2, 1)) + } + assertEquals( + """expected to contain exactly in any order:<[2, 1]> but was:<[1, 2, 2]> + | extra elements found:<[2]> + """.trimMargin(), error.message + ) + } + + @Test fun containsExactlyInAnyOrder_of_another_iterable_duplicate_elements_fails2() { + val error = assertFailsWith { + assertThat(iterableOf(1, 2)).containsExactlyInAnyOrder(iterableOf(2, 2, 1)) + } + assertEquals( + """expected to contain exactly in any order:<[2, 2, 1]> but was:<[1, 2]> + | elements not found:<[2]> + """.trimMargin(), error.message + ) + } + + @Test fun containsExactlyInAnyOrder__of_another_iterable_more_elements_fails() { + val error = assertFailsWith { + assertThat(iterableOf(1, 2, 3)).containsExactlyInAnyOrder(iterableOf(2, 1)) + } + assertEquals( + """expected to contain exactly in any order:<[2, 1]> but was:<[1, 2, 3]> + | extra elements found:<[3]> + """.trimMargin(), error.message + ) + } + + @Test fun containsExactlyInAnyOrder_of_another_iterable_less_elements_fails() { + val error = assertFailsWith { + assertThat(iterableOf(1, 2, 3)).containsExactlyInAnyOrder(iterableOf(2, 1, 3, 4)) + } + assertEquals( + """expected to contain exactly in any order:<[2, 1, 3, 4]> but was:<[1, 2, 3]> + | elements not found:<[4]> + """.trimMargin(), + error.message + ) + } + + @Test fun containsExactlyInAnyOrder_of_another_iterable_different_elements_fails() { + val error = assertFailsWith { + assertThat(iterableOf(1)).containsExactlyInAnyOrder(iterableOf(2)) + } + assertEquals( + """expected to contain exactly in any order:<[2]> but was:<[1]> + | elements not found:<[2]> + | extra elements found:<[1]> + """.trimMargin(), + error.message + ) + } //endregion //region each From d5ac13c3941fc48f5d5ae33b1eaf441466ab69fb Mon Sep 17 00:00:00 2001 From: Yahor Barkouski Date: Sun, 4 Jun 2023 17:39:04 +0200 Subject: [PATCH 2/3] chore: avoid spread operator --- assertk/src/commonMain/kotlin/assertk/assertions/iterable.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/assertk/src/commonMain/kotlin/assertk/assertions/iterable.kt b/assertk/src/commonMain/kotlin/assertk/assertions/iterable.kt index 0995a274..55c2cec0 100644 --- a/assertk/src/commonMain/kotlin/assertk/assertions/iterable.kt +++ b/assertk/src/commonMain/kotlin/assertk/assertions/iterable.kt @@ -117,7 +117,7 @@ fun Assert>.containsExactlyInAnyOrder(vararg elements: Any?) = given } inline fun Assert>.containsExactlyInAnyOrder(expected: Iterable) = given { actual -> - assertThat(actual).containsExactlyInAnyOrder(*expected.toList().toTypedArray()) + assertThat(actual).containsExactlyInAnyOrder(expected.toMutableList().toTypedArray()) } internal fun MutableList<*>.removeFirst(value: Any?) { From e469b0d843ea55afe4965b21a974eb7351421b66 Mon Sep 17 00:00:00 2001 From: Yahor Barkouski Date: Sun, 4 Jun 2023 18:04:37 +0200 Subject: [PATCH 3/3] chore: change contains any mechanism to align with js --- .../kotlin/assertk/assertions/iterable.kt | 19 ++++++++++++++++++- 1 file changed, 18 insertions(+), 1 deletion(-) diff --git a/assertk/src/commonMain/kotlin/assertk/assertions/iterable.kt b/assertk/src/commonMain/kotlin/assertk/assertions/iterable.kt index 55c2cec0..dda585c6 100644 --- a/assertk/src/commonMain/kotlin/assertk/assertions/iterable.kt +++ b/assertk/src/commonMain/kotlin/assertk/assertions/iterable.kt @@ -117,7 +117,24 @@ fun Assert>.containsExactlyInAnyOrder(vararg elements: Any?) = given } inline fun Assert>.containsExactlyInAnyOrder(expected: Iterable) = given { actual -> - assertThat(actual).containsExactlyInAnyOrder(expected.toMutableList().toTypedArray()) + val actualMap = actual.groupingBy { it }.eachCount() + val expectedMap = expected.groupingBy { it }.eachCount() + + if (actualMap == expectedMap) { + return + } + + val notInActual = expectedMap.filter { (key, value) -> (actualMap[key] ?: 0) < value }.map { it.key } + val notInExpected = actualMap.filter { (key, value) -> (expectedMap[key] ?: 0) < value }.map { it.key } + + expected(StringBuilder("to contain exactly in any order:${show(expected)} but was:${show(actual)}").apply { + if (notInActual.isNotEmpty()) { + append("\n elements not found:${show(notInActual)}") + } + if (notInExpected.isNotEmpty()) { + append("\n extra elements found:${show(notInExpected)}") + } + }.toString()) } internal fun MutableList<*>.removeFirst(value: Any?) {