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

org.scalacheck.Gen.scala Maven / Gradle / Ivy

There is a newer version: 1.18.1
Show newest version
/*-------------------------------------------------------------------------*\
**  ScalaCheck                                                             **
**  Copyright (c) 2007-2021 Rickard Nilsson. All rights reserved.          **
**  http://www.scalacheck.org                                              **
**                                                                         **
**  This software is released under the terms of the Revised BSD License.  **
**  There is NO WARRANTY. See the file LICENSE for the full text.          **
\*------------------------------------------------------------------------ */

package org.scalacheck

import language.higherKinds
import language.implicitConversions

import rng.Seed
import util.Buildable
import util.SerializableCanBuildFroms._
import ScalaVersionSpecific._

import scala.annotation.tailrec
import scala.collection.immutable.TreeMap
import scala.collection.mutable.ArrayBuffer
import scala.concurrent.duration.{Duration, FiniteDuration}

import java.util.{ Calendar, UUID }
import java.math.{BigInteger, BigDecimal => JavaDecimal}

sealed abstract class Gen[+T] extends Serializable { self =>

  //// Private interface ////

  import Gen.{R, gen}

  // This is no longer used but preserved here for binary compatibility.
  private[scalacheck] def sieveCopy(x: Any): Boolean = true

  // If you implement new Gen[_] directly (instead of using
  // combinators), make sure to use p.initialSeed or p.useInitialSeed
  // in the implementation, instead of using seed directly.
  private[scalacheck] def doApply(p: Gen.Parameters, seed: Seed): R[T]

  //// Public interface ////

  /** A class supporting filtered operations. */
  final class WithFilter(p: T => Boolean) {
    def map[U](f: T => U): Gen[U] = self.suchThat(p).map(f)
    def flatMap[U](f: T => Gen[U]): Gen[U] = self.suchThat(p).flatMap(f)
    def withFilter(q: T => Boolean): WithFilter = self.withFilter(x => p(x) && q(x))
  }

  /** Evaluate this generator with the given parameters */
  def apply(p: Gen.Parameters, seed: Seed): Option[T] =
    doApply(p, seed).retrieve

  def doPureApply(p: Gen.Parameters, seed: Seed, retries: Int = 100): Gen.R[T] = {
    @tailrec def loop(r: Gen.R[T], i: Int): Gen.R[T] =
      if (r.retrieve.isDefined) r
      else if (i > 0) loop(doApply(p, r.seed), i - 1)
      else throw new Gen.RetrievalError()
    loop(doApply(p, seed), retries)
  }

  /**
   * Evaluate this generator with the given parameters.
   *
   * The generator will attempt to generate a valid `T` value. If a
   * valid value is not produced it may retry several times,
   * determined by the `retries` parameter (which defaults to 100).
   *
   * If all the retries fail it will throw a `Gen.RetrievalError`
   * exception.
   */
  def pureApply(p: Gen.Parameters, seed: Seed, retries: Int = 100): T =
    doPureApply(p, seed, retries).retrieve.get

  /** Create a new generator by mapping the result of this generator */
  def map[U](f: T => U): Gen[U] = gen { (p, seed) => doApply(p, seed).map(f) }

  /** Create a new generator by flat-mapping the result of this generator */
  def flatMap[U](f: T => Gen[U]): Gen[U] = gen { (p, seed) =>
    val rt = doApply(p, seed)
    rt.flatMap(t => f(t).doApply(p, rt.seed))
  }

  /** Create a new generator that uses this generator to produce a value
   *  that fulfills the given condition. If the condition is not fulfilled,
   *  the generator fails (returns None). Also, make sure that the provided
   *  test property is side-effect free, e.g. it should not use external vars. */
  def filter(p: T => Boolean): Gen[T] = suchThat(p)

  /** Create a new generator that uses this generator to produce a value
   *  that doesn't fulfill the given condition. If the condition is fulfilled,
   *  the generator fails (returns None). Also, make sure that the provided
   *  test property is side-effect free, e.g. it should not use external vars. */
  def filterNot(p: T => Boolean): Gen[T] = suchThat(x => !p(x))

  /** Creates a non-strict filtered version of this generator. */
  def withFilter(p: T => Boolean): WithFilter = new WithFilter(p)

  /** Create a new generator that uses this generator to produce a value
   *  that fulfills the given condition. If the condition is not fulfilled,
   *  the generator fails (returns None). Also, make sure that the provided
   *  test property is side-effect free, e.g. it should not use external vars.
   *  This method is identical to [Gen.filter]. */
  def suchThat(f: T => Boolean): Gen[T] =
    new Gen[T] {
      def doApply(p: Gen.Parameters, seed: Seed): Gen.R[T] =
        p.useInitialSeed(seed) { (p0, s0) =>
          val r = self.doApply(p0, s0)
          r.copy(r = r.retrieve.filter(f))
        }
    }

  case class RetryUntilException(n: Int) extends RuntimeException(s"retryUntil failed after $n attempts")

  /**
   * Create a generator that calls this generator repeatedly until the
   * given condition is fulfilled. The generated value is then
   * returned. Make sure that the provided test property is
   * side-effect free (it should not use external vars).
   *
   * If the generator fails more than maxTries, a RetryUntilException
   * will be thrown.
   */
  def retryUntil(p: T => Boolean, maxTries: Int): Gen[T] = {
    require(maxTries > 0)
    def loop(params: Gen.Parameters, seed: Seed, tries: Int): R[T] =
      if (tries > maxTries) throw RetryUntilException(tries) else {
        val r = self.doApply(params, seed)
        if (r.retrieve.exists(p)) r else loop(params, r.seed, tries + 1)
      }
    Gen.gen((params, seed) => loop(params, seed, 1))
  }

  /**
   * Create a generator that calls this generator repeatedly until the
   * given condition is fulfilled. The generated value is then
   * returned. Make sure that the provided test property is
   * side-effect free (it should not use external vars).
   *
   *
   * If the generator fails more than 10000 times, a
   * RetryUntilException will be thrown. You can call `retryUntil`
   * with a second parameter to change this number.
   */
  def retryUntil(p: T => Boolean): Gen[T] =
    retryUntil(p, 10000)

  def sample: Option[T] =
    doApply(Gen.Parameters.default, Seed.random()).retrieve

  /** Returns a new property that holds if and only if both this
   *  and the given generator generates the same result, or both
   *  generators generate no result.  */
  def ==[U](g: Gen[U]): Prop = Prop { prms =>
    // test equality using a random seed
    val seed = Seed.random()
    val lhs = doApply(prms, seed).retrieve
    val rhs = g.doApply(prms, seed).retrieve
    if (lhs == rhs) Prop.proved(prms) else Prop.falsified(prms)
  }

  def !=[U](g: Gen[U]): Prop =
    Prop.forAll(this)(r => Prop.forAll(g)(_ != r))

  def !==[U](g: Gen[U]): Prop = Prop { prms =>
    // test inequality using a random seed
    val seed = Seed.random()
    val lhs = doApply(prms, seed).retrieve
    val rhs = g.doApply(prms, seed).retrieve
    if (lhs != rhs) Prop.proved(prms) else Prop.falsified(prms)
  }

  /** Put a label on the generator to make test reports clearer */
  def label(l: String): Gen[T] = new Gen[T] {
    def doApply(p: Gen.Parameters, seed: Seed) =
      p.useInitialSeed(seed) { (p0, s0) =>
        val r = self.doApply(p0, s0)
        r.copy(l = r.labels + l)
      }
  }

  /** Put a label on the generator to make test reports clearer */
  def :|(l: String): Gen[T] = label(l)

  /** Put a label on the generator to make test reports clearer */
  def |:(l: String): Gen[T] = label(l)

  /** Put a label on the generator to make test reports clearer */
  def :|(l: Symbol): Gen[T] = label(l.name)

  /** Put a label on the generator to make test reports clearer */
  def |:(l: Symbol): Gen[T] = label(l.name)

  /** Perform some RNG perturbation before generating */
  def withPerturb(f: Seed => Seed): Gen[T] =
    Gen.gen((p, seed) => doApply(p, f(seed)))
}

object Gen extends GenArities with GenVersionSpecific {

  //// Private interface ////

  import Arbitrary.arbitrary

  /** Just an alias */
  private type P = Parameters

  class RetrievalError extends RuntimeException("couldn't generate value")

  private[scalacheck] trait R[+T] {
    def labels: Set[String] = Set()
    // sieve is no longer used but preserved for binary compatibility
    final def sieve[U >: T]: U => Boolean = (_: U) => true
    protected def result: Option[T]
    def seed: Seed

    def retrieve: Option[T] = result

    def copy[U >: T](
      l: Set[String] = this.labels,
      // s is no longer used but preserved for binary compatibility
      s: U => Boolean = this.sieve,
      r: Option[U] = this.result,
      sd: Seed = this.seed
    ): R[U] = new R[U] {
      override val labels = l
      val seed = sd
      val result = r
    }

    def map[U](f: T => U): R[U] =
      r(retrieve.map(f), seed).copy(l = labels)

    def flatMap[U](f: T => R[U]): R[U] =
      retrieve match {
        case None =>
          r(None, seed).copy(l = labels)
        case Some(t) =>
          val r = f(t)
          r.copy(l = labels | r.labels)
      }
  }

  private[scalacheck] def r[T](r: Option[T], sd: Seed): R[T] = new R[T] {
    val result = r
    val seed = sd
  }

  /** Generator factory method */
  private[scalacheck] def gen[T](f: (P, Seed) => R[T]): Gen[T] = new Gen[T] {
    def doApply(p: P, seed: Seed): R[T] = p.useInitialSeed(seed)(f)
  }

  //// Public interface ////

  /** Generator parameters, used by [[org.scalacheck.Gen.apply]] */
  sealed abstract class Parameters extends Serializable { outer =>

    override def toString: String = {
      val sb = new StringBuilder
      sb.append("Parameters(")
      sb.append(s"size=$size, ")
      sb.append(s"initialSeed=$initialSeed, ")
      sb.append(s"useLegacyShrinking=$useLegacyShrinking)")
      sb.toString
    }

    /**
     * The size of the generated value. Generator implementations are
     * allowed to freely interpret (or ignore) this value. During test
     * execution, the value of this parameter is controlled by
     * [[Test.Parameters.minSize]] and [[Test.Parameters.maxSize]].
     */
    val size: Int

    private[this] def cpy(
      size0: Int = outer.size,
      initialSeed0: Option[Seed] = outer.initialSeed,
      useLegacyShrinking0: Boolean = outer.useLegacyShrinking
    ): Parameters =
      new Parameters {
        val size: Int = size0
        val initialSeed: Option[Seed] = initialSeed0
        override val useLegacyShrinking: Boolean = useLegacyShrinking0
      }

    /**
     * Create a copy of this [[Gen.Parameters]] instance with
     * [[Gen.Parameters.size]] set to the specified value.
     */
    def withSize(size: Int): Parameters =
      cpy(size0 = size)

    /**
     *
     */
    val initialSeed: Option[Seed]

    def withInitialSeed(o: Option[Seed]): Parameters =
      cpy(initialSeed0 = o)

    def withInitialSeed(seed: Seed): Parameters =
      cpy(initialSeed0 = Some(seed))

    def withInitialSeed(n: Long): Parameters =
      cpy(initialSeed0 = Some(Seed(n)))

    def withNoInitialSeed: Parameters =
      cpy(initialSeed0 = None)

    def useInitialSeed[A](seed: Seed)(f: (Parameters, Seed) => A): A =
      initialSeed match {
        case Some(s) => f(this.withNoInitialSeed, s)
        case None => f(this, seed)
      }

    val useLegacyShrinking: Boolean = true

    def disableLegacyShrinking: Parameters =
      withLegacyShrinking(false)

    def enableLegacyShrinking: Parameters =
      withLegacyShrinking(true)

    def withLegacyShrinking(b: Boolean): Parameters =
      cpy(useLegacyShrinking0 = b)

    // no longer used, but preserved for binary compatibility
    @deprecated("cp is deprecated. use cpy.", "1.14.1")
    private case class cp(size: Int = size, initialSeed: Option[Seed] = None) extends Parameters
  }

  /** Provides methods for creating [[org.scalacheck.Gen.Parameters]] values */
  object Parameters {
    /** Default generator parameters instance. */
    val default: Parameters = new Parameters {
      val size: Int = 100
      val initialSeed: Option[Seed] = None
    }
  }

  /** A wrapper type for range types */
  trait Choose[T] extends Serializable {
    /** Creates a generator that returns a value in the given inclusive range */
    def choose(min: T, max: T): Gen[T]
  }

  /** Provides implicit [[org.scalacheck.Gen.Choose]] instances */
  object Choose extends time.JavaTimeChoose {

    class IllegalBoundsError[A](low: A, high: A)
        extends IllegalArgumentException(s"invalid bounds: low=$low, high=$high")

    /**
     * This method gets a ton of use -- so we want it to be as fast as
     * possible for many of our common cases.
     */
    private def chLng(l: Long, h: Long)(p: P, seed: Seed): R[Long] = {
      if (h < l) {
        throw new IllegalBoundsError(l, h)
      } else if (h == l) {
        const(l).doApply(p, seed)
      } else if (l == Long.MinValue && h == Long.MaxValue) {
        val (n, s) = seed.long
        r(Some(n), s)
      } else if (l == Int.MinValue && h == Int.MaxValue) {
        val (n, s) = seed.long
        r(Some(n.toInt.toLong), s)
      } else if (l == Short.MinValue && h == Short.MaxValue) {
        val (n, s) = seed.long
        r(Some(n.toShort.toLong), s)
      } else if (l == 0L && h == Char.MaxValue) {
        val (n, s) = seed.long
        r(Some(n.toChar.toLong), s)
      } else if (l == Byte.MinValue && h == Byte.MaxValue) {
        val (n, s) = seed.long
        r(Some(n.toByte.toLong), s)
      } else {
        val d = h - l + 1
        if (d <= 0) {
          var tpl = seed.long
          var n = tpl._1
          var s = tpl._2
          while (n < l || n > h) {
            tpl = s.long
            n = tpl._1
            s = tpl._2
          }
          r(Some(n), s)
        } else {
          val (n, s) = seed.long
          r(Some(l + (n & 0x7fffffffffffffffL) % d), s)
        }
      }
    }

    private def chDbl(l: Double, h: Double)(p: P, seed: Seed): R[Double] = {
      val d = h - l
      if (d < 0) {
        throw new IllegalBoundsError(l, h)
      } else if (d > Double.MaxValue) {
        val (x, seed2) = seed.long
        if (x < 0) chDbl(l, 0d)(p, seed2) else chDbl(0d, h)(p, seed2)
      } else if (d == 0) {
        r(Some(l), seed)
      } else {
        val (n, s) = seed.double
        r(Some(n * (h-l) + l), s)
      }
    }

    /**
     * Generate a random BigInt within [lower, lower + span).
     *
     * Note that unlike the choose method, whose bounds are inclusive,
     * this method's upper bound is exclusive. We determine how many
     * random bits we need (bitLen), and then round up to the nearest
     * number of bytes (byteLen). We generate the bytes, possibly
     * truncating the most significant byte (bytes(0)) if bitLen is
     * not evenly-divisible by 8.
     *
     * Finally, we check to see if the BigInt we ended up with is in
     * our range. If it is not, we restart this method. The likelihood
     * of needing to restart depends on span. In the worst case we
     * have almost a 50% chance of this (which occurs when span is a
     * power of 2 + 1) and in the best case we never restart (which
     * occurs when span is a power of 2).
     */
    private def chBigInteger(lower: BigInteger, span: BigInteger, seed0: Seed): R[BigInteger] = {
      val bitLen = span.bitLength
      val byteLen = (bitLen + 7) / 8
      val bytes = new Array[Byte](byteLen)
      var seed = seed0
      var i = 0
      while (i < bytes.length) {

        // generate a random long value (i.e. 8 random bytes)
        val (x0, seed1) = seed.long
        var x = x0
        seed = seed1

        // extract each byte in turn and add them to our byte array
        var j = 0
        while (j < 8 && i < bytes.length) {
          val b = (x & 0xff).toByte
          bytes(i) = b
          x = x >>> 8
          i += 1
          j += 1
        }
      }

      // we may not need all 8 bits of our most significant byte. if
      // not, mask off any unneeded upper bits.
      val bitRem = bitLen & 7
      if (bitRem != 0) {
        val mask = 0xff >>> (8 - bitRem)
        bytes(0) = (bytes(0) & mask).toByte
      }

      // construct a BigInteger and see if its valid. if so, we're
      // done. otherwise, we need to restart using our new seed.
      val big = new BigInteger(1, bytes)
      if (big.compareTo(span) < 0) {
        r(Some(big.add(lower)), seed)
      } else {
        chBigInteger(lower, span, seed)
      }
    }

    implicit val chooseLong: Choose[Long] =
      new Choose[Long] {
        def choose(low: Long, high: Long): Gen[Long] =
          if (low > high) throw new IllegalBoundsError(low, high)
          else gen(chLng(low,high))
      }

    implicit val chooseInt: Choose[Int] =
      Choose.xmap[Long, Int](_.toInt, _.toLong)

    implicit val chooseShort: Choose[Short] =
      Choose.xmap[Long, Short](_.toShort, _.toLong)

    implicit val chooseChar: Choose[Char] =
      Choose.xmap[Long, Char](_.toChar, _.toLong)
    implicit val chooseByte: Choose[Byte] =
      Choose.xmap[Long, Byte](_.toByte, _.toLong)

    implicit val chooseDouble: Choose[Double] =
      new Choose[Double] {
        def choose(low: Double, high: Double) =
          if (low > high) throw new IllegalBoundsError(low, high)
          else if (low == Double.NegativeInfinity)
            frequency(1 -> const(Double.NegativeInfinity),
                      9 -> choose(Double.MinValue, high))
          else if (high == Double.PositiveInfinity)
            frequency(1 -> const(Double.PositiveInfinity),
                      9 -> choose(low, Double.MaxValue))
          else gen(chDbl(low,high))
      }

    implicit val chooseFloat: Choose[Float] =
      Choose.xmap[Double, Float](_.toFloat, _.toDouble)

    implicit val chooseFiniteDuration: Choose[FiniteDuration] =
      Choose.xmap[Long, FiniteDuration](Duration.fromNanos, _.toNanos)

    implicit object chooseBigInt extends Choose[BigInt] {
      def choose(low: BigInt, high: BigInt): Gen[BigInt] =
        chooseBigInteger
          .choose(low.bigInteger, high.bigInteger)
          .map(BigInt(_))
    }

    implicit object chooseBigInteger extends Choose[BigInteger] {
      def choose(low: BigInteger, high: BigInteger): Gen[BigInteger] =
        (low compareTo high) match {
          case n if n > 0 => throw new IllegalBoundsError(low, high)
          case 0 => Gen.const(low)
          case _ => /* n < 0 */
            val span = high.subtract(low).add(BigInteger.ONE)
            gen((_, seed) => chBigInteger(low, span, seed))
        }
    }

    /**
     * Choose a BigDecimal number between two given numbers.
     *
     * The minimum scale used will be 34. That means that the
     * fractional part will have at least 34 digits (more if one of
     * the given numbers has a scale larger than 34).
     *
     * The minimum scale was chosen based on Scala's default scale for
     * expanding infinite fractions:
     *
     *   BigDecimal(1) / 3   // 0.3333333333333333333333333333333333
     *
     * See chooseBigDecimalScale for more information about scale.
     */
    implicit val chooseBigDecimal: Choose[BigDecimal] =
      chooseBigDecimalScale(minScale = 34)

