All Downloads are FREE. Search and download functionalities are using the official Maven repository.

commonMain.io.kotest.matchers.collections.CollectionMatchers.kt Maven / Gradle / Ivy

package io.kotest.matchers.collections

import io.kotest.assertions.show.show
import io.kotest.matchers.Matcher
import io.kotest.matchers.MatcherResult
import io.kotest.matchers.neverNullMatcher

fun  haveSizeMatcher(size: Int) = object : Matcher> {
  override fun test(value: Collection) =
    MatcherResult(
      value.size == size,
      { "Collection should have size $size but has size ${value.size}. Values: ${value.show().value}" },
      { "Collection should not have size $size. Values: ${value.show().value}" }
    )
}


fun  beEmpty(): Matcher> = object : Matcher> {
  override fun test(value: Collection): MatcherResult = MatcherResult(
    value.isEmpty(),
    { "Collection should be empty but contained ${value.show().value}" },
    { "Collection should not be empty" }
  )
}

fun  existInOrder(vararg ps: (T) -> Boolean): Matcher?> = existInOrder(ps.asList())

/**
 * Assert that a collections contains a subsequence that matches the given subsequence of predicates, possibly with
 * values in between.
 */
fun  existInOrder(predicates: List<(T) -> Boolean>): Matcher?> = neverNullMatcher { actual ->
   require(predicates.isNotEmpty()) { "predicates must not be empty" }

   var subsequenceIndex = 0
   val actualIterator = actual.iterator()

   while (actualIterator.hasNext() && subsequenceIndex < predicates.size) {
      if (predicates[subsequenceIndex](actualIterator.next())) subsequenceIndex += 1
   }

   MatcherResult(
      subsequenceIndex == predicates.size,
      { "${actual.show().value} did not match the predicates ${predicates.show().value} in order" },
      { "${actual.show().value} should not match the predicates ${predicates.show().value} in order" }
   )
}

fun  haveSize(size: Int): Matcher> = haveSizeMatcher(size)

fun  singleElement(t: T): Matcher> = object : Matcher> {
  override fun test(value: Collection) = MatcherResult(
    value.size == 1 && value.first() == t,
    { "Collection should be a single element of $t but has ${value.size} elements: ${value.show().value}" },
    { "Collection should not be a single element of $t" }
  )
}

fun  singleElement(p: (T) -> Boolean): Matcher> = object : Matcher> {
   override fun test(value: Collection): MatcherResult {
      val filteredValue: List = value.filter(p)
      return MatcherResult(
         filteredValue.size == 1,
         { "Collection should have a single element by a given predicate but has ${filteredValue.size} elements: ${value.show().value}" },
         { "Collection should not have a single element by a given predicate" }
      )
   }
}

fun > beSorted(): Matcher> = sorted()
fun > sorted(): Matcher> = object : Matcher> {
  override fun test(value: List): MatcherResult {
    val failure = value.withIndex().firstOrNull { (i, it) -> i != value.lastIndex && it > value[i + 1] }
    val elementMessage = when (failure) {
      null -> ""
      else -> ". Element ${failure.value} at index ${failure.index} was greater than element ${value[failure.index + 1]}"
    }
    return MatcherResult(
      failure == null,
      { "List ${value.show().value} should be sorted$elementMessage" },
      { "List ${value.show().value} should not be sorted" }
    )
  }
}

fun > beMonotonicallyIncreasing(): Matcher> = monotonicallyIncreasing()
fun > monotonicallyIncreasing(): Matcher> = object : Matcher> {
  override fun test(value: List): MatcherResult {
    return testMonotonicallyIncreasingWith(value,
      Comparator { a, b -> a.compareTo(b) })
  }
}

fun  beMonotonicallyIncreasingWith(comparator: Comparator): Matcher> =
  monotonicallyIncreasingWith(comparator)
fun  monotonicallyIncreasingWith(comparator: Comparator): Matcher> = object : Matcher> {
  override fun test(value: List): MatcherResult {
    return testMonotonicallyIncreasingWith(value, comparator)
  }
}
private fun testMonotonicallyIncreasingWith(value: List, comparator: Comparator): MatcherResult {
  val failure = value.zipWithNext().withIndex().find { (_, pair) -> comparator.compare(pair.first, pair.second) > 0 }
  val snippet = value.show().value
  val elementMessage = when (failure) {
    null -> ""
    else -> ". Element ${failure.value.second} at index ${failure.index + 1} was not monotonically increased from previous element."
  }
  return MatcherResult(
    failure == null,
    { "List [$snippet] should be monotonically increasing$elementMessage" },
    { "List [$snippet] should not be monotonically increasing" }
  )
}

