
commonMain.io.kotest.matchers.sequences.matchers.kt Maven / Gradle / Ivy
package io.kotest.matchers.sequences
import io.kotest.matchers.*
private fun Sequence.toString(limit: Int = 10) = this.joinToString(", ", limit = limit)
/*
How should infinite sequences be detected, and how should they be dealt with?
Sequence.count() may run through the whole sequence (sequences from `generateSequence()` do so), so isn't always a safe way to detect infinite sequences.
For now, the documentation should mention that infinite sequences will cause these matchers never to halt.
*/
fun Sequence.shouldContainOnlyNulls() = this should containOnlyNulls()
fun Sequence.shouldNotContainOnlyNulls() = this shouldNot containOnlyNulls()
fun containOnlyNulls() = object : Matcher> {
override fun test(value: Sequence) =
MatcherResult(
value.all { it == null },
"Sequence should contain only nulls",
"Sequence should not contain only nulls"
)
}
fun Sequence.shouldContainNull() = this should containNull()
fun Sequence.shouldNotContainNull() = this shouldNot containNull()
fun containNull() = object : Matcher> {
override fun test(value: Sequence) =
MatcherResult(
value.any { it == null },
"Sequence should contain at least one null",
"Sequence should not contain any nulls"
)
}
fun Sequence.shouldHaveElementAt(index: Int, element: T) = this should haveElementAt(index, element)
fun Sequence.shouldNotHaveElementAt(index: Int, element: T) = this shouldNot haveElementAt(index, element)
fun > haveElementAt(index: Int, element: T) = object : Matcher {
override fun test(value: S) =
MatcherResult(
value.elementAt(index) == element,
{ "Sequence should contain $element at index $index" },
{ "Sequence should not contain $element at index $index" }
)
}
fun Sequence.shouldContainNoNulls() = this should containNoNulls()
fun Sequence.shouldNotContainNoNulls() = this shouldNot containNoNulls()
fun containNoNulls() = object : Matcher> {
override fun test(value: Sequence) =
MatcherResult(
value.all { it != null },
{ "Sequence should not contain nulls" },
{ "Sequence should have at least one null" }
)
}
infix fun > C.shouldContain(t: T) = this should contain(t)
infix fun > C.shouldNotContain(t: T) = this shouldNot contain(t)
fun > contain(t: T) = object : Matcher {
override fun test(value: C) = MatcherResult(
value.contains(t),
{ "Sequence should contain element $t" },
{ "Sequence should not contain element $t" }
)
}
infix fun > C?.shouldNotContainExactly(expected: C) = this shouldNot containExactly(expected)
fun > C?.shouldNotContainExactly(vararg expected: T) = this shouldNot containExactly(*expected)
infix fun > C?.shouldContainExactly(expected: C) = this should containExactly(expected)
fun > C?.shouldContainExactly(vararg expected: T) = this should containExactly(*expected)
fun containExactly(vararg expected: T): Matcher?> = containExactly(expected.asSequence())
/** Assert that a sequence contains exactly the given values and nothing else, in order. */
fun > containExactly(expected: C): Matcher = neverNullMatcher { value ->
var passed: Boolean = value.count() == expected.count()
var failMessage = "Sequence should contain exactly $expected but was $value"
if (passed) {
val diff = value.zip(expected) { a, b -> Triple(a, b, a == b) }.withIndex().find { !it.value.third }
if (diff != null) {
passed = false
failMessage += " (expected ${diff.value.second} at ${diff.index} but found ${diff.value.first})"
}
} else {
failMessage += " (expected ${expected.count()} elements but found ${value.count()})"
}
MatcherResult(
passed,
failMessage,
"Sequence should not be exactly $expected"
)
}
@Deprecated("use shouldNotContainAllInAnyOrder", ReplaceWith("shouldNotContainAllInAnyOrder"))
infix fun > C?.shouldNotContainExactlyInAnyOrder(expected: C) =
this shouldNot containAllInAnyOrder(expected)
@Deprecated("use shouldNotContainAllInAnyOrder", ReplaceWith("shouldNotContainAllInAnyOrder"))
fun > C?.shouldNotContainExactlyInAnyOrder(vararg expected: T) =
this shouldNot containAllInAnyOrder(*expected)
@Deprecated("use shouldContainAllInAnyOrder", ReplaceWith("shouldContainAllInAnyOrder"))
infix fun > C?.shouldContainExactlyInAnyOrder(expected: C) =
this should containAllInAnyOrder(expected)
@Deprecated("use shouldContainAllInAnyOrder", ReplaceWith("shouldContainAllInAnyOrder"))
fun > C?.shouldContainExactlyInAnyOrder(vararg expected: T) =
this should containAllInAnyOrder(*expected)
@Deprecated("use containAllInAnyOrder", ReplaceWith("containAllInAnyOrder"))
fun containExactlyInAnyOrder(vararg expected: T): Matcher?> =
containAllInAnyOrder(expected.asSequence())
@Deprecated("use containAllInAnyOrder", ReplaceWith("containAllInAnyOrder"))
/** Assert that a sequence contains the given values and nothing else, in any order. */
fun > containExactlyInAnyOrder(expected: C): Matcher = containAllInAnyOrder(expected)
infix fun > C?.shouldNotContainAllInAnyOrder(expected: C) =
this shouldNot containAllInAnyOrder(expected)
fun > C?.shouldNotContainAllInAnyOrder(vararg expected: T) =
this shouldNot containAllInAnyOrder(*expected)
infix fun > C?.shouldContainAllInAnyOrder(expected: C) =
this should containAllInAnyOrder(expected)
fun > C?.shouldContainAllInAnyOrder(vararg expected: T) =
this should containAllInAnyOrder(*expected)
fun containAllInAnyOrder(vararg expected: T): Matcher?> =
containAllInAnyOrder(expected.asSequence())
/** Assert that a sequence contains all the given values and nothing else, in any order. */
fun > containAllInAnyOrder(expected: C): Matcher = neverNullMatcher { value ->
val passed = value.count() == expected.count() && expected.all { value.contains(it) }
MatcherResult(
passed,
{ "Sequence should contain the values of $expected in any order, but was $value" },
{ "Sequence should not contain the values of $expected in any order" }
)
}
infix fun , C : Sequence> C.shouldHaveUpperBound(t: T) = this should haveUpperBound(t)
fun , C : Sequence> haveUpperBound(t: T) = object : Matcher {
override fun test(value: C) = MatcherResult(
(value.max() ?: t) <= t,
{ "Sequence should have upper bound $t" },
{ "Sequence should not have upper bound $t" }
)
}
infix fun , C : Sequence> C.shouldHaveLowerBound(t: T) = this should haveLowerBound(t)
fun , C : Sequence> haveLowerBound(t: T) = object : Matcher {
override fun test(value: C) = MatcherResult(
(value.min() ?: t) >= t,
{ "Sequence should have lower bound $t" },
{ "Sequence should not have lower bound $t" }
)
}
fun Sequence.shouldBeUnique() = this should beUnique()
fun Sequence.shouldNotBeUnique() = this shouldNot beUnique()
fun beUnique() = object : Matcher> {
override fun test(value: Sequence) = MatcherResult(
value.toSet().size == value.count(),
{ "Sequence should be Unique" },
{ "Sequence should contain at least one duplicate element" }
)
}
fun Sequence.shouldContainDuplicates() = this should containDuplicates()
fun Sequence.shouldNotContainDuplicates() = this shouldNot containDuplicates()
fun containDuplicates() = object : Matcher> {
override fun test(value: Sequence) = MatcherResult(
value.toSet().size < value.count(),
{ "Sequence should contain duplicates" },
{ "Sequence should not contain duplicates" }
)
}
fun > Sequence.shouldBeSorted() = this should beSorted()
fun > Sequence.shouldNotBeSorted() = this shouldNot beSorted()
fun > beSorted(): Matcher> = sorted()
fun > sorted(): Matcher> = object : Matcher> {
override fun test(value: Sequence): MatcherResult {
@Suppress("UNUSED_DESTRUCTURED_PARAMETER_ENTRY")
val failure = value.zipWithNext().withIndex().firstOrNull { (i, it) -> it.first > it.second }
val snippet = value.joinToString(",", limit = 10)
val elementMessage = when (failure) {
null -> ""
else -> ". Element ${failure.value.first} at index ${failure.index} was greater than element ${failure.value.second}"
}
return MatcherResult(
failure == null,
{ "Sequence $snippet should be sorted$elementMessage" },
{ "Sequence $snippet should not be sorted" }
)
}
}
infix fun Sequence.shouldBeSortedWith(comparator: Comparator) = this should beSortedWith(comparator)
infix fun Sequence.shouldBeSortedWith(cmp: (T, T) -> Int) = this should beSortedWith(cmp)
fun beSortedWith(comparator: Comparator): Matcher> = sortedWith(comparator)
fun beSortedWith(cmp: (T, T) -> Int): Matcher> = sortedWith(cmp)
fun sortedWith(comparator: Comparator): Matcher> = sortedWith { a, b ->
comparator.compare(a, b)
}
fun sortedWith(cmp: (T, T) -> Int): Matcher> = object : Matcher> {
override fun test(value: Sequence): MatcherResult {
@Suppress("UNUSED_DESTRUCTURED_PARAMETER_ENTRY")
val failure = value.zipWithNext().withIndex().firstOrNull { (i, it) -> cmp(it.first, it.second) > 0 }
val snippet = value.joinToString(",", limit = 10)
val elementMessage = when (failure) {
null -> ""
else -> ". Element ${failure.value.first} at index ${failure.index} shouldn't precede element ${failure.value.second}"
}
return MatcherResult(
failure == null,
{ "Sequence $snippet should be sorted$elementMessage" },
{ "Sequence $snippet should not be sorted" }
)
}
}
infix fun Sequence.shouldNotBeSortedWith(comparator: Comparator) = this shouldNot beSortedWith(comparator)
infix fun Sequence.shouldNotBeSortedWith(cmp: (T, T) -> Int) = this shouldNot beSortedWith(cmp)
infix fun Sequence.shouldHaveSingleElement(t: T) = this should singleElement(t)
infix fun Sequence.shouldNotHaveSingleElement(t: T) = this shouldNot singleElement(t)
fun singleElement(t: T) = object : Matcher> {
override fun test(value: Sequence) = MatcherResult(
value.count() == 1 && value.first() == t,
{ "Sequence should be a single element of $t but has ${value.count()} elements" },
{ "Sequence should not be a single element of $t" }
)
}
infix fun Sequence.shouldHaveCount(count: Int) = this should haveCount(count)
infix fun Sequence.shouldNotHaveCount(count: Int) = this shouldNot haveCount(
count)
infix fun Sequence.shouldHaveSize(size: Int) = this should haveCount(size)
infix fun Sequence.shouldNotHaveSize(size: Int) = this shouldNot haveCount(size)
//fun haveSize(size: Int) = haveCount(size)
fun haveSize(size: Int): Matcher> = haveCount(size)
fun haveCount(count: Int): Matcher> = object : Matcher> {
override fun test(value: Sequence) =
MatcherResult(
value.count() == count,
{ "Sequence should have count $count but has count ${value.count()}" },
{ "Sequence should not have count $count" }
)
}
infix fun Sequence.shouldBeLargerThan(other: Sequence) = this should beLargerThan(other)
fun beLargerThan(other: Sequence) = object : Matcher> {
override fun test(value: Sequence) = MatcherResult(
value.count() > other.count(),
{ "Sequence of count ${value.count()} should be larger than sequence of count ${other.count()}" },
{ "Sequence of count ${value.count()} should not be larger than sequence of count ${other.count()}" }
)
}
infix fun Sequence.shouldBeSmallerThan(other: Sequence) = this should beSmallerThan(other)
fun beSmallerThan(other: Sequence) = object : Matcher> {
override fun test(value: Sequence) = MatcherResult(
value.count() < other.count(),
{ "Sequence of count ${value.count()} should be smaller than sequence of count ${other.count()}" },
{ "Sequence of count ${value.count()} should not be smaller than sequence of count ${other.count()}" }
)
}
infix fun Sequence.shouldBeSameCountAs(other: Sequence) = this should beSameCountAs(
other)
fun beSameCountAs(other: Sequence) = object : Matcher> {
override fun test(value: Sequence) = MatcherResult(
value.count() == other.count(),
{ "Sequence of count ${value.count()} should be the same count as sequence of count ${other.count()}" },
{ "Sequence of count ${value.count()} should not be the same count as sequence of count ${other.count()}" }
)
}
infix fun Sequence.shouldBeSameSizeAs(other: Sequence) = this.shouldBeSameCountAs(other)
infix fun Sequence.shouldHaveAtLeastCount(n: Int) = this shouldHave atLeastCount(n)
fun atLeastCount(n: Int) = object : Matcher> {
override fun test(value: Sequence) = MatcherResult(
value.count() >= n,
{ "Sequence should contain at least $n elements" },
{ "Sequence should contain less than $n elements" }
)
}
infix fun Sequence.shouldHaveAtLeastSize(n: Int) = this.shouldHaveAtLeastCount(n)
infix fun Sequence.shouldHaveAtMostCount(n: Int) = this shouldHave atMostCount(n)
fun atMostCount(n: Int) = object : Matcher> {
override fun test(value: Sequence) = MatcherResult(
value.count() <= n,
{ "Sequence should contain at most $n elements" },
{ "Sequence should contain more than $n elements" }
)
}
infix fun Sequence.shouldHaveAtMostSize(n: Int) = this shouldHave atMostCount(n)
infix fun Sequence.shouldExist(p: (T) -> Boolean) = this should exist(p)
fun exist(p: (T) -> Boolean) = object : Matcher> {
override fun test(value: Sequence) = MatcherResult(
value.any { p(it) },
{ "Sequence should contain an element that matches the predicate $p" },
{ "Sequence should not contain an element that matches the predicate $p" }
)
}
fun > Sequence.shouldContainInOrder(vararg ts: T) =
this should containsInOrder(ts.asSequence())
infix fun > Sequence.shouldContainInOrder(expected: Sequence) =
this should containsInOrder(expected)
fun > Sequence.shouldNotContainInOrder(expected: Sequence) =
this shouldNot containsInOrder(expected)
/** Assert that a sequence contains a given subsequence, possibly with values in between. */
fun containsInOrder(subsequence: Sequence): Matcher?> = neverNullMatcher { actual ->
val subsequenceCount = subsequence.count()
require(subsequenceCount > 0) { "expected values must not be empty" }
var subsequenceIndex = 0
val actualIterator = actual.iterator()
while (actualIterator.hasNext() && subsequenceIndex < subsequenceCount) {
if (actualIterator.next() == subsequence.elementAt(subsequenceIndex)) subsequenceIndex += 1
}
MatcherResult(
subsequenceIndex == subsequence.count(),
{ "[$actual] did not contain the elements [$subsequence] in order" },
{ "[$actual] should not contain the elements [$subsequence] in order" }
)
}
fun Sequence.shouldBeEmpty() = this should beEmpty()
fun Sequence.shouldNotBeEmpty() = this shouldNot beEmpty()
fun beEmpty(): Matcher> = object : Matcher> {
override fun test(value: Sequence): MatcherResult = MatcherResult(
value.count() == 0,
{ "Sequence should be empty" },
{ "Sequence should not be empty" }
)
}
fun Sequence.shouldContainAll(vararg ts: T) = this should containAll(ts.asSequence())
infix fun Sequence.shouldContainAll(ts: Collection) = this should containAll(ts.asSequence())
infix fun Sequence.shouldContainAll(ts: Sequence) = this should containAll(ts)
fun Sequence.shouldNotContainAll(vararg ts: T) = this shouldNot containAll(ts.asSequence())
infix fun Sequence.shouldNotContainAll(ts: Collection) = this shouldNot containAll(ts.asSequence())
infix fun Sequence.shouldNotContainAll(ts: Sequence) = this shouldNot containAll(ts)
fun > containAll(ts: C): Matcher> = object : Matcher> {
override fun test(value: Sequence): MatcherResult = MatcherResult(
ts.all { value.contains(it) },
{ "Sequence should contain all of ${value.joinToString(",", limit = 10)}" },
{ "Sequence should not contain all of ${value.joinToString(",", limit = 10)}" }
)
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy