import * as Clock from "../../Clock"
import * as HashMap from "../../Collections/Immutable/HashMap"
import * as List from "../../Collections/Immutable/List"
import * as SortedSet from "../../Collections/Immutable/SortedSet"
import * as Tuple from "../../Collections/Immutable/Tuple"
import * as T from "../../Effect"
import * as Fiber from "../../Fiber"
import * as L from "../../Layer"
import * as Promise from "../../Promise"
import * as Ref from "../../Ref"
import * as RefM from "../../RefM"
import { Annotations } from "../Annotations"
import { Live } from "../Live"
import type { Restorable } from "../Restorable"
export interface DurationBrand {
  readonly DurationBrand: unique symbol
}
export declare type Duration = number & DurationBrand
export declare function Duration(n: number): Duration
/**
 * `TestClock` makes it easy to deterministically and efficiently test
 * effects involving the passage of time.
 *
 * Instead of waiting for actual time to pass, `sleep` and methods
 * implemented in terms of it schedule effects to take place at a given clock
 * time. Users can adjust the clock time using the `adjust` and `setTime`
 * methods, and all effects scheduled to take place on or before that time
 * will automatically be run in order.
 *
 * For example, here is how we can test `ZIO#timeout` using `TestClock:
 *
 * {{{
 *  import zio.ZIO
 *  import zio.duration._
 *  import zio.test.environment.TestClock
 *
 *  for {
 *    fiber  <- ZIO.sleep(5.minutes).timeout(1.minute).fork
 *    _      <- TestClock.adjust(1.minute)
 *    result <- fiber.join
 *  } yield result == None
 * }}}
 *
 * Note how we forked the fiber that `sleep` was invoked on. Calls to `sleep`
 * and methods derived from it will semantically block until the time is set
 * to on or after the time they are scheduled to run. If we didn't fork the
 * fiber on which we called sleep we would never get to set the time on the
 * line below. Thus, a useful pattern when using `TestClock` is to fork the
 * effect being tested, then adjust the clock time, and finally verify that
 * the expected effects have been performed.
 *
 * For example, here is how we can test an effect that recurs with a fixed
 * delay:
 *
 * {{{
 *  import zio.Queue
 *  import zio.duration._
 *  import zio.test.environment.TestClock
 *
 *  for {
 *    q <- Queue.unbounded[Unit]
 *    _ <- q.offer(()).delay(60.minutes).forever.fork
 *    a <- q.poll.map(_.isEmpty)
 *    _ <- TestClock.adjust(60.minutes)
 *    b <- q.take.as(true)
 *    c <- q.poll.map(_.isEmpty)
 *    _ <- TestClock.adjust(60.minutes)
 *    d <- q.take.as(true)
 *    e <- q.poll.map(_.isEmpty)
 *  } yield a && b && c && d && e
 * }}}
 *
 * Here we verify that no effect is performed before the recurrence period,
 * that an effect is performed after the recurrence period, and that the
 * effect is performed exactly once. The key thing to note here is that after
 * each recurrence the next recurrence is scheduled to occur at the
 * appropriate time in the future, so when we adjust the clock by 60 minutes
 * exactly one value is placed in the queue, and when we adjust the clock by
 * another 60 minutes exactly one more value is placed in the queue.
 */
export interface TestClock extends Restorable {
  readonly adjust: (duration: number) => T.UIO<void>
  readonly setTime: (duration: number) => T.UIO<void>
  readonly sleeps: T.UIO<List.List<Duration>>
}
export declare const TestClock: import("../../Has").Tag<TestClock>
declare const Data_base: import("../../Case").CaseConstructorTagged<"Data", "_tag">
/**
 * `Data` represents the state of the `TestClock`, including the clock time
 */
export declare class Data extends Data_base<{
  readonly duration: Duration
  readonly sleeps: List.List<Tuple.Tuple<[Duration, Promise.Promise<never, void>]>>
}> {}
/**
 * `WarningData` describes the state of the warning message that is
 * displayed if a test is using time by is not advancing the `TestClock`.
 * The possible states are `Start` if a test has not used time, `Pending`
 * if a test has used time but has not adjusted the `TestClock`, and `Done`
 * if a test has adjusted the `TestClock` or the warning message has
 * already been displayed.
 */
