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

commonMain.io.kotest.assertions.until.until.kt Maven / Gradle / Ivy

package io.kotest.assertions.until

import io.kotest.assertions.failure
import kotlinx.coroutines.delay
import kotlin.time.Duration
import kotlin.time.ExperimentalTime
import kotlin.time.TimeSource
import kotlin.time.seconds

interface UntilListener {
   fun onEval(t: T)

   companion object {
      val noop = object : UntilListener {
         override fun onEval(t: Any?) {}
      }
   }
}

fun  untilListener(f: (T) -> Unit) = object : UntilListener {
   override fun onEval(t: T) {
      f(t)
   }
}

/**
 * Executes a function until it returns true or the duration elapses.
 *
 * @param f the function to execute
 * @param duration the maximum amount of time to continue trying for success
 * @param interval the delay between invocations
 */
@OptIn(ExperimentalTime::class)
suspend fun until(
   duration: Duration,
   interval: Interval = 1.seconds.fixed(),
   f: () -> Boolean
) = until(duration, interval, { it }, UntilListener.noop, f)

@OptIn(ExperimentalTime::class)
suspend fun  until(
   duration: Duration,
   predicate: (T) -> Boolean,
   f: () -> T
): T = until(duration, 1.seconds.fixed(), predicate, UntilListener.noop, f)

@OptIn(ExperimentalTime::class)
suspend fun  until(
   duration: Duration,
   interval: Interval,
   predicate: (T) -> Boolean,
   f: () -> T
): T = until(duration, interval, predicate = predicate, listener = UntilListener.noop, f = f)

/**
 * Executes a function until the given predicate returns true or the duration elapses.
 *
 * @param f the function to execute
 * @param predicate passed the result of the function f to evaluate if successful
 * @param listener notified on each invocation of f
 * @param duration the maximum amount of time to continue trying for success
 * @param interval the delay between invocations
 */
@OptIn(ExperimentalTime::class)
suspend fun  until(
   duration: Duration,
   interval: Interval,
   predicate: (T) -> Boolean,
   listener: UntilListener,
   f: () -> T
): T {
   val end = TimeSource.Monotonic.markNow().plus(duration)
   var count = 0
   while (end.hasNotPassedNow()) {
      val result = f()
      if (predicate(result)) {
         return result
      } else {
         listener.onEval(result)
         count++
      }
      delay(interval.next(count).toLongMilliseconds())
   }
   throw failure("Test failed after ${duration.toLongMilliseconds()}ms; attempted $count times")
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy