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

commonMain.io.kotest.properties.shrinking.shrink.kt Maven / Gradle / Ivy

package io.kotest.properties.shrinking

import io.kotest.assertions.show.show
import io.kotest.properties.Gen
import io.kotest.properties.PropertyContext
import io.kotest.properties.PropertyFailureInput
import io.kotest.properties.PropertyTesting
import io.kotest.properties.propertyAssertionError

fun  shrink(t: T, gen: Gen, test: (T) -> Unit): T = shrink2(t, gen.shrinker(), test)

fun  shrink2(t: T, shrinker: Shrinker?, test: (T) -> Unit): T {
  return when (shrinker) {
    null -> t
    else -> shrink(t, shrinker, test)
  }
}

fun  shrink(t: T, shrinker: Shrinker, test: (T) -> Unit): T {
  val sb = StringBuilder()
  sb.append("Attempting to shrink failed arg ${t.show().value}\n")
  var candidate = t
  val tested = HashSet()
  var count = 0
  while (true) {
    val candidates = shrinker.shrink(candidate).filterNot { tested.contains(it) }
    if (candidates.isEmpty()) {
      sb.append("Shrink result => ${candidate.show().value}\n")
      if (PropertyTesting.shouldPrintShrinkSteps) {
        println(sb)
      }
      return candidate
    } else {
      val next = candidates.firstOrNull {
        tested.add(it)
        count++
        try {
          test(it)
          sb.append("Shrink #$count: ${it.show().value} pass\n")
          false
        } catch (t: Throwable) {
          sb.append("Shrink #$count: ${it.show().value} fail\n")
          true
        }
      }
      if (next == null) {
        sb.append("Shrink result => ${candidate.show().value}\n")
        if (PropertyTesting.shouldPrintShrinkSteps) {
          println(sb)
        }
        return candidate
      } else {
        candidate = next
      }
    }
  }

}

fun  shrinkInputs(a: A,
                              b: B,
                              c: C,
                              d: D,
                              gena: Gen,
                              genb: Gen,
                              genc: Gen,
                              gend: Gen,
                              context: PropertyContext,
                              fn: PropertyContext.(a: A, b: B, c: C, d: D) -> Unit,
                              e: AssertionError) {
  val smallestA = shrink(a, gena) { context.fn(it, b, c, d) }
  val smallestB = shrink(b, genb) { context.fn(smallestA, it, c, d) }
  val smallestC = shrink(c, genc) { context.fn(smallestA, smallestB, it, d) }
  val smallestD = shrink(d, gend) { context.fn(smallestA, smallestB, smallestC, it) }
  val inputs = listOf(
      PropertyFailureInput(a, smallestA),
      PropertyFailureInput(b, smallestB),
      PropertyFailureInput(c, smallestC),
      PropertyFailureInput(d, smallestD)
  )
  throw propertyAssertionError(e, context.attempts(), inputs)
}