    /**
     * The "scale" of a decimal number refers to the number of digits
     * in the fractional part. For example, 3.0000 has a scale of 4.
     *
     * We can generate an arbitrary number of digits in the decimal
     * expansion of a number, so if a user calls choose(0, 1) we need
     * to decide "how much" work to do. The minScale ensures that we
     * do "enough" work to generate interesting numbers.
     *
     * The implicit instance fixes this value, but since users may
     * want to use other scales we expose this method as well.
     */
    private[this] def chooseBigDecimalScale(minScale: Int): Choose[BigDecimal] =
      new Choose[BigDecimal] {
        private val c = chooseJavaBigDecimalScale(minScale)
        def choose(low: BigDecimal, high: BigDecimal): Gen[BigDecimal] =
          c.choose(low.bigDecimal, high.bigDecimal).map(BigDecimal(_))
      }

    /**
     * Choose a java.math.BigDecimal number between two given numbers.
     *
     * See chooseBigDecimal and chooseBigDecimalScale for more comments.
     */
    implicit val chooseJavaBigDecimal: Choose[JavaDecimal] =
      chooseJavaBigDecimalScale(minScale = 34)

    /**
     * See chooseBigDecimalScale for comments.
     */
    private[this] def chooseJavaBigDecimalScale(minScale: Int): Choose[JavaDecimal] =
      new Choose[JavaDecimal] {
        def choose(low: JavaDecimal, high: JavaDecimal): Gen[JavaDecimal] =
        (low compareTo high) match {
          case n if n > 0 => throw new IllegalBoundsError(low, high)
          case 0 => Gen.const(low)
          case _ => /* n < 0 */
            val s = (low.scale max high.scale) max minScale
            val x = if (low.scale < s) low.setScale(s) else low
            val y = if (high.scale < s) high.setScale(s) else high
            chooseBigInteger
              .choose(x.unscaledValue, y.unscaledValue)
              .map(n => new JavaDecimal(n, s))
        }
      }

    /** Transform a Choose[T] to a Choose[U] where T and U are two isomorphic
     *  types whose relationship is described by the provided transformation
     *  functions. (exponential functor map) */
    def xmap[T, U](from: T => U, to: U => T)(implicit c: Choose[T]): Choose[U] =
      new Choose[U] {
        def choose(low: U, high: U): Gen[U] =
          c.choose(to(low), to(high)).map(from)
      }
  }


  //// Various Generator Combinators ////

  /** A generator that always generates the given value */
  implicit def const[T](x: T): Gen[T] = gen((p, seed) => r(Some(x), seed))

  /** A generator that never generates a value */
  def fail[T]: Gen[T] = gen((p, seed) => failed[T](seed))


  /**
   * A fixed point generator. This is useful for making recusive structures
   * e.g.
   *
   * Gen.recursive[List[Int]] { recurse =>
   *   Gen.choose(0, 10).flatMap { idx =>
   *     if (idx < 5) recurse.map(idx :: _)
   *     else Gen.const(idx :: Nil)
   *   }
   * }
   */
  def recursive[A](fn: Gen[A] => Gen[A]): Gen[A] = {
    lazy val result: Gen[A] = lzy(fn(result))
    result
  }

  /** A result that never contains a value */
  private[scalacheck] def failed[T](seed0: Seed): R[T] =
    new R[T] {
      val result: Option[T] = None
      val seed = seed0
    }

  /** A generator that generates a random value in the given (inclusive)
   *  range. If the range is invalid, an IllegalBoundsError exception will be
   *  thrown. */
  def choose[T](min: T, max: T)(implicit c: Choose[T]): Gen[T] =
    c.choose(min, max)

  /** Sequences generators. If any of the given generators fails, the
   *  resulting generator will also fail. */
  def sequence[C,T](gs: Traversable[Gen[T]])(implicit b: Buildable[T, C]): Gen[C] = {
    val g = gen { (p, seed) =>
      gs.foldLeft(r(Some(Vector.empty[T]), seed)) {
        case (rs,g) =>
          val rt = g.doApply(p, rs.seed)
          rt.flatMap(t => rs.map(_ :+ t)).copy(sd = rt.seed)
      }
    }
    g.map(b.fromIterable)
  }

  /** Monadic recursion on Gen
   * This is a stack-safe loop that is the same as:
   *
   * {{{
   *
   * fn(a).flatMap {
   *   case Left(a) => tailRec(a)(fn)
   *   case Right(b) => Gen.const(b)
   *   }
   *
   * }}}
   *
   * which is useful for doing monadic loops without blowing up the
   * stack
   */
  def tailRecM[A, B](a0: A)(fn: A => Gen[Either[A, B]]): Gen[B] = {
    @tailrec
    def tailRecMR(a: A, seed: Seed, labs: Set[String])(fn: (A, Seed) => R[Either[A, B]]): R[B] = {
      val re = fn(a, seed)
      val nextLabs = labs | re.labels
      re.retrieve match {
        case None => r(None, re.seed).copy(l = nextLabs)
        case Some(Right(b)) => r(Some(b), re.seed).copy(l = nextLabs)
        case Some(Left(a)) => tailRecMR(a, re.seed, nextLabs)(fn)
      }
    }

    // This is the "Reader-style" approach to making a stack-safe loop:
    // we put one outer closure around an explicitly tailrec loop
    gen[B] { (p: P, seed: Seed) =>
      tailRecMR(a0, seed, Set.empty) { (a, seed) => fn(a).doApply(p, seed) }
    }
  }

  /** Wraps a generator lazily. The given parameter is only evaluated once,
   *  and not until the wrapper generator is evaluated. */
  def lzy[T](g: => Gen[T]): Gen[T] = {
    lazy val h = g
    gen { (p, seed) => h.doApply(p, seed) }
  }

  /** Wraps a generator for later evaluation. The given parameter is
   *  evaluated each time the wrapper generator is evaluated. */
  def delay[T](g: => Gen[T]): Gen[T] =
    gen { (p, seed) => g.doApply(p, seed) }

  /** Creates a generator that can access its generation parameters */
  def parameterized[T](f: Parameters => Gen[T]): Gen[T] =
    gen { (p, seed) => f(p).doApply(p, seed) }

  /** Creates a generator that can access its generation size */
  def sized[T](f: Int => Gen[T]): Gen[T] =
    gen { (p, seed) => f(p.size).doApply(p, seed) }

  /** A generator that returns the current generation size */
  lazy val size: Gen[Int] = sized { sz => sz }

  /** Creates a resized version of a generator */
  def resize[T](s: Int, g: Gen[T]) = gen((p, seed) => g.doApply(p.withSize(s), seed))

  /** Picks a random value from a list. */
  def oneOf[T](xs: Iterable[T]): Gen[T] =
    if (xs.isEmpty) {
      throw new IllegalArgumentException("oneOf called on empty collection")
    } else {
      val vector = xs.toVector
      choose(0, vector.size - 1).map(vector(_))
    }

  /** Picks a random value from a list.
   *  @todo Remove this overloaded method in the next major release. See #438.
   */
  def oneOf[T](xs: Seq[T]): Gen[T] =
    oneOf(xs: Iterable[T])

  /** Picks a random value from a list */
  def oneOf[T](t0: T, t1: T, tn: T*): Gen[T] = oneOf(t0 +: t1 +: tn)

  /** Picks a random generator from a list */
  def oneOf[T](g0: Gen[T], g1: Gen[T], gn: Gen[T]*): Gen[T] = {
    val gs = g0 +: g1 +: gn
    choose(0, gs.size - 1).flatMap(i => gs(i))
  }

  /** Makes a generator result optional. Either `Some(T)` or `None` will be provided. */
  def option[T](g: Gen[T]): Gen[Option[T]] =
    frequency(1 -> const(None), 9 -> some(g))

  /** A generator that returns `Some(T)` */
  def some[T](g: Gen[T]): Gen[Option[T]] =
    g.map(Some.apply)

  /** Generates a `Left` of `T` or a `Right` of `U` with equal probability. */
  def either[T, U](gt: Gen[T], gu: Gen[U]): Gen[Either[T, U]] =
    oneOf(gt.map(Left(_)), gu.map(Right(_)))

  /** Chooses one of the given generators with a weighted random distribution */
  def frequency[T](gs: (Int, Gen[T])*): Gen[T] = {
    val filtered = gs.iterator.filter(_._1 > 0).toVector
    if (filtered.isEmpty) {
      throw new IllegalArgumentException("no items with positive weights")
    } else {
      var total = 0L
      val builder = TreeMap.newBuilder[Long, Gen[T]]
      filtered.foreach { case (weight, value) =>
        total += weight
        builder += ((total, value))
      }
      val tree = builder.result
      choose(1L, total).flatMap(r => tree.rangeFrom(r).head._2)
    }
  }

  /** Implicit convenience method for using the `frequency` method
   *  like this:
   *  {{{
   *   frequency((1, "foo"), (3, "bar"))
   *  }}}
   */
  implicit def freqTuple[T](t: (Int,T)): (Int,Gen[T]) = (t._1, const(t._2))


  //// List Generators ////

  /** Generates a container of any Traversable type for which there exists an
   *  implicit [[org.scalacheck.util.Buildable]] instance. The elements in the
   *  container will be generated by the given generator. The size of the
   *  generated container is limited by `n`. Depending on what kind of container
   *  that is generated, the resulting container may contain fewer elements than
   *  `n`, but not more. If the given generator fails generating a value, the
   *  complete container generator will also fail. */
  def buildableOfN[C,T](n: Int, g: Gen[T])(implicit
    evb: Buildable[T,C], evt: C => Traversable[T]
  ): Gen[C] = {
    require(n >= 0, s"invalid size given: $n")
    new Gen[C] {
      def doApply(p: P, seed0: Seed): R[C] = {
        var seed: Seed = p.initialSeed.getOrElse(seed0)
        val bldr = evb.builder
        val allowedFailures = Gen.collectionRetries(n)
        var failures = 0
        var count = 0
        while (count < n) {
          val res = g.doApply(p, seed)
          res.retrieve match {
            case Some(t) =>
              bldr += t
              count += 1
            case None =>
              failures += 1
              if (failures >= allowedFailures) return r(None, res.seed)
          }
          seed = res.seed
        }
        r(Some(bldr.result), seed)
      }
    }
  }

  /** Generates a container of any Traversable type for which there exists an
   *  implicit [[org.scalacheck.util.Buildable]] instance. The elements in the
   *  container will be generated by the given generator. The size of the
   *  container is bounded by the size parameter used when generating values. */
  def buildableOf[C,T](g: Gen[T])(implicit
    evb: Buildable[T,C], evt: C => Traversable[T]
  ): Gen[C] =
    sized(s => choose(0, Integer.max(s, 0)))
      .flatMap(n => buildableOfN(n, g)(evb, evt))

  /** Generates a non-empty container of any Traversable type for which there
   *  exists an implicit [[org.scalacheck.util.Buildable]] instance. The
   *  elements in the container will be generated by the given generator. The
   *  size of the container is bounded by the size parameter used when
   *  generating values. */
  def nonEmptyBuildableOf[C,T](g: Gen[T])(implicit
    evb: Buildable[T,C], evt: C => Traversable[T]
  ): Gen[C] =
    sized(s => choose(1, Integer.max(s, 1)))
      .flatMap(n => buildableOfN(n, g)(evb, evt))

  /** A convenience method for calling `buildableOfN[C[T],T](n,g)`. */
  def containerOfN[C[_],T](n: Int, g: Gen[T])(implicit
    evb: Buildable[T,C[T]], evt: C[T] => Traversable[T]
  ): Gen[C[T]] = buildableOfN[C[T], T](n, g)(evb, evt)

  /** A convenience method for calling `buildableOf[C[T],T](g)`. */
  def containerOf[C[_],T](g: Gen[T])(implicit
    evb: Buildable[T,C[T]], evt: C[T] => Traversable[T]
  ): Gen[C[T]] = buildableOf[C[T], T](g)(evb, evt)

  /** A convenience method for calling `nonEmptyBuildableOf[C[T],T](g)`. */
  def nonEmptyContainerOf[C[_],T](g: Gen[T])(implicit
    evb: Buildable[T,C[T]], evt: C[T] => Traversable[T]
  ): Gen[C[T]] = nonEmptyBuildableOf[C[T], T](g)(evb, evt)

  /** Generates a list of random length. The maximum length depends on the
   *  size parameter. This method is equal to calling
   *  `containerOf[List,T](g)`. */
  def listOf[T](g: => Gen[T]) = buildableOf[List[T], T](g)

  /** Generates a non-empty list of random length. The maximum length depends
   *  on the size parameter. This method is equal to calling
   *  `nonEmptyContainerOf[List,T](g)`. */
  def nonEmptyListOf[T](g: => Gen[T]) = nonEmptyBuildableOf[List[T], T](g)

