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

org.scalatest.prop.GeneratorChecks.scala Maven / Gradle / Ivy

The newest version!
/*
 * Copyright 2001-2015 Artima, Inc.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package org.scalatest.prop

import org.scalactic._
import org.scalatest.FailureMessages
import org.scalatest.UnquotedString
import org.scalatest.exceptions.StackDepthException
import scala.annotation.tailrec
import scala.util.{Try, Failure, Success}
import org.scalatest.exceptions.DiscardedEvaluationException
import org.scalatest.exceptions.GeneratorDrivenPropertyCheckFailedException
import org.scalatest.exceptions.StackDepth
import org.scalatest.exceptions.TestFailedException

// For now, hard coding a size of 10. Later will need to do the size based on config
private[prop] trait GeneratorChecks extends Configuration with Whenever {
  import GeneratorChecks.prettyArgs
import GeneratorChecks.stackDepthFileName
import GeneratorChecks.stackDepthMethodName
  def forAll[A](fun: (A) => Unit)
      (implicit 
        config: PropertyCheckConfiguration,
        genA: org.scalatest.prop.Generator[A],
        prettifier: Prettifier,
        pos: source.Position
      ): Unit = {
    val maxDiscarded = PropertyCheckConfiguration.calculateMaxDiscarded(config.maxDiscardedFactor, config.minSuccessful)
    val maxSize = config.minSize + config.sizeRange
    @tailrec
    def loop(succeededCount: Int, discardedCount: Int, nextRandomizer: Randomizer, initialSizes: List[Int]): Unit = {
      val (size, nextInitialSizes, nextRandomizer2) =
        initialSizes match {
          case head :: tail => (head, tail, nextRandomizer)
          case Nil =>
            val (sz, r2) = nextRandomizer.chooseInt(config.minSize, maxSize)
            (sz, Nil, r2)
        }
      val (v, r) = genA.next(size, nextRandomizer2)
      val result: Try[Unit] = Try { fun(v) }
      val argsPassed = List(v)
      val scalaCheckLabels = Set.empty[String]
      result match {
        case Success(()) =>
          val nextSucceededCount = succeededCount + 1
          if (nextSucceededCount < config.minSuccessful)
            loop(nextSucceededCount, discardedCount, r, nextInitialSizes)
        case Failure(ex: DiscardedEvaluationException) =>
          val nextDiscardedCount = discardedCount + 1
          if (nextDiscardedCount < maxDiscarded)
            loop(succeededCount, nextDiscardedCount, r, nextInitialSizes)
          else throw new TestFailedException((sde: StackDepthException) => Some("too many discarded evaluations"), None, pos, None)
        case Failure(ex) => 
          throw new GeneratorDrivenPropertyCheckFailedException(
            (sde: StackDepthException) => FailureMessages.propertyException(prettifier, UnquotedString(sde.getClass.getSimpleName)) + "\n" +
              ( sde.failedCodeFileNameAndLineNumberString match { case Some(s) => " (" + s + ")"; case None => "" }) + "\n" + 
              "  " + FailureMessages.propertyFailed(prettifier, succeededCount) + "\n" +
              (
                sde match {
                  case sd: StackDepth if sd.failedCodeFileNameAndLineNumberString.isDefined =>
                    "  " + FailureMessages.thrownExceptionsLocation(prettifier, UnquotedString(sd.failedCodeFileNameAndLineNumberString.get)) + "\n"
                  case _ => ""
                }
              ) +
              "  " + FailureMessages.occurredOnValues + "\n" +
              prettyArgs(argsPassed, prettifier) + "\n" +
              "  )" +
              "", // getLabelDisplay(scalaCheckLabels),
            Some(ex),
            pos,
            None,
            FailureMessages.propertyFailed(prettifier, succeededCount),
            argsPassed,
            None,
            scalaCheckLabels.toList
          )
      }
    }
    // Make a List of 10 sizes between minSize and maxSize and sort them. Will
    // do those sizes first, and after that, use a random size between minSize and maxSize
    // The reason 10 is chosen is it will be the default minSuccessful, and o
    // When a different minSuccessful is used, we'll just generate random ones so
    // the max preallocated list will always have size 10.
    @tailrec
    def sizesLoop(sizes: List[Int], count: Int, rnd: Randomizer): List[Int] = {
      sizes match {
        case Nil => sizesLoop(List(config.minSize), 1, rnd)
        case szs if count < 10 =>
          val (nextSize, nextRandomizer) = rnd.chooseInt(config.minSize, maxSize)
          sizesLoop(nextSize :: sizes, count + 1,  nextRandomizer)
        case _ => sizes.sorted
      }
    }
    val initialSizes = sizesLoop(Nil, 0, Randomizer.default)
    loop(0, 0, Randomizer.default, initialSizes)
  }
  def forAll[A, B](fun: (A, B) => Unit)
      (implicit 
        config: PropertyCheckConfiguration,
        genA: org.scalatest.prop.Generator[A],
        genB: org.scalatest.prop.Generator[B],
        pos: source.Position
      ): Unit = {
    val maxDiscarded = PropertyCheckConfiguration.calculateMaxDiscarded(config.maxDiscardedFactor, config.minSuccessful)
    @tailrec
    def loop(succeededCount: Int, discardedCount: Int, nextRandomizer: Randomizer): Unit = {
      val (a, ar) = genA.next(10, nextRandomizer)
      val (b, br) = genB.next(10, ar)
      val result: Try[Unit] = Try { fun(a, b) }
      result match {
        case Success(()) =>
          val nextSucceededCount = succeededCount + 1
          if (nextSucceededCount < config.minSuccessful)
            loop(nextSucceededCount, discardedCount, br)
        case Failure(ex: DiscardedEvaluationException) =>
          val nextDiscardedCount = discardedCount + 1
          if (nextDiscardedCount < maxDiscarded)
            loop(succeededCount, nextDiscardedCount, br)
          else throw new TestFailedException((sde: StackDepthException) => Some("too many discarded evaluations"), None, pos)
        case Failure(ex) => throw ex
      }
    }
    loop(0, 0, Randomizer.default)
  }
  def forAll[A, B, C](fun: (A, B, C) => Unit)
      (implicit 
        config: PropertyCheckConfiguration,
        genA: org.scalatest.prop.Generator[A],
        genB: org.scalatest.prop.Generator[B],
        genC: org.scalatest.prop.Generator[C],
        pos: source.Position
      ): Unit = {
    val maxDiscarded = PropertyCheckConfiguration.calculateMaxDiscarded(config.maxDiscardedFactor, config.minSuccessful)
    @tailrec
    def loop(succeededCount: Int, discardedCount: Int, nextRandomizer: Randomizer): Unit = {
      val (a, ar) = genA.next(10, nextRandomizer)
      val (b, br) = genB.next(10, ar)
      val (c, cr) = genC.next(10, br)
      val result: Try[Unit] = Try { fun(a, b, c) }
      result match {
        case Success(()) =>
          val nextSucceededCount = succeededCount + 1
          if (nextSucceededCount < config.minSuccessful)
            loop(nextSucceededCount, discardedCount, cr)
        case Failure(ex: DiscardedEvaluationException) =>
          val nextDiscardedCount = discardedCount + 1
          if (nextDiscardedCount < maxDiscarded)
            loop(succeededCount, nextDiscardedCount, cr)
          else throw new TestFailedException((sde: StackDepthException) => Some("too many discarded evaluations"), None, pos)
        case Failure(ex) => throw ex
      }
    }
    loop(0, 0, Randomizer.default)
  }
}

private[prop] object GeneratorChecks extends GeneratorChecks {
  private val stackDepthFileName = "GeneratorChecks.scala"
  private val stackDepthMethodName = "apply"
  import FailureMessages.decorateToStringValue
  private def prettyArgs(args: List[Any], prettifier: Prettifier) = {
    val strs = for((a, i) <- args.zipWithIndex) yield (
      "    " +
      ("arg" + i) +
      " = " + decorateToStringValue(prettifier, a) + (if (i < args.length - 1) "," else "") // +
      // (if (a.shrinks > 0) " // " + a.shrinks + (if (a.shrinks == 1) " shrink" else " shrinks") else "")
    )
    strs.mkString("\n")
  }
}





© 2015 - 2025 Weber Informatics LLC | Privacy Policy