fun > beMonotonicallyDecreasing(): Matcher> = monotonicallyDecreasing()
fun > monotonicallyDecreasing(): Matcher> = object : Matcher> {
  override fun test(value: List): MatcherResult {
    return testMonotonicallyDecreasingWith(value,
      Comparator { a, b -> a.compareTo(b) })
  }
}

fun  beMonotonicallyDecreasingWith(comparator: Comparator): Matcher> = monotonicallyDecreasingWith(
  comparator)
fun  monotonicallyDecreasingWith(comparator: Comparator): Matcher> = object : Matcher> {
  override fun test(value: List): MatcherResult {
    return testMonotonicallyDecreasingWith(value, comparator)
  }
}
private fun  testMonotonicallyDecreasingWith(value: List, comparator: Comparator): MatcherResult {
  val failure = value.zipWithNext().withIndex().find { (_, pair) -> comparator.compare(pair.first, pair.second) < 0 }
  val snippet = value.show().value
  val elementMessage = when (failure) {
    null -> ""
    else -> ". Element ${failure.value.second} at index ${failure.index + 1} was not monotonically decreased from previous element."
  }
  return MatcherResult(
    failure == null,
    { "List [$snippet] should be monotonically decreasing$elementMessage" },
    { "List [$snippet] should not be monotonically decreasing" }
  )
}

fun > beStrictlyIncreasing(): Matcher> = strictlyIncreasing()
fun > strictlyIncreasing(): Matcher> = object : Matcher> {
  override fun test(value: List): MatcherResult {
    return testStrictlyIncreasingWith(value, Comparator { a, b -> a.compareTo(b) })
  }
}

fun  beStrictlyIncreasingWith(comparator: Comparator): Matcher> = strictlyIncreasingWith(
  comparator)
fun  strictlyIncreasingWith(comparator: Comparator): Matcher> = object : Matcher> {
  override fun test(value: List): MatcherResult {
    return testStrictlyIncreasingWith(value, comparator)
  }
}
private fun  testStrictlyIncreasingWith(value: List, comparator: Comparator): MatcherResult {
  val failure = value.zipWithNext().withIndex().find { (_, pair) -> comparator.compare(pair.first, pair.second) >= 0 }
  val snippet = value.show().value
  val elementMessage = when (failure) {
    null -> ""
    else -> ". Element ${failure.value.second} at index ${failure.index + 1} was not strictly increased from previous element."
  }
  return MatcherResult(
    failure == null,
    { "List [$snippet] should be strictly increasing$elementMessage" },
    { "List [$snippet] should not be strictly increasing" }
  )
}

fun > beStrictlyDecreasing(): Matcher> = strictlyDecreasing()
fun > strictlyDecreasing(): Matcher> = object : Matcher> {
  override fun test(value: List): MatcherResult {
    return testStrictlyDecreasingWith(value, Comparator { a, b -> a.compareTo(b) })
  }
}

fun  beStrictlyDecreasingWith(comparator: Comparator): Matcher> = strictlyDecreasingWith(
  comparator)
fun  strictlyDecreasingWith(comparator: Comparator): Matcher> = object : Matcher> {
  override fun test(value: List): MatcherResult {
    return testStrictlyDecreasingWith(value, comparator)
  }
}
private fun  testStrictlyDecreasingWith(value: List, comparator: Comparator): MatcherResult {
  val failure = value.zipWithNext().withIndex().find { (_, pair) -> comparator.compare(pair.first, pair.second) <= 0 }
  val snippet = value.show().value
  val elementMessage = when (failure) {
    null -> ""
    else -> ". Element ${failure.value.second} at index ${failure.index + 1} was not strictly decreased from previous element."
  }
  return MatcherResult(
    failure == null,
    { "List [$snippet] should be strictly decreasing$elementMessage" },
    { "List [$snippet] should not be strictly decreasing" }
  )
}





© 2015 - 2025 Weber Informatics LLC | Privacy Policy