  /** Generates a list with at most the given number of elements. This method
   *  is equal to calling `containerOfN[List,T](n,g)`. */
  def listOfN[T](n: Int, g: Gen[T]) = buildableOfN[List[T], T](n, g)

  /** Generates a map of random length. The maximum length depends on the
   *  size parameter. This method is equal to calling
   *  containerOf[Map,(T,U)](g). */
  def mapOf[T, U](g: => Gen[(T, U)]) = buildableOf[Map[T, U], (T, U)](g)

  /** Generates a non-empty map of random length. The maximum length depends
   *  on the size parameter. This method is equal to calling
   *  nonEmptyContainerOf[Map,(T,U)](g). */
  def nonEmptyMap[T,U](g: => Gen[(T,U)]) = nonEmptyBuildableOf[Map[T, U],(T, U)](g)

  /** Generates a map with at most the given number of elements. This method
   *  is equal to calling containerOfN[Map,(T,U)](n,g). */
  def mapOfN[T,U](n: Int, g: Gen[(T, U)]) = buildableOfN[Map[T, U],(T, U)](n, g)

  /**
   * Generates an infinite stream.
   *
   * Failures in the underlying generator may terminate the stream.
   * Otherwise it will continue forever.
   */
  def infiniteStream[T](g: => Gen[T]): Gen[Stream[T]] = {
    val attemptsPerItem = 10
    def unfold(p: P, seed: Seed, attemptsLeft: Int): Stream[T] =
      if (attemptsLeft <= 0) {
        Stream.empty
      } else {
        val r = g.doPureApply(p, seed)
        r.retrieve match {
          case Some(t) => t #:: unfold(p, r.seed, attemptsPerItem)
          case None => unfold(p, r.seed, attemptsLeft - 1)
        }
      }
    gen { (p, seed0) =>
      val stream = unfold(p, seed0, attemptsPerItem)
      r(Some(stream), seed0.slide)
    }
  }

  /** A generator that picks a random number of elements from a list */
  def someOf[T](l: Iterable[T]) =
    choose(0, l.size).flatMap(pick(_,l))

  /** A generator that picks a random number of elements from a list */
  def someOf[T](g1: Gen[T], g2: Gen[T], gs: Gen[T]*) =
    choose(0, gs.length+2).flatMap(pick(_, g1, g2, gs: _*))

  /** A generator that picks at least one element from a list */
  def atLeastOne[T](l: Iterable[T]) = {
    require(l.size > 0, "There has to be at least one option to choose from")
    choose(1,l.size).flatMap(pick(_,l))
  }

  /** A generator that picks at least one element from a list */
  def atLeastOne[T](g1: Gen[T], g2: Gen[T], gs: Gen[T]*) =
    choose(1, gs.length+2).flatMap(pick(_, g1, g2, gs: _*))

  /** A generator that randomly picks a given number of elements from a list
   *
   * The elements are not guaranteed to be permuted in random order.
   */
  def pick[T](n: Int, l: Iterable[T]): Gen[collection.Seq[T]] = {
    if (n > l.size || n < 0) throw new IllegalArgumentException(s"invalid choice: $n")
    else if (n == 0) Gen.const(Nil)
    else gen { (p, seed0) =>
      val buf = ArrayBuffer.empty[T]
      val it = l.iterator
      var seed = seed0
      var count = 0
      while (it.hasNext) {
        val t = it.next
        count += 1
        if (count <= n) {
          buf += t
        } else {
          val (x, s) = seed.long
          val i = (x & Long.MaxValue % count).toInt
          if (i < n) buf(i) = t
          seed = s
        }
      }
      r(Some(buf), seed)
    }
  }

  /** A generator that randomly picks a given number of elements from a list
   *
   * The elements are not guaranteed to be permuted in random order.
   */
  def pick[T](n: Int, g1: Gen[T], g2: Gen[T], gn: Gen[T]*): Gen[Seq[T]] =
    pick(n, g1 +: g2 +: gn).flatMap(sequence[Seq[T], T](_))

  /** Takes a function and returns a generator that generates arbitrary
   *  results of that function by feeding it with arbitrarily generated input
   *  parameters. */
  def resultOf[T,R0](f: T => R0)(implicit a: Arbitrary[T]): Gen[R0] =
    arbitrary[T] map f

  /** Creates a Function0 generator. */
  def function0[A](g: Gen[A]): Gen[() => A] =
    g.map(a => () => a)


  //// Character Generators ////

  private def charSample(cs: Array[Char]): Gen[Char] =
    new Gen[Char] {
      def doApply(p: P, seed0: Seed): Gen.R[Char] = {
        val seed1 = p.initialSeed.getOrElse(seed0)
        val (x, seed2) = seed1.long
        val i = ((x & Long.MaxValue) % cs.length).toInt
        r(Some(cs(i)), seed2)
      }
    }

  /** Generates a numerical character */
  val numChar: Gen[Char] =
    charSample(('0' to '9').toArray)

  /** Generates an upper-case alpha character */
  val alphaUpperChar: Gen[Char] =
    charSample(('A' to 'Z').toArray)

  /** Generates a lower-case alpha character */
  val alphaLowerChar: Gen[Char] =
    charSample(('a' to 'z').toArray)

  /** Generates an alpha character */
  val alphaChar: Gen[Char] =
    charSample((('A' to 'Z') ++ ('a' to 'z')).toArray)

  /** Generates an alphanumerical character */
  val alphaNumChar: Gen[Char] =
    charSample((('0' to '9') ++ ('A' to 'Z') ++ ('a' to 'z')).toArray)

  /** Generates a ASCII character, with extra weighting for printable characters */
  val asciiChar: Gen[Char] =
    charSample((0.toChar to 127.toChar).toArray)

  /** Generates a ASCII printable character */
  val asciiPrintableChar: Gen[Char] =
    charSample((32.toChar to 126.toChar).toArray)

  /** Generates a character that can represent a valid hexadecimal digit. This
    * includes both upper and lower case values.
    */
  val hexChar: Gen[Char] =
    charSample("0123456789abcdef0123456789ABCDEF".toArray)

  //// String Generators ////

  private def mkString(n: Int, sb: StringBuilder, gc: Gen[Char], p: P, seed0: Seed): R[String] = {
    var seed: Seed = seed0
    val allowedFailures = Gen.collectionRetries(n)
    var failures = 0
    var count = 0
    while (count < n) {
      val res = gc.doApply(p, seed)
      res.retrieve match {
        case Some(c) =>
          sb += c
          count += 1
        case None =>
          failures += 1
          if (failures >= allowedFailures) return r(None, res.seed)
      }
      seed = res.seed
    }
    r(Some(sb.toString), seed)
  }

  def stringOfN(n: Int, gc: Gen[Char]): Gen[String] =
    gen { (p, seed) =>
      mkString(n, new StringBuilder, gc, p, seed)
    }

  def stringOf(gc: Gen[Char]): Gen[String] =
    gen { (p, seed0) =>
      val (n, seed1) = Gen.mkSize(p, seed0)
      mkString(n, new StringBuilder, gc, p, seed1)
    }

  /** Generates a string that starts with a lower-case alpha character,
   *  and only contains alphanumerical characters */
  val identifier: Gen[String] =
    gen { (p, seed0) =>
      val (n, seed1) = Gen.mkSize(p, seed0)
      val sb = new StringBuilder
      val res1 = alphaLowerChar.doApply(p, seed1)
      sb += res1.retrieve.get
      mkString(n - 1, sb, alphaNumChar, p, res1.seed)
    }

  /** Generates a string of digits */
  val numStr: Gen[String] =
    stringOf(numChar)

  /** Generates a string of upper-case alpha characters */
  val alphaUpperStr: Gen[String] =
    stringOf(alphaUpperChar)

  /** Generates a string of lower-case alpha characters */
  val alphaLowerStr: Gen[String] =
    stringOf(alphaLowerChar)

  /** Generates a string of alpha characters */
  val alphaStr: Gen[String] =
    stringOf(alphaChar)

  /** Generates a string of alphanumerical characters */
  val alphaNumStr: Gen[String] =
    stringOf(alphaNumChar)

  /** Generates a string of ASCII characters, with extra weighting for printable characters */
  val asciiStr: Gen[String] =
    stringOf(asciiChar)

  /** Generates a string of ASCII printable characters */
  val asciiPrintableStr: Gen[String] =
    stringOf(asciiPrintableChar)

  /** Generates a string that can represent a valid hexadecimal digit. This
    * includes both upper and lower case values.
    */
  val hexStr: Gen[String] =
    stringOf(hexChar)

  //// Number Generators ////

  /**
   * Generate a uniformly-distributed Long.
   *
   * This method has an equally likely method of generating every
   * possible Long value.
   */
  val long: Gen[Long] =
    gen { (_, s0) =>
      val (n, s1) = s0.long
      r(Some(n), s1)
    }

  /**
   * Generate a Double uniformly-distributed in [0, 1).
   *
   * This method will generate one of 2^53 distinct Double values in
   * the unit interval.
   */
  val double: Gen[Double] =
    gen { (_, s0) =>
      val (x, s1) = s0.double
      r(Some(x), s1)
    }

  /**
   * Generates a Boolean which has the given chance to be true.
   *
   *  - prob(1.0) is always true
   *  - prob(0.5) is true 50% of the time
   *  - prob(0.1) is true 10% of the time
   *  - prob(0.0) is never true
   */
  def prob(chance: Double): Gen[Boolean] =
    if (chance <= 0.0) Gen.const(false)
    else if (chance >= 1.0) Gen.const(true)
    else gen { (_, s0) =>
      val (x, s1) = s0.double
      r(Some(x < chance), s1)
    }

  /**
   * Generates Double values according to the given gaussian
   * distribution, specified by its mean and standard deviation.
   *
   * Gaussian distributions are also called normal distributions.
   *
   * The range of values is theoretically (-∞, ∞) but 99.7% of all
   * values will be contained within (mean ± 3 * stdDev).
   */
  def gaussian(mean: Double, stdDev: Double): Gen[Double] = {
    def loop(s0: Seed): R[Double] = {
      val (x0, s1) = s0.double
      val (y0, s2) = s1.double
      val x = x0 * 2.0 - 1.0
      val y = y0 * 2.0 - 1.0
      val s = x * x + y * y
      if (s >= 1.0 || s == 0.0) {
        loop(s2)
      } else {
        val scale = stdDev * Math.sqrt(-2.0 * Math.log(s) / s)
        val res = x * scale + mean // dropping y * scale + mean
        r(Some(res), s2)
      }
    }
    gen((_, seed) => loop(seed))
  }

  /**
   * Generates Double values according to the given exponential
   * distribution, specified by its rate parameter.
   *
   * The mean and standard deviation are both equal to 1/rate.
   *
   * The range of values is [0, ∞).
   */
  def exponential(rate: Double): Gen[Double] = {
    require(rate > 0.0, s"rate must be positive (got: $rate)")
    val mean = 1.0 / rate
    gen { (_, s0) =>
      val (x, s1) = s0.double
      r(Some(-Math.log(x) * mean), s1)
    }
  }

  /**
   * Generates Int values according to the given geometric
   * distribution, specified by its mean.
   *
   * This distribution represents the expected number of failures
   * before a successful test, where the probability of a successful
   * test is p = 1 / (mean + 1).
   *
   * The ideal range of values is [0, ∞), although the largest value
   * that can be produced here is 2147483647 (Int.MaxValue).
   */
  def geometric(mean: Double): Gen[Int] = {
    require(mean > 0.0, s"mean must be positive (got: $mean)")
    val p = 1.0 / (mean + 1.0)
    val lognp = Math.log1p(-p) // log(1 - p)
    gen { (_, s0) =>
      val (u, s1) = s0.double
      r(Some(Math.floor(Math.log(u) / lognp).toInt), s1)
    }
  }

  /**
   * Generates Int values according to the given Poisson distribution,
   * specified by its rate parameters.
   *
   * The mean equals the rate; the standard deviation is sqrt(rate).
   *
   * In principle any positive value is a valid rate parameter.
   * However, our method of generating values cannot handle large
   * rates, so we require rate <= 745.
   */
  def poisson(rate: Double): Gen[Int] = {
    require(0 < rate && rate <= 745.0, s"rate must be between 0 and 745 (got $rate)")
    val L = Math.exp(-rate)
    def loop(s0: Seed, k: Int, p: Double): R[Int] =
      if (p <= L) {
        r(Some(k - 1), s0)
      } else {
        val (x, s1) = s0.double
        loop(s1, k + 1, p * x)
      }

    gen((_, s) => loop(s, 0, 1.0))
  }

