org.scalacheck.Prop.scala Maven / Gradle / Ivy
/*-------------------------------------------------------------------------*\
** ScalaCheck **
** Copyright (c) 2007-2016 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.implicitConversions
import language.reflectiveCalls
import rng.Seed
import util.{Pretty, FreqMap, Buildable, ConsoleReporter}
import scala.annotation.tailrec
/** Helper class to satisfy ScalaJS compilation. Do not use this directly,
* use `Prop.apply` instead. */
sealed class PropFromFun(f: Gen.Parameters => Prop.Result) extends Prop {
def apply(prms: Gen.Parameters) = f(prms)
}
@Platform.JSExportDescendentClasses
@Platform.JSExportDescendentObjects
sealed abstract class Prop {
import Prop.{Result, Proof, True, False, Exception, Undecided,
provedToTrue, secure, mergeRes}
import Gen.Parameters
def apply(prms: Parameters): Result
def contramap(f: Parameters => Parameters): Prop =
new PropFromFun(params => apply(f(params)))
def map(f: Result => Result): Prop = Prop(prms => f(this(prms)))
def flatMap(f: Result => Prop): Prop = Prop(prms => f(this(prms))(prms))
def combine(p: => Prop)(f: (Result, Result) => Result) =
for(r1 <- this; r2 <- p) yield f(r1,r2)
/** Convenience method that checks this property with the given parameters
* and reports the result on the console. Should only be used when running
* tests interactively within the Scala REPL.*/
def check(prms: Test.Parameters): Unit = Test.check(
if(prms.testCallback.isInstanceOf[ConsoleReporter]) prms
else prms.withTestCallback(prms.testCallback.chain(ConsoleReporter(1))),
this
)
/** Convenience method that checks this property with the given parameters
* and reports the result on the console. Should only be used when running
* tests interactively within the Scala REPL.
*
* The default test parameters
* ([[Test.Parameters.default]]) are used for the check. */
def check: Unit = check(Test.Parameters.default)
/** Convenience method that checks this property and reports the result
* on the console. Should only be used when running
* tests interactively within the Scala REPL.
*
* The provided argument should be a function that takes
* the default test parameters ([[Test.Parameters.default]])
* as input and outputs a modified [[Test.Parameters]] instance that
* Example use:
*
* {{{
* p.check(_.withMinSuccessfulTests(500))
* p.check { _.
* withMinSuccessfulTests(80000).
* withWorkers(4)
* }
* }}}
*/
def check(paramFun: Test.Parameters => Test.Parameters): Unit = check(
paramFun(Test.Parameters.default)
)
/** Convenience method that makes it possible to use this property
* as an application that checks itself on execution. Calls `System.exit`
* with a non-zero exit code if the property check fails. */
def main(args: Array[String]): Unit = {
val ret = Test.cmdLineParser.parseParams(args) match {
case (params, Nil) =>
if (Test.check(params, this).passed) 0
else 1
case (_, os) =>
println(s"Incorrect options: $os")
Test.cmdLineParser.printHelp
-1
}
if (ret != 0) System.exit(ret)
}
/** Returns a new property that holds if and only if both this
* and the given property hold. If one of the properties doesn't
* generate a result, the new property will generate false. */
def &&(p: => Prop) = combine(p)(_ && _)
/** Returns a new property that holds if either this
* or the given property (or both) hold. */
def ||(p: => Prop) = combine(p)(_ || _)
/** Returns a new property that holds if and only if both this
* and the given property hold. If one of the properties doesn't
* generate a result, the new property will generate the same result
* as the other property. */
def ++(p: => Prop): Prop = combine(p)(_ ++ _)
/** Combines two properties through implication */
def ==>(p: => Prop): Prop = flatMap { r1 =>
if(r1.proved) p map { r2 => mergeRes(r1,r2,r2.status) }
else if(!r1.success) Prop(r1.copy(status = Undecided))
else p map { r2 => provedToTrue(mergeRes(r1,r2,r2.status)) }
}
/** Returns a new property that holds if and only if both this
* and the given property generates a result with the exact
* same status. Note that this means that if one of the properties is
* proved, and the other one passed, then the resulting property
* will fail. */
def ==(p: => Prop) = this.flatMap { r1 =>
p.map { r2 =>
mergeRes(r1, r2, if(r1.status == r2.status) True else False)
}
}
override def toString = "Prop"
/** Put a label on the property to make test reports clearer */
def label(l: String) = map(_.label(l))
/** Put a label on the property to make test reports clearer */
def :|(l: String) = label(l)
/** Put a label on the property to make test reports clearer */
def |:(l: String) = label(l)
/** Put a label on the property to make test reports clearer */
def :|(l: Symbol) = label(l.name)
/** Put a label on the property to make test reports clearer */
def |:(l: Symbol) = label(l.name)
}
object Prop {
import Gen.{fail, frequency, oneOf, Parameters}
import Arbitrary.{arbitrary}
import Shrink.{shrink}
// Types
/** A property argument */
case class Arg[+T](
label: String,
arg: T,
shrinks: Int,
origArg: T,
prettyArg: Pretty,
prettyOrigArg: Pretty
)
private[scalacheck] def mergeRes(x: Result, y: Result, st: Status) =
Result(
status = st,
args = x.args ++ y.args,
collected = x.collected ++ y.collected,
labels = x.labels ++ y.labels
)
/** The result of evaluating a property */
case class Result(
status: Status,
args: List[Arg[Any]] = Nil,
collected: Set[Any] = Set.empty,
labels: Set[String] = Set.empty
) {
def success = status match {
case True => true
case Proof => true
case _ => false
}
def failure = status match {
case False => true
case Exception(_) => true
case _ => false
}
def proved = status == Proof
def addArg(a: Arg[Any]) = copy(args = a::args)
def collect(x: Any) = copy(collected = collected+x)
def label(l: String) = copy(labels = labels+l)
def &&(r: Result) = (this.status, r.status) match {
case (Exception(_),_) => this
case (_,Exception(_)) => r
case (False,_) => this
case (_,False) => r
case (Undecided,_) => this
case (_,Undecided) => r
case (_,Proof) => mergeRes(this, r, this.status)
case (Proof,_) => mergeRes(this, r, r.status)
case (True,True) => mergeRes(this, r, True)
}
def ||(r: Result) = (this.status, r.status) match {
case (Exception(_),_) => this
case (_,Exception(_)) => r
case (False,False) => mergeRes(this, r, False)
case (False,_) => r
case (_,False) => this
case (Proof,_) => this
case (_,Proof) => r
case (True,_) => this
case (_,True) => r
case (Undecided,Undecided) => mergeRes(this, r, Undecided)
}
def ++(r: Result) = (this.status, r.status) match {
case (Exception(_),_) => this
case (_,Exception(_)) => r
case (_, Undecided) => this
case (Undecided, _) => r
case (_, Proof) => this
case (Proof, _) => r
case (_, True) => this
case (True, _) => r
case (False, _) => this
}
def ==>(r: Result) = (this.status, r.status) match {
case (Exception(_),_) => this
case (_,Exception(_)) => r
case (False,_) => mergeRes(this, r, Undecided)
case (Undecided,_) => this
case (Proof,_) => mergeRes(this, r, r.status)
case (True,_) => mergeRes(this, r, r.status)
}
}
sealed trait Status
/** The property was proved */
case object Proof extends Status
/** The property was true */
case object True extends Status
/** The property was false */
case object False extends Status
/** The property could not be falsified or proved */
case object Undecided extends Status
/** Evaluating the property raised an exception */
sealed case class Exception(e: Throwable) extends Status {
override def equals(o: Any) = o match {
case Exception(_) => true
case _ => false
}
}
/** Create a new property from the given function. */
def apply(f: Parameters => Result): Prop = new PropFromFun(prms =>
try f(prms) catch {
case e: Throwable => Result(status = Exception(e))
}
)
/** Create a property that returns the given result */
def apply(r: Result): Prop = Prop.apply(prms => r)
/** Create a property from a boolean value */
def apply(b: Boolean): Prop = if(b) proved else falsified
// Implicits
/** A collection of property operators on `Any` values.
* Import [[Prop.AnyOperators]] to make the operators available. */
class ExtendedAny[T <% Pretty](x: => T) {
/** See [[Prop.imply]] */
def imply(f: PartialFunction[T,Prop]) = Prop.imply(x,f)
/** See [[Prop.iff]] */
def iff(f: PartialFunction[T,Prop]) = Prop.iff(x,f)
/** See [[Prop.?=]] */
def ?=(y: T) = Prop.?=(x, y)
/** See [[Prop.=?]] */
def =?(y: T) = Prop.=?(x, y)
}
/** A collection of property operators on `Boolean` values.
* Import [[Prop.BooleanOperators]] to make the operators available. */
class ExtendedBoolean(b: => Boolean) {
/** See the documentation for [[org.scalacheck.Prop]] */
def ==>(p: => Prop) = Prop(b) ==> p
/** See the documentation for [[org.scalacheck.Prop]] */
def :|(l: String) = Prop(b) :| l
/** See the documentation for [[org.scalacheck.Prop]] */
def |:(l: String) = l |: Prop(b)
/** See the documentation for [[org.scalacheck.Prop]] */
def :|(l: Symbol) = Prop(b) :| l
/** See the documentation for [[org.scalacheck.Prop]] */
def |:(l: Symbol) = l |: Prop(b)
}
/** Implicit method that makes a number of property operators on values of
* type `Any` available in the current scope.
* See [[Prop.ExtendedAny]] for documentation on the operators. */
implicit def AnyOperators[T <% Pretty](x: => T) = new ExtendedAny[T](x)
/** Implicit method that makes a number of property operators on boolean
* values available in the current scope. See [[Prop.ExtendedBoolean]] for
* documentation on the operators. */
implicit def BooleanOperators(b: => Boolean) = new ExtendedBoolean(b)
/** Implicit conversion of Boolean values to Prop values. */
implicit def propBoolean(b: Boolean): Prop = Prop(b)
// Private support functions
private def provedToTrue(r: Result) = r.status match {
case Proof => r.copy(status = True)
case _ => r
}
// Property combinators
/** A property that never is proved or falsified */
lazy val undecided = Prop(Result(status = Undecided))
/** A property that always is false */
lazy val falsified = Prop(Result(status = False))
/** A property that always is proved */
lazy val proved = Prop(Result(status = Proof))
/** A property that always is passed */
lazy val passed = Prop(Result(status = True))
/** A property that denotes an exception */
def exception(e: Throwable): Prop = Prop(Result(status = Exception(e)))
/** A property that denotes an exception */
lazy val exception: Prop = exception(null)
/** Create a property that compares to values. If the values aren't equal,
* the property will fail and report that first value doesn't match the
* expected (second) value. */
def ?=[T](x: T, y: T)(implicit pp: T => Pretty): Prop =
if(x == y) proved else falsified :| {
val exp = Pretty.pretty[T](y, Pretty.Params(0))
val act = Pretty.pretty[T](x, Pretty.Params(0))
"Expected "+exp+" but got "+act
}
/** Create a property that compares to values. If the values aren't equal,
* the property will fail and report that second value doesn't match the
* expected (first) value. */
def =?[T](x: T, y: T)(implicit pp: T => Pretty): Prop = ?=(y, x)
/** A property that depends on the generator size */
def sizedProp(f: Int => Prop): Prop = Prop { prms =>
// provedToTrue since if the property is proved for
// one size, it shouldn't be regarded as proved for
// all sizes.
provedToTrue(f(prms.size)(prms))
}
/** Implication with several conditions */
def imply[T](x: T, f: PartialFunction[T,Prop]): Prop = secure {
if(f.isDefinedAt(x)) f(x) else undecided
}
/** Property holds only if the given partial function is defined at
* `x`, and returns a property that holds */
def iff[T](x: T, f: PartialFunction[T,Prop]): Prop = secure {
if(f.isDefinedAt(x)) f(x) else falsified
}
/** Combines properties into one, which is true if and only if all the
* properties are true */
def all(ps: Prop*) = if(ps.isEmpty) proved else Prop(prms =>
ps.map(p => p(prms)).reduceLeft(_ && _)
)
/** Combines properties into one, which is true if at least one of the
* properties is true */
def atLeastOne(ps: Prop*) = if(ps.isEmpty) falsified else Prop(prms =>
ps.map(p => p(prms)).reduceLeft(_ || _)
)
/** A property that holds if at least one of the given generators
* fails generating a value */
def someFailing[T](gs: Seq[Gen[T]]) = atLeastOne(gs.map(_ == fail):_*)
/** A property that holds iff none of the given generators
* fails generating a value */
def noneFailing[T](gs: Seq[Gen[T]]) = all(gs.map(_ !== fail):_*)
/** Returns true if the given statement throws an exception
* of the specified type */
def throws[T <: Throwable](c: Class[T])(x: => Any): Boolean =
try { x; false } catch { case e if c.isInstance(e) => true }
/** Collect data for presentation in test report */
def collect[T, P <% Prop](f: T => P): T => Prop = t => Prop { prms =>
val prop = f(t)
prop(prms).collect(t)
}
/** Collect data for presentation in test report */
def collect[T](t: T)(prop: Prop) = Prop { prms =>
prop(prms).collect(t)
}
/** Collect data for presentation in test report */
def classify(c: => Boolean, ifTrue: Any)(prop: Prop): Prop =
if(c) collect(ifTrue)(prop) else collect(())(prop)
/** Collect data for presentation in test report */
def classify(c: => Boolean, ifTrue: Any, ifFalse: Any)(prop: Prop): Prop =
if(c) collect(ifTrue)(prop) else collect(ifFalse)(prop)
/** Wraps and protects a property, turning exceptions thrown
* by the property into test failures. */
def secure[P <% Prop](p: => P): Prop =
try (p: Prop) catch { case e: Throwable => exception(e) }
/** Wraps a property to delay its evaluation. The given parameter is
* evaluated each time the wrapper property is evaluated. */
def delay(p: => Prop): Prop =
Prop(params => p(params))
/** Wraps a property lazily. The given parameter is only evaluated once,
* and not until the wrapper property is evaluated. */
def lzy(p: => Prop): Prop = {
lazy val q = p
Prop(params => q(params))
}
/** Wraps and protects a property, delaying its evaluation
* and turning exceptions into test failures. */
def protect(p: => Prop): Prop =
delay(secure(p))
/** Existential quantifier for an explicit generator. */
def exists[A,P](f: A => P)(implicit
pv: P => Prop,
pp: A => Pretty,
aa: Arbitrary[A]
): Prop = exists(aa.arbitrary)(f)
/** Existential quantifier for an explicit generator. */
def exists[A,P](g: Gen[A])(f: A => P)(implicit
pv: P => Prop,
pp: A => Pretty
): Prop = Prop { prms =>
val gr = g.doApply(prms, Seed.random())
gr.retrieve match {
case None => undecided(prms)
case Some(x) =>
val p = secure(f(x))
val labels = gr.labels.mkString(",")
val r = p(prms).addArg(Arg(labels,x,0,x,pp(x),pp(x)))
r.status match {
case True => r.copy(status = Proof)
case False => r.copy(status = Undecided)
case _ => r
}
}
}
/** Universal quantifier for an explicit generator. Does not shrink failed
* test cases. */
def forAllNoShrink[T1,P](
g1: Gen[T1])(
f: T1 => P)(implicit
pv: P => Prop,
pp1: T1 => Pretty
): Prop = Prop { prms =>
val gr = g1.doApply(prms, Seed.random())
gr.retrieve match {
case None => undecided(prms)
case Some(x) =>
val p = secure(f(x))
val labels = gr.labels.mkString(",")
provedToTrue(p(prms)).addArg(Arg(labels,x,0,x,pp1(x),pp1(x)))
}
}
/** Universal quantifier for two explicit generators.
* Does not shrink failed test cases. */
def forAllNoShrink[T1,T2,P](
g1: Gen[T1], g2: Gen[T2])(
f: (T1,T2) => P)(implicit
p: P => Prop,
pp1: T1 => Pretty,
pp2: T2 => Pretty
): Prop = forAllNoShrink(g1)(t => forAllNoShrink(g2)(f(t, _:T2)))
/** Universal quantifier for three explicit generators.
* Does not shrink failed test cases. */
def forAllNoShrink[T1,T2,T3,P](
g1: Gen[T1], g2: Gen[T2], g3: Gen[T3])(
f: (T1,T2,T3) => P)(implicit
p: P => Prop,
pp1: T1 => Pretty,
pp2: T2 => Pretty,
pp3: T3 => Pretty
): Prop = forAllNoShrink(g1)(t => forAllNoShrink(g2,g3)(f(t, _:T2, _:T3)))
/** Universal quantifier for four explicit generators.
* Does not shrink failed test cases. */
def forAllNoShrink[T1,T2,T3,T4,P](
g1: Gen[T1], g2: Gen[T2], g3: Gen[T3], g4: Gen[T4])(
f: (T1,T2,T3,T4) => P)(implicit
p: P => Prop,
pp1: T1 => Pretty,
pp2: T2 => Pretty,
pp3: T3 => Pretty,
pp4: T4 => Pretty
): Prop = forAllNoShrink(g1)(t => forAllNoShrink(g2,g3,g4)(f(t, _:T2, _:T3, _:T4)))
/** Universal quantifier for five explicit generators.
* Does not shrink failed test cases. */
def forAllNoShrink[T1,T2,T3,T4,T5,P](
g1: Gen[T1], g2: Gen[T2], g3: Gen[T3], g4: Gen[T4], g5: Gen[T5])(
f: (T1,T2,T3,T4,T5) => P)(implicit
p: P => Prop,
pp1: T1 => Pretty,
pp2: T2 => Pretty,
pp3: T3 => Pretty,
pp4: T4 => Pretty,
pp5: T5 => Pretty
): Prop = forAllNoShrink(g1)(t => forAllNoShrink(g2,g3,g4,g5)(f(t, _:T2, _:T3, _:T4, _:T5)))
/** Universal quantifier for six explicit generators.
* Does not shrink failed test cases. */
def forAllNoShrink[T1,T2,T3,T4,T5,T6,P](
g1: Gen[T1], g2: Gen[T2], g3: Gen[T3], g4: Gen[T4], g5: Gen[T5], g6: Gen[T6])(
f: (T1,T2,T3,T4,T5,T6) => P)(implicit
p: P => Prop,
pp1: T1 => Pretty,
pp2: T2 => Pretty,
pp3: T3 => Pretty,
pp4: T4 => Pretty,
pp5: T5 => Pretty,
pp6: T6 => Pretty
): Prop = forAllNoShrink(g1)(t => forAllNoShrink(g2,g3,g4,g5,g6)(f(t, _:T2, _:T3, _:T4, _:T5, _:T6)))
/** Universal quantifier for seven explicit generators.
* Does not shrink failed test cases. */
def forAllNoShrink[T1,T2,T3,T4,T5,T6,T7,P](
g1: Gen[T1], g2: Gen[T2], g3: Gen[T3], g4: Gen[T4], g5: Gen[T5], g6: Gen[T6], g7: Gen[T7])(
f: (T1,T2,T3,T4,T5,T6,T7) => P)(implicit
p: P => Prop,
pp1: T1 => Pretty,
pp2: T2 => Pretty,
pp3: T3 => Pretty,
pp4: T4 => Pretty,
pp5: T5 => Pretty,
pp6: T6 => Pretty,
pp7: T7 => Pretty
): Prop = forAllNoShrink(g1)(t => forAllNoShrink(g2,g3,g4,g5,g6,g7)(f(t, _:T2, _:T3, _:T4, _:T5, _:T6, _:T7)))
/** Universal quantifier for eight explicit generators.
* Does not shrink failed test cases. */
def forAllNoShrink[T1,T2,T3,T4,T5,T6,T7,T8,P](
g1: Gen[T1], g2: Gen[T2], g3: Gen[T3], g4: Gen[T4], g5: Gen[T5], g6: Gen[T6], g7: Gen[T7], g8: Gen[T8])(
f: (T1,T2,T3,T4,T5,T6,T7,T8) => P)(implicit
p: P => Prop,
pp1: T1 => Pretty,
pp2: T2 => Pretty,
pp3: T3 => Pretty,
pp4: T4 => Pretty,
pp5: T5 => Pretty,
pp6: T6 => Pretty,
pp7: T7 => Pretty,
pp8: T8 => Pretty
): Prop = forAllNoShrink(g1)(t => forAllNoShrink(g2,g3,g4,g5,g6,g7,g8)(f(t, _:T2, _:T3, _:T4, _:T5, _:T6, _:T7, _:T8)))
/** Converts a function into a universally quantified property */
def forAllNoShrink[A1,P](
f: A1 => P)(implicit
pv: P => Prop,
a1: Arbitrary[A1], pp1: A1 => Pretty
): Prop = forAllNoShrink(arbitrary[A1])(f)
/** Converts a function into a universally quantified property */
def forAllNoShrink[A1,A2,P](
f: (A1,A2) => P)(implicit
pv: P => Prop,
a1: Arbitrary[A1], pp1: A1 => Pretty,
a2: Arbitrary[A2], pp2: A2 => Pretty
): Prop = forAllNoShrink(arbitrary[A1], arbitrary[A2])(f)
/** Converts a function into a universally quantified property */
def forAllNoShrink[A1,A2,A3,P](
f: (A1,A2,A3) => P)(implicit
pv: P => Prop,
a1: Arbitrary[A1], pp1: A1 => Pretty,
a2: Arbitrary[A2], pp2: A2 => Pretty,
a3: Arbitrary[A3], pp3: A3 => Pretty
): Prop = forAllNoShrink(arbitrary[A1], arbitrary[A2], arbitrary[A3])(f)
/** Converts a function into a universally quantified property */
def forAllNoShrink[A1,A2,A3,A4,P](
f: (A1,A2,A3,A4) => P)(implicit
pv: P => Prop,
a1: Arbitrary[A1], pp1: A1 => Pretty,
a2: Arbitrary[A2], pp2: A2 => Pretty,
a3: Arbitrary[A3], pp3: A3 => Pretty,
a4: Arbitrary[A4], pp4: A4 => Pretty
): Prop = forAllNoShrink(arbitrary[A1], arbitrary[A2], arbitrary[A3], arbitrary[A4])(f)
/** Converts a function into a universally quantified property */
def forAllNoShrink[A1,A2,A3,A4,A5,P](
f: (A1,A2,A3,A4,A5) => P)(implicit
pv: P => Prop,
a1: Arbitrary[A1], pp1: A1 => Pretty,
a2: Arbitrary[A2], pp2: A2 => Pretty,
a3: Arbitrary[A3], pp3: A3 => Pretty,
a4: Arbitrary[A4], pp4: A4 => Pretty,
a5: Arbitrary[A5], pp5: A5 => Pretty
): Prop = forAllNoShrink(arbitrary[A1], arbitrary[A2], arbitrary[A3], arbitrary[A4], arbitrary[A5])(f)
/** Converts a function into a universally quantified property */
def forAllNoShrink[A1,A2,A3,A4,A5,A6,P](
f: (A1,A2,A3,A4,A5,A6) => P)(implicit
pv: P => Prop,
a1: Arbitrary[A1], pp1: A1 => Pretty,
a2: Arbitrary[A2], pp2: A2 => Pretty,
a3: Arbitrary[A3], pp3: A3 => Pretty,
a4: Arbitrary[A4], pp4: A4 => Pretty,
a5: Arbitrary[A5], pp5: A5 => Pretty,
a6: Arbitrary[A6], pp6: A6 => Pretty
): Prop = forAllNoShrink(arbitrary[A1], arbitrary[A2], arbitrary[A3], arbitrary[A4], arbitrary[A5], arbitrary[A6])(f)
/** Converts a function into a universally quantified property */
def forAllNoShrink[A1,A2,A3,A4,A5,A6,A7,P](
f: (A1,A2,A3,A4,A5,A6,A7) => P)(implicit
pv: P => Prop,
a1: Arbitrary[A1], pp1: A1 => Pretty,
a2: Arbitrary[A2], pp2: A2 => Pretty,
a3: Arbitrary[A3], pp3: A3 => Pretty,
a4: Arbitrary[A4], pp4: A4 => Pretty,
a5: Arbitrary[A5], pp5: A5 => Pretty,
a6: Arbitrary[A6], pp6: A6 => Pretty,
a7: Arbitrary[A7], pp7: A7 => Pretty
): Prop = {
forAllNoShrink(arbitrary[A1], arbitrary[A2], arbitrary[A3], arbitrary[A4], arbitrary[A5], arbitrary[A6],
arbitrary[A7])(f)
}
/** Converts a function into a universally quantified property */
def forAllNoShrink[A1,A2,A3,A4,A5,A6,A7,A8,P](
f: (A1,A2,A3,A4,A5,A6,A7,A8) => P)(implicit
pv: P => Prop,
a1: Arbitrary[A1], pp1: A1 => Pretty,
a2: Arbitrary[A2], pp2: A2 => Pretty,
a3: Arbitrary[A3], pp3: A3 => Pretty,
a4: Arbitrary[A4], pp4: A4 => Pretty,
a5: Arbitrary[A5], pp5: A5 => Pretty,
a6: Arbitrary[A6], pp6: A6 => Pretty,
a7: Arbitrary[A7], pp7: A7 => Pretty,
a8: Arbitrary[A8], pp8: A8 => Pretty
): Prop = {
forAllNoShrink(arbitrary[A1], arbitrary[A2], arbitrary[A3], arbitrary[A4], arbitrary[A5], arbitrary[A6],
arbitrary[A7], arbitrary[A8])(f)
}
/** Universal quantifier for an explicit generator. Shrinks failed arguments
* with the given shrink function */
def forAllShrink[T, P](g: Gen[T],
shrink: T => Stream[T])(f: T => P
)(implicit pv: P => Prop, pp: T => Pretty
): Prop = Prop { prms =>
val gr = g.doApply(prms, Seed.random())
val labels = gr.labels.mkString(",")
def result(x: T) = {
val p = secure(pv(f(x)))
provedToTrue(p(prms))
}
/** Returns the first failed result in Left or success in Right */
def getFirstFailure(xs: Stream[T]): Either[(T,Result),(T,Result)] = {
assert(!xs.isEmpty, "Stream cannot be empty")
val results = xs.map(x => (x, result(x)))
results.dropWhile(!_._2.failure).headOption match {
case None => Right(results.head)
case Some(xr) => Left(xr)
}
}
def shrinker(x: T, r: Result, shrinks: Int, orig: T): Result = {
val xs = shrink(x).filter(gr.sieve)
val res = r.addArg(Arg(labels,x,shrinks,orig,pp(x),pp(orig)))
if(xs.isEmpty) res else getFirstFailure(xs) match {
case Right((x2,r2)) => res
case Left((x2,r2)) => shrinker(x2, replOrig(r,r2), shrinks+1, orig)
}
}
def replOrig(r0: Result, r1: Result) = (r0.args,r1.args) match {
case (a0::_,a1::as) =>
r1.copy(
args = a1.copy(
origArg = a0.origArg,
prettyOrigArg = a0.prettyOrigArg
) :: as
)
case _ => r1
}
gr.retrieve match {
case None => undecided(prms)
case Some(x) =>
val r = result(x)
if (!r.failure) r.addArg(Arg(labels,x,0,x,pp(x),pp(x)))
else shrinker(x,r,0,x)
}
}
/** Universal quantifier for an explicit generator. Shrinks failed arguments
* with the default shrink function for the type */
def forAll[T1,P](
g1: Gen[T1])(
f: T1 => P)(implicit
p: P => Prop,
s1: Shrink[T1],
pp1: T1 => Pretty
): Prop = forAllShrink[T1,P](g1, shrink[T1])(f)
/** Universal quantifier for two explicit generators. Shrinks failed arguments
* with the default shrink function for the type */
def forAll[T1,T2,P](
g1: Gen[T1], g2: Gen[T2])(
f: (T1,T2) => P)(implicit
p: P => Prop,
s1: Shrink[T1], pp1: T1 => Pretty,
s2: Shrink[T2], pp2: T2 => Pretty
): Prop = forAll(g1)(t => forAll(g2)(f(t, _:T2)))
/** Universal quantifier for three explicit generators. Shrinks failed arguments
* with the default shrink function for the type */
def forAll[T1,T2,T3,P](
g1: Gen[T1], g2: Gen[T2], g3: Gen[T3])(
f: (T1,T2,T3) => P)(implicit
p: P => Prop,
s1: Shrink[T1], pp1: T1 => Pretty,
s2: Shrink[T2], pp2: T2 => Pretty,
s3: Shrink[T3], pp3: T3 => Pretty
): Prop = forAll(g1)(t => forAll(g2,g3)(f(t, _:T2, _:T3)))
/** Universal quantifier for four explicit generators. Shrinks failed arguments
* with the default shrink function for the type */
def forAll[T1,T2,T3,T4,P](
g1: Gen[T1], g2: Gen[T2], g3: Gen[T3], g4: Gen[T4])(
f: (T1,T2,T3,T4) => P)(implicit
p: P => Prop,
s1: Shrink[T1], pp1: T1 => Pretty,
s2: Shrink[T2], pp2: T2 => Pretty,
s3: Shrink[T3], pp3: T3 => Pretty,
s4: Shrink[T4], pp4: T4 => Pretty
): Prop = forAll(g1)(t => forAll(g2,g3,g4)(f(t, _:T2, _:T3, _:T4)))
/** Universal quantifier for five explicit generators. Shrinks failed arguments
* with the default shrink function for the type */
def forAll[T1,T2,T3,T4,T5,P](
g1: Gen[T1], g2: Gen[T2], g3: Gen[T3], g4: Gen[T4], g5: Gen[T5])(
f: (T1,T2,T3,T4,T5) => P)(implicit
p: P => Prop,
s1: Shrink[T1], pp1: T1 => Pretty,
s2: Shrink[T2], pp2: T2 => Pretty,
s3: Shrink[T3], pp3: T3 => Pretty,
s4: Shrink[T4], pp4: T4 => Pretty,
s5: Shrink[T5], pp5: T5 => Pretty
): Prop = forAll(g1)(t => forAll(g2,g3,g4,g5)(f(t, _:T2, _:T3, _:T4, _:T5)))
/** Universal quantifier for six explicit generators. Shrinks failed arguments
* with the default shrink function for the type */
def forAll[T1,T2,T3,T4,T5,T6,P](
g1: Gen[T1], g2: Gen[T2], g3: Gen[T3], g4: Gen[T4], g5: Gen[T5], g6: Gen[T6])(
f: (T1,T2,T3,T4,T5,T6) => P)(implicit
p: P => Prop,
s1: Shrink[T1], pp1: T1 => Pretty,
s2: Shrink[T2], pp2: T2 => Pretty,
s3: Shrink[T3], pp3: T3 => Pretty,
s4: Shrink[T4], pp4: T4 => Pretty,
s5: Shrink[T5], pp5: T5 => Pretty,
s6: Shrink[T6], pp6: T6 => Pretty
): Prop = forAll(g1)(t => forAll(g2,g3,g4,g5,g6)(f(t, _:T2, _:T3, _:T4, _:T5, _:T6)))
/** Universal quantifier for seven explicit generators. Shrinks failed arguments
* with the default shrink function for the type */
def forAll[T1,T2,T3,T4,T5,T6,T7,P](
g1: Gen[T1], g2: Gen[T2], g3: Gen[T3], g4: Gen[T4], g5: Gen[T5], g6: Gen[T6], g7: Gen[T7])(
f: (T1,T2,T3,T4,T5,T6,T7) => P)(implicit
p: P => Prop,
s1: Shrink[T1], pp1: T1 => Pretty,
s2: Shrink[T2], pp2: T2 => Pretty,
s3: Shrink[T3], pp3: T3 => Pretty,
s4: Shrink[T4], pp4: T4 => Pretty,
s5: Shrink[T5], pp5: T5 => Pretty,
s6: Shrink[T6], pp6: T6 => Pretty,
s7: Shrink[T7], pp7: T7 => Pretty
): Prop = forAll(g1)(t => forAll(g2,g3,g4,g5,g6,g7)(f(t, _:T2, _:T3, _:T4, _:T5, _:T6, _:T7)))
/** Universal quantifier for eight explicit generators. Shrinks failed arguments
* with the default shrink function for the type */
def forAll[T1,T2,T3,T4,T5,T6,T7,T8,P](
g1: Gen[T1], g2: Gen[T2], g3: Gen[T3], g4: Gen[T4], g5: Gen[T5], g6: Gen[T6], g7: Gen[T7], g8: Gen[T8])(
f: (T1,T2,T3,T4,T5,T6,T7,T8) => P)(implicit
p: P => Prop,
s1: Shrink[T1], pp1: T1 => Pretty,
s2: Shrink[T2], pp2: T2 => Pretty,
s3: Shrink[T3], pp3: T3 => Pretty,
s4: Shrink[T4], pp4: T4 => Pretty,
s5: Shrink[T5], pp5: T5 => Pretty,
s6: Shrink[T6], pp6: T6 => Pretty,
s7: Shrink[T7], pp7: T7 => Pretty,
s8: Shrink[T8], pp8: T8 => Pretty
): Prop = forAll(g1)(t => forAll(g2,g3,g4,g5,g6,g7,g8)(f(t, _:T2, _:T3, _:T4, _:T5, _:T6, _:T7, _:T8)))
/** Converts a function into a universally quantified property */
def forAll[A1,P] (
f: A1 => P)(implicit
p: P => Prop,
a1: Arbitrary[A1], s1: Shrink[A1], pp1: A1 => Pretty
): Prop = forAllShrink(arbitrary[A1],shrink[A1])(f andThen p)
/** Converts a function into a universally quantified property */
def forAll[A1,A2,P] (
f: (A1,A2) => P)(implicit
p: P => Prop,
a1: Arbitrary[A1], s1: Shrink[A1], pp1: A1 => Pretty,
a2: Arbitrary[A2], s2: Shrink[A2], pp2: A2 => Pretty
): Prop = forAll((a: A1) => forAll(f(a, _:A2)))
/** Converts a function into a universally quantified property */
def forAll[A1,A2,A3,P] (
f: (A1,A2,A3) => P)(implicit
p: P => Prop,
a1: Arbitrary[A1], s1: Shrink[A1], pp1: A1 => Pretty,
a2: Arbitrary[A2], s2: Shrink[A2], pp2: A2 => Pretty,
a3: Arbitrary[A3], s3: Shrink[A3], pp3: A3 => Pretty
): Prop = forAll((a: A1) => forAll(f(a, _:A2, _:A3)))
/** Converts a function into a universally quantified property */
def forAll[A1,A2,A3,A4,P] (
f: (A1,A2,A3,A4) => P)(implicit
p: P => Prop,
a1: Arbitrary[A1], s1: Shrink[A1], pp1: A1 => Pretty,
a2: Arbitrary[A2], s2: Shrink[A2], pp2: A2 => Pretty,
a3: Arbitrary[A3], s3: Shrink[A3], pp3: A3 => Pretty,
a4: Arbitrary[A4], s4: Shrink[A4], pp4: A4 => Pretty
): Prop = forAll((a: A1) => forAll(f(a, _:A2, _:A3, _:A4)))
/** Converts a function into a universally quantified property */
def forAll[A1,A2,A3,A4,A5,P] (
f: (A1,A2,A3,A4,A5) => P)(implicit
p: P => Prop,
a1: Arbitrary[A1], s1: Shrink[A1], pp1: A1 => Pretty,
a2: Arbitrary[A2], s2: Shrink[A2], pp2: A2 => Pretty,
a3: Arbitrary[A3], s3: Shrink[A3], pp3: A3 => Pretty,
a4: Arbitrary[A4], s4: Shrink[A4], pp4: A4 => Pretty,
a5: Arbitrary[A5], s5: Shrink[A5], pp5: A5 => Pretty
): Prop = forAll((a: A1) => forAll(f(a, _:A2, _:A3, _:A4, _:A5)))
/** Converts a function into a universally quantified property */
def forAll[A1,A2,A3,A4,A5,A6,P] (
f: (A1,A2,A3,A4,A5,A6) => P)(implicit
p: P => Prop,
a1: Arbitrary[A1], s1: Shrink[A1], pp1: A1 => Pretty,
a2: Arbitrary[A2], s2: Shrink[A2], pp2: A2 => Pretty,
a3: Arbitrary[A3], s3: Shrink[A3], pp3: A3 => Pretty,
a4: Arbitrary[A4], s4: Shrink[A4], pp4: A4 => Pretty,
a5: Arbitrary[A5], s5: Shrink[A5], pp5: A5 => Pretty,
a6: Arbitrary[A6], s6: Shrink[A6], pp6: A6 => Pretty
): Prop = forAll((a: A1) => forAll(f(a, _:A2, _:A3, _:A4, _:A5, _:A6)))
/** Converts a function into a universally quantified property */
def forAll[A1,A2,A3,A4,A5,A6,A7,P] (
f: (A1,A2,A3,A4,A5,A6,A7) => P)(implicit
p: P => Prop,
a1: Arbitrary[A1], s1: Shrink[A1], pp1: A1 => Pretty,
a2: Arbitrary[A2], s2: Shrink[A2], pp2: A2 => Pretty,
a3: Arbitrary[A3], s3: Shrink[A3], pp3: A3 => Pretty,
a4: Arbitrary[A4], s4: Shrink[A4], pp4: A4 => Pretty,
a5: Arbitrary[A5], s5: Shrink[A5], pp5: A5 => Pretty,
a6: Arbitrary[A6], s6: Shrink[A6], pp6: A6 => Pretty,
a7: Arbitrary[A7], s7: Shrink[A7], pp7: A7 => Pretty
): Prop = forAll((a: A1) => forAll(f(a, _:A2, _:A3, _:A4, _:A5, _:A6, _:A7)))
/** Converts a function into a universally quantified property */
def forAll[A1,A2,A3,A4,A5,A6,A7,A8,P] (
f: (A1,A2,A3,A4,A5,A6,A7,A8) => P)(implicit
p: P => Prop,
a1: Arbitrary[A1], s1: Shrink[A1], pp1: A1 => Pretty,
a2: Arbitrary[A2], s2: Shrink[A2], pp2: A2 => Pretty,
a3: Arbitrary[A3], s3: Shrink[A3], pp3: A3 => Pretty,
a4: Arbitrary[A4], s4: Shrink[A4], pp4: A4 => Pretty,
a5: Arbitrary[A5], s5: Shrink[A5], pp5: A5 => Pretty,
a6: Arbitrary[A6], s6: Shrink[A6], pp6: A6 => Pretty,
a7: Arbitrary[A7], s7: Shrink[A7], pp7: A7 => Pretty,
a8: Arbitrary[A8], s8: Shrink[A8], pp8: A8 => Pretty
): Prop = forAll((a: A1) => forAll(f(a, _:A2, _:A3, _:A4, _:A5, _:A6, _:A7, _:A8)))
/** Ensures that the property expression passed in completes within the given
* space of time. */
def within(maximumMs: Long)(wrappedProp: => Prop): Prop = {
@tailrec def attempt(prms: Parameters, endTime: Long): Result = {
val result = wrappedProp.apply(prms)
if (System.currentTimeMillis > endTime) {
(if(result.failure) result else Result(status = False)).label("Timeout")
} else {
if (result.success) result
else attempt(prms, endTime)
}
}
Prop.apply(prms => attempt(prms, System.currentTimeMillis + maximumMs))
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy