Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

ContainDuplicates should print them (#20) #3846

Merged
merged 2 commits into from
Jan 24, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
package io.kotest.matchers.collections

import io.kotest.assertions.print.print
import io.kotest.matchers.Matcher
import io.kotest.matchers.MatcherResult
import io.kotest.matchers.should
Expand Down Expand Up @@ -35,10 +36,18 @@ fun <T> Collection<T>.shouldNotContainDuplicates(): Collection<T> {
}

fun <T> containDuplicates() = object : Matcher<Collection<T>> {
override fun test(value: Collection<T>) = MatcherResult(
value.toSet().size < value.size,
{ "Collection should contain duplicates" },
{
"Collection should not contain duplicates"
})
override fun test(value: Collection<T>): MatcherResult {
val duplicates = value.duplicates()
return MatcherResult(
duplicates.isNotEmpty(),
{ "Collection should contain duplicates" },
{
"Collection should not contain duplicates, but has some: ${duplicates.print().value}"
})
}
}

internal fun<T> Collection<T>.duplicates(): Collection<T> = this.groupingBy { it }
.eachCount().entries
.filter { it.value > 1 }
.map { it.key }
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ package com.sksamuel.kotest.matchers.collections
import io.kotest.assertions.shouldFail
import io.kotest.assertions.throwables.shouldNotThrow
import io.kotest.assertions.throwables.shouldThrow
import io.kotest.assertions.throwables.shouldThrowAny
import io.kotest.assertions.withClue
import io.kotest.core.spec.style.WordSpec
import io.kotest.equals.Equality
Expand Down Expand Up @@ -230,6 +231,12 @@ class CollectionMatchersTest : WordSpec() {
listOf(1, 2, 3, 3).shouldContainDuplicates()
listOf(1, 2, 3, 4).shouldNotContainDuplicates()
}

"print duplicates in message" {
shouldThrowAny {
listOf(1, 2, 3, 4, 2, 1) shouldNot containDuplicates()
}.shouldHaveMessage("Collection should not contain duplicates, but has some: [1, 2]")
}
}

"singleElement" should {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
package com.sksamuel.kotest.matchers.collections

import io.kotest.core.spec.style.StringSpec
import io.kotest.matchers.collections.duplicates
import io.kotest.matchers.collections.shouldBeEmpty
import io.kotest.matchers.collections.shouldContainExactlyInAnyOrder

class DuplicatesTest : StringSpec(){
init {
"return empty list" {
listOf(1, 2, 3, 4, null).duplicates().shouldBeEmpty()
}

"return not null duplicates" {
listOf(1, 2, 3, 4, 3, 2).duplicates() shouldContainExactlyInAnyOrder listOf(2, 3)
}

"return null duplicates" {
listOf(1, 2, 3, null, 4, 3, null, 2).duplicates() shouldContainExactlyInAnyOrder listOf(2, 3, null)
}
}
}
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
package io.kotest.property.arbitrary

import io.kotest.mpp.bestName
import io.kotest.property.Arb
import java.lang.reflect.ParameterizedType
import java.lang.reflect.Type
Expand All @@ -12,16 +11,14 @@ import java.time.LocalDateTime
import java.time.LocalTime
import java.time.OffsetDateTime
import java.time.Period
import java.time.Year
import java.time.YearMonth
import java.time.ZonedDateTime
import java.util.Date
import kotlin.reflect.KClass
import kotlin.reflect.KParameter
import kotlin.reflect.KProperty1
import kotlin.reflect.KType
import kotlin.reflect.full.isSubclassOf
import kotlin.reflect.javaType
import kotlin.reflect.jvm.jvmErasure
import kotlin.reflect.typeOf

@Suppress("UNCHECKED_CAST")
Expand All @@ -40,6 +37,7 @@ fun targetDefaultForType(
typeOf<LocalDateTime>(), typeOf<LocalDateTime?>() -> Arb.localDateTime()
typeOf<LocalTime>(), typeOf<LocalTime?>() -> Arb.localTime()
typeOf<Period>(), typeOf<Period?>() -> Arb.period()
typeOf<Year>(), typeOf<Year?>() -> Arb.year()
typeOf<YearMonth>(), typeOf<YearMonth?>() -> Arb.yearMonth()
typeOf<ZonedDateTime>(), typeOf<ZonedDateTime?>() -> Arb.zonedDateTime()
typeOf<OffsetDateTime>(), typeOf<OffsetDateTime?>() -> Arb.offsetDateTime()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ import java.time.LocalDateTime
import java.time.LocalTime
import java.time.OffsetDateTime
import java.time.Period
import java.time.Year
import java.time.YearMonth
import java.time.ZonedDateTime
import kotlin.reflect.KClass
Expand Down Expand Up @@ -100,9 +101,10 @@ class ReflectiveBindTest : StringSpec(
val b: LocalDateTime,
val c: LocalTime,
val d: Period,
val e: YearMonth,
val f: OffsetDateTime,
val g: ZonedDateTime
val e: Year,
val f: YearMonth,
val g: OffsetDateTime,
val h: ZonedDateTime
)

val arb = Arb.bind<DateContainer>()
Expand All @@ -115,9 +117,10 @@ class ReflectiveBindTest : StringSpec(
val b: LocalDateTime?,
val c: LocalTime?,
val d: Period?,
val e: YearMonth?,
val f: OffsetDateTime?,
val g: ZonedDateTime?
val e: Year?,
val f: YearMonth?,
val g: OffsetDateTime?,
val h: ZonedDateTime?
)

val arb = Arb.bind<DateNullableContainer>()
Expand Down