export declare type WarningData = Start | Done | Pending
declare const Start_base: import("../../Case").CaseConstructorTagged<"Start", "_tag">
export declare class Start extends Start_base<{}> {
  static of: WarningData
}
declare const Done_base: import("../../Case").CaseConstructorTagged<"Done", "_tag">
export declare class Done extends Done_base<{}> {
  static of: WarningData
}
declare const Pending_base: import("../../Case").CaseConstructorTagged<
  "Pending",
  "_tag"
>
export declare class Pending extends Pending_base<{
  readonly fiber: Fiber.Fiber<never, void>
}> {
  static of: (fiber: Fiber.Fiber<never, void>) => WarningData
}
export declare class Test implements TestClock {
  readonly clockState: Ref.Ref<Data>
  readonly live: Live
  readonly annotations: Annotations
  readonly warningState: RefM.RefM<WarningData>
  constructor(
    clockState: Ref.Ref<Data>,
    live: Live,
    annotations: Annotations,
    warningState: RefM.RefM<WarningData>
  )
  /**
   * Increments the current clock time by the specified duration. Any
   * effects that were scheduled to occur on or before the new time will be
   * run in order.
   */
  readonly adjust: (duration: number) => T.UIO<void>
  /**
   * Returns the current clock time.
   */
  readonly currentTime: T.UIO<Duration>
  /**
   * Saves the `TestClock`'s current state in an effect which, when run,
   * will restore the `TestClock` state to the saved state
   */
  readonly save: T.UIO<T.UIO<void>>
  /**
   * Sets the current clock time to the specified time in terms of duration
   * since the epoch. Any effects that were scheduled to occur on or before
   * the new time will immediately be run in order.
   */
  readonly setTime: (duration: number) => T.UIO<void>
  /**
   * Semantically blocks the current fiber until the clock time is equal
   * to or greater than the specified duration. Once the clock time is
   * adjusted to on or after the duration, the fiber will automatically be
   * resumed.
   */
  readonly sleep: (duration: Duration) => T.UIO<void>
  /**
   * Returns a list of the times at which all queued effects are scheduled
   * to resume.
   */
  readonly sleeps: T.UIO<List.List<Duration>>
  /**
   * The warning message that will be displayed if a test is using time but
   * is not advancing the `TestClock`.
   */
  private warning
  /**
   * Forks a fiber that will display a warning message if a test is using
   * time but is not advancing the `TestClock`.
   */
  private warningStart
  /**
   * Cancels the warning message that is displayed if a test is using time
   * but is not advancing the `TestClock`.
   */
  readonly warningDone: T.UIO<void>
  /**
   * Returns a set of all fibers in this test.
   */
  readonly supervisedFibers: T.UIO<SortedSet.SortedSet<Fiber.Runtime<unknown, unknown>>>
  /**
   * Captures a "snapshot" of the identifier and status of all fibers in
   * this test other than the current fiber. Fails with the `Unit` value if
   * any of these fibers are not done or suspended. Note that because we
   * cannot synchronize on the status of multiple fibers at the same time
   * this snapshot may not be fully consistent.
   */
  readonly freeze: T.IO<void, HashMap.HashMap<Fiber.FiberID, Fiber.Status>>
  /**
   * Delays for a short period of time.
   */
  readonly delay: T.Effect<unknown, never, void>
  /**
   * Returns whether all descendants of this fiber are done or suspended.
   */
  readonly suspended: T.IO<void, HashMap.HashMap<Fiber.FiberID, Fiber.Status>>
  /**
   * Polls until all descendants of this fiber are done or suspended.
   */
  readonly awaitSuspended: T.UIO<void>
  /**
   * Runs all effects scheduled to occur on or before the specified
   * duration, which may depend on the current time, in order.
   */
  private run
}
export declare function live(
  data: Data
): L.Layer<
  import("../../Has").Has<Live> & import("../../Has").Has<Annotations>,
  never,
  import("../../Has").Has<Clock.Clock> & import("../../Has").Has<TestClock>
>
export declare const defaultTestClock: L.Layer<
  import("../../Has").Has<Live> & import("../../Has").Has<Annotations>,
  never,
  import("../../Has").Has<Clock.Clock> & import("../../Has").Has<TestClock>
>
export {}
//# sourceMappingURL=index.d.ts.map