  /**
   * Generates Int values according to the given binomial
   * distribution, specified by the number of trials to conduct, and
   * the probability of a true test.
   *
   * This distribution counts the number of trials which were
   * successful according to a given test probability.
   *
   * The range of values is [0, trials].
   */
  def binomial(test: Gen[Boolean], trials: Int): Gen[Int] = {
    def loop(ps: Gen.Parameters, s: Seed, i: Int, n: Int): R[Int] =
      if (i >= trials) {
        r(Some(n), s)
      } else {
        val r = test.doPureApply(ps, s)
        val success = r.retrieve.get
        loop(ps, r.seed, i + 1, if (success) n + 1 else n)
      }
    gen((ps, s) => loop(ps, s, 0, 0))
  }


  /** Generates positive numbers of uniform distribution, with an
   *  upper bound of the generation size parameter. */
  def posNum[T](implicit num: Numeric[T], c: Choose[T]): Gen[T] = {
    import num._
    num match {
      case _: Fractional[_] => sized(n => c.choose(zero, max(fromInt(n), one)).suchThat(_ != zero))
      case _ => sized(n => c.choose(one, max(fromInt(n), one)))
    }
  }

  /** Generates negative numbers of uniform distribution, with an
   *  lower bound of the negated generation size parameter. */
  def negNum[T](implicit num: Numeric[T], c: Choose[T]): Gen[T] = posNum.map(num.negate _)

  /** Generates numbers within the given inclusive range, with
   *  extra weight on zero, +/- unity, both extremities, and any special
   *  numbers provided. The special numbers must lie within the given range,
   *  otherwise they won't be included. */
  def chooseNum[T](minT: T, maxT: T, specials: T*)(
    implicit num: Numeric[T], c: Choose[T]
  ): Gen[T] = {
    import num._
    val basics = List(minT, maxT, zero, one, -one)
    val basicsAndSpecials = for {
      t <- specials ++ basics if t >= minT && t <= maxT
    } yield (1, const(t))
    val other = (basicsAndSpecials.length, c.choose(minT, maxT))
    val allGens = basicsAndSpecials :+ other
    frequency(allGens: _*)
  }


  //// Misc Generators ////

  /** Generates a version 4 (random) UUID. */
  lazy val uuid: Gen[UUID] = for {  // FIXME: Remove lazy
    l1 <- Gen.choose(Long.MinValue, Long.MaxValue)
    l2 <- Gen.choose(Long.MinValue, Long.MaxValue)
    y <- Gen.oneOf('8', '9', 'a', 'b')
  } yield UUID.fromString(
    new UUID(l1,l2).toString.updated(14, '4').updated(19, y)
  )

  lazy val calendar: Gen[Calendar] = { // FIXME: Remove lazy
    import Calendar._

    def adjust(c: Calendar)(f: Calendar => Unit): Calendar = { f(c); c }

    // We want to be sure we always initialize the calendar's time. By
    // default, Calendar.getInstance uses the system time. We always
    // overwrite it with a determinisitcally-generated time to be sure
    // that calendar generation is also deterministic.
    //
    // We limit the time (in milliseconds) because extreme values will
    // cause Calendar.getTime calls to fail. This range is relatively
    // large but safe:
    //
    //   -62135751600000 is 1 CE
    //    64087186649116 is 4000 CE
    val calendar: Gen[Calendar] =
      Gen.chooseNum(-62135751600000L, 64087186649116L).map { t =>
        adjust(Calendar.getInstance)(_.setTimeInMillis(t))
      }

    def yearGen(c: Calendar): Gen[Int] =
      Gen.chooseNum(c.getGreatestMinimum(YEAR), c.getLeastMaximum(YEAR))

    def moveToNearestLeapDate(c: Calendar, year: Int): Calendar = {
      @tailrec def loop(y: Int): Calendar = {
        c.set(YEAR, y)
        if (c.getActualMaximum(DAY_OF_YEAR) > 365) c else loop(y + 1)
      }
      loop(if (year + 4 > c.getLeastMaximum(YEAR)) year - 5 else year)
    }

    val beginningOfDayGen: Gen[Calendar] =
      calendar.map(c => adjust(c) { c =>
        c.set(HOUR_OF_DAY, 0)
        c.set(MINUTE, 0)
        c.set(SECOND, 0)
        c.set(MILLISECOND, 0)
      })

    val endOfDayGen: Gen[Calendar] =
      calendar.map(c => adjust(c) { c =>
        c.set(HOUR_OF_DAY, 23)
        c.set(MINUTE, 59)
        c.set(SECOND, 59)
        c.set(MILLISECOND, 59)
      })

    val firstDayOfYearGen: Gen[Calendar] =
      for { c <- calendar; y <- yearGen(c) } yield adjust(c)(_.set(y, JANUARY, 1))

    val lastDayOfYearGen: Gen[Calendar] =
      for { c <- calendar; y <- yearGen(c) } yield adjust(c)(_.set(y, DECEMBER, 31))

    val closestLeapDateGen: Gen[Calendar] =
      for { c <- calendar; y <- yearGen(c) } yield moveToNearestLeapDate(c, y)

    val lastDayOfMonthGen: Gen[Calendar] =
      calendar.map(c => adjust(c)(_.set(DAY_OF_MONTH, c.getActualMaximum(DAY_OF_MONTH))))

    val firstDayOfMonthGen: Gen[Calendar] =
      calendar.map(c => adjust(c)(_.set(DAY_OF_MONTH, 1)))

    Gen.frequency(
      (1, firstDayOfYearGen),
      (1, lastDayOfYearGen),
      (1, closestLeapDateGen),
      (1, beginningOfDayGen),
      (1, endOfDayGen),
      (1, firstDayOfMonthGen),
      (1, lastDayOfMonthGen),
      (7, calendar))
  }

  val finiteDuration: Gen[FiniteDuration] =
    // Duration.fromNanos doesn't allow Long.MinValue since it would create a
    // duration that cannot be negated.
    chooseNum(Long.MinValue + 1, Long.MaxValue).map(Duration.fromNanos)

  /**
   * Generates instance of Duration.
   *
   * In addition to `FiniteDuration` values, this can generate `Duration.Inf`,
   * `Duration.MinusInf`, and `Duration.Undefined`.
   */
  val duration: Gen[Duration] = frequency(
    1 -> const(Duration.Inf),
    1 -> const(Duration.MinusInf),
    1 -> const(Duration.Undefined),
    1 -> const(Duration.Zero),
    6 -> finiteDuration)

  // used to compute a uniformly-distributed size
  private def mkSize(p: Gen.Parameters, seed0: Seed): (Int, Seed) = {
    val maxSize = Integer.max(p.size + 1, 1)
    val (x, seed1) = seed0.long
    (((x & Long.MaxValue) % maxSize).toInt, seed1)
  }

  // used to calculate how many per-item retries we should allow.
  private def collectionRetries(n: Int): Int =
    Integer.max(10, n / 10)
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy