From dd555229a3cc31dce940daec1b7b1d674de4e681 Mon Sep 17 00:00:00 2001 From: Goooler Date: Wed, 15 Jan 2025 15:56:10 +0800 Subject: [PATCH 1/3] Overload single assertion --- CHANGELOG.md | 3 ++ .../kotlin/assertk/assertions/iterable.kt | 15 ++++++++++ .../test/assertk/assertions/IterableTest.kt | 28 +++++++++++++++---- 3 files changed, 40 insertions(+), 6 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index a47343b9..dfe97b42 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,6 +6,9 @@ and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0. ## [Unreleased] +### Added +- Overload `single` assertion . + ### Changed - renamed `prop` to `having` as part of effort to unify API naming, old name is deprecated. - renamed `suspendCall` to `having` as part of effort to unify API naming, old name is deprecated. diff --git a/assertk/src/commonMain/kotlin/assertk/assertions/iterable.kt b/assertk/src/commonMain/kotlin/assertk/assertions/iterable.kt index 65861d3d..768e2255 100644 --- a/assertk/src/commonMain/kotlin/assertk/assertions/iterable.kt +++ b/assertk/src/commonMain/kotlin/assertk/assertions/iterable.kt @@ -331,3 +331,18 @@ fun > Assert.single(): Assert { } } } + +/** + * Asserts the iterable contains exactly one element matching the expected element, + * and returns an assert on that element. + */ +inline fun > Assert.single(predicate: (E) -> Boolean): Assert { + return transform(appendName("single", ".")) { iterable -> + val matching = iterable.filter(predicate) + when (matching.size) { + 1 -> matching.single() + 0 -> expected("to have single element matching predicate but none found") + else -> expected("to have single element matching predicate but has ${matching.size}: ${show(matching)}") + } + } +} diff --git a/assertk/src/commonTest/kotlin/test/assertk/assertions/IterableTest.kt b/assertk/src/commonTest/kotlin/test/assertk/assertions/IterableTest.kt index 79ed523b..c3faf722 100644 --- a/assertk/src/commonTest/kotlin/test/assertk/assertions/IterableTest.kt +++ b/assertk/src/commonTest/kotlin/test/assertk/assertions/IterableTest.kt @@ -599,30 +599,46 @@ class IterableTest { @Test fun single_single_element_match_passes() { assertThat(listOf(1)).single().isEqualTo(1) + assertThat(listOf(1)).single { it > 0 }.isEqualTo(1) } @Test fun single_single_element_mismatch_fails() { - val error = assertFailsWith { + val error1 = assertFailsWith { assertThat(listOf(1)).single().isEqualTo(2) } - assertEquals("expected [single]:<[2]> but was:<[1]> ([1])", error.message) + assertEquals("expected [single]:<[2]> but was:<[1]> ([1])", error1.message) + + val error2 = assertFailsWith { + assertThat(listOf(1)).single { it > 0 }.isEqualTo(2) + } + assertEquals("expected [single]:<[2]> but was:<[1]> ([1])", error2.message) } @Test fun single_no_element_fails() { - val error = assertFailsWith { + val error1 = assertFailsWith { assertThat(emptyList()).single().isEqualTo(1) } - assertEquals("expected to have single element but was empty", error.message) + assertEquals("expected to have single element but was empty", error1.message) + + val error2 = assertFailsWith { + assertThat(emptyList()).single { it != null }.isEqualTo(1) + } + assertEquals("expected to have single element matching predicate but none found", error2.message) } @Test fun single_multiple_fails() { - val error = assertFailsWith { + val error1 = assertFailsWith { assertThat(listOf(1, 2)).single().isEqualTo(1) } - assertEquals("expected to have single element but has 2: <[1, 2]>", error.message) + assertEquals("expected to have single element but has 2: <[1, 2]>", error1.message) + + val error2 = assertFailsWith { + assertThat(listOf(1, 2)).single { it > 0 }.isEqualTo(1) + } + assertEquals("expected to have single element matching predicate but has 2: <[1, 2]>", error2.message) } //endregion From a21b8f948ae72e7d4edfbe208800d89ae7885b17 Mon Sep 17 00:00:00 2001 From: Zongle Wang Date: Wed, 15 Jan 2025 21:35:37 +0800 Subject: [PATCH 2/3] Update CHANGELOG.md Co-authored-by: Jake Wharton --- CHANGELOG.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index dfe97b42..d90344b1 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,7 +7,7 @@ and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0. ## [Unreleased] ### Added -- Overload `single` assertion . +- Add version of the `single` function which takes a predicate for selecting the element from a collection. ### Changed - renamed `prop` to `having` as part of effort to unify API naming, old name is deprecated. From 1f528605b37df22094f631f51d4e894563843c0f Mon Sep 17 00:00:00 2001 From: Zongle Wang Date: Wed, 15 Jan 2025 21:43:35 +0800 Subject: [PATCH 3/3] Apply suggestions from code review Co-authored-by: Jake Wharton --- assertk/src/commonMain/kotlin/assertk/assertions/iterable.kt | 2 +- .../commonTest/kotlin/test/assertk/assertions/IterableTest.kt | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/assertk/src/commonMain/kotlin/assertk/assertions/iterable.kt b/assertk/src/commonMain/kotlin/assertk/assertions/iterable.kt index 768e2255..58211daa 100644 --- a/assertk/src/commonMain/kotlin/assertk/assertions/iterable.kt +++ b/assertk/src/commonMain/kotlin/assertk/assertions/iterable.kt @@ -336,7 +336,7 @@ fun > Assert.single(): Assert { * Asserts the iterable contains exactly one element matching the expected element, * and returns an assert on that element. */ -inline fun > Assert.single(predicate: (E) -> Boolean): Assert { +fun > Assert.single(predicate: (E) -> Boolean): Assert { return transform(appendName("single", ".")) { iterable -> val matching = iterable.filter(predicate) when (matching.size) { diff --git a/assertk/src/commonTest/kotlin/test/assertk/assertions/IterableTest.kt b/assertk/src/commonTest/kotlin/test/assertk/assertions/IterableTest.kt index c3faf722..6ca401eb 100644 --- a/assertk/src/commonTest/kotlin/test/assertk/assertions/IterableTest.kt +++ b/assertk/src/commonTest/kotlin/test/assertk/assertions/IterableTest.kt @@ -599,7 +599,7 @@ class IterableTest { @Test fun single_single_element_match_passes() { assertThat(listOf(1)).single().isEqualTo(1) - assertThat(listOf(1)).single { it > 0 }.isEqualTo(1) + assertThat(listOf(-1, 1, 0, -2)).single { it > 0 }.isEqualTo(1) } @Test