summaryrefslogtreecommitdiff
path: root/src/partest-extras
diff options
context:
space:
mode:
authorJason Zaugg <jzaugg@gmail.com>2016-06-14 16:54:08 +0200
committerJason Zaugg <jzaugg@gmail.com>2016-06-27 15:04:21 +1000
commit22dac3118e97b2a4707d42ef1f47ac292a8ed385 (patch)
tree226d14a0946110230ba488227307330c928504b8 /src/partest-extras
parent4e950838cbee187f3cee2ef197164792db74e56a (diff)
downloadscala-22dac3118e97b2a4707d42ef1f47ac292a8ed385.tar.gz
scala-22dac3118e97b2a4707d42ef1f47ac292a8ed385.tar.bz2
scala-22dac3118e97b2a4707d42ef1f47ac292a8ed385.zip
Temporarily insource Scalacheck 1.11.6
This is a temporary measure until we release Scala 2.12.0. It means we are able to release milestones, and RCs of Scala without needing a public release of Scalacheck. While we've never had to wait very long for these in the past (Thanks, Rickard!) we'd like to spare the maintainer some work betwen now and 2.12.0. After we release Scala 2.12.0, we'll revert to a binary dependency on the standard Scalacheck. I have replaced the scala-parser-combinator based command line option parsing with a quick and dirty version. I've had to remove scalacheck as a SBT test framework in our build. We don't use it directly as such (instead, it is used indirectly through `partest --scalacheck`), and it's test discovery (which we expect to return nothing) fails after re-STARR-ing due to an unsolved problem with SBT's testLoader including either STARR or sbt-launch.jar on the classpath used to discover and spawn tests. For the record, I tried the following to no avail: ``` // Two modifications are needed from the stock SBT configuration in order to exclude STARR // from the classloader that performs test discovery. // - We make `isManagedVersion` hold by providing an explicit Scala version, in order to go into the desired // branch in `createTestLoader` // - We remove STARR from the classloader of the scala instance def fixTestLoader = testLoader := { val s = scalaInstance.value val scalaInstance1 = new ScalaInstance(s.version, appConfiguration.value.provider.scalaProvider.loader(), s.libraryJar, s.compilerJar, s.extraJars, Some(s.actualVersion)) assert(scalaInstance1.isManagedVersion) TestFramework.createTestLoader(Attributed.data(fullClasspath.value), scalaInstance1, IO.createUniqueDirectory(taskTemporaryDirectory.value)) } ``` f
Diffstat (limited to 'src/partest-extras')
-rw-r--r--src/partest-extras/scala/org/scalacheck/Arbitrary.scala433
-rw-r--r--src/partest-extras/scala/org/scalacheck/Commands.scala146
-rw-r--r--src/partest-extras/scala/org/scalacheck/Commands2.scala150
-rw-r--r--src/partest-extras/scala/org/scalacheck/Gen.scala813
-rw-r--r--src/partest-extras/scala/org/scalacheck/Prop.scala953
-rw-r--r--src/partest-extras/scala/org/scalacheck/Properties.scala82
-rw-r--r--src/partest-extras/scala/org/scalacheck/ScalaCheckFramework.scala93
-rw-r--r--src/partest-extras/scala/org/scalacheck/Shrink.scala215
-rw-r--r--src/partest-extras/scala/org/scalacheck/Test.scala372
-rw-r--r--src/partest-extras/scala/org/scalacheck/util/Buildable.scala77
-rw-r--r--src/partest-extras/scala/org/scalacheck/util/CmdLineParser.scala41
-rw-r--r--src/partest-extras/scala/org/scalacheck/util/ConsoleReporter.scala44
-rw-r--r--src/partest-extras/scala/org/scalacheck/util/FreqMap.scala65
-rw-r--r--src/partest-extras/scala/org/scalacheck/util/Pretty.scala129
14 files changed, 3613 insertions, 0 deletions
diff --git a/src/partest-extras/scala/org/scalacheck/Arbitrary.scala b/src/partest-extras/scala/org/scalacheck/Arbitrary.scala
new file mode 100644
index 0000000000..1cbd668f0c
--- /dev/null
+++ b/src/partest-extras/scala/org/scalacheck/Arbitrary.scala
@@ -0,0 +1,433 @@
+/*-------------------------------------------------------------------------*\
+** ScalaCheck **
+** Copyright (c) 2007-2014 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 util.{FreqMap, Buildable, Buildable2}
+
+
+sealed abstract class Arbitrary[T] {
+ val arbitrary: Gen[T]
+}
+
+/** Defines implicit [[org.scalacheck.Arbitrary]] instances for common types.
+ * <p>
+ * ScalaCheck
+ * uses implicit [[org.scalacheck.Arbitrary]] instances when creating properties
+ * out of functions with the `Prop.property` method, and when
+ * the `Arbitrary.arbitrary` method is used. For example, the
+ * following code requires that there exists an implicit
+ * `Arbitrary[MyClass]` instance:
+ * </p>
+ *
+ * {{{
+ * val myProp = Prop.forAll { myClass: MyClass =>
+ * ...
+ * }
+ *
+ * val myGen = Arbitrary.arbitrary[MyClass]
+ * }}}
+ *
+ * <p>
+ * The required implicit definition could look like this:
+ * </p>
+ *
+ * {{{
+ * implicit val arbMyClass: Arbitrary[MyClass] = Arbitrary(...)
+ * }}}
+ *
+ * <p>
+ * The factory method `Arbitrary(...)` takes a generator of type
+ * `Gen[T]` and returns an instance of `Arbitrary[T]`.
+ * </p>
+ *
+ * <p>
+ * The `Arbitrary` module defines implicit [[org.scalacheck.Arbitrary]]
+ * instances for common types, for convenient use in your properties and
+ * generators.
+ * </p>
+ */
+object Arbitrary {
+
+ import Gen.{const, choose, sized, frequency, oneOf, containerOf, resize}
+ import collection.{immutable, mutable}
+ import java.util.Date
+
+ /** Creates an Arbitrary instance */
+ def apply[T](g: => Gen[T]): Arbitrary[T] = new Arbitrary[T] {
+ lazy val arbitrary = g
+ }
+
+ /** Returns an arbitrary generator for the type T. */
+ def arbitrary[T](implicit a: Arbitrary[T]): Gen[T] = a.arbitrary
+
+ /**** Arbitrary instances for each AnyVal ****/
+
+ /** Arbitrary AnyVal */
+ implicit lazy val arbAnyVal: Arbitrary[AnyVal] = Arbitrary(oneOf(
+ arbitrary[Unit], arbitrary[Boolean], arbitrary[Char], arbitrary[Byte],
+ arbitrary[Short], arbitrary[Int], arbitrary[Long], arbitrary[Float],
+ arbitrary[Double]
+ ))
+
+ /** Arbitrary instance of Boolean */
+ implicit lazy val arbBool: Arbitrary[Boolean] =
+ Arbitrary(oneOf(true, false))
+
+ /** Arbitrary instance of Int */
+ implicit lazy val arbInt: Arbitrary[Int] = Arbitrary(
+ Gen.chooseNum(Int.MinValue, Int.MaxValue)
+ )
+
+ /** Arbitrary instance of Long */
+ implicit lazy val arbLong: Arbitrary[Long] = Arbitrary(
+ Gen.chooseNum(Long.MinValue, Long.MaxValue)
+ )
+
+ /** Arbitrary instance of Float */
+ implicit lazy val arbFloat: Arbitrary[Float] = Arbitrary(
+ Gen.chooseNum(
+ Float.MinValue, Float.MaxValue
+ // I find that including these by default is a little TOO testy.
+ // Float.Epsilon, Float.NaN, Float.PositiveInfinity, Float.NegativeInfinity
+ )
+ )
+
+ /** Arbitrary instance of Double */
+ implicit lazy val arbDouble: Arbitrary[Double] = Arbitrary(
+ Gen.chooseNum(
+ Double.MinValue / 2, Double.MaxValue / 2
+ // As above. Perhaps behind some option?
+ // Double.Epsilon, Double.NaN, Double.PositiveInfinity, Double.NegativeInfinity
+ )
+ )
+
+ /** Arbitrary instance of Char */
+ implicit lazy val arbChar: Arbitrary[Char] = Arbitrary(
+ Gen.frequency(
+ (0xD800-Char.MinValue, Gen.choose[Char](Char.MinValue,0xD800-1)),
+ (Char.MaxValue-0xDFFF, Gen.choose[Char](0xDFFF+1,Char.MaxValue))
+ )
+ )
+
+ /** Arbitrary instance of Byte */
+ implicit lazy val arbByte: Arbitrary[Byte] = Arbitrary(
+ Gen.chooseNum(Byte.MinValue, Byte.MaxValue)
+ )
+
+ /** Arbitrary instance of Short */
+ implicit lazy val arbShort: Arbitrary[Short] = Arbitrary(
+ Gen.chooseNum(Short.MinValue, Short.MaxValue)
+ )
+
+ /** Absolutely, totally, 100% arbitrarily chosen Unit. */
+ implicit lazy val arbUnit: Arbitrary[Unit] = Arbitrary(const(()))
+
+ /**** Arbitrary instances of other common types ****/
+
+ /** Arbitrary instance of String */
+ implicit lazy val arbString: Arbitrary[String] =
+ Arbitrary(arbitrary[List[Char]] map (_.mkString))
+
+ /** Arbitrary instance of Date */
+ implicit lazy val arbDate: Arbitrary[Date] = Arbitrary(for {
+ l <- arbitrary[Long]
+ d = new Date
+ } yield new Date(d.getTime + l))
+
+ /** Arbitrary instance of Throwable */
+ implicit lazy val arbThrowable: Arbitrary[Throwable] =
+ Arbitrary(oneOf(const(new Exception), const(new Error)))
+
+ /** Arbitrary instance of Exception */
+ implicit lazy val arbException: Arbitrary[Exception] =
+ Arbitrary(const(new Exception))
+
+ /** Arbitrary instance of Error */
+ implicit lazy val arbError: Arbitrary[Error] =
+ Arbitrary(const(new Error))
+
+ /** Arbitrary BigInt */
+ implicit lazy val arbBigInt: Arbitrary[BigInt] = {
+ def chooseBigInt: Gen[BigInt] =
+ sized((s: Int) => choose(-s, s)) map (x => BigInt(x))
+
+ def chooseReallyBigInt: Gen[BigInt] = for {
+ bi <- chooseBigInt
+ n <- choose(32,128)
+ } yield bi << n
+
+ Arbitrary(
+ frequency(
+ (5, chooseBigInt),
+ (10, chooseReallyBigInt),
+ (1, BigInt(0)),
+ (1, BigInt(1)),
+ (1, BigInt(-1)),
+ (1, BigInt(Int.MaxValue) + 1),
+ (1, BigInt(Int.MinValue) - 1),
+ (1, BigInt(Long.MaxValue)),
+ (1, BigInt(Long.MinValue)),
+ (1, BigInt(Long.MaxValue) + 1),
+ (1, BigInt(Long.MinValue) - 1)
+ )
+ )
+ }
+
+ /** Arbitrary BigDecimal */
+ implicit lazy val arbBigDecimal: Arbitrary[BigDecimal] = {
+ import java.math.MathContext._
+ val mcGen = oneOf(UNLIMITED, DECIMAL32, DECIMAL64, DECIMAL128)
+ val bdGen = for {
+ x <- arbBigInt.arbitrary
+ mc <- mcGen
+ limit <- const(if(mc == UNLIMITED) 0 else math.max(x.abs.toString.length - mc.getPrecision, 0))
+ scale <- Gen.chooseNum(Int.MinValue + limit , Int.MaxValue)
+ } yield {
+ try {
+ BigDecimal(x, scale, mc)
+ } catch {
+ case ae: java.lang.ArithmeticException => BigDecimal(x, scale, UNLIMITED) // Handle the case where scale/precision conflict
+ }
+ }
+ Arbitrary(bdGen)
+ }
+
+ /** Arbitrary java.lang.Number */
+ implicit lazy val arbNumber: Arbitrary[Number] = {
+ val gen = Gen.oneOf(
+ arbitrary[Byte], arbitrary[Short], arbitrary[Int], arbitrary[Long],
+ arbitrary[Float], arbitrary[Double]
+ )
+ Arbitrary(gen map (_.asInstanceOf[Number]))
+ // XXX TODO - restore BigInt and BigDecimal
+ // Arbitrary(oneOf(arbBigInt.arbitrary :: (arbs map (_.arbitrary) map toNumber) : _*))
+ }
+
+ /** Generates an arbitrary property */
+ implicit lazy val arbProp: Arbitrary[Prop] = {
+ import Prop._
+ val undecidedOrPassed = forAll { b: Boolean =>
+ b ==> true
+ }
+ Arbitrary(frequency(
+ (4, falsified),
+ (4, passed),
+ (3, proved),
+ (3, undecidedOrPassed),
+ (2, undecided),
+ (1, exception(null))
+ ))
+ }
+
+ /** Arbitrary instance of test parameters */
+ implicit lazy val arbTestParameters: Arbitrary[Test.Parameters] =
+ Arbitrary(for {
+ _minSuccTests <- choose(10,200)
+ _maxDiscardRatio <- choose(0.2f,10f)
+ _minSize <- choose(0,500)
+ sizeDiff <- choose(0,500)
+ _maxSize <- choose(_minSize, _minSize + sizeDiff)
+ _workers <- choose(1,4)
+ } yield new Test.Parameters.Default {
+ override val minSuccessfulTests = _minSuccTests
+ override val maxDiscardRatio = _maxDiscardRatio
+ override val minSize = _minSize
+ override val maxSize = _maxSize
+ override val workers = _workers
+ })
+
+ /** Arbitrary instance of gen params */
+ implicit lazy val arbGenParams: Arbitrary[Gen.Parameters] =
+ Arbitrary(for {
+ sz <- arbitrary[Int] suchThat (_ >= 0)
+ } yield (new Gen.Parameters.Default {
+ override val size = sz
+ }))
+
+
+ // Higher-order types //
+
+ /** Arbitrary instance of [[org.scalacheck.Gen]] */
+ implicit def arbGen[T](implicit a: Arbitrary[T]): Arbitrary[Gen[T]] =
+ Arbitrary(frequency(
+ (5, arbitrary[T] map (const(_))),
+ (1, Gen.fail)
+ ))
+
+ /** Arbitrary instance of the Option type */
+ implicit def arbOption[T](implicit a: Arbitrary[T]): Arbitrary[Option[T]] =
+ Arbitrary(sized(n =>
+ // When n is larger, make it less likely that we generate None,
+ // but still do it some of the time. When n is zero, we always
+ // generate None, since it's the smallest value.
+ frequency(
+ (n, resize(n / 2, arbitrary[T]).map(Some(_))),
+ (1, const(None)))))
+
+ /** Arbitrary instance of the Either type */
+ implicit def arbEither[T, U](implicit at: Arbitrary[T], au: Arbitrary[U]): Arbitrary[Either[T, U]] =
+ Arbitrary(oneOf(arbitrary[T].map(Left(_)), arbitrary[U].map(Right(_))))
+
+ /** Arbitrary instance of any [[org.scalacheck.util.Buildable]] container
+ * (such as lists, arrays, streams, etc). The maximum size of the container
+ * depends on the size generation parameter. */
+ implicit def arbContainer[C[_],T](implicit
+ a: Arbitrary[T], b: Buildable[T,C], t: C[T] => Traversable[T]
+ ): Arbitrary[C[T]] = Arbitrary(containerOf[C,T](arbitrary[T]))
+
+ /** Arbitrary instance of any [[org.scalacheck.util.Buildable2]] container
+ * (such as maps, etc). The maximum size of the container depends on the size
+ * generation parameter. */
+ implicit def arbContainer2[C[_,_],T,U](implicit
+ a: Arbitrary[(T,U)], b: Buildable2[T,U,C], t: C[T,U] => Traversable[(T,U)]
+ ): Arbitrary[C[T,U]] = Arbitrary(containerOf[C,T,U](arbitrary[(T,U)]))
+
+ // Functions //
+
+ /** Arbitrary instance of Function1 */
+ implicit def arbFunction1[T1,R](implicit a: Arbitrary[R]
+ ): Arbitrary[T1 => R] = Arbitrary(
+ for(r <- arbitrary[R]) yield (t1: T1) => r
+ )
+
+ /** Arbitrary instance of Function2 */
+ implicit def arbFunction2[T1,T2,R](implicit a: Arbitrary[R]
+ ): Arbitrary[(T1,T2) => R] = Arbitrary(
+ for(r <- arbitrary[R]) yield (t1: T1, t2: T2) => r
+ )
+
+ /** Arbitrary instance of Function3 */
+ implicit def arbFunction3[T1,T2,T3,R](implicit a: Arbitrary[R]
+ ): Arbitrary[(T1,T2,T3) => R] = Arbitrary(
+ for(r <- arbitrary[R]) yield (t1: T1, t2: T2, t3: T3) => r
+ )
+
+ /** Arbitrary instance of Function4 */
+ implicit def arbFunction4[T1,T2,T3,T4,R](implicit a: Arbitrary[R]
+ ): Arbitrary[(T1,T2,T3,T4) => R] = Arbitrary(
+ for(r <- arbitrary[R]) yield (t1: T1, t2: T2, t3: T3, t4: T4) => r
+ )
+
+ /** Arbitrary instance of Function5 */
+ implicit def arbFunction5[T1,T2,T3,T4,T5,R](implicit a: Arbitrary[R]
+ ): Arbitrary[(T1,T2,T3,T4,T5) => R] = Arbitrary(
+ for(r <- arbitrary[R]) yield (t1: T1, t2: T2, t3: T3, t4: T4, t5: T5) => r
+ )
+
+
+ // Tuples //
+
+ /** Arbitrary instance of 2-tuple */
+ implicit def arbTuple2[T1,T2](implicit
+ a1: Arbitrary[T1], a2: Arbitrary[T2]
+ ): Arbitrary[(T1,T2)] =
+ Arbitrary(for {
+ t1 <- arbitrary[T1]
+ t2 <- arbitrary[T2]
+ } yield (t1,t2))
+
+ /** Arbitrary instance of 3-tuple */
+ implicit def arbTuple3[T1,T2,T3](implicit
+ a1: Arbitrary[T1], a2: Arbitrary[T2], a3: Arbitrary[T3]
+ ): Arbitrary[(T1,T2,T3)] =
+ Arbitrary(for {
+ t1 <- arbitrary[T1]
+ t2 <- arbitrary[T2]
+ t3 <- arbitrary[T3]
+ } yield (t1,t2,t3))
+
+ /** Arbitrary instance of 4-tuple */
+ implicit def arbTuple4[T1,T2,T3,T4](implicit
+ a1: Arbitrary[T1], a2: Arbitrary[T2], a3: Arbitrary[T3], a4: Arbitrary[T4]
+ ): Arbitrary[(T1,T2,T3,T4)] =
+ Arbitrary(for {
+ t1 <- arbitrary[T1]
+ t2 <- arbitrary[T2]
+ t3 <- arbitrary[T3]
+ t4 <- arbitrary[T4]
+ } yield (t1,t2,t3,t4))
+
+ /** Arbitrary instance of 5-tuple */
+ implicit def arbTuple5[T1,T2,T3,T4,T5](implicit
+ a1: Arbitrary[T1], a2: Arbitrary[T2], a3: Arbitrary[T3], a4: Arbitrary[T4],
+ a5: Arbitrary[T5]
+ ): Arbitrary[(T1,T2,T3,T4,T5)] =
+ Arbitrary(for {
+ t1 <- arbitrary[T1]
+ t2 <- arbitrary[T2]
+ t3 <- arbitrary[T3]
+ t4 <- arbitrary[T4]
+ t5 <- arbitrary[T5]
+ } yield (t1,t2,t3,t4,t5))
+
+ /** Arbitrary instance of 6-tuple */
+ implicit def arbTuple6[T1,T2,T3,T4,T5,T6](implicit
+ a1: Arbitrary[T1], a2: Arbitrary[T2], a3: Arbitrary[T3], a4: Arbitrary[T4],
+ a5: Arbitrary[T5], a6: Arbitrary[T6]
+ ): Arbitrary[(T1,T2,T3,T4,T5,T6)] =
+ Arbitrary(for {
+ t1 <- arbitrary[T1]
+ t2 <- arbitrary[T2]
+ t3 <- arbitrary[T3]
+ t4 <- arbitrary[T4]
+ t5 <- arbitrary[T5]
+ t6 <- arbitrary[T6]
+ } yield (t1,t2,t3,t4,t5,t6))
+
+ /** Arbitrary instance of 7-tuple */
+ implicit def arbTuple7[T1,T2,T3,T4,T5,T6,T7](implicit
+ a1: Arbitrary[T1], a2: Arbitrary[T2], a3: Arbitrary[T3], a4: Arbitrary[T4],
+ a5: Arbitrary[T5], a6: Arbitrary[T6], a7: Arbitrary[T7]
+ ): Arbitrary[(T1,T2,T3,T4,T5,T6,T7)] =
+ Arbitrary(for {
+ t1 <- arbitrary[T1]
+ t2 <- arbitrary[T2]
+ t3 <- arbitrary[T3]
+ t4 <- arbitrary[T4]
+ t5 <- arbitrary[T5]
+ t6 <- arbitrary[T6]
+ t7 <- arbitrary[T7]
+ } yield (t1,t2,t3,t4,t5,t6,t7))
+
+ /** Arbitrary instance of 8-tuple */
+ implicit def arbTuple8[T1,T2,T3,T4,T5,T6,T7,T8](implicit
+ a1: Arbitrary[T1], a2: Arbitrary[T2], a3: Arbitrary[T3], a4: Arbitrary[T4],
+ a5: Arbitrary[T5], a6: Arbitrary[T6], a7: Arbitrary[T7], a8: Arbitrary[T8]
+ ): Arbitrary[(T1,T2,T3,T4,T5,T6,T7,T8)] =
+ Arbitrary(for {
+ t1 <- arbitrary[T1]
+ t2 <- arbitrary[T2]
+ t3 <- arbitrary[T3]
+ t4 <- arbitrary[T4]
+ t5 <- arbitrary[T5]
+ t6 <- arbitrary[T6]
+ t7 <- arbitrary[T7]
+ t8 <- arbitrary[T8]
+ } yield (t1,t2,t3,t4,t5,t6,t7,t8))
+
+ /** Arbitrary instance of 9-tuple */
+ implicit def arbTuple9[T1,T2,T3,T4,T5,T6,T7,T8,T9](implicit
+ a1: Arbitrary[T1], a2: Arbitrary[T2], a3: Arbitrary[T3], a4: Arbitrary[T4],
+ a5: Arbitrary[T5], a6: Arbitrary[T6], a7: Arbitrary[T7], a8: Arbitrary[T8],
+ a9: Arbitrary[T9]
+ ): Arbitrary[(T1,T2,T3,T4,T5,T6,T7,T8,T9)] =
+ Arbitrary(for {
+ t1 <- arbitrary[T1]
+ t2 <- arbitrary[T2]
+ t3 <- arbitrary[T3]
+ t4 <- arbitrary[T4]
+ t5 <- arbitrary[T5]
+ t6 <- arbitrary[T6]
+ t7 <- arbitrary[T7]
+ t8 <- arbitrary[T8]
+ t9 <- arbitrary[T9]
+ } yield (t1,t2,t3,t4,t5,t6,t7,t8,t9))
+
+}
diff --git a/src/partest-extras/scala/org/scalacheck/Commands.scala b/src/partest-extras/scala/org/scalacheck/Commands.scala
new file mode 100644
index 0000000000..5ff3a397e5
--- /dev/null
+++ b/src/partest-extras/scala/org/scalacheck/Commands.scala
@@ -0,0 +1,146 @@
+/*-------------------------------------------------------------------------*\
+** ScalaCheck **
+** Copyright (c) 2007-2014 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
+
+/** See User Guide for usage examples */
+@deprecated("Will be replaced with a new implementation in 1.12.0", "1.11.4")
+trait Commands extends Prop {
+
+ /** The abstract state data type. This type must be immutable.
+ * The state type that encodes the abstract state. The abstract state
+ * should model all the features we need from the real state, the system
+ * under test. We should leave out all details that aren't needed for
+ * specifying our pre- and postconditions. The state type must be called
+ * State and be immutable. */
+ type State <: AnyRef
+
+ class Binding(private val key: State) {
+ def get: Any = bindings.find(_._1 eq key) match {
+ case None => sys.error("No value bound")
+ case Some(x) => x._2
+ }
+ }
+
+ /** Abstract commands are defined as subtypes of the traits Command or SetCommand.
+ * Each command must have a run method and a method that returns the new abstract
+ * state, as it should look after the command has been run.
+ * A command can also define a precondition that states how the current
+ * abstract state must look if the command should be allowed to run.
+ * Finally, we can also define a postcondition which verifies that the
+ * system under test is in a correct state after the command exectution. */
+ trait Command {
+
+ /** Used internally. */
+ protected[Commands] def run_(s: State) = run(s)
+
+ def run(s: State): Any
+ def nextState(s: State): State
+
+ /** Returns all preconditions merged into a single function */
+ def preCondition: (State => Boolean) =
+ s => preConditions.toList.forall(_.apply(s))
+
+ /** A precondition is a function that
+ * takes the current abstract state as parameter and returns a boolean
+ * that says if the precondition is fulfilled or not. You can add several
+ * conditions to the precondition list */
+ val preConditions = new collection.mutable.ListBuffer[State => Boolean]
+
+ /** Returns all postconditions merged into a single function */
+ def postCondition: (State,State,Any) => Prop =
+ (s0,s1,r) => Prop.all(postConditions.map(_.apply(s0,s1,r)): _*)
+
+ /** A postcondition is a function that
+ * takes three parameters, s0, s1 and r. s0 is the abstract state before
+ * the command was run, s1 is the abstract state after the command was
+ * run, and r is the result from the command's run
+ * method. The postcondition function should return a Boolean (or
+ * a Prop instance) that says if the condition holds or not. You can add several
+ * conditions to the postConditions list. */
+ val postConditions = new collection.mutable.ListBuffer[(State,State,Any) => Prop]
+ }
+
+ /** A command that binds its result for later use */
+ trait SetCommand extends Command {
+ /** Used internally. */
+ protected[Commands] final override def run_(s: State) = {
+ val r = run(s)
+ bindings += ((s,r))
+ r
+ }
+
+ final def nextState(s: State) = nextState(s, new Binding(s))
+ def nextState(s: State, b: Binding): State
+ }
+
+ private case class Cmds(cs: List[Command], ss: List[State]) {
+ override def toString = cs.map(_.toString).mkString(", ")
+ }
+
+ private val bindings = new scala.collection.mutable.ListBuffer[(State,Any)]
+
+ private def initState() = {
+ bindings.clear()
+ initialState()
+ }
+
+ private def genCmds: Gen[Cmds] = {
+ def sizedCmds(s: State, sz: Int): Gen[Cmds] = {
+ if(sz <= 0) Gen.const(Cmds(Nil, Nil)) else for {
+ c <- genCommand(s) suchThat (_.preCondition(s))
+ Cmds(cs,ss) <- sizedCmds(c.nextState(s), sz-1)
+ } yield Cmds(c::cs, s::ss)
+ }
+
+ Gen.sized(sz => sizedCmds(initialState(), sz))
+ }
+
+ private def validCmds(s: State, cs: List[Command]): Option[Cmds] =
+ cs match {
+ case Nil => Some(Cmds(Nil, s::Nil))
+ case c::_ if !c.preCondition(s) => None
+ case c::cmds => for {
+ Cmds(_, ss) <- validCmds(c.nextState(s), cmds)
+ } yield Cmds(cs, s::ss)
+ }
+
+ private def runCommands(cmds: Cmds): Prop = Prop.all {
+ cmds.cs.indices.map { i =>
+ val (c,s) = (cmds.cs(i), cmds.ss(i))
+ c.postCondition(s,c.nextState(s),c.run_(s))
+ } : _*
+ }
+
+ private def commandsProp: Prop = {
+ def shrinkCmds(cmds: Cmds) =
+ Shrink.shrink(cmds.cs)(Shrink.shrinkContainer).flatMap { cs =>
+ validCmds(initialState(), cs).toList
+ }
+
+ Prop.forAllShrink(genCmds label "COMMANDS", shrinkCmds)(runCommands _)
+ }
+
+ def apply(p: Gen.Parameters) = commandsProp(p)
+
+ /** initialState should reset the system under test to a well defined
+ * initial state, and return the abstract version of that state. */
+ def initialState(): State
+
+ /** The command generator. Given an abstract state, the generator
+ * should return a command that is allowed to run in that state. Note that
+ * it is still neccessary to define preconditions on the commands if there
+ * are any. The generator is just giving a hint of which commands that are
+ * suitable for a given state, the preconditions will still be checked before
+ * a command runs. Sometimes you maybe want to adjust the distribution of
+ * your command generator according to the state, or do other calculations
+ * based on the state. */
+ def genCommand(s: State): Gen[Command]
+
+}
diff --git a/src/partest-extras/scala/org/scalacheck/Commands2.scala b/src/partest-extras/scala/org/scalacheck/Commands2.scala
new file mode 100644
index 0000000000..67393a7a70
--- /dev/null
+++ b/src/partest-extras/scala/org/scalacheck/Commands2.scala
@@ -0,0 +1,150 @@
+/*-------------------------------------------------------------------------*\
+** ScalaCheck **
+** Copyright (c) 2007-2014 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
+
+private[scalacheck] trait Commands2 {
+
+ /** The abstract state type. Must be immutable.
+ * The [[Commands2.State]] type should model the state of the system under test (SUT).
+ * It should leave out all details that aren't needed for specifying our
+ * pre- and postconditions. */
+ type State
+
+ /** A type representing one instance of the system under test (SUT).
+ * The [[Commands2.System]] type should be a proxy to the actual system under test.
+ * It is used in the postconditions to verify that the real system
+ * behaves according to specification. It should be possible to have
+ * up to [[Commands2.maxSystemInstanceCount]] co-existing instances of the System
+ * type, and each System instance should be a proxy to a distinct
+ * SUT instance. There should be no dependencies between the System
+ * instances, as they might be used in parallel by ScalaCheck.
+ * System instances are created by [[Commands2.newSystemInstance]] and destroyed by
+ * [[Commands2.destroySystemInstance]]. [[Commands2.newSystemInstance]] and
+ * [[Commands2.destroySystemInstance]] might be called at any time by ScalaCheck,
+ * as long as [[Commands2.maxSystemInstanceCount]] isn't violated. */
+ type System
+
+ /** The maximum number of concurrent [[Commands2.System]] instances allowed to exist. */
+ def maxSystemInstanceCount: Int
+
+ /** Should create a new [[Commands2.System]] instance with an internal state that
+ * corresponds to the provided abstract state instance. The provided state
+ * is guaranteed to fulfill [[Commands2.initialPreCondition]], and
+ * [[Commands2.newSystemInstance]] will never be called if there already
+ * is [[Commands2.maxSystemInstanceCount]] instances of [[Commands2.System]] */
+ def newSystemInstance(state: State): System
+
+ /** Should destroy the given SUT, so that a new [[Commands2.System]] instance can be
+ * created with [[Commands2.newSystemInstance]]. */
+ def destroySystemInstance(system: System): Unit
+
+ /** The precondition for the initial state, when no commands yet have
+ * run. This is used by ScalaCheck when command sequences are shrinked
+ * and the first state might differ from what is returned from
+ * [[Commands2.initialState]]. */
+ def initialPreCondition(state: State): Boolean
+
+ /** A generator that should produce an initial [[Commands2.State]] instance that is
+ * usable by [[Commands2.newSystemInstance]] to create a new system under test.
+ * The state returned by this generator is always checked with the
+ * [[Commands2.initialPreCondition]] method before it is used. */
+ def genInitialState: Gen[State]
+
+ /** A generator that, given the current abstract state, should produce
+ * a suitable Command instance. */
+ def genCommand(state: State): Gen[Command]
+
+ /** Abstract commands are defined as subtypes of the trait [[Commands2.Command]].
+ * Each command must have a run method and a method
+ * that returns the new abstract state, as it is supposed to look after
+ * the command has been run. A command can also define a precondition
+ * that defines how the current abstract state must look if the command
+ * should be allowed to run. Finally, you can also define a postcondition
+ * that verifies that the system under test is in a correct state after
+ * the command execution. */
+ trait Command {
+ /** Runs this command in the system under test,
+ * represented by the provided [[Commands2.System]] instance. This method
+ * can return any value as result. The returned value will be
+ * used by the postcondition to decide if the system behaves as
+ * expected. */
+ def run(state: State, system: System): Any
+
+ /** Returns a new abstract [[Commands2.State]] instance that represents the
+ * state of the system after this command has run. */
+ def nextState(state: State): State
+
+ /** The precondition that decides if this command is allowed to run
+ * when the system under test is in the specified (abstract) state. */
+ def preCondition(state: State): Boolean
+
+ /** The postcondition that decides if the system under test behaved
+ * correctly when the command ran.
+ * @param s0 The abstract state as it looked before this command ran.
+ * @param s1 The abstract state as it looked after this command ran.
+ * @param system The proxy for the system under test. The postcondition
+ * can query the system for its current state, but care must be taken
+ * not to mutate the system under test in any way.
+ * @param result The result returned from the [[Command.run]] method.
+ */
+ def postCondition(s0: State, s1: State, system: System, result: Any): Prop
+ }
+
+/* WIP
+ private case class Cmds(cs: List[Command], ss: List[State]) {
+ override def toString = cs.map(_.toString).mkString(", ")
+ }
+
+ private val bindings = new scala.collection.mutable.ListBuffer[(State,Any)]
+
+ private def initState() = {
+ bindings.clear()
+ initialState()
+ }
+
+ private def genCmds: Gen[Cmds] = {
+ def sizedCmds(s: State, sz: Int): Gen[Cmds] = {
+ if(sz <= 0) Gen.const(Cmds(Nil, Nil)) else for {
+ c <- genCommand(s) suchThat (_.preCondition(s))
+ Cmds(cs,ss) <- sizedCmds(c.nextState(s), sz-1)
+ } yield Cmds(c::cs, s::ss)
+ }
+
+ Gen.sized(sz => sizedCmds(initialState(), sz))
+ }
+
+ private def validCmds(s: State, cs: List[Command]): Option[Cmds] =
+ cs match {
+ case Nil => Some(Cmds(Nil, s::Nil))
+ case c::_ if !c.preCondition(s) => None
+ case c::cmds => for {
+ Cmds(_, ss) <- validCmds(c.nextState(s), cmds)
+ } yield Cmds(cs, s::ss)
+ }
+
+ private def runCommands(cmds: Cmds): Prop = Prop.all {
+ cmds.cs.indices.map { i =>
+ val (c,s) = (cmds.cs(i), cmds.ss(i))
+ c.postCondition(s,c.nextState(s),c.run_(s))
+ } : _*
+ }
+
+ private def commandsProp: Prop = {
+ def shrinkCmds(cmds: Cmds) =
+ Shrink.shrink(cmds.cs)(Shrink.shrinkContainer).flatMap { cs =>
+ validCmds(initialState(), cs).toList
+ }
+
+ Prop.forAllShrink(genCmds label "COMMANDS", shrinkCmds)(runCommands _)
+ }
+
+ def apply(p: Prop.Params) = commandsProp(p)
+*/
+}
diff --git a/src/partest-extras/scala/org/scalacheck/Gen.scala b/src/partest-extras/scala/org/scalacheck/Gen.scala
new file mode 100644
index 0000000000..ba82c9ea95
--- /dev/null
+++ b/src/partest-extras/scala/org/scalacheck/Gen.scala
@@ -0,0 +1,813 @@
+/*-------------------------------------------------------------------------*\
+** ScalaCheck **
+** Copyright (c) 2007-2014 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 util.{Buildable, Buildable2}
+import scala.collection.immutable.TreeMap
+
+sealed trait Gen[+T] {
+
+ //// Private interface ////
+
+ import Gen.{R, r, gen}
+
+ /** Just an alias */
+ private type P = Gen.Parameters
+
+ /** Should be a copy of R.sieve. Used internally in Gen when some generators
+ * with suchThat-claues are created (when R is not available). This method
+ * actually breaks covariance, but since this method will only ever be
+ * called with a value of exactly type T, it is OK. */
+ protected def sieveCopy(x: Any): Boolean = true
+
+ private[scalacheck] def doApply(p: P): R[T]
+
+
+ //// Public interface ////
+
+ /** A class supporting filtered operations. */
+ final class WithFilter(p: T => Boolean) {
+ def map[U](f: T => U): Gen[U] = Gen.this.suchThat(p).map(f)
+ def flatMap[U](f: T => Gen[U]): Gen[U] = Gen.this.suchThat(p).flatMap(f)
+ def withFilter(q: T => Boolean): WithFilter = Gen.this.withFilter(x => p(x) && q(x))
+ }
+
+ /** Evaluate this generator with the given parameters */
+ def apply(p: Gen.Parameters): Option[T] = doApply(p).retrieve
+
+ /** Create a new generator by mapping the result of this generator */
+ def map[U](f: T => U): Gen[U] = gen { p => doApply(p).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 =>
+ doApply(p).flatMap(t => f(t).doApply(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). */
+ def filter(p: T => Boolean): Gen[T] = suchThat(p)
+
+ /** 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). This method is identical to
+ * [Gen.filter]. */
+ def suchThat(f: T => Boolean): Gen[T] = new Gen[T] {
+ def doApply(p: P) = {
+ val res = Gen.this.doApply(p)
+ res.copy(s = { x:T => res.sieve(x) && f(x) })
+ }
+ override def sieveCopy(x: Any) =
+ try Gen.this.sieveCopy(x) && f(x.asInstanceOf[T])
+ catch { case _: java.lang.ClassCastException => false }
+ }
+
+ /** Create a generator that calls this generator repeatedly until
+ * the given condition is fulfilled. The generated value is then
+ * returned. Use this combinator with care, since it may result
+ * in infinite loops. */
+ def retryUntil(p: T => Boolean): Gen[T] = flatMap { t =>
+ if (p(t)) Gen.const(t).suchThat(p) else retryUntil(p)
+ }
+
+ def sample: Option[T] = doApply(Gen.Parameters.default).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 { prms =>
+ (doApply(prms).retrieve, g.doApply(prms).retrieve) match {
+ case (None,None) => Prop.proved(prms)
+ case (Some(r1),Some(r2)) if r1 == r2 => Prop.proved(prms)
+ case _ => Prop.falsified(prms)
+ }
+ }
+
+ def !=[U](g: Gen[U]) = Prop.forAll(this)(r => Prop.forAll(g)(_ != r))
+
+ def !==[U](g: Gen[U]) = Prop { prms =>
+ (doApply(prms).retrieve, g.doApply(prms).retrieve) match {
+ case (None,None) => Prop.falsified(prms)
+ case (Some(r1),Some(r2)) if r1 == r2 => Prop.falsified(prms)
+ case _ => Prop.proved(prms)
+ }
+ }
+
+ /** Put a label on the generator to make test reports clearer */
+ def label(l: String) = new Gen[T] {
+ def doApply(p: P) = {
+ val r = Gen.this.doApply(p)
+ r.copy(l = r.labels + l)
+ }
+ override def sieveCopy(x: Any) = Gen.this.sieveCopy(x)
+ }
+
+ /** Put a label on the generator to make test reports clearer */
+ def :|(l: String) = label(l)
+
+ /** Put a label on the generator to make test reports clearer */
+ def |:(l: String) = label(l)
+
+ /** Put a label on the generator to make test reports clearer */
+ def :|(l: Symbol) = label(l.toString.drop(1))
+
+ /** Put a label on the generator to make test reports clearer */
+ def |:(l: Symbol) = label(l.toString.drop(1))
+
+}
+
+object Gen {
+
+ //// Private interface ////
+
+ import Arbitrary.arbitrary
+
+ /** Just an alias */
+ private type P = Parameters
+
+ private[scalacheck] trait R[+T] {
+ def labels: Set[String] = Set()
+ def sieve[U >: T]: U => Boolean = _ => true
+ protected def result: Option[T]
+
+ def retrieve = result.filter(sieve)
+
+ def copy[U >: T](
+ l: Set[String] = this.labels,
+ s: U => Boolean = this.sieve,
+ r: Option[U] = this.result
+ ): R[U] = new R[U] {
+ override val labels = l
+ override def sieve[V >: U] = { x:Any =>
+ try s(x.asInstanceOf[U])
+ catch { case _: java.lang.ClassCastException => false }
+ }
+ val result = r
+ }
+
+ def map[U](f: T => U): R[U] = r(retrieve.map(f)).copy(l = labels)
+
+ def flatMap[U](f: T => R[U]): R[U] = retrieve match {
+ case None => r(None).copy(l = labels)
+ case Some(t) =>
+ val r = f(t)
+ r.copy(l = labels ++ r.labels)
+ }
+ }
+
+ private[scalacheck] def r[T](r: Option[T]): R[T] = new R[T] {
+ val result = r
+ }
+
+ /** Generator factory method */
+ private[scalacheck] def gen[T](f: P => R[T]): Gen[T] = new Gen[T] {
+ def doApply(p: P) = f(p)
+ }
+
+ //// Public interface ////
+
+ /** Generator parameters, used by [[org.scalacheck.Gen.apply]] */
+ trait Parameters {
+
+ /** 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
+
+ /** Create a copy of this [[Gen.Parameters]] instance with
+ * [[Gen.Parameters.size]] set to the specified value. */
+ def withSize(size: Int): Parameters = cp(size = size)
+
+ /** The random number generator used. */
+ val rng: scala.util.Random
+
+ /** Create a copy of this [[Gen.Parameters]] instance with
+ * [[Gen.Parameters.rng]] set to the specified value. */
+ def withRng(rng: scala.util.Random): Parameters = cp(rng = rng)
+
+ /** Change the size parameter.
+ * @deprecated Use [[Gen.Parameters.withSize]] instead. */
+ @deprecated("Use withSize instead.", "1.11.2")
+ def resize(newSize: Int): Parameters = withSize(newSize)
+
+ // private since we can't guarantee binary compatibility for this one
+ private case class cp(
+ size: Int = size,
+ rng: scala.util.Random = rng
+ ) extends Parameters
+ }
+
+ /** Provides methods for creating [[org.scalacheck.Gen.Parameters]] values */
+ object Parameters {
+ /** Default generator parameters trait. This can be overriden if you
+ * need to tweak the parameters. */
+ trait Default extends Parameters {
+ val size: Int = 100
+ val rng: scala.util.Random = scala.util.Random
+ }
+
+ /** Default generator parameters instance. */
+ val default: Parameters = new Default {}
+ }
+
+ /** A wrapper type for range types */
+ trait Choose[T] {
+ /** 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 {
+
+ private def chLng(l: Long, h: Long)(p: P): R[Long] = {
+ if (h < l) r(None) else {
+ val d = h - l + 1
+ if (d <= 0) {
+ var n = p.rng.nextLong
+ while (n < l || n > h) {
+ n = p.rng.nextLong
+ }
+ r(Some(n))
+ } else {
+ r(Some(l + math.abs(p.rng.nextLong % d)))
+ }
+ }
+ }
+
+ private def chDbl(l: Double, h: Double)(p: P): R[Double] = {
+ val d = h-l
+ if (d < 0 || d > Double.MaxValue) r(None)
+ else if (d == 0) r(Some(l))
+ else r(Some(p.rng.nextDouble * (h-l) + l))
+ }
+
+ implicit val chooseLong: Choose[Long] = new Choose[Long] {
+ def choose(low: Long, high: Long) =
+ gen(chLng(low,high)).suchThat(x => x >= low && x <= high)
+ }
+ implicit val chooseInt: Choose[Int] = new Choose[Int] {
+ def choose(low: Int, high: Int) =
+ gen(chLng(low,high)).map(_.toInt).suchThat(x => x >= low && x <= high)
+ }
+ implicit val chooseByte: Choose[Byte] = new Choose[Byte] {
+ def choose(low: Byte, high: Byte) =
+ gen(chLng(low,high)).map(_.toByte).suchThat(x => x >= low && x <= high)
+ }
+ implicit val chooseShort: Choose[Short] = new Choose[Short] {
+ def choose(low: Short, high: Short) =
+ gen(chLng(low,high)).map(_.toShort).suchThat(x => x >= low && x <= high)
+ }
+ implicit val chooseChar: Choose[Char] = new Choose[Char] {
+ def choose(low: Char, high: Char) =
+ gen(chLng(low,high)).map(_.toChar).suchThat(x => x >= low && x <= high)
+ }
+ implicit val chooseDouble: Choose[Double] = new Choose[Double] {
+ def choose(low: Double, high: Double) =
+ gen(chDbl(low,high)).suchThat(x => x >= low && x <= high)
+ }
+ implicit val chooseFloat: Choose[Float] = new Choose[Float] {
+ def choose(low: Float, high: Float) =
+ gen(chDbl(low,high)).map(_.toFloat).suchThat(x => x >= low && x <= high)
+ }
+
+ /** 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) =
+ c.choose(to(low), to(high)).map(from)
+ }
+ }
+
+
+ //// Various Generator Combinators ////
+
+ /** A generator that always generates the given value */
+ @deprecated("Use Gen.const instead", "1.11.0")
+ def value[T](x: T): Gen[T] = const(x)
+
+ /** A generator that always generates the given value */
+ implicit def const[T](x: T): Gen[T] = gen(_ => r(Some(x))).suchThat(_ == x)
+
+ /** A generator that never generates a value */
+ def fail[T]: Gen[T] = gen(_ => r(None)).suchThat(_ => false)
+
+ /** A generator that generates a random value in the given (inclusive)
+ * range. If the range is invalid, the generator will not generate
+ * any value. */
+ 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[T]] = {
+ val g = gen { p =>
+ gs.foldLeft(r(Some(collection.immutable.Vector.empty[T]))) {
+ case (rs,g) => g.doApply(p).flatMap(r => rs.map(_ :+ r))
+ }
+ }
+ g.map(b.fromIterable)
+ }
+
+ /** Sequences generators. If any of the given generators fails, the
+ * resulting generator will also fail. */
+ def sequence[C[_,_],T,U](gs: Traversable[Gen[(T,U)]])(implicit b: Buildable2[T,U,C]): Gen[C[T,U]] = {
+ val g = gen { p =>
+ gs.foldLeft(r(Some(collection.immutable.Vector.empty[(T,U)]))) {
+ case (rs,g) => g.doApply(p).flatMap(r => rs.map(_ :+ r))
+ }
+ }
+ g.map(b.fromIterable)
+ }
+
+ /** 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 => h.doApply(p) }
+ }
+
+ /** Wraps a generator for later evaluation. The given parameter is
+ * evaluated each time the wrapper generator is evaluated. */
+ def wrap[T](g: => Gen[T]) = gen { p => g.doApply(p) }
+
+ /** Creates a generator that can access its generation parameters */
+ def parameterized[T](f: Parameters => Gen[T]) = gen { p => f(p).doApply(p) }
+
+ /** Creates a generator that can access its generation size */
+ def sized[T](f: Int => Gen[T]) = gen { p => f(p.size).doApply(p) }
+
+ /** 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 => g.doApply(p.withSize(s)))
+
+ /** Picks a random value from a list */
+ def oneOf[T](xs: Seq[T]): Gen[T] =
+ choose(0, xs.size-1).map(xs(_)).suchThat(xs.contains)
+
+ /** 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(gs(_)).suchThat(x => gs.exists(_.sieveCopy(x)))
+ }
+
+ /** Makes a generator result optional. Either `Some(T)` or `None` will be provided. */
+ def option[T](g: Gen[T]): Gen[Option[T]] =
+ oneOf[Option[T]](g.map(Some.apply), None)
+
+ /** Chooses one of the given generators with a weighted random distribution */
+ def frequency[T](gs: (Int,Gen[T])*): Gen[T] = {
+ gs.filter(_._1 > 0) match {
+ case Nil => fail
+ case filtered =>
+ var tot = 0l
+ val tree: TreeMap[Long, Gen[T]] = {
+ val builder = TreeMap.newBuilder[Long, Gen[T]]
+ filtered.foreach {
+ case (f, v) =>
+ tot += f
+ builder.+=((tot, v))
+ }
+ builder.result()
+ }
+ choose(1L, tot).flatMap(r => tree.from(r).head._2).suchThat { x =>
+ gs.exists(_._2.sieveCopy(x))
+ }
+ }
+ }
+
+ /** 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 containerOfN[C[_],T](n: Int, g: Gen[T])(implicit
+ evb: Buildable[T,C], evt: C[T] => Traversable[T]
+ ): Gen[C[T]] =
+ sequence[C,T](Traversable.fill(n)(g)) suchThat { c =>
+ // TODO: Can we guarantee c.size == n (See issue #89)?
+ c.forall(g.sieveCopy)
+ }
+
+ /** 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 containerOf[C[_],T](g: Gen[T])(implicit
+ evb: Buildable[T,C], evt: C[T] => Traversable[T]
+ ): Gen[C[T]] =
+ sized(s => choose(0,s).flatMap(containerOfN[C,T](_,g))) suchThat { c =>
+ c.forall(g.sieveCopy)
+ }
+
+ /** 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 nonEmptyContainerOf[C[_],T](g: Gen[T])(implicit
+ evb: Buildable[T,C], evt: C[T] => Traversable[T]
+ ): Gen[C[T]] =
+ sized(s => choose(1,s).flatMap(containerOfN[C,T](_,g))) suchThat { c =>
+ c.size > 0 && c.forall(g.sieveCopy)
+ }
+
+ /** 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. */
+ @deprecated("Use Gen.nonEmptyContainerOf instead", "1.11.0")
+ def containerOf1[C[_],T](g: Gen[T])(implicit
+ evb: Buildable[T,C], evt: C[T] => Traversable[T]
+ ): Gen[C[T]] = nonEmptyContainerOf[C,T](g)
+
+ /** Generates a container of any Traversable type for which there exists an
+ * implicit [[org.scalacheck.util.Buildable2]] instance. The elements in
+ * 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 containerOfN[C[_,_],T,U](n: Int, g: Gen[(T,U)])(implicit
+ evb: Buildable2[T,U,C], evt: C[T,U] => Traversable[(T,U)]
+ ): Gen[C[T,U]] =
+ sequence[C,T,U](Traversable.fill(n)(g)).suchThat { c =>
+ // TODO: Can we guarantee c.size == n (See issue #89)?
+ c.forall(g.sieveCopy)
+ }
+
+ /** Generates a container of any Traversable type for which there exists
+ * an implicit <code>Buildable2</code> 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 containerOf[C[_,_],T,U](g: Gen[(T,U)])(implicit
+ evb: Buildable2[T,U,C], evt: C[T,U] => Traversable[(T,U)]
+ ): Gen[C[T,U]] =
+ sized(s => choose(0,s).flatMap(containerOfN[C,T,U](_,g))) suchThat { c =>
+ c.forall(g.sieveCopy)
+ }
+
+ /** Generates a non-empty container of any type for which there exists an
+ * implicit <code>Buildable2</code> 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 nonEmptyContainerOf[C[_,_],T,U](g: Gen[(T,U)])(implicit
+ evb: Buildable2[T,U,C], evt: C[T,U] => Traversable[(T,U)]
+ ): Gen[C[T,U]] =
+ sized(s => choose(1,s).flatMap(containerOfN[C,T,U](_,g))) suchThat { c =>
+ c.size > 0 && c.forall(g.sieveCopy)
+ }
+
+ /** 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]) = containerOf[List,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]) = nonEmptyContainerOf[List,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)`. */
+ @deprecated("Use Gen.nonEmptyListOf instead", "1.11.0")
+ def listOf1[T](g: => Gen[T]) = nonEmptyListOf[T](g)
+
+ /** Generates a list of the given length. This method is equal to calling
+ * `containerOfN[List,T](n,g)`. */
+ def listOfN[T](n: Int, g: Gen[T]) = containerOfN[List,T](n,g)
+
+ /** Generates a map of random length. The maximum length depends on the
+ * size parameter. This method is equal to calling
+ * <code>containerOf[Map,T,U](g)</code>. */
+ def mapOf[T,U](g: => Gen[(T,U)]) = containerOf[Map,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
+ * <code>nonEmptyContainerOf[Map,T,U](g)</code>. */
+ def nonEmptyMap[T,U](g: => Gen[(T,U)]) = nonEmptyContainerOf[Map,T,U](g)
+
+ /** Generates a map of with at least the given number of elements. This method
+ * is equal to calling <code>containerOfN[Map,T,U](n,g)</code>. */
+ def mapOfN[T,U](n: Int, g: Gen[(T,U)]) = containerOfN[Map,T,U](n,g)
+
+ /** 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 a given number of elements from a list, randomly */
+ def pick[T](n: Int, l: Iterable[T]): Gen[Seq[T]] =
+ if(n > l.size || n < 0) fail
+ else (gen { p =>
+ val b = new collection.mutable.ListBuffer[T]
+ b ++= l
+ while(b.length > n) b.remove(choose(0, b.length-1).doApply(p).retrieve.get)
+ r(Some(b))
+ }).suchThat(_.forall(x => l.exists(x == _)))
+
+ /** A generator that picks a given number of elements from a list, randomly */
+ def pick[T](n: Int, g1: Gen[T], g2: Gen[T], gn: Gen[T]*): Gen[Seq[T]] = {
+ val gs = g1 +: g2 +: gn
+ pick(n, 0 until gs.size).flatMap(idxs =>
+ sequence[List,T](idxs.toList.map(gs(_)))
+ ).suchThat(_.forall(x => gs.exists(_.sieveCopy(x))))
+ }
+
+
+ //// Character Generators ////
+
+ /** Generates a numerical character */
+ def numChar: Gen[Char] = choose(48.toChar, 57.toChar)
+
+ /** Generates an upper-case alpha character */
+ def alphaUpperChar: Gen[Char] = choose(65.toChar, 90.toChar)
+
+ /** Generates a lower-case alpha character */
+ def alphaLowerChar: Gen[Char] = choose(97.toChar, 122.toChar)
+
+ /** Generates an alpha character */
+ def alphaChar = frequency((1,alphaUpperChar), (9,alphaLowerChar))
+
+ /** Generates an alphanumerical character */
+ def alphaNumChar = frequency((1,numChar), (9,alphaChar))
+
+
+ //// String Generators ////
+
+ /** Generates a string that starts with a lower-case alpha character,
+ * and only contains alphanumerical characters */
+ def identifier: Gen[String] = (for {
+ c <- alphaLowerChar
+ cs <- listOf(alphaNumChar)
+ } yield (c::cs).mkString).suchThat(_.forall(c => c.isLetter || c.isDigit))
+
+ /** Generates a string of alpha characters */
+ def alphaStr: Gen[String] =
+ listOf(alphaChar).map(_.mkString).suchThat(_.forall(_.isLetter))
+
+ /** Generates a string of digits */
+ def numStr: Gen[String] =
+ listOf(numChar).map(_.mkString).suchThat(_.forall(_.isDigit))
+
+
+ //// Number Generators ////
+
+ /** 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._
+ sized(max => c.choose(one, fromInt(max)))
+ }
+
+ /** 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] = {
+ import num._
+ sized(max => c.choose(-fromInt(max), -one))
+ }
+
+ /** 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 allGens = basicsAndSpecials ++ List(
+ (basicsAndSpecials.length, c.choose(minT, maxT))
+ )
+ frequency(allGens: _*)
+ }
+
+ /** Generates a version 4 (random) UUID. */
+ lazy val uuid: Gen[java.util.UUID] = for {
+ l1 <- Gen.choose(Long.MinValue, Long.MaxValue)
+ l2 <- Gen.choose(Long.MinValue, Long.MaxValue)
+ y <- Gen.oneOf('8', '9', 'a', 'b')
+ } yield java.util.UUID.fromString(
+ new java.util.UUID(l1,l2).toString.updated(14, '4').updated(19, y)
+ )
+
+ /** Combines the given generators into one generator that produces a
+ * tuple of their generated values. */
+ def zip[T1,T2](g1: Gen[T1], g2: Gen[T2]): Gen[(T1,T2)] = {
+ val g = for {
+ t1 <- g1; t2 <- g2
+ } yield (t1,t2)
+ g.suchThat { case (t1,t2) => g1.sieveCopy(t1) && g2.sieveCopy(t2) }
+ }
+
+ /** Combines the given generators into one generator that produces a
+ * tuple of their generated values. */
+ def zip[T1,T2,T3](g1: Gen[T1], g2: Gen[T2], g3: Gen[T3]): Gen[(T1,T2,T3)] = {
+ val g0 = zip(g1,g2)
+ val g = for {
+ (t1,t2) <- g0; t3 <- g3
+ } yield (t1,t2,t3)
+ g.suchThat { case (t1,t2,t3) => g0.sieveCopy(t1,t2) && g3.sieveCopy(t3) }
+ }
+
+ /** Combines the given generators into one generator that produces a
+ * tuple of their generated values. */
+ def zip[T1,T2,T3,T4](g1: Gen[T1], g2: Gen[T2], g3: Gen[T3], g4: Gen[T4]
+ ): Gen[(T1,T2,T3,T4)] = {
+ val g0 = zip(g1,g2,g3)
+ val g = for {
+ (t1,t2,t3) <- g0; t4 <- g4
+ } yield (t1,t2,t3,t4)
+ g.suchThat { case (t1,t2,t3,t4) => g0.sieveCopy(t1,t2,t3) && g4.sieveCopy(t4) }
+ }
+
+ /** Combines the given generators into one generator that produces a
+ * tuple of their generated values. */
+ def zip[T1,T2,T3,T4,T5](g1: Gen[T1], g2: Gen[T2], g3: Gen[T3], g4: Gen[T4],
+ g5: Gen[T5]
+ ): Gen[(T1,T2,T3,T4,T5)] = {
+ val g0 = zip(g1,g2,g3,g4)
+ val g = for {
+ (t1,t2,t3,t4) <- g0; t5 <- g5
+ } yield (t1,t2,t3,t4,t5)
+ g.suchThat { case (t1,t2,t3,t4,t5) =>
+ g0.sieveCopy(t1,t2,t3,t4) && g5.sieveCopy(t5)
+ }
+ }
+
+ /** Combines the given generators into one generator that produces a
+ * tuple of their generated values. */
+ def zip[T1,T2,T3,T4,T5,T6](g1: Gen[T1], g2: Gen[T2], g3: Gen[T3], g4: Gen[T4],
+ g5: Gen[T5], g6: Gen[T6]
+ ): Gen[(T1,T2,T3,T4,T5,T6)] = {
+ val g0 = zip(g1,g2,g3,g4,g5)
+ val g = for {
+ (t1,t2,t3,t4,t5) <- g0; t6 <- g6
+ } yield (t1,t2,t3,t4,t5,t6)
+ g.suchThat { case (t1,t2,t3,t4,t5,t6) =>
+ g0.sieveCopy(t1,t2,t3,t4,t5) && g6.sieveCopy(t6)
+ }
+ }
+
+ /** Combines the given generators into one generator that produces a
+ * tuple of their generated values. */
+ def zip[T1,T2,T3,T4,T5,T6,T7](g1: Gen[T1], g2: Gen[T2], g3: Gen[T3],
+ g4: Gen[T4], g5: Gen[T5], g6: Gen[T6], g7: Gen[T7]
+ ): Gen[(T1,T2,T3,T4,T5,T6,T7)] = {
+ val g0 = zip(g1,g2,g3,g4,g5,g6)
+ val g = for {
+ (t1,t2,t3,t4,t5,t6) <- g0; t7 <- g7
+ } yield (t1,t2,t3,t4,t5,t6,t7)
+ g.suchThat { case (t1,t2,t3,t4,t5,t6,t7) =>
+ g0.sieveCopy(t1,t2,t3,t4,t5,t6) && g7.sieveCopy(t7)
+ }
+ }
+
+ /** Combines the given generators into one generator that produces a
+ * tuple of their generated values. */
+ def zip[T1,T2,T3,T4,T5,T6,T7,T8](g1: Gen[T1], g2: Gen[T2], g3: Gen[T3],
+ g4: Gen[T4], g5: Gen[T5], g6: Gen[T6], g7: Gen[T7], g8: Gen[T8]
+ ): Gen[(T1,T2,T3,T4,T5,T6,T7,T8)] = {
+ val g0 = zip(g1,g2,g3,g4,g5,g6,g7)
+ val g = for {
+ (t1,t2,t3,t4,t5,t6,t7) <- g0; t8 <- g8
+ } yield (t1,t2,t3,t4,t5,t6,t7,t8)
+ g.suchThat { case (t1,t2,t3,t4,t5,t6,t7,t8) =>
+ g0.sieveCopy(t1,t2,t3,t4,t5,t6,t7) && g8.sieveCopy(t8)
+ }
+ }
+
+ /** Combines the given generators into one generator that produces a
+ * tuple of their generated values. */
+ def zip[T1,T2,T3,T4,T5,T6,T7,T8,T9](g1: Gen[T1], g2: Gen[T2], g3: Gen[T3],
+ g4: Gen[T4], g5: Gen[T5], g6: Gen[T6], g7: Gen[T7], g8: Gen[T8], g9: Gen[T9]
+ ): Gen[(T1,T2,T3,T4,T5,T6,T7,T8,T9)] = {
+ val g0 = zip(g1,g2,g3,g4,g5,g6,g7,g8)
+ val g = for {
+ (t1,t2,t3,t4,t5,t6,t7,t8) <- g0; t9 <- g9
+ } yield (t1,t2,t3,t4,t5,t6,t7,t8,t9)
+ g.suchThat { case (t1,t2,t3,t4,t5,t6,t7,t8,t9) =>
+ g0.sieveCopy(t1,t2,t3,t4,t5,t6,t7,t8) && g9.sieveCopy(t9)
+ }
+ }
+
+ /** 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,R](f: T => R)(implicit a: Arbitrary[T]): Gen[R] =
+ arbitrary[T] map f
+
+ /** Takes a function and returns a generator that generates arbitrary
+ * results of that function by feeding it with arbitrarily generated input
+ * parameters. */
+ def resultOf[T1,T2,R](f: (T1,T2) => R)(implicit
+ a1: Arbitrary[T1], a2: Arbitrary[T2]
+ ): Gen[R] = arbitrary[T1] flatMap { t => resultOf(f(t, _:T2)) }
+
+ /** Takes a function and returns a generator that generates arbitrary
+ * results of that function by feeding it with arbitrarily generated input
+ * parameters. */
+ def resultOf[T1,T2,T3,R](f: (T1,T2,T3) => R)(implicit
+ a1: Arbitrary[T1], a2: Arbitrary[T2], a3: Arbitrary[T3]
+ ): Gen[R] = arbitrary[T1] flatMap { t => resultOf(f(t, _:T2, _:T3)) }
+
+ /** Takes a function and returns a generator that generates arbitrary
+ * results of that function by feeding it with arbitrarily generated input
+ * parameters. */
+ def resultOf[T1,T2,T3,T4,R](f: (T1,T2,T3,T4) => R)(implicit
+ a1: Arbitrary[T1], a2: Arbitrary[T2], a3: Arbitrary[T3], a4: Arbitrary[T4]
+ ): Gen[R] = arbitrary[T1] flatMap {
+ t => resultOf(f(t, _:T2, _:T3, _:T4))
+ }
+
+ /** Takes a function and returns a generator that generates arbitrary
+ * results of that function by feeding it with arbitrarily generated input
+ * parameters. */
+ def resultOf[T1,T2,T3,T4,T5,R](f: (T1,T2,T3,T4,T5) => R)(implicit
+ a1: Arbitrary[T1], a2: Arbitrary[T2], a3: Arbitrary[T3], a4: Arbitrary[T4],
+ a5: Arbitrary[T5]
+ ): Gen[R] = arbitrary[T1] flatMap {
+ t => resultOf(f(t, _:T2, _:T3, _:T4, _:T5))
+ }
+
+ /** Takes a function and returns a generator that generates arbitrary
+ * results of that function by feeding it with arbitrarily generated input
+ * parameters. */
+ def resultOf[T1,T2,T3,T4,T5,T6,R](
+ f: (T1,T2,T3,T4,T5,T6) => R)(implicit
+ a1: Arbitrary[T1], a2: Arbitrary[T2], a3: Arbitrary[T3],
+ a4: Arbitrary[T4], a5: Arbitrary[T5], a6: Arbitrary[T6]
+ ): Gen[R] = arbitrary[T1] flatMap {
+ t => resultOf(f(t, _:T2, _:T3, _:T4, _:T5, _:T6))
+ }
+
+ /** Takes a function and returns a generator that generates arbitrary
+ * results of that function by feeding it with arbitrarily generated input
+ * parameters. */
+ def resultOf[T1,T2,T3,T4,T5,T6,T7,R](
+ f: (T1,T2,T3,T4,T5,T6,T7) => R)(implicit
+ a1: Arbitrary[T1], a2: Arbitrary[T2], a3: Arbitrary[T3],
+ a4: Arbitrary[T4], a5: Arbitrary[T5], a6: Arbitrary[T6], a7: Arbitrary[T7]
+ ): Gen[R] = arbitrary[T1] flatMap {
+ t => resultOf(f(t, _:T2, _:T3, _:T4, _:T5, _:T6, _:T7))
+ }
+
+ /** Takes a function and returns a generator that generates arbitrary
+ * results of that function by feeding it with arbitrarily generated input
+ * parameters. */
+ def resultOf[T1,T2,T3,T4,T5,T6,T7,T8,R](
+ f: (T1,T2,T3,T4,T5,T6,T7,T8) => R)(implicit
+ a1: Arbitrary[T1], a2: Arbitrary[T2], a3: Arbitrary[T3], a4: Arbitrary[T4],
+ a5: Arbitrary[T5], a6: Arbitrary[T6], a7: Arbitrary[T7], a8: Arbitrary[T8]
+ ): Gen[R] = arbitrary[T1] flatMap {
+ t => resultOf(f(t, _:T2, _:T3, _:T4, _:T5, _:T6, _:T7, _:T8))
+ }
+
+ /** Takes a function and returns a generator that generates arbitrary
+ * results of that function by feeding it with arbitrarily generated input
+ * parameters. */
+ def resultOf[T1,T2,T3,T4,T5,T6,T7,T8,T9,R](
+ f: (T1,T2,T3,T4,T5,T6,T7,T8,T9) => R)(implicit
+ a1: Arbitrary[T1], a2: Arbitrary[T2], a3: Arbitrary[T3], a4: Arbitrary[T4],
+ a5: Arbitrary[T5], a6: Arbitrary[T6], a7: Arbitrary[T7], a8: Arbitrary[T8],
+ a9: Arbitrary[T9]
+ ): Gen[R] = arbitrary[T1] flatMap {
+ t => resultOf(f(t, _:T2, _:T3, _:T4, _:T5, _:T6, _:T7, _:T8, _:T9))
+ }
+}
diff --git a/src/partest-extras/scala/org/scalacheck/Prop.scala b/src/partest-extras/scala/org/scalacheck/Prop.scala
new file mode 100644
index 0000000000..6b607002fd
--- /dev/null
+++ b/src/partest-extras/scala/org/scalacheck/Prop.scala
@@ -0,0 +1,953 @@
+/*-------------------------------------------------------------------------*\
+** ScalaCheck **
+** Copyright (c) 2007-2014 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 util.{Pretty, FreqMap, Buildable, ConsoleReporter}
+import scala.annotation.tailrec
+
+trait Prop {
+
+ import Prop.{Result, Proof, True, False, Exception, Undecided,
+ provedToTrue, secure, mergeRes}
+ import Gen.Parameters
+
+ def apply(prms: Parameters): Result
+
+ def map(f: Result => Result): Prop = Prop(prms => f(this(prms)))
+
+ def flatMap(f: Result => Prop): Prop = Prop(prms => f(this(prms))(prms))
+
+ // TODO In 1.12.0, make p call-by-name, and remove the calls to secure()
+ // in the methods that use combine()
+ 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. */
+ 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 and reports the
+ * result on the console. 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. 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 checks this property with specified minimal
+ * number of successful test and the given testing parameters, and
+ * reports the result on the console. If you need to get the results
+ * from the test use the `check` methods in [[org.scalacheck.Test]]
+ * instead. */
+ @deprecated("Use check(prms.withMinSuccessfulTests(n)) instead", "1.11.2")
+ def check(minSuccessfulTests: Int, prms: Test.Parameters): Unit = check(
+ prms.withMinSuccessfulTests(minSuccessfulTests)
+ )
+
+ /** Convenience method that checks this property with specified minimal
+ * number of successful test and reports the result on the console.
+ * If you need to get the results from the test use
+ * the `check` methods in [[org.scalacheck.Test]] instead. */
+ @deprecated("Use check(_.withMinSuccessfulTests(n)) instead", "1.11.2")
+ def check(minSuccessfulTests: Int): Unit = check(
+ _.withMinSuccessfulTests(minSuccessfulTests)
+ )
+
+ /** The logic for main, separated out to make it easier to
+ * avoid System.exit calls. Returns exit code.
+ */
+ def mainRunner(args: Array[String]): Int = {
+ Test.parseParams(args) match {
+ case Some(params) =>
+ if (Test.check(params, this).passed) 0
+ else 1
+ case None =>
+ println("Incorrect options")
+ -1
+ }
+ }
+
+ /** Whether main should call System.exit with an exit code.
+ * Defaults to true; override to change. */
+ def mainCallsExit = true
+
+ /** Convenience method that makes it possible to use this property
+ * as an application that checks itself on execution */
+ def main(args: Array[String]): Unit = {
+ val code = mainRunner(args)
+ if (mainCallsExit && code != 0)
+ System exit code
+ }
+
+ /** 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(secure(p))(_ && _)
+
+ /** Returns a new property that holds if either this
+ * or the given property (or both) hold. */
+ def ||(p: => Prop) = combine(secure(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(secure(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.toString.drop(1))
+
+ /** Put a label on the property to make test reports clearer */
+ def |:(l: Symbol) = label(l.toString.drop(1))
+
+}
+
+object Prop {
+
+ import Gen.{value, 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
+ )
+
+ object Result {
+ @deprecated("Will be removed in 1.12.0", "1.11.2")
+ def apply(st: Status): Result = Result(status = st)
+ @deprecated("Will be removed in 1.12.0", "1.11.2")
+ def merge(x: Result, y: Result, status: Status) = mergeRes(x,y,status)
+ }
+
+ 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
+ case (_, False) => r
+ }
+
+ 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 Prop {
+ def apply(prms: Parameters) = 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 */
+ def secure[P <% Prop](p: => P): Prop =
+ try (p: Prop) catch { case e: Throwable => exception(e) }
+
+ /** 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)
+ 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)
+ 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)
+ 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 = new Prop {
+ @tailrec private 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)
+ }
+ }
+ def apply(prms: Parameters) = attempt(prms, System.currentTimeMillis + maximumMs)
+ }
+}
diff --git a/src/partest-extras/scala/org/scalacheck/Properties.scala b/src/partest-extras/scala/org/scalacheck/Properties.scala
new file mode 100644
index 0000000000..abaac61c7f
--- /dev/null
+++ b/src/partest-extras/scala/org/scalacheck/Properties.scala
@@ -0,0 +1,82 @@
+/*-------------------------------------------------------------------------*\
+** ScalaCheck **
+** Copyright (c) 2007-2014 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 util.ConsoleReporter
+
+/** Represents a collection of properties, with convenient methods
+ * for checking all properties at once. This class is itself a property, which
+ * holds if and only if all of the contained properties hold.
+ * <p>Properties are added in the following way:</p>
+ *
+ * {{{
+ * object MyProps extends Properties("MyProps") {
+ * property("myProp1") = forAll { (n:Int, m:Int) =>
+ * n+m == m+n
+ * }
+ * }
+ * }}}
+ */
+class Properties(val name: String) extends Prop {
+
+ private val props = new scala.collection.mutable.ListBuffer[(String,Prop)]
+
+ /** Returns one property which holds if and only if all of the
+ * properties in this property collection hold */
+ private def oneProperty: Prop = Prop.all((properties map (_._2)):_*)
+
+ /** Returns all properties of this collection in a list of name/property
+ * pairs. */
+ def properties: Seq[(String,Prop)] = props
+
+ def apply(p: Gen.Parameters) = oneProperty(p)
+
+ /** Convenience method that checks the properties with the given parameters
+ * and reports the result on the console. If you need to get the results
+ * from the test use the `check` methods in [[org.scalacheck.Test]]
+ * instead. */
+ override def check(prms: Test.Parameters): Unit = Test.checkProperties(
+ prms.withTestCallback(ConsoleReporter(1) chain prms.testCallback), this
+ )
+
+ /** Convenience method that checks the properties and reports the
+ * result on the console. If you need to get the results from the test use
+ * the `check` methods in [[org.scalacheck.Test]] instead. */
+ override def check: Unit = check(Test.Parameters.default)
+
+ /** The logic for main, separated out to make it easier to
+ * avoid System.exit calls. Returns exit code.
+ */
+ override def mainRunner(args: Array[String]): Int = {
+ Test.parseParams(args) match {
+ case Some(params) =>
+ val res = Test.checkProperties(params, this)
+ val failed = res.filter(!_._2.passed).size
+ failed
+ case None =>
+ println("Incorrect options")
+ -1
+ }
+ }
+
+ /** Adds all properties from another property collection to this one. */
+ def include(ps: Properties) = for((n,p) <- ps.properties) property(n) = p
+
+ /** Used for specifying properties. Usage:
+ * {{{
+ * property("myProp") = ...
+ * }}}
+ */
+ class PropertySpecifier() {
+ def update(propName: String, p: Prop) = props += ((name+"."+propName, p))
+ }
+
+ lazy val property = new PropertySpecifier()
+}
diff --git a/src/partest-extras/scala/org/scalacheck/ScalaCheckFramework.scala b/src/partest-extras/scala/org/scalacheck/ScalaCheckFramework.scala
new file mode 100644
index 0000000000..754b67764d
--- /dev/null
+++ b/src/partest-extras/scala/org/scalacheck/ScalaCheckFramework.scala
@@ -0,0 +1,93 @@
+/*-------------------------------------------------------------------------*\
+** ScalaCheck **
+** Copyright (c) 2007-2014 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 util.Pretty
+
+import org.scalatools.testing._
+
+class ScalaCheckFramework extends Framework {
+
+ private def mkFP(mod: Boolean, cname: String) =
+ new SubclassFingerprint {
+ val superClassName = cname
+ val isModule = mod
+ }
+
+ val name = "ScalaCheck"
+
+ val tests = Array[Fingerprint](
+ mkFP(true, "org.scalacheck.Properties"),
+ mkFP(false, "org.scalacheck.Prop"),
+ mkFP(false, "org.scalacheck.Properties"),
+ mkFP(true, "org.scalacheck.Prop")
+ )
+
+ def testRunner(loader: ClassLoader, loggers: Array[Logger]) = new Runner2 {
+
+ private def asEvent(nr: (String, Test.Result)) = nr match {
+ case (n: String, r: Test.Result) => new Event {
+ val testName = n
+ val description = n
+ val result = r.status match {
+ case Test.Passed => Result.Success
+ case _:Test.Proved => Result.Success
+ case _:Test.Failed => Result.Failure
+ case Test.Exhausted => Result.Skipped
+ case _:Test.PropException | _:Test.GenException => Result.Error
+ }
+ val error = r.status match {
+ case Test.PropException(_, e, _) => e
+ case _:Test.Failed => new Exception(Pretty.pretty(r,Pretty.Params(0)))
+ case _ => null
+ }
+ }
+ }
+
+ def run(testClassName: String, fingerprint: Fingerprint, handler: EventHandler, args: Array[String]) {
+
+ val testCallback = new Test.TestCallback {
+ override def onPropEval(n: String, w: Int, s: Int, d: Int) = {}
+
+ override def onTestResult(n: String, r: Test.Result) = {
+ for (l <- loggers) {
+ import Pretty._
+ val verbosityOpts = Set("-verbosity", "-v")
+ val verbosity = args.grouped(2).filter(twos => verbosityOpts(twos.head)).toSeq.headOption.map(_.last).map(_.toInt).getOrElse(0)
+ l.info(
+ (if (r.passed) "+ " else "! ") + n + ": " + pretty(r, Params(verbosity))
+ )
+ }
+ handler.handle(asEvent((n,r)))
+ }
+ }
+
+ val prms = Test.parseParams(args) match {
+ case Some(params) =>
+ params.withTestCallback(testCallback).withCustomClassLoader(Some(loader))
+ // TODO: Maybe handle this a bit better than throwing exception?
+ case None => throw new Exception()
+ }
+
+ fingerprint match {
+ case fp: SubclassFingerprint =>
+ val obj =
+ if(fp.isModule) Class.forName(testClassName + "$", true, loader).getField("MODULE$").get(null)
+ else Class.forName(testClassName, true, loader).newInstance
+ if(obj.isInstanceOf[Properties])
+ Test.checkProperties(prms, obj.asInstanceOf[Properties])
+ else
+ handler.handle(asEvent((testClassName, Test.check(prms, obj.asInstanceOf[Prop]))))
+ }
+ }
+
+ }
+
+}
diff --git a/src/partest-extras/scala/org/scalacheck/Shrink.scala b/src/partest-extras/scala/org/scalacheck/Shrink.scala
new file mode 100644
index 0000000000..8ec28f4c4b
--- /dev/null
+++ b/src/partest-extras/scala/org/scalacheck/Shrink.scala
@@ -0,0 +1,215 @@
+/*-------------------------------------------------------------------------*\
+** ScalaCheck **
+** Copyright (c) 2007-2014 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 util.{Buildable,Buildable2}
+import scala.collection.{ JavaConversions => jcl }
+
+sealed abstract class Shrink[T] {
+ def shrink(x: T): Stream[T]
+}
+
+object Shrink {
+
+ import Stream.{cons, empty}
+ import scala.collection._
+ import java.util.ArrayList
+
+ /** Interleaves two streams */
+ private def interleave[T](xs: Stream[T], ys: Stream[T]): Stream[T] =
+ if(xs.isEmpty) ys
+ else if(ys.isEmpty) xs
+ else cons(xs.head, cons(ys.head, interleave(xs.tail, ys.tail)))
+
+ /** Shrink instance factory */
+ def apply[T](s: T => Stream[T]): Shrink[T] = new Shrink[T] {
+ override def shrink(x: T) = s(x)
+ }
+
+ /** Shrink a value */
+ def shrink[T](x: T)(implicit s: Shrink[T]): Stream[T] = s.shrink(x)
+
+ /** Default shrink instance */
+ implicit def shrinkAny[T]: Shrink[T] = Shrink(x => empty)
+
+ /** Shrink instance of container */
+ implicit def shrinkContainer[C[_],T](implicit v: C[T] => Traversable[T], s: Shrink[T],
+ b: Buildable[T,C]
+ ): Shrink[C[T]] = Shrink { xs: C[T] =>
+ val ys = v(xs)
+ val zs = ys.toStream
+ removeChunks(ys.size,zs).append(shrinkOne(zs)).map(b.fromIterable)
+ }
+
+ /** Shrink instance of container2 */
+ implicit def shrinkContainer2[C[_,_],T,U](implicit v: C[T,U] => Traversable[(T,U)], s: Shrink[(T,U)],
+ b: Buildable2[T,U,C]
+ ): Shrink[C[T,U]] = Shrink { xs: C[T,U] =>
+ val ys = v(xs)
+ val zs = ys.toStream
+ removeChunks(ys.size,zs).append(shrinkOne(zs)).map(b.fromIterable)
+ }
+
+ private def removeChunks[T](n: Int, xs: Stream[T]): Stream[Stream[T]] =
+ if (xs.isEmpty) empty
+ else if (xs.tail.isEmpty) cons(empty, empty)
+ else {
+ val n1 = n / 2
+ val n2 = n - n1
+ lazy val xs1 = xs.take(n1)
+ lazy val xs2 = xs.drop(n1)
+ lazy val xs3 =
+ for (ys1 <- removeChunks(n1, xs1) if !ys1.isEmpty) yield ys1 append xs2
+ lazy val xs4 =
+ for (ys2 <- removeChunks(n2, xs2) if !ys2.isEmpty) yield xs1 append ys2
+
+ cons(xs1, cons(xs2, interleave(xs3, xs4)))
+ }
+
+ private def shrinkOne[T : Shrink](zs: Stream[T]): Stream[Stream[T]] =
+ if (zs.isEmpty) empty
+ else {
+ val x = zs.head
+ val xs = zs.tail
+ shrink(x).map(cons(_,xs)).append(shrinkOne(xs).map(cons(x,_)))
+ }
+
+ /** Shrink instance of integer */
+ implicit lazy val shrinkInt: Shrink[Int] = Shrink { n =>
+
+ def halfs(n: Int): Stream[Int] =
+ if(n == 0) empty else cons(n, halfs(n/2))
+
+ if(n == 0) empty else {
+ val ns = halfs(n/2).map(n - _)
+ cons(0, interleave(ns, ns.map(-1 * _)))
+ }
+ }
+
+ /** Shrink instance of String */
+ implicit lazy val shrinkString: Shrink[String] = Shrink { s =>
+ shrinkContainer[List,Char].shrink(s.toList).map(_.mkString)
+ }
+
+ /** Shrink instance of Option */
+ implicit def shrinkOption[T : Shrink]: Shrink[Option[T]] = Shrink {
+ case None => empty
+ case Some(x) => cons(None, for(y <- shrink(x)) yield Some(y))
+ }
+
+ /** Shrink instance of 2-tuple */
+ implicit def shrinkTuple2[
+ T1:Shrink, T2:Shrink
+ ]: Shrink[(T1,T2)] =
+ Shrink { case (t1,t2) =>
+ shrink(t1).map((_,t2)) append
+ shrink(t2).map((t1,_))
+ }
+
+ /** Shrink instance of 3-tuple */
+ implicit def shrinkTuple3[
+ T1:Shrink, T2:Shrink, T3:Shrink
+ ]: Shrink[(T1,T2,T3)] =
+ Shrink { case (t1,t2,t3) =>
+ shrink(t1).map((_, t2, t3)) append
+ shrink(t2).map((t1, _, t3)) append
+ shrink(t3).map((t1, t2, _))
+ }
+
+ /** Shrink instance of 4-tuple */
+ implicit def shrinkTuple4[
+ T1:Shrink, T2:Shrink, T3:Shrink, T4:Shrink
+ ]: Shrink[(T1,T2,T3,T4)] =
+ Shrink { case (t1,t2,t3,t4) =>
+ shrink(t1).map((_, t2, t3, t4)) append
+ shrink(t2).map((t1, _, t3, t4)) append
+ shrink(t3).map((t1, t2, _, t4)) append
+ shrink(t4).map((t1, t2, t3, _))
+ }
+
+ /** Shrink instance of 5-tuple */
+ implicit def shrinkTuple5[
+ T1:Shrink, T2:Shrink, T3:Shrink, T4:Shrink, T5:Shrink
+ ]: Shrink[(T1,T2,T3,T4,T5)] =
+ Shrink { case (t1,t2,t3,t4,t5) =>
+ shrink(t1).map((_, t2, t3, t4, t5)) append
+ shrink(t2).map((t1, _, t3, t4, t5)) append
+ shrink(t3).map((t1, t2, _, t4, t5)) append
+ shrink(t4).map((t1, t2, t3, _, t5)) append
+ shrink(t5).map((t1, t2, t3, t4, _))
+ }
+
+ /** Shrink instance of 6-tuple */
+ implicit def shrinkTuple6[
+ T1:Shrink, T2:Shrink, T3:Shrink, T4:Shrink, T5:Shrink, T6:Shrink
+ ]: Shrink[(T1,T2,T3,T4,T5,T6)] =
+ Shrink { case (t1,t2,t3,t4,t5,t6) =>
+ shrink(t1).map((_, t2, t3, t4, t5, t6)) append
+ shrink(t2).map((t1, _, t3, t4, t5, t6)) append
+ shrink(t3).map((t1, t2, _, t4, t5, t6)) append
+ shrink(t4).map((t1, t2, t3, _, t5, t6)) append
+ shrink(t5).map((t1, t2, t3, t4, _, t6)) append
+ shrink(t6).map((t1, t2, t3, t4, t5, _))
+ }
+
+ /** Shrink instance of 7-tuple */
+ implicit def shrinkTuple7[
+ T1:Shrink, T2:Shrink, T3:Shrink, T4:Shrink, T5:Shrink, T6:Shrink, T7:Shrink
+ ]: Shrink[(T1,T2,T3,T4,T5,T6,T7)] =
+ Shrink { case (t1,t2,t3,t4,t5,t6,t7) =>
+ shrink(t1).map((_, t2, t3, t4, t5, t6, t7)) append
+ shrink(t2).map((t1, _, t3, t4, t5, t6, t7)) append
+ shrink(t3).map((t1, t2, _, t4, t5, t6, t7)) append
+ shrink(t4).map((t1, t2, t3, _, t5, t6, t7)) append
+ shrink(t5).map((t1, t2, t3, t4, _, t6, t7)) append
+ shrink(t6).map((t1, t2, t3, t4, t5, _, t7)) append
+ shrink(t7).map((t1, t2, t3, t4, t5, t6, _))
+ }
+
+ /** Shrink instance of 8-tuple */
+ implicit def shrinkTuple8[
+ T1:Shrink, T2:Shrink, T3:Shrink, T4:Shrink, T5:Shrink, T6:Shrink,
+ T7:Shrink, T8:Shrink
+ ]: Shrink[(T1,T2,T3,T4,T5,T6,T7,T8)] =
+ Shrink { case (t1,t2,t3,t4,t5,t6,t7,t8) =>
+ shrink(t1).map((_, t2, t3, t4, t5, t6, t7, t8)) append
+ shrink(t2).map((t1, _, t3, t4, t5, t6, t7, t8)) append
+ shrink(t3).map((t1, t2, _, t4, t5, t6, t7, t8)) append
+ shrink(t4).map((t1, t2, t3, _, t5, t6, t7, t8)) append
+ shrink(t5).map((t1, t2, t3, t4, _, t6, t7, t8)) append
+ shrink(t6).map((t1, t2, t3, t4, t5, _, t7, t8)) append
+ shrink(t7).map((t1, t2, t3, t4, t5, t6, _, t8)) append
+ shrink(t8).map((t1, t2, t3, t4, t5, t6, t7, _))
+ }
+
+ /** Shrink instance of 9-tuple */
+ implicit def shrinkTuple9[
+ T1:Shrink, T2:Shrink, T3:Shrink, T4:Shrink, T5:Shrink, T6:Shrink,
+ T7:Shrink, T8:Shrink, T9:Shrink
+ ]: Shrink[(T1,T2,T3,T4,T5,T6,T7,T8,T9)] =
+ Shrink { case (t1,t2,t3,t4,t5,t6,t7,t8,t9) =>
+ shrink(t1).map((_, t2, t3, t4, t5, t6, t7, t8, t9)) append
+ shrink(t2).map((t1, _, t3, t4, t5, t6, t7, t8, t9)) append
+ shrink(t3).map((t1, t2, _, t4, t5, t6, t7, t8, t9)) append
+ shrink(t4).map((t1, t2, t3, _, t5, t6, t7, t8, t9)) append
+ shrink(t5).map((t1, t2, t3, t4, _, t6, t7, t8, t9)) append
+ shrink(t6).map((t1, t2, t3, t4, t5, _, t7, t8, t9)) append
+ shrink(t7).map((t1, t2, t3, t4, t5, t6, _, t8, t9)) append
+ shrink(t8).map((t1, t2, t3, t4, t5, t6, t7, _, t9)) append
+ shrink(t9).map((t1, t2, t3, t4, t5, t6, t7, t8, _))
+ }
+
+ /** Transform a Shrink[T] to a Shrink[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 st: Shrink[T]): Shrink[U] = Shrink[U] { u: U ⇒
+ st.shrink(to(u)).map(from)
+ }
+}
diff --git a/src/partest-extras/scala/org/scalacheck/Test.scala b/src/partest-extras/scala/org/scalacheck/Test.scala
new file mode 100644
index 0000000000..9a9c62b93f
--- /dev/null
+++ b/src/partest-extras/scala/org/scalacheck/Test.scala
@@ -0,0 +1,372 @@
+/*-------------------------------------------------------------------------*\
+** ScalaCheck **
+** Copyright (c) 2007-2014 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 Prop.Arg
+
+object Test {
+
+ import util.{FreqMap, ConsoleReporter}
+
+ /** Test parameters used by the check methods. Default
+ * parameters are defined by [[Test.Parameters.Default]]. */
+ trait Parameters {
+ /** The minimum number of tests that must succeed for ScalaCheck to
+ * consider a property passed. */
+ val minSuccessfulTests: Int
+
+ /** Create a copy of this [[Test.Parameters]] instance with
+ * [[Test.Parameters.minSuccessfulTests]] set to the specified value. */
+ def withMinSuccessfulTests(minSuccessfulTests: Int): Parameters = cp(
+ minSuccessfulTests = minSuccessfulTests
+ )
+
+ /** The starting size given as parameter to the generators. */
+ val minSize: Int
+
+ /** Create a copy of this [[Test.Parameters]] instance with
+ * [[Test.Parameters.minSize]] set to the specified value. */
+ def withMinSize(minSize: Int): Parameters = cp(
+ minSize = minSize
+ )
+
+ /** The maximum size given as parameter to the generators. */
+ val maxSize: Int
+
+ /** Create a copy of this [[Test.Parameters]] instance with
+ * [[Test.Parameters.maxSize]] set to the specified value. */
+ def withMaxSize(maxSize: Int): Parameters = cp(
+ maxSize = maxSize
+ )
+
+ /** The random number generator used. */
+ val rng: scala.util.Random
+
+ /** Create a copy of this [[Test.Parameters]] instance with
+ * [[Test.Parameters.rng]] set to the specified value. */
+ def withRng(rng: scala.util.Random): Parameters = cp(
+ rng = rng
+ )
+
+ /** The number of tests to run in parallel. */
+ val workers: Int
+
+ /** Create a copy of this [[Test.Parameters]] instance with
+ * [[Test.Parameters.workers]] set to the specified value. */
+ def withWorkers(workers: Int): Parameters = cp(
+ workers = workers
+ )
+
+ /** A callback that ScalaCheck calls each time a test is executed. */
+ val testCallback: TestCallback
+
+ /** Create a copy of this [[Test.Parameters]] instance with
+ * [[Test.Parameters.testCallback]] set to the specified value. */
+ def withTestCallback(testCallback: TestCallback): Parameters = cp(
+ testCallback = testCallback
+ )
+
+ /** The maximum ratio between discarded and passed tests allowed before
+ * ScalaCheck gives up and discards the property. At least
+ * `minSuccesfulTests` will always be run, though. */
+ val maxDiscardRatio: Float
+
+ /** Create a copy of this [[Test.Parameters]] instance with
+ * [[Test.Parameters.maxDiscardRatio]] set to the specified value. */
+ def withMaxDiscardRatio(maxDiscardRatio: Float): Parameters = cp(
+ maxDiscardRatio = maxDiscardRatio
+ )
+
+ /** A custom class loader that should be used during test execution. */
+ val customClassLoader: Option[ClassLoader]
+
+ /** Create a copy of this [[Test.Parameters]] instance with
+ * [[Test.Parameters.customClassLoader]] set to the specified value. */
+ def withCustomClassLoader(customClassLoader: Option[ClassLoader]
+ ): Parameters = cp(
+ customClassLoader = customClassLoader
+ )
+
+ // private since we can't guarantee binary compatibility for this one
+ private case class cp(
+ minSuccessfulTests: Int = minSuccessfulTests,
+ minSize: Int = minSize,
+ maxSize: Int = maxSize,
+ rng: scala.util.Random = rng,
+ workers: Int = workers,
+ testCallback: TestCallback = testCallback,
+ maxDiscardRatio: Float = maxDiscardRatio,
+ customClassLoader: Option[ClassLoader] = customClassLoader
+ ) extends Parameters
+ }
+
+ /** Test parameters used by the check methods. Default
+ * parameters are defined by [[Test.Parameters.Default]]. */
+ object Parameters {
+ /** Default test parameters trait. This can be overriden if you need to
+ * tweak the parameters:
+ *
+ * {{{
+ * val myParams = new Parameters.Default {
+ * override val minSuccesfulTests = 600
+ * override val maxDiscardRatio = 8
+ * }
+ * }}}
+ *
+ * You can also use the withXXX-methods in
+ * [[org.scalacheck.Test.Parameters]] to achieve
+ * the same thing:
+ *
+ * {{{
+ * val myParams = Parameters.default
+ * .withMinSuccessfulTests(600)
+ * .withMaxDiscardRatio(8)
+ * }}} */
+ trait Default extends Parameters {
+ val minSuccessfulTests: Int = 100
+ val minSize: Int = 0
+ val maxSize: Int = Gen.Parameters.default.size
+ val rng: scala.util.Random = Gen.Parameters.default.rng
+ val workers: Int = 1
+ val testCallback: TestCallback = new TestCallback {}
+ val maxDiscardRatio: Float = 5
+ val customClassLoader: Option[ClassLoader] = None
+ }
+
+ /** Default test parameters instance. */
+ val default: Parameters = new Default {}
+
+ /** Verbose console reporter test parameters instance. */
+ val defaultVerbose: Parameters = new Default {
+ override val testCallback = ConsoleReporter(2)
+ }
+ }
+
+ /** Test statistics */
+ case class Result(
+ status: Status,
+ succeeded: Int,
+ discarded: Int,
+ freqMap: FreqMap[Set[Any]],
+ time: Long = 0
+ ) {
+ def passed = status match {
+ case Passed => true
+ case Proved(_) => true
+ case _ => false
+ }
+ }
+
+ /** Test status */
+ sealed trait Status
+
+ /** ScalaCheck found enough cases for which the property holds, so the
+ * property is considered correct. (It is not proved correct, though). */
+ case object Passed extends Status
+
+ /** ScalaCheck managed to prove the property correct */
+ sealed case class Proved(args: List[Arg[Any]]) extends Status
+
+ /** The property was proved wrong with the given concrete arguments. */
+ sealed case class Failed(args: List[Arg[Any]], labels: Set[String]) extends Status
+
+ /** The property test was exhausted, it wasn't possible to generate enough
+ * concrete arguments satisfying the preconditions to get enough passing
+ * property evaluations. */
+ case object Exhausted extends Status
+
+ /** An exception was raised when trying to evaluate the property with the
+ * given concrete arguments. If an exception was raised before or during
+ * argument generation, the argument list will be empty. */
+ sealed case class PropException(args: List[Arg[Any]], e: Throwable,
+ labels: Set[String]) extends Status
+
+ /** An exception was raised when trying to generate concrete arguments
+ * for evaluating the property.
+ * @deprecated Not used. The type PropException is used for all exceptions.
+ */
+ @deprecated("Not used. The type PropException is used for all exceptions.", "1.11.2")
+ sealed case class GenException(e: Throwable) extends Status
+
+ trait TestCallback { self =>
+ /** Called each time a property is evaluated */
+ def onPropEval(name: String, threadIdx: Int, succeeded: Int,
+ discarded: Int): Unit = ()
+
+ /** Called whenever a property has finished testing */
+ def onTestResult(name: String, result: Result): Unit = ()
+
+ def chain(testCallback: TestCallback) = new TestCallback {
+ override def onPropEval(name: String, threadIdx: Int,
+ succeeded: Int, discarded: Int
+ ): Unit = {
+ self.onPropEval(name,threadIdx,succeeded,discarded)
+ testCallback.onPropEval(name,threadIdx,succeeded,discarded)
+ }
+
+ override def onTestResult(name: String, result: Result): Unit = {
+ self.onTestResult(name,result)
+ testCallback.onTestResult(name,result)
+ }
+ }
+ }
+
+ private def assertParams(prms: Parameters) = {
+ import prms._
+ if(
+ minSuccessfulTests <= 0 ||
+ maxDiscardRatio <= 0 ||
+ minSize < 0 ||
+ maxSize < minSize ||
+ workers <= 0
+ ) throw new IllegalArgumentException("Invalid test parameters")
+ }
+
+ private def secure[T](x: => T): Either[T,Throwable] =
+ try { Left(x) } catch { case e: Throwable => Right(e) }
+
+ def parseParams(args: Array[String]): Option[Parameters] = {
+ var params = Parameters.default
+ args.grouped(2).filter(_.size > 1).map(a => (a(0), a(1))).foreach {
+ case ("-workers" | "-w", n) => params = params.withWorkers(n.toInt)
+ case ("-minSize" | "-n", n) => params = params.withMinSize(n.toInt)
+ case ("-maxSize" | "-x", n) => params = params.withMaxSize(n.toInt)
+ case ("-verbosity" | "-v", n) => params = params.withTestCallback(ConsoleReporter(n.toInt))
+ case ("-maxDiscardRatio" | "-r", n) => params = params.withMaxDiscardRatio(n.toFloat)
+ case ("-minSuccessfulTests" | "-s", n) => params = params.withMinSuccessfulTests(n.toInt)
+ case _ =>
+ }
+ Some(params)
+ }
+
+ /** Tests a property with parameters that are calculated by applying
+ * the provided function to [[Test.Parameters.default]].
+ * Example use:
+ *
+ * {{{
+ * Test.check(p) { _.
+ * withMinSuccessfulTests(80000).
+ * withWorkers(4)
+ * }
+ * }}}
+ */
+ def check(p: Prop)(f: Parameters => Parameters): Result =
+ check(f(Parameters.default), p)
+
+ /** Tests a property with the given testing parameters, and returns
+ * the test results. */
+ def check(params: Parameters, p: Prop): Result = {
+ import params._
+ import concurrent._
+
+ assertParams(params)
+ if(workers > 1) {
+ assert(!p.isInstanceOf[Commands], "Commands cannot be checked multi-threaded")
+ }
+
+ val iterations = math.ceil(minSuccessfulTests / (workers: Double))
+ val sizeStep = (maxSize-minSize) / (iterations*workers)
+ var stop = false
+ val genPrms = new Gen.Parameters.Default { override val rng = params.rng }
+ val tp = java.util.concurrent.Executors.newFixedThreadPool(workers)
+ implicit val ec = ExecutionContext.fromExecutor(tp)
+
+ def workerFun(workerIdx: Int): Result = {
+ var n = 0 // passed tests
+ var d = 0 // discarded tests
+ var res: Result = null
+ var fm = FreqMap.empty[Set[Any]]
+ while(!stop && res == null && n < iterations) {
+ val size = (minSize: Double) + (sizeStep * (workerIdx + (workers*(n+d))))
+ val propRes = p(genPrms.withSize(size.round.toInt))
+ fm = if(propRes.collected.isEmpty) fm else fm + propRes.collected
+ propRes.status match {
+ case Prop.Undecided =>
+ d += 1
+ testCallback.onPropEval("", workerIdx, n, d)
+ // The below condition is kind of hacky. We have to have
+ // some margin, otherwise workers might stop testing too
+ // early because they have been exhausted, but the overall
+ // test has not.
+ if (n+d > minSuccessfulTests && 1+workers*maxDiscardRatio*n < d)
+ res = Result(Exhausted, n, d, fm)
+ case Prop.True =>
+ n += 1
+ testCallback.onPropEval("", workerIdx, n, d)
+ case Prop.Proof =>
+ n += 1
+ res = Result(Proved(propRes.args), n, d, fm)
+ stop = true
+ case Prop.False =>
+ res = Result(Failed(propRes.args,propRes.labels), n, d, fm)
+ stop = true
+ case Prop.Exception(e) =>
+ res = Result(PropException(propRes.args,e,propRes.labels), n, d, fm)
+ stop = true
+ }
+ }
+ if (res == null) {
+ if (maxDiscardRatio*n > d) Result(Passed, n, d, fm)
+ else Result(Exhausted, n, d, fm)
+ } else res
+ }
+
+ def mergeResults(r1: Result, r2: Result): Result = {
+ val Result(st1, s1, d1, fm1, _) = r1
+ val Result(st2, s2, d2, fm2, _) = r2
+ if (st1 != Passed && st1 != Exhausted)
+ Result(st1, s1+s2, d1+d2, fm1++fm2, 0)
+ else if (st2 != Passed && st2 != Exhausted)
+ Result(st2, s1+s2, d1+d2, fm1++fm2, 0)
+ else {
+ if (s1+s2 >= minSuccessfulTests && maxDiscardRatio*(s1+s2) >= (d1+d2))
+ Result(Passed, s1+s2, d1+d2, fm1++fm2, 0)
+ else
+ Result(Exhausted, s1+s2, d1+d2, fm1++fm2, 0)
+ }
+ }
+
+ try {
+ val start = System.currentTimeMillis
+ val r =
+ if(workers < 2) workerFun(0)
+ else {
+ val fs = List.range(0,workers) map (idx => Future {
+ params.customClassLoader.map(
+ Thread.currentThread.setContextClassLoader(_)
+ )
+ blocking { workerFun(idx) }
+ })
+ val zeroRes = Result(Passed,0,0,FreqMap.empty[Set[Any]],0)
+ val res = Future.fold(fs)(zeroRes)(mergeResults)
+ Await.result(res, concurrent.duration.Duration.Inf)
+ }
+ val timedRes = r.copy(time = System.currentTimeMillis-start)
+ params.testCallback.onTestResult("", timedRes)
+ timedRes
+ } finally {
+ stop = true
+ tp.shutdown()
+ }
+ }
+
+ /** Check a set of properties. */
+ def checkProperties(prms: Parameters, ps: Properties): Seq[(String,Result)] =
+ ps.properties.map { case (name,p) =>
+ val testCallback = new TestCallback {
+ override def onPropEval(n: String, t: Int, s: Int, d: Int) =
+ prms.testCallback.onPropEval(name,t,s,d)
+ override def onTestResult(n: String, r: Result) =
+ prms.testCallback.onTestResult(name,r)
+ }
+ val res = check(prms.withTestCallback(testCallback), p)
+ (name,res)
+ }
+}
diff --git a/src/partest-extras/scala/org/scalacheck/util/Buildable.scala b/src/partest-extras/scala/org/scalacheck/util/Buildable.scala
new file mode 100644
index 0000000000..6a275b05c2
--- /dev/null
+++ b/src/partest-extras/scala/org/scalacheck/util/Buildable.scala
@@ -0,0 +1,77 @@
+/*-------------------------------------------------------------------------*\
+** ScalaCheck **
+** Copyright (c) 2007-2014 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.util
+
+import collection._
+
+trait Buildable[T,C[_]] {
+ def builder: mutable.Builder[T,C[T]]
+ def fromIterable(it: Traversable[T]): C[T] = {
+ val b = builder
+ b ++= it
+ b.result()
+ }
+}
+
+trait Buildable2[T,U,C[_,_]] {
+ def builder: mutable.Builder[(T,U),C[T,U]]
+ def fromIterable(it: Traversable[(T,U)]): C[T,U] = {
+ val b = builder
+ b ++= it
+ b.result()
+ }
+}
+
+object Buildable {
+ import generic.CanBuildFrom
+
+ implicit def buildableCanBuildFrom[T, C[_]](implicit c: CanBuildFrom[C[_], T, C[T]]) =
+ new Buildable[T, C] {
+ def builder = c.apply
+ }
+
+ import java.util.ArrayList
+ implicit def buildableArrayList[T] = new Buildable[T,ArrayList] {
+ def builder = new mutable.Builder[T,ArrayList[T]] {
+ val al = new ArrayList[T]
+ def +=(x: T) = {
+ al.add(x)
+ this
+ }
+ def clear() = al.clear()
+ def result() = al
+ }
+ }
+
+}
+
+object Buildable2 {
+
+ implicit def buildableMutableMap[T,U] = new Buildable2[T,U,mutable.Map] {
+ def builder = mutable.Map.newBuilder
+ }
+
+ implicit def buildableImmutableMap[T,U] = new Buildable2[T,U,immutable.Map] {
+ def builder = immutable.Map.newBuilder
+ }
+
+ implicit def buildableMap[T,U] = new Buildable2[T,U,Map] {
+ def builder = Map.newBuilder
+ }
+
+ implicit def buildableImmutableSortedMap[T: Ordering, U] = new Buildable2[T,U,immutable.SortedMap] {
+ def builder = immutable.SortedMap.newBuilder
+ }
+
+ implicit def buildableSortedMap[T: Ordering, U] = new Buildable2[T,U,SortedMap] {
+ def builder = SortedMap.newBuilder
+ }
+
+}
diff --git a/src/partest-extras/scala/org/scalacheck/util/CmdLineParser.scala b/src/partest-extras/scala/org/scalacheck/util/CmdLineParser.scala
new file mode 100644
index 0000000000..45b6ac6948
--- /dev/null
+++ b/src/partest-extras/scala/org/scalacheck/util/CmdLineParser.scala
@@ -0,0 +1,41 @@
+/*-------------------------------------------------------------------------*\
+** ScalaCheck **
+** Copyright (c) 2007-2014 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.util
+
+import scala.collection.Set
+import org.scalacheck.Test
+
+private[scalacheck] trait CmdLineParser {
+
+ type Elem = String
+
+ trait Opt[+T] {
+ val default: T
+ val names: Set[String]
+ val help: String
+ }
+ trait Flag extends Opt[Unit]
+ trait IntOpt extends Opt[Int]
+ trait FloatOpt extends Opt[Float]
+ trait StrOpt extends Opt[String]
+
+ class OptMap {
+ private val opts = new collection.mutable.HashMap[Opt[_], Any]
+ def apply(flag: Flag): Boolean = opts.contains(flag)
+ def apply[T](opt: Opt[T]): T = opts.get(opt) match {
+ case None => opt.default
+ case Some(v) => v.asInstanceOf[T]
+ }
+ def update[T](opt: Opt[T], optVal: T) = opts.update(opt, optVal)
+ }
+
+ val opts: Set[Opt[_]]
+
+}
diff --git a/src/partest-extras/scala/org/scalacheck/util/ConsoleReporter.scala b/src/partest-extras/scala/org/scalacheck/util/ConsoleReporter.scala
new file mode 100644
index 0000000000..89858dfb64
--- /dev/null
+++ b/src/partest-extras/scala/org/scalacheck/util/ConsoleReporter.scala
@@ -0,0 +1,44 @@
+/*-------------------------------------------------------------------------*\
+** ScalaCheck **
+** Copyright (c) 2007-2014 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.util
+
+import Pretty.{Params, pretty, format}
+import org.scalacheck.{Prop, Properties, Test}
+
+/** A [[org.scalacheck.Test.TestCallback]] implementation that prints
+ * test results directly to the console. This is the callback used
+ * by ScalaCheck's command line test runner, and when you run [[org.scalacheck.Prop!.check:Unit*]]
+ */
+class ConsoleReporter(val verbosity: Int) extends Test.TestCallback {
+
+ private val prettyPrms = Params(verbosity)
+
+ override def onTestResult(name: String, res: Test.Result) = {
+ if(verbosity > 0) {
+ if(name == "") {
+ val s = (if(res.passed) "+ " else "! ") + pretty(res, prettyPrms)
+ printf("\r%s\n", format(s, "", "", 75))
+ } else {
+ val s = (if(res.passed) "+ " else "! ") + name + ": " +
+ pretty(res, prettyPrms)
+ printf("\r%s\n", format(s, "", "", 75))
+ }
+ }
+ }
+
+}
+
+object ConsoleReporter {
+
+ /** Factory method, creates a ConsoleReporter with the
+ * the given verbosity */
+ def apply(verbosity: Int = 0) = new ConsoleReporter(verbosity)
+
+}
diff --git a/src/partest-extras/scala/org/scalacheck/util/FreqMap.scala b/src/partest-extras/scala/org/scalacheck/util/FreqMap.scala
new file mode 100644
index 0000000000..2a9f36f1e5
--- /dev/null
+++ b/src/partest-extras/scala/org/scalacheck/util/FreqMap.scala
@@ -0,0 +1,65 @@
+/*-------------------------------------------------------------------------*\
+** ScalaCheck **
+** Copyright (c) 2007-2014 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.util
+
+trait FreqMap[T] {
+ protected val underlying: scala.collection.immutable.Map[T,Int]
+ val total: Int
+
+ def +(t: T) = new FreqMap[T] {
+ private val n = FreqMap.this.underlying.get(t) match {
+ case None => 1
+ case Some(n) => n+1
+ }
+ val underlying = FreqMap.this.underlying + (t -> n)
+ val total = FreqMap.this.total + 1
+ }
+
+ def -(t: T) = new FreqMap[T] {
+ val underlying = FreqMap.this.underlying.get(t) match {
+ case None => FreqMap.this.underlying
+ case Some(n) => FreqMap.this.underlying + (t -> (n-1))
+ }
+ val total = FreqMap.this.total + 1
+ }
+
+ def ++(fm: FreqMap[T]) = new FreqMap[T] {
+ private val keys = FreqMap.this.underlying.keySet ++ fm.underlying.keySet
+ private val mappings = keys.toStream.map { x =>
+ (x, fm.getCount(x).getOrElse(0) + FreqMap.this.getCount(x).getOrElse(0))
+ }
+ val underlying = scala.collection.immutable.Map(mappings: _*)
+ val total = FreqMap.this.total + fm.total
+ }
+
+ def --(fm: FreqMap[T]) = new FreqMap[T] {
+ val underlying = FreqMap.this.underlying transform {
+ case (x,n) => n - fm.getCount(x).getOrElse(0)
+ }
+ lazy val total = (0 /: underlying.valuesIterator) (_ + _)
+ }
+
+ def getCount(t: T) = underlying.get(t)
+
+ def getCounts: List[(T,Int)] = underlying.toList.sortBy(-_._2)
+
+ def getRatio(t: T) = for(c <- getCount(t)) yield (c: Float)/total
+
+ def getRatios = for((t,c) <- getCounts) yield (t, (c: Float)/total)
+
+ override def toString = underlying.toString
+}
+
+object FreqMap {
+ def empty[T] = new FreqMap[T] {
+ val underlying = scala.collection.immutable.Map.empty[T,Int]
+ val total = 0
+ }
+}
diff --git a/src/partest-extras/scala/org/scalacheck/util/Pretty.scala b/src/partest-extras/scala/org/scalacheck/util/Pretty.scala
new file mode 100644
index 0000000000..13a1b44b51
--- /dev/null
+++ b/src/partest-extras/scala/org/scalacheck/util/Pretty.scala
@@ -0,0 +1,129 @@
+/*-------------------------------------------------------------------------*\
+** ScalaCheck **
+** Copyright (c) 2007-2014 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.util
+
+import org.scalacheck.Prop.Arg
+import org.scalacheck.Test
+
+import math.round
+
+
+sealed trait Pretty {
+ def apply(prms: Pretty.Params): String
+
+ def map(f: String => String) = Pretty(prms => f(Pretty.this(prms)))
+
+ def flatMap(f: String => Pretty) = Pretty(prms => f(Pretty.this(prms))(prms))
+}
+
+object Pretty {
+
+ case class Params(verbosity: Int)
+
+ val defaultParams = Params(0)
+
+ def apply(f: Params => String) = new Pretty { def apply(p: Params) = f(p) }
+
+ def pretty[T <% Pretty](t: T, prms: Params): String = t(prms)
+
+ def pretty[T <% Pretty](t: T): String = t(defaultParams)
+
+ implicit def strBreak(s1: String) = new {
+ def /(s2: String) = if(s2 == "") s1 else s1+"\n"+s2
+ }
+
+ def pad(s: String, c: Char, length: Int) =
+ if(s.length >= length) s
+ else s + List.fill(length-s.length)(c).mkString
+
+ def break(s: String, lead: String, length: Int): String =
+ if(s.length <= length) s
+ else s.substring(0, length) / break(lead+s.substring(length), lead, length)
+
+ def format(s: String, lead: String, trail: String, width: Int) =
+ s.lines.map(l => break(lead+l+trail, " ", width)).mkString("\n")
+
+ implicit def prettyAny(t: Any) = Pretty { p => t.toString }
+
+ implicit def prettyString(t: String) = Pretty { p => "\""++t++"\"" }
+
+ implicit def prettyList(l: List[Any]) = Pretty { p =>
+ l.map("\""+_+"\"").mkString("List(", ", ", ")")
+ }
+
+ implicit def prettyThrowable(e: Throwable) = Pretty { prms =>
+ val strs = e.getStackTrace.map { st =>
+ import st._
+ getClassName+"."+getMethodName + "("+getFileName+":"+getLineNumber+")"
+ }
+
+ val strs2 =
+ if(prms.verbosity <= 0) Array[String]()
+ else if(prms.verbosity <= 1) strs.take(5)
+ else strs
+
+ e.getClass.getName + ": " + e.getMessage / strs2.mkString("\n")
+ }
+
+ def prettyArgs(args: Seq[Arg[Any]]): Pretty = Pretty { prms =>
+ if(args.isEmpty) "" else {
+ for((a,i) <- args.zipWithIndex) yield {
+ val l = "> "+(if(a.label == "") "ARG_"+i else a.label)
+ val s =
+ if(a.shrinks == 0) ""
+ else "\n"+l+"_ORIGINAL: "+a.prettyOrigArg(prms)
+ l+": "+a.prettyArg(prms)+""+s
+ }
+ }.mkString("\n")
+ }
+
+ implicit def prettyFreqMap(fm: FreqMap[Set[Any]]) = Pretty { prms =>
+ if(fm.total == 0) ""
+ else {
+ "> Collected test data: " / {
+ for {
+ (xs,r) <- fm.getRatios
+ ys = xs - (())
+ if !ys.isEmpty
+ } yield round(r*100)+"% " + ys.mkString(", ")
+ }.mkString("\n")
+ }
+ }
+
+ implicit def prettyTestRes(res: Test.Result) = Pretty { prms =>
+ def labels(ls: collection.immutable.Set[String]) =
+ if(ls.isEmpty) ""
+ else "> Labels of failing property: " / ls.mkString("\n")
+ val s = res.status match {
+ case Test.Proved(args) => "OK, proved property."/prettyArgs(args)(prms)
+ case Test.Passed => "OK, passed "+res.succeeded+" tests."
+ case Test.Failed(args, l) =>
+ "Falsified after "+res.succeeded+" passed tests."/labels(l)/prettyArgs(args)(prms)
+ case Test.Exhausted =>
+ "Gave up after only "+res.succeeded+" passed tests. " +
+ res.discarded+" tests were discarded."
+ case Test.PropException(args,e,l) =>
+ "Exception raised on property evaluation."/labels(l)/prettyArgs(args)(prms)/
+ "> Exception: "+pretty(e,prms)
+ case Test.GenException(e) =>
+ "Exception raised on argument generation."/
+ "> Exception: "+pretty(e,prms)
+ }
+ val t = if(prms.verbosity <= 1) "" else "Elapsed time: "+prettyTime(res.time)
+ s/t/pretty(res.freqMap,prms)
+ }
+
+ def prettyTime(millis: Long): String = {
+ val min = millis/(60*1000)
+ val sec = (millis-(60*1000*min)) / 1000d
+ if(min <= 0) "%.3f sec ".format(sec)
+ else "%d min %.3f sec ".format(min, sec)
+ }
+}