summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAleksandar Pokopec <aleksandar.prokopec@epfl.ch>2010-08-31 09:51:23 +0000
committerAleksandar Pokopec <aleksandar.prokopec@epfl.ch>2010-08-31 09:51:23 +0000
commit9db3f49ff41bb9d037924cd6995ed598c9619650 (patch)
tree27af7284ff60253039fbb01bbf86bc637ef77d57
parent4af85c28c4d3e1bf57f773fe7feb7c03d6afe052 (diff)
downloadscala-9db3f49ff41bb9d037924cd6995ed598c9619650.tar.gz
scala-9db3f49ff41bb9d037924cd6995ed598c9619650.tar.bz2
scala-9db3f49ff41bb9d037924cd6995ed598c9619650.zip
Added scalacheck folder, scalacheck source upda...
Added scalacheck folder, scalacheck source update script, and scalacheck ant tasks. Build process will now generate a scalacheck jar in the build/pack/lib directory. It generates it from the scalacheck source in the src/scalacheck dir. If the source there gets out of date, it is to be updated manually using the tools/updatescalacheck script. Review by phaller.
-rw-r--r--build.xml66
-rw-r--r--src/scalacheck/org/scalacheck/Arbitrary.scala407
-rw-r--r--src/scalacheck/org/scalacheck/Arg.scala20
-rw-r--r--src/scalacheck/org/scalacheck/Commands.scala171
-rw-r--r--src/scalacheck/org/scalacheck/ConsoleReporter.scala89
-rw-r--r--src/scalacheck/org/scalacheck/Gen.scala487
-rw-r--r--src/scalacheck/org/scalacheck/Pretty.scala114
-rw-r--r--src/scalacheck/org/scalacheck/Prop.scala741
-rw-r--r--src/scalacheck/org/scalacheck/Properties.scala76
-rw-r--r--src/scalacheck/org/scalacheck/Shrink.scala208
-rw-r--r--src/scalacheck/org/scalacheck/Test.scala312
-rw-r--r--src/scalacheck/org/scalacheck/util/Buildable.scala63
-rw-r--r--src/scalacheck/org/scalacheck/util/CmdLineParser.scala94
-rw-r--r--src/scalacheck/org/scalacheck/util/FreqMap.scala65
-rw-r--r--src/scalacheck/org/scalacheck/util/StdRand.scala12
-rw-r--r--test/benchmarks/source.list4
-rw-r--r--test/benchmarks/src/scala/collection/parallel/Benchmarking.scala1
-rw-r--r--test/benchmarks/src/scala/collection/parallel/benchmarks/hashtries/ParallelHashTries.scala55
-rw-r--r--test/benchmarks/src/scala/collection/parallel/benchmarks/parallel_array/CountLight.scala1
-rwxr-xr-xtools/updatescalacheck12
20 files changed, 2960 insertions, 38 deletions
diff --git a/build.xml b/build.xml
index d6edf7cab1..570a90d5aa 100644
--- a/build.xml
+++ b/build.xml
@@ -133,7 +133,7 @@ END-USER TARGETS
description="Requires forkjoin library to be rebuilt. Add this target before any other if class file format is incompatible.">
<property name="forkjoin.outdated" value="yes"/>
</target>
-
+
<!-- ===========================================================================
PROPERTIES
============================================================================ -->
@@ -451,7 +451,6 @@ QUICK BUILD (QUICK)
<include name="library/**"/>
<include name="dbc/**"/>
<include name="actors/**"/>
- <!--<include name="parallel-collections/**"/>-->
<include name="continuations/**"/>
<include name="swing/**"/>
</srcfiles>
@@ -496,18 +495,6 @@ QUICK BUILD (QUICK)
<include name="**/*.scala"/>
<compilationpath refid="quick.compilation.path"/>
</scalacfork>
- <!--<scalacfork
- destdir="${build-quick.dir}/classes/library"
- compilerpathref="locker.classpath"
- params="${scalac.args.quick}"
- srcdir="${src.dir}/parallel-collections"
- jvmargs="${scalacfork.jvmargs}">
- <include name="**/*.scala"/>
- <compilationpath>
- <pathelement location="${build-quick.dir}/classes/library"/>
- <pathelement location="${lib.dir}/forkjoin.jar"/>
- </compilationpath>
- </scalacfork>-->
<scalacfork
destdir="${build-quick.dir}/classes/library"
compilerpathref="locker.classpath"
@@ -652,8 +639,23 @@ QUICK BUILD (QUICK)
<touch file="${build-quick.dir}/plugins.complete" verbose="no"/>
<stopwatch name="quick.plugins.timer" action="total"/>
</target>
-
- <target name="quick.pre-scalap" depends="quick.plugins">
+
+ <target name="quick.scalacheck" depends="quick.plugins">
+ <mkdir dir="${build-quick.dir}/classes/scalacheck"/>
+ <scalacfork
+ destdir="${build-quick.dir}/classes/scalacheck"
+ compilerpathref="locker.classpath"
+ params="${scalac.args.all}"
+ srcdir="${src.dir}/scalacheck"
+ jvmargs="${scalacfork.jvmargs}">
+ <include name="**/*.scala"/>
+ <compilationpath>
+ <pathelement location="${build-quick.dir}/classes/library"/>
+ </compilationpath>
+ </scalacfork>
+ </target>
+
+ <target name="quick.pre-scalap" depends="quick.scalacheck">
<uptodate property="quick.scalap.available" targetfile="${build-quick.dir}/scalap.complete">
<srcfiles dir="${src.dir}/scalap"/>
</uptodate>
@@ -784,7 +786,7 @@ QUICK BUILD (QUICK)
<chmod perm="ugo+rx" file="${build-quick.dir}/bin/scalap"/>
<touch file="${build-quick.dir}/bin.complete" verbose="no"/>
</target>
-
+
<target name="quick.done" depends="quick.bin">
<path id="quick.classpath">
<pathelement location="${build-quick.dir}/classes/library"/>
@@ -836,7 +838,7 @@ PACKED QUICK BUILD (PACK)
</fileset>
</jar>
</target>
-
+
<target name="pack.pre-comp" depends="pack.lib">
<uptodate
property="pack.comp.available"
@@ -874,7 +876,13 @@ PACKED QUICK BUILD (PACK)
</jar>
</target>
- <target name="pack.pre-partest" depends="pack.plugins">
+ <target name="pack.scalacheck" depends="pack.plugins">
+ <jar destfile="${build-pack.dir}/lib/scalacheck.jar">
+ <fileset dir="${build-quick.dir}/classes/scalacheck"/>
+ </jar>
+ </target>
+
+ <target name="pack.pre-partest" depends="pack.scalacheck">
<uptodate
property="pack.partest.available"
targetfile="${build-pack.dir}/lib/scala-partest.jar"
@@ -1019,18 +1027,6 @@ BOOTSTRAPPING BUILD (STRAP)
<include name="**/*.scala"/>
<compilationpath refid="strap.compilation.path"/>
</scalacfork>
- <!--<scalacfork
- destdir="${build-strap.dir}/classes/library"
- compilerpathref="pack.classpath"
- params="${scalac.args.all}"
- srcdir="${src.dir}/parallel-collections"
- jvmargs="${scalacfork.jvmargs}">
- <include name="**/*.scala"/>
- <compilationpath>
- <pathelement location="${build-strap.dir}/classes/library"/>
- <pathelement location="${forkjoin.jar}"/>
- </compilationpath>
- </scalacfork>-->
<scalacfork
destdir="${build-strap.dir}/classes/library"
compilerpathref="pack.classpath"
@@ -1286,7 +1282,7 @@ LIBRARIES (MSIL, FJBG maybe later)
<fileset dir="${build-libs.dir}/classes/forkjoin"/>
</jar>
</target>
-
+
<target name="libs.pre-msil" depends="libs.start">
<uptodate property="libs.msil.available" targetfile="${build-libs.dir}/msil.complete">
<srcfiles dir="${src.dir}/msil">
@@ -1367,7 +1363,7 @@ LIBRARIES (MSIL, FJBG maybe later)
<target name="libs.done" depends="libs.msilpack, libs.fjbgpack"/>
<target name="forkjoin.done" depends="libs.forkjoinpack"/>
-
+
<target name="libs.clean" depends="pack.clean">
<delete dir="${build-libs.dir}" includeemptydirs="yes" quiet="yes" failonerror="no"/>
</target>
@@ -1384,7 +1380,6 @@ DOCUMENTATION
<include name="library/**"/>
<include name="dbc/**"/>
<include name="actors/**"/>
- <!--<include name="parallel-collections/**"/>-->
<include name="swing/**"/>
</srcfiles>
</uptodate>
@@ -1402,7 +1397,6 @@ DOCUMENTATION
classpathref="pack.classpath">
<src>
<files includes="${src.dir}/actors"/>
- <!--<files includes="${src.dir}/parallel-collections"/>-->
<files includes="${src.dir}/library/scala"/>
<files includes="${src.dir}/swing"/>
<files includes="${src.dir}/continuations/library"/>
@@ -1641,7 +1635,6 @@ DISTRIBUTION
<jar destfile="${dist.dir}/src/scala-library-src.jar">
<fileset dir="${src.dir}/library"/>
<fileset dir="${src.dir}/actors"/>
- <!--<fileset dir="${src.dir}/parallel-collections"/>-->
<fileset dir="${src.dir}/continuations/library"/>
</jar>
<jar destfile="${dist.dir}/src/scala-dbc-src.jar">
@@ -1730,7 +1723,6 @@ STABLE REFERENCE (STARR)
<jar destfile="${basedir}/lib/scala-library-src.jar">
<fileset dir="${basedir}/src/library"/>
<fileset dir="${basedir}/src/actors"/>
- <!--<fileset dir="${basedir}/src/parallel-collections"/>-->
<fileset dir="${basedir}/src/swing"/>
<fileset dir="${basedir}/src/dbc"/>
</jar>
diff --git a/src/scalacheck/org/scalacheck/Arbitrary.scala b/src/scalacheck/org/scalacheck/Arbitrary.scala
new file mode 100644
index 0000000000..14d2b9b924
--- /dev/null
+++ b/src/scalacheck/org/scalacheck/Arbitrary.scala
@@ -0,0 +1,407 @@
+/*-------------------------------------------------------------------------*\
+** ScalaCheck **
+** Copyright (c) 2007-2010 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}
+
+sealed abstract class Arbitrary[T] {
+ val arbitrary: Gen[T]
+}
+
+/** Defines implicit <code>Arbitrary</code> instances for common types.
+ * <p>
+ * ScalaCheck
+ * uses implicit <code>Arbitrary</code> instances when creating properties
+ * out of functions with the <code>Prop.property</code> method, and when
+ * the <code>Arbitrary.arbitrary</code> method is used. For example, the
+ * following code requires that there exists an implicit
+ * <code>Arbitrary[MyClass]</code> instance:
+ * </p>
+ *
+ * <p>
+ * <code>
+ * val myProp = Prop.forAll { myClass: MyClass =&gt;<br />
+ * ...<br />
+ * }<br />
+ *
+ * val myGen = Arbitrary.arbitrary[MyClass]
+ * </code>
+ * </p>
+ *
+ * <p>
+ * The required implicit definition could look like this:
+ * </p>
+ *
+ * <p>
+ * <code>
+ * implicit val arbMyClass: Arbitrary[MyClass] = Arbitrary(...)
+ * </code>
+ * </p>
+ *
+ * <p>
+ * The factory method <code>Arbitrary(...)</code> takes a generator of type
+ * <code>Gen[T]</code> and returns an instance of <code>Arbitrary[T]</code>.
+ * </p>
+ *
+ * <p>
+ * The <code>Arbitrary</code> module defines implicit <code>Arbitrary</code>
+ * instances for common types, for convenient use in your properties and
+ * generators.
+ * </p>
+ */
+object Arbitrary {
+
+ import Gen.{value, choose, sized, listOf, listOf1,
+ frequency, oneOf, containerOf, resize}
+ import util.StdRand
+ import scala.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 / 2, Long.MaxValue / 2)
+ )
+
+ /** 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.choose(Char.MinValue, 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(value(()))
+
+ /**** 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(value(new Exception))
+
+ /** Arbitrary BigInt */
+ implicit lazy val arbBigInt: Arbitrary[BigInt] = {
+ def chooseBigInt: Gen[BigInt] = sized((s: Int) => choose(-s, s)) map (x => BigInt(x))
+ def chooseReallyBigInt = chooseBigInt.combine(choose(32, 128))((x, y) => Some(x.get << y.get))
+
+ 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 {
+ mc <- mcGen
+ scale <- arbInt.arbitrary
+ x <- arbBigInt.arbitrary
+ } yield BigDecimal(x, scale, mc)
+ 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] =
+ Arbitrary(frequency(
+ (5, Prop.proved),
+ (4, Prop.falsified),
+ (2, Prop.undecided),
+ (1, Prop.exception(null))
+ ))
+
+ /** Arbitrary instance of test params */
+ implicit lazy val arbTestParams: Arbitrary[Test.Params] =
+ Arbitrary(for {
+ minSuccTests <- choose(10,150)
+ maxDiscTests <- choose(100,500)
+ minSize <- choose(0,500)
+ sizeDiff <- choose(0,500)
+ maxSize <- choose(minSize, minSize + sizeDiff)
+ } yield Test.Params(minSuccTests,maxDiscTests,minSize,maxSize))
+
+ /** Arbitrary instance of gen params */
+ implicit lazy val arbGenParams: Arbitrary[Gen.Params] =
+ Arbitrary(for {
+ size <- arbitrary[Int] suchThat (_ >= 0)
+ } yield Gen.Params(size, StdRand))
+
+ /** Arbitrary instance of prop params */
+ implicit lazy val arbPropParams: Arbitrary[Prop.Params] =
+ Arbitrary(for {
+ genPrms <- arbitrary[Gen.Params]
+ } yield Prop.Params(genPrms, FreqMap.empty[immutable.Set[Any]]))
+
+
+ // Higher-order types //
+
+ /** Arbitrary instance of Gen */
+ implicit def arbGen[T](implicit a: Arbitrary[T]): Arbitrary[Gen[T]] =
+ Arbitrary(frequency(
+ (5, arbitrary[T] map (value(_))),
+ (1, Gen.fail)
+ ))
+
+ /** Arbitrary instance of option type */
+ implicit def arbOption[T](implicit a: Arbitrary[T]): Arbitrary[Option[T]] =
+ Arbitrary(sized(n => if(n == 0) value(None) else resize(n - 1, arbitrary[T]).map(Some(_))))
+
+ 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 immutable map */
+ implicit def arbImmutableMap[T,U](implicit at: Arbitrary[T], au: Arbitrary[U]
+ ): Arbitrary[immutable.Map[T,U]] = Arbitrary(
+ for(seq <- arbitrary[Stream[(T,U)]]) yield immutable.Map(seq: _*)
+ )
+
+ /** Arbitrary instance of mutable map */
+ implicit def arbMutableMap[T,U](implicit at: Arbitrary[T], au: Arbitrary[U]
+ ): Arbitrary[mutable.Map[T,U]] = Arbitrary(
+ for(seq <- arbitrary[Stream[(T,U)]]) yield mutable.Map(seq: _*)
+ )
+
+ /** Arbitrary instance of any 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]
+ ): Arbitrary[C[T]] = Arbitrary(containerOf[C,T](arbitrary[T]))
+
+ /** Arbitrary instance of any array. */
+ implicit def arbArray[T](implicit a: Arbitrary[T], c: ClassManifest[T]
+ ): Arbitrary[Array[T]] = Arbitrary(containerOf[Array,T](arbitrary[T]))
+
+
+ // 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/scalacheck/org/scalacheck/Arg.scala b/src/scalacheck/org/scalacheck/Arg.scala
new file mode 100644
index 0000000000..99657db29b
--- /dev/null
+++ b/src/scalacheck/org/scalacheck/Arg.scala
@@ -0,0 +1,20 @@
+/*-------------------------------------------------------------------------*\
+** ScalaCheck **
+** Copyright (c) 2007-2010 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
+
+case class Arg[+T](
+ label: String,
+ arg: T,
+ shrinks: Int,
+ origArg: T
+)(implicit prettyPrinter: T => Pretty) {
+ lazy val prettyArg: Pretty = prettyPrinter(arg)
+ lazy val prettyOrigArg: Pretty = prettyPrinter(origArg)
+}
diff --git a/src/scalacheck/org/scalacheck/Commands.scala b/src/scalacheck/org/scalacheck/Commands.scala
new file mode 100644
index 0000000000..0d16505d96
--- /dev/null
+++ b/src/scalacheck/org/scalacheck/Commands.scala
@@ -0,0 +1,171 @@
+/*-------------------------------------------------------------------------*\
+** ScalaCheck **
+** Copyright (c) 2007-2010 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 Gen._
+import Prop._
+import Shrink._
+
+/** See User Guide for usage examples */
+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 => error("No value bound")
+ case Some(x) => x
+ }
+ }
+
+ /** 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
+
+ /** @deprecated Use <code>preConditions += ...</code> instead. */
+ @deprecated("Use 'preConditions += ...' instead.")
+ def preCondition_=(f: State => Boolean) = {
+ preConditions.clear
+ preConditions += f
+ }
+
+ /** 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]
+
+ /** @deprecated Use <code>postConditions += ...</code> instead. */
+ @deprecated("Use 'postConditions += ...' instead.")
+ def postCondition_=(f: (State,Any) => Prop) = {
+ postConditions.clear
+ postConditions += ((s0,s1,r) => f(s0,r))
+ }
+
+ /** @deprecated Use <code>postConditions += ...</code> instead. */
+ @deprecated("Use 'postConditions += ...' instead.")
+ def postCondition_=(f: (State,State,Any) => Prop) = {
+ postConditions.clear
+ postConditions += f
+ }
+
+ /** Returns all postconditions merged into a single function */
+ def postCondition: (State,State,Any) => Prop = (s0,s1,r) => 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) value(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)
+
+ for {
+ s0 <- wrap(value(initialState()))
+ cmds <- sized(sizedCmds(s0))
+ } yield cmds
+ }
+
+ 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 = cmds match {
+ case Cmds(Nil, _) => proved
+ case Cmds(c::cs, s::ss) =>
+ c.postCondition(s,c.nextState(s),c.run(s)) && runCommands(Cmds(cs,ss))
+ case _ => error("Should not be here")
+ }
+
+ private def commandsProp: Prop = {
+
+ def shrinkCmds(cmds: Cmds) = cmds match { case Cmds(cs,_) =>
+ shrink(cs)(shrinkContainer).flatMap(cs => validCmds(initialState(), cs).toList)
+ }
+
+ forAllShrink(genCmds label "COMMANDS", shrinkCmds)(runCommands _)
+
+ }
+
+ def apply(p: Prop.Params) = 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/scalacheck/org/scalacheck/ConsoleReporter.scala b/src/scalacheck/org/scalacheck/ConsoleReporter.scala
new file mode 100644
index 0000000000..ed2a08d3ae
--- /dev/null
+++ b/src/scalacheck/org/scalacheck/ConsoleReporter.scala
@@ -0,0 +1,89 @@
+/*-------------------------------------------------------------------------*\
+** ScalaCheck **
+** Copyright (c) 2007-2010 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 Pretty._
+import util.FreqMap
+
+class ConsoleReporter(val verbosity: Int) extends Test.TestCallback {
+
+ private val prettyPrms = Params(verbosity)
+
+ override def onPropEval(name: String, w: Int, s: Int, d: Int) =
+ if(verbosity > 0) {
+ if(name == "") {
+ if(d == 0) printf("\rPassed %s tests\r", s)
+ else printf("\rPassed %s tests; %s discarded\r", s, d)
+ } else {
+ if(d == 0) printf("\r %s: Passed %s tests\r", name, s)
+ else printf("\r %s: Passed %s tests; %s discarded\r", name, s, d)
+ }
+ Console.flush
+ }
+
+ override def onTestResult(name: String, res: Test.Result) = {
+ if(name == "") {
+ print(List.fill(78)(' ').mkString)
+ val s = (if(res.passed) "+ " else "! ") + pretty(res, prettyPrms)
+ printf("\r%s\n", format(s, "", "", 75))
+ } else {
+ print(List.fill(78)(' ').mkString)
+ 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)
+
+ @deprecated("(v1.8)")
+ def propReport(s: Int, d: Int) = {
+ if(d == 0) printf("\rPassed %s tests\r", s)
+ else printf("\rPassed %s tests; %s discarded\r", s, d)
+ Console.flush
+ }
+
+ @deprecated("(v1.8)")
+ def propReport(pName: String, s: Int, d: Int) = {
+ if(d == 0) printf("\r %s: Passed %s tests\r", pName, s)
+ else printf("\r %s: Passed %s tests; %s discarded\r", pName, s, d)
+ Console.flush
+ }
+
+ @deprecated("(v1.8)")
+ def testReport(res: Test.Result) = {
+ print(List.fill(78)(' ').mkString)
+ val s = (if(res.passed) "+ " else "! ") + pretty(res, Params(0))
+ printf("\r%s\n", format(s, "", "", 75))
+ res
+ }
+
+ @deprecated("(v1.8)")
+ def testStatsEx(res: Test.Result): Unit = testStatsEx("", res)
+
+ def testStatsEx(msg: String, res: Test.Result) = {
+ lazy val m = if(msg.length == 0) "" else msg + ": "
+ res.status match {
+ case Test.Proved(_) => {}
+ case Test.Passed => {}
+ case f @ Test.Failed(_, _) => error(m + f)
+ case Test.Exhausted => {}
+ case f @ Test.GenException(_) => error(m + f)
+ case f @ Test.PropException(_, _, _) => error(m + f)
+ }
+ }
+
+}
diff --git a/src/scalacheck/org/scalacheck/Gen.scala b/src/scalacheck/org/scalacheck/Gen.scala
new file mode 100644
index 0000000000..ca1dae0d3c
--- /dev/null
+++ b/src/scalacheck/org/scalacheck/Gen.scala
@@ -0,0 +1,487 @@
+/*-------------------------------------------------------------------------*\
+** ScalaCheck **
+** Copyright (c) 2007-2010 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 scala.collection.mutable.ListBuffer
+import util.Buildable
+import Prop._
+import Arbitrary._
+
+trait Choose[T] {
+ def choose(min: T, max: T): Gen[T]
+}
+
+object Choose {
+ import Gen.{fail, parameterized, value}
+
+ implicit val chooseLong: Choose[Long] = new Choose[Long] {
+ def choose(low: Long, high: Long) =
+ if(low > high || (high-low < 0)) fail
+ else parameterized(prms => value(prms.choose(low,high)))
+ }
+
+ implicit val chooseDouble: Choose[Double] = new Choose[Double] {
+ def choose(low: Double, high: Double) =
+ if (low > high || (high-low > Double.MaxValue)) fail
+ else parameterized(prms => value(prms.choose(low,high)))
+ }
+
+ implicit val chooseInt: Choose[Int] = new Choose[Int] {
+ def choose(low: Int, high: Int) =
+ chooseLong.choose(low, high).map(_.toInt)
+ }
+
+ implicit val chooseByte: Choose[Byte] = new Choose[Byte] {
+ def choose(low: Byte, high: Byte) =
+ chooseLong.choose(low, high).map(_.toByte)
+ }
+
+ implicit val chooseShort: Choose[Short] = new Choose[Short] {
+ def choose(low: Short, high: Short) =
+ chooseLong.choose(low, high).map(_.toShort)
+ }
+
+ implicit val chooseChar: Choose[Char] = new Choose[Char] {
+ def choose(low: Char, high: Char) =
+ chooseLong.choose(low, high).map(_.toChar)
+ }
+
+ implicit val chooseFloat: Choose[Float] = new Choose[Float] {
+ def choose(low: Float, high: Float) =
+ chooseDouble.choose(low, high).map(_.toFloat)
+ }
+}
+
+
+/** Class that represents a generator. */
+sealed trait Gen[+T] {
+
+ import Gen.choose
+
+ var label = "" // TODO: Ugly mutable field
+
+ /** Put a label on the generator to make test reports clearer */
+ def label(l: String): Gen[T] = {
+ label = l
+ this
+ }
+
+ /** 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))
+
+ def apply(prms: Gen.Params): Option[T]
+
+ def map[U](f: T => U): Gen[U] = Gen(prms => this(prms).map(f)).label(label)
+
+ def map2[U, V](g: Gen[U])(f: (T, U) => V) =
+ combine(g)((t, u) => t.flatMap(t => u.flatMap(u => Some(f(t, u)))))
+
+ def map3[U, V, W](gu: Gen[U], gv: Gen[V])(f: (T, U, V) => W) =
+ combine3(gu, gv)((t, u, v) => t.flatMap(t => u.flatMap(u => v.flatMap(v => Some(f(t, u, v))))))
+
+ def map4[U, V, W, X](gu: Gen[U], gv: Gen[V], gw: Gen[W])(f: (T, U, V, W) => X) =
+ combine4(gu, gv, gw)((t, u, v, w) => t.flatMap(t => u.flatMap(u => v.flatMap(v => w.flatMap(w => Some(f(t, u, v, w)))))))
+
+ def map5[U, V, W, X, Y](gu: Gen[U], gv: Gen[V], gw: Gen[W], gx: Gen[X])(f: (T, U, V, W, X) => Y) =
+ combine5(gu, gv, gw, gx)((t, u, v, w, x) => t.flatMap(t => u.flatMap(u => v.flatMap(v => w.flatMap(w => x.flatMap(x => Some(f(t, u, v, w, x))))))))
+
+ def map6[U, V, W, X, Y, Z](gu: Gen[U], gv: Gen[V], gw: Gen[W], gx: Gen[X], gy: Gen[Y])(f: (T, U, V, W, X, Y) => Z) =
+ combine6(gu, gv, gw, gx, gy)((t, u, v, w, x, y) => t.flatMap(t => u.flatMap(u => v.flatMap(v => w.flatMap(w => x.flatMap(x => y.flatMap(y => Some(f(t, u, v, w, x, y)))))))))
+
+ def flatMap[U](f: T => Gen[U]): Gen[U] = Gen(prms => for {
+ t <- this(prms)
+ u <- f(t)(prms)
+ } yield u)
+
+ def filter(p: T => Boolean): Gen[T] = Gen(prms => for {
+ t <- this(prms)
+ u <- if (p(t)) Some(t) else None
+ } yield u).label(label)
+
+ def withFilter(p: T => Boolean) = new GenWithFilter[T](this, p)
+
+ final class GenWithFilter[+A](self: Gen[A], p: A => Boolean) {
+ def map[B](f: A => B): Gen[B] = self filter p map f
+ def flatMap[B](f: A => Gen[B]): Gen[B] = self filter p flatMap f
+ def withFilter(q: A => Boolean): GenWithFilter[A] = new GenWithFilter[A](self, x => p(x) && q(x))
+ }
+
+ def suchThat(p: T => Boolean): Gen[T] = filter(p)
+
+ def combine[U,V](g: Gen[U])(f: (Option[T],Option[U]) => Option[V]): Gen[V] =
+ Gen(prms => f(this(prms), g(prms)))
+
+ def combine3[U, V, W](gu: Gen[U], gv: Gen[V])
+ (f: (Option[T], Option[U], Option[V]) => Option[W]) =
+ Gen(prms => f(this(prms), gu(prms), gv(prms)))
+
+ def combine4[U, V, W, X](gu: Gen[U], gv: Gen[V], gw: Gen[W])
+ (f: (Option[T], Option[U], Option[V], Option[W]) => Option[X]) =
+ Gen(prms => f(this(prms), gu(prms), gv(prms), gw(prms)))
+
+ def combine5[U, V, W, X, Y](gu: Gen[U], gv: Gen[V], gw: Gen[W], gx: Gen[X])
+ (f: (Option[T], Option[U], Option[V], Option[W], Option[X]) => Option[Y]) =
+ Gen(prms => f(this(prms), gu(prms), gv(prms), gw(prms), gx(prms)))
+
+ def combine6[U, V, W, X, Y, Z](gu: Gen[U], gv: Gen[V], gw: Gen[W], gx: Gen[X], gy: Gen[Y])
+ (f: (Option[T], Option[U], Option[V], Option[W], Option[X], Option[Y]) => Option[Z]) =
+ Gen(prms => f(this(prms), gu(prms), gv(prms), gw(prms), gx(prms), gy(prms)))
+
+ def ap[U](g: Gen[T => U]) = flatMap(t => g.flatMap(u => Gen(p => Some(u(t)))))
+
+ override def toString =
+ if(label.length == 0) "Gen()" else "Gen(\"" + label + "\")"
+
+ /** 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.
+ * @deprecated Use <code>==</code> instead */
+ @deprecated("Use == instead")
+ def ===[U](g: Gen[U]): Prop = this == g
+
+ /** 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 =>
+ (this(prms.genPrms), g(prms.genPrms)) match {
+ case (None,None) => proved(prms)
+ case (Some(r1),Some(r2)) if r1 == r2 => proved(prms)
+ case _ => falsified(prms)
+ }
+ )
+
+ def !=[U](g: Gen[U]) = forAll(this)(r => forAll(g)(_ != r))
+
+ def !==[U](g: Gen[U]) = Prop(prms =>
+ (this(prms.genPrms), g(prms.genPrms)) match {
+ case (None,None) => falsified(prms)
+ case (Some(r1),Some(r2)) if r1 == r2 => falsified(prms)
+ case _ => proved(prms)
+ }
+ )
+
+ private var freq = 1
+ def |[U >: T](g: Gen[U]): Gen[U] = {
+ val h = Gen.frequency((freq, this), (1, g))
+ h.freq = freq+1
+ h
+ }
+
+ /** Generates a sample value by using default parameters */
+ def sample: Option[T] = apply(Gen.Params())
+
+}
+
+
+/** Contains combinators for building generators. */
+object Gen {
+
+ import Arbitrary._
+ import Shrink._
+
+ /** Record that encapsulates all parameters required for data generation */
+ case class Params(
+ size: Int = 100,
+ rng: java.util.Random = util.StdRand
+ ) {
+ def resize(newSize: Int) = this.copy(size = newSize)
+
+ /** @throws IllegalArgumentException if l is greater than h, or if
+ * the range between l and h doesn't fit in a Long. */
+ def choose(l: Long, h: Long): Long = {
+ val d = h-l
+ if (d < 0) throw new IllegalArgumentException("Invalid range")
+ else if (d == 0) l
+ else {
+ val r = math.abs(rng.nextLong)
+ val a = if(r == Long.MinValue) 1 else 0
+ l + (math.abs(r+a) % d) + a
+ }
+ }
+
+ /** @throws IllegalArgumentException if l is greater than h, or if
+ * the range between l and h doesn't fit in a Double. */
+ def choose(l: Double, h: Double) = {
+ val d = h-l
+ if (d < 0 || d > Double.MaxValue)
+ throw new IllegalArgumentException("Invalid range")
+ else if (d == 0) l
+ else rng.nextDouble * (h-l) + l
+ }
+ }
+
+ /* Default generator parameters
+ * @deprecated Use <code>Gen.Params()</code> instead */
+ @deprecated("Use Gen.Params() instead")
+ val defaultParams = Params()
+
+ /* Generator factory method */
+ def apply[T](g: Gen.Params => Option[T]) = new Gen[T] {
+ def apply(p: Gen.Params) = g(p)
+ }
+
+ /* Convenience method for using the <code>frequency</code> method like this:
+ * <code>frequency((1, "foo"), (3, "bar"))</code> */
+ implicit def freqTuple[T](t: (Int, T)): (Int, Gen[T]) = (t._1, value(t._2))
+
+
+ //// Various Generator Combinators ////
+
+ /** Sequences generators. If any of the given generators fails, the
+ * resulting generator will also fail. */
+ def sequence[C[_],T](gs: Iterable[Gen[T]])(implicit b: Buildable[T,C]): Gen[C[T]] = Gen(prms => {
+ val builder = b.builder
+ var none = false
+ val xs = gs.iterator
+ while(xs.hasNext && !none) xs.next.apply(prms) match {
+ case None => none = true
+ case Some(x) => builder += x
+ }
+ if(none) None else Some(builder.result())
+ })
+
+ /** Wraps a generator lazily. The given parameter is only evalutated once,
+ * and not until the wrapper generator is evaluated. */
+ def lzy[T](g: => Gen[T]) = new Gen[T] {
+ lazy val h = g
+ def apply(prms: Params) = h(prms)
+ }
+
+ /** 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(p))
+
+ /** A generator that always generates the given value */
+ implicit def value[T](x: T) = Gen(p => Some(x))
+
+ /** A generator that never generates a value */
+ def fail[T]: Gen[T] = Gen(p => None)
+
+ /** 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)
+ }
+
+ /** Creates a generator that can access its generation parameters */
+ def parameterized[T](f: Params => Gen[T]): Gen[T] = Gen(prms => f(prms)(prms))
+
+ /** Creates a generator that can access its generation size */
+ def sized[T](f: Int => Gen[T]) = parameterized(prms => f(prms.size))
+
+ /** Creates a resized version of a generator */
+ def resize[T](s: Int, g: Gen[T]) = Gen(prms => g(prms.resize(s)))
+
+ /** Chooses one of the given generators with a weighted random distribution */
+ def frequency[T](gs: (Int,Gen[T])*): Gen[T] = {
+ lazy val tot = (gs.map(_._1) :\ 0) (_+_)
+
+ def pick(n: Int, l: List[(Int,Gen[T])]): Gen[T] = l match {
+ case Nil => fail
+ case (k,g)::gs => if(n <= k) g else pick(n-k, gs)
+ }
+
+ for {
+ n <- choose(1,tot)
+ x <- pick(n,gs.toList)
+ } yield x
+ }
+
+ /** Picks a random value from a list */
+ def oneOf[T](xs: Seq[T]): Gen[T] = if(xs.isEmpty) fail else for {
+ i <- choose(0, xs.size-1)
+ } yield xs(i)
+
+ /** Picks a random generator from a list */
+ def oneOf[T](g1: Gen[T], g2: Gen[T], gs: Gen[T]*) = for {
+ i <- choose(0, gs.length+1)
+ x <- if(i == 0) g1 else if(i == 1) g2 else gs(i-2)
+ } yield x
+
+ /** Chooses one of the given values, with a weighted random distribution.
+ * @deprecated Use <code>frequency</code> with constant generators
+ * instead. */
+ @deprecated("Use 'frequency' with constant generators instead.")
+ def elementsFreq[T](vs: (Int, T)*): Gen[T] =
+ frequency(vs.map { case (w,v) => (w, value(v)) } : _*)
+
+ /** A generator that returns a random element from a list
+ * @deprecated Use <code>oneOf</code> with constant generators instead. */
+ @deprecated("Use 'oneOf' with constant generators instead.")
+ def elements[T](xs: T*): Gen[T] = if(xs.isEmpty) fail else for {
+ i <- choose(0,xs.length-1)
+ } yield xs(i)
+
+
+ //// List Generators ////
+
+ /** Generates a container of any type for which there exists an implicit
+ * <code>Buildable</code> instance. The elements in the container will
+ * be generated by the given generator. The size of the generated container
+ * is given by <code>n</code>. */
+ def containerOfN[C[_],T](n: Int, g: Gen[T])(implicit b: Buildable[T,C]
+ ): Gen[C[T]] = sequence[C,T](new Iterable[Gen[T]] {
+ def iterator = new Iterator[Gen[T]] {
+ var i = 0
+ def hasNext = i < n
+ def next = { i += 1; g }
+ }
+ })
+
+ /** Generates a container of any type for which there exists an implicit
+ * <code>Buildable</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](g: Gen[T])(implicit b: Buildable[T,C]): Gen[C[T]] =
+ sized(size => for(n <- choose(0,size); c <- containerOfN[C,T](n,g)) yield c)
+
+ /** Generates a non-empty container of any type for which there exists an
+ * implicit <code>Buildable</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 containerOf1[C[_],T](g: Gen[T])(implicit b: Buildable[T,C]): Gen[C[T]] =
+ sized(size => for(n <- choose(1,size); c <- containerOfN[C,T](n,g)) yield c)
+
+ /** Generates a list of random length. The maximum length depends on the
+ * size parameter. This method is equal to calling
+ * <code>containerOf[List,T](g)</code>. */
+ 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
+ * <code>containerOf1[List,T](g)</code>. */
+ def listOf1[T](g: => Gen[T]) = containerOf1[List,T](g)
+
+ /** Generates a list of the given length. This method is equal to calling
+ * <code>containerOfN[List,T](n,g)</code>. */
+ def listOfN[T](n: Int, g: Gen[T]) = containerOfN[List,T](n,g)
+
+ /** Generates a list of the given length. This method is equal to calling
+ * <code>containerOfN[List,T](n,g)</code>.
+ * @deprecated Use the method <code>listOfN</code> instead. */
+ @deprecated("Use 'listOfN' instead.")
+ def vectorOf[T](n: Int, g: Gen[T]) = containerOfN[List,T](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]*) = for {
+ n <- choose(0, gs.length+2)
+ x <- pick(n, g1, g2, gs: _*)
+ } yield x
+
+ /** 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(prms => {
+ val buf = new ListBuffer[T]
+ buf ++= l
+ while(buf.length > n) {
+ val g = choose(0, buf.length-1)
+ buf.remove(g(prms).get)
+ }
+ Some(buf)
+ })
+
+ /** A generator that picks a given number of elements from a list, randomly */
+ def pick[T](n: Int, g1: Gen[T], g2: Gen[T], gs: Gen[T]*): Gen[Seq[T]] = for {
+ is <- pick(n, 0 until (gs.size+2))
+ allGs = gs ++ (g1::g2::Nil)
+ xs <- sequence[List,T](is.toList.map(allGs(_)))
+ } yield xs
+
+
+ //// Character Generators ////
+
+ /* Generates a numerical character */
+ def numChar: Gen[Char] = choose(48,57) map (_.toChar)
+
+ /* Generates an upper-case alpha character */
+ def alphaUpperChar: Gen[Char] = choose(65,90) map (_.toChar)
+
+ /* Generates a lower-case alpha character */
+ def alphaLowerChar: Gen[Char] = choose(97,122) map (_.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
+
+ /* Generates a string of alpha characters */
+ def alphaStr: Gen[String] = for(cs <- listOf(Gen.alphaChar)) yield cs.mkString
+
+ /* Generates a string of digits */
+ def numStr: Gen[String] = for(cs <- listOf(Gen.numChar)) yield cs.mkString
+
+ //// Number Generators ////
+
+ /* Generates positive integers
+ * @deprecated Use <code>posNum[Int]code> instead */
+ @deprecated("Use posNum[Int] instead")
+ def posInt: Gen[Int] = sized(max => choose(1, max))
+
+ /* Generates negative integers
+ * @deprecated Use <code>negNum[Int]code> instead */
+ @deprecated("Use negNum[Int] instead")
+ def negInt: Gen[Int] = sized(max => choose(-max, -1))
+
+ /** 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, value(t))
+ val allGens = basicsAndSpecials ++ List(
+ (basicsAndSpecials.length, c.choose(minT, maxT))
+ )
+ frequency(allGens: _*)
+ }
+}
diff --git a/src/scalacheck/org/scalacheck/Pretty.scala b/src/scalacheck/org/scalacheck/Pretty.scala
new file mode 100644
index 0000000000..d3945a1985
--- /dev/null
+++ b/src/scalacheck/org/scalacheck/Pretty.scala
@@ -0,0 +1,114 @@
+/*-------------------------------------------------------------------------*\
+** ScalaCheck **
+** Copyright (c) 2007-2010 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 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 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) strs else strs.take(5)
+
+ e.getClass.getName + ": " + e.getMessage / strs2.mkString("\n")
+ }
+
+ implicit def prettyArgs(args: List[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 " (orig arg: "+a.prettyOrigArg(prms)+")"
+
+ "> "+l+": "+a.prettyArg(prms)+""+s
+ }
+ }.mkString("\n")
+ }
+
+ implicit def prettyFreqMap(fm: Prop.FM) = 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."/pretty(args,prms)
+ case Test.Passed => "OK, passed "+res.succeeded+" tests."
+ case Test.Failed(args, l) =>
+ "Falsified after "+res.succeeded+" passed tests."/labels(l)/pretty(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)/pretty(args,prms)/
+ "> Exception: "+pretty(e,prms)
+ case Test.GenException(e) =>
+ "Exception raised on argument generation."/"> Stack trace: "/pretty(e,prms)
+ }
+ s/pretty(res.freqMap,prms)
+ }
+
+}
diff --git a/src/scalacheck/org/scalacheck/Prop.scala b/src/scalacheck/org/scalacheck/Prop.scala
new file mode 100644
index 0000000000..68e4b89660
--- /dev/null
+++ b/src/scalacheck/org/scalacheck/Prop.scala
@@ -0,0 +1,741 @@
+/*-------------------------------------------------------------------------*\
+** ScalaCheck **
+** Copyright (c) 2007-2010 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}
+import scala.collection._
+
+/** A property is a generator that generates a property result */
+trait Prop {
+
+ import Prop.{Result,Params,Proof,True,False,Exception,Undecided,provedToTrue}
+ import Test.cmdLineParser.{Success, NoSuccess}
+ import Result.merge
+
+ def apply(prms: Params): Result
+
+ def map(f: Result => Result): Prop = Prop(prms => f(this(prms)))
+
+ def flatMap(f: Result => Prop): Prop = Prop(prms => f(this(prms))(prms))
+
+ def combine(p: Prop)(f: (Result, Result) => Result) =
+ for(r1 <- this; r2 <- p) yield f(r1,r2)
+
+ /** Convenience method that checks this property with the given parameters
+ * and reports the result on the console. If you need to get the results
+ * from the test use the <code>check</code> methods in <code>Test</code>
+ * instead. */
+ def check(prms: Test.Params): Unit = Test.check(
+ prms copy (testCallback = ConsoleReporter(1) chain prms.testCallback), this
+ )
+
+ /** Convenience method that checks this property and reports the
+ * result on the console. If you need to get the results from the test use
+ * the <code>check</code> methods in <code>Test</code> instead. */
+ def check: Unit = check(Test.Params())
+
+ /** Convenience method that makes it possible to use a this property
+ * as an application that checks itself on execution */
+ def main(args: Array[String]): Unit =
+ Test.cmdLineParser.parseParams(args) match {
+ case Success(params, _) => Test.check(params, this)
+ case e: NoSuccess =>
+ println("Incorrect options:"+"\n"+e+"\n")
+ Test.cmdLineParser.printHelp
+ }
+
+ /** Returns a new property that holds if and only if both this
+ * and the given property hold. If one of the properties doesn't
+ * generate a result, the new property will generate false. */
+ def &&(p: Prop) = combine(p)(_ && _)
+
+ /** Returns a new property that holds if either this
+ * or the given property (or both) hold. */
+ def ||(p: Prop) = combine(p)(_ || _)
+
+ /** Returns a new property that holds if and only if both this
+ * and the given property hold. If one of the properties doesn't
+ * generate a result, the new property will generate the same result
+ * as the other property. */
+ def ++(p: Prop): Prop = combine(p)(_ ++ _)
+
+ /** Combines two properties through implication */
+ def ==>(p: => Prop): Prop = flatMap { r1 =>
+ if(r1.proved) p map { r2 => merge(r1,r2,r2.status) }
+ else if(r1.success) p map { r2 => provedToTrue(merge(r1,r2,r2.status)) }
+ else Prop(r1.copy(status = Undecided))
+ }
+
+ /** 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 =>
+ Result.merge(r1, r2, if(r1.status == r2.status) True else False)
+ }
+ }
+
+ /** 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.
+ * @deprecated Use <code>==</code> instead */
+ @deprecated("Use == instead.")
+ def ===(p: Prop): Prop = this == p
+
+ 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}
+ import Arbitrary._
+ import Shrink._
+
+
+ // Types
+
+ type Args = List[Arg[Any]]
+ type FM = FreqMap[immutable.Set[Any]]
+
+ /** Property parameters */
+ case class Params(val genPrms: Gen.Params, val freqMap: FM)
+
+ object Result {
+ def apply(st: Status) = new Result(
+ st,
+ Nil,
+ immutable.Set.empty[Any],
+ immutable.Set.empty[String]
+ )
+
+ def merge(x: Result, y: Result, status: Status) = new Result(
+ status,
+ x.args ++ y.args,
+ (x.collected.asInstanceOf[Set[AnyRef]] ++ y.collected).asInstanceOf[immutable.Set[Any]],
+ x.labels ++ y.labels
+ )
+ }
+
+ /** The result of evaluating a property */
+ case class Result(
+ status: Status,
+ args: Args,
+ collected: immutable.Set[Any],
+ labels: immutable.Set[String]
+ ) {
+ 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)
+
+ import Result.merge
+
+ 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) => merge(this, r, this.status)
+ case (Proof,_) => merge(this, r, this.status)
+
+ case (True,True) => merge(this, r, True)
+ }
+
+ def ||(r: Result) = (this.status, r.status) match {
+ case (Exception(_),_) => this
+ case (_,Exception(_)) => r
+
+ case (False,False) => merge(this, r, False)
+ case (False,_) => r
+ case (_,False) => this
+
+ case (Proof,_) => this
+ case (_,Proof) => r
+
+ case (True,_) => this
+ case (_,True) => r
+
+ case (Undecided,Undecided) => merge(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,_) => merge(this, r, Undecided)
+
+ case (Undecided,_) => this
+
+ case (Proof,_) => merge(this, r, r.status)
+ case (True,_) => merge(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
+ }
+ }
+
+ def apply(f: Params => Result): Prop = new Prop {
+ def apply(prms: Params) = f(prms)
+ }
+
+ def apply(r: Result): Prop = Prop(prms => r)
+
+
+ // Implicit defs
+
+ class ExtendedAny[T <% Pretty](x: => T) {
+ def imply(f: PartialFunction[T,Prop]) = Prop.imply(x,f)
+ def iff(f: PartialFunction[T,Prop]) = Prop.iff(x,f)
+ def throws[U <: Throwable](c: Class[U]) = Prop.throws(x, c)
+ def ?=(y: T) = Prop.?=(x, y)
+ def =?(y: T) = Prop.=?(x, y)
+ }
+
+ implicit def extendedAny[T <% Pretty](x: => T) = new ExtendedAny[T](x)
+
+ implicit def propBoolean(b: Boolean): Prop = if(b) proved else falsified
+
+
+ // Private support functions
+
+ private def provedToTrue(r: Result) = r.status match {
+ case Proof => new Result(True, r.args, r.collected, r.labels)
+ case _ => r
+ }
+
+
+ // Property combinators
+
+ /** A property that never is proved or falsified */
+ lazy val undecided = Prop(Result(Undecided))
+
+ /** A property that always is false */
+ lazy val falsified = Prop(Result(False))
+
+ /** A property that always is proved */
+ lazy val proved = Prop(Result(Proof))
+
+ /** A property that always is passed */
+ lazy val passed = Prop(Result(True))
+
+ /** A property that denotes an exception */
+ def exception(e: Throwable): Prop = Prop(Result(Exception(e)))
+
+ /** A property that denotes an exception */
+ lazy val exception: Prop = exception(null)
+
+ 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
+ }
+
+ 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 => f(prms.genPrms.size)(prms))
+
+ /** Implication
+ * @deprecated Use the implication operator of the Prop class instead
+ */
+ @deprecated("Use the implication operator of the Prop class instead")
+ def ==>(b: => Boolean, p: => Prop): Prop = (b: Prop) ==> p
+
+ /** 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
+ * <code>x</code>, 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):_*)
+
+ /** A property that holds if the given statement throws an exception
+ * of the specified type */
+ def throws[T <: Throwable](x: => Any, c: Class[T]) =
+ try { x; falsified } catch { case e if c.isInstance(e) => proved }
+
+ /** 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 => 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 =>
+ g(prms.genPrms) match {
+ case None => undecided(prms)
+ case Some(x) =>
+ val p = secure(f(x))
+ val r = p(prms).addArg(Arg(g.label,x,0,x))
+ r.status match {
+ case True => new Result(Proof, r.args, r.collected, r.labels)
+ case False => new Result(Undecided, r.args, r.collected, r.labels)
+ 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 =>
+ g1(prms.genPrms) match {
+ case None => undecided(prms)
+ case Some(x) =>
+ val p = secure(f(x))
+ provedToTrue(p(prms)).addArg(Arg(g1.label,x,0,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)))
+
+ /** Universal quantifier for an explicit generator. Shrinks failed arguments
+ * with the given shrink function */
+ def forAllShrink[T <% Pretty, P <% Prop](g: Gen[T],
+ shrink: T => Stream[T])(f: T => P
+ ): Prop = Prop { 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 =>
+ val p = secure(f(x))
+ (x, provedToTrue(p(prms)))
+ }
+ 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)
+ val res = r.addArg(Arg(g.label,x,shrinks,orig))
+ if(xs.isEmpty) res else getFirstFailure(xs) match {
+ case Right(_) => res
+ case Left((x2,r2)) => shrinker(x2, r2, shrinks+1, orig)
+ }
+ }
+
+ g(prms.genPrms) match {
+ case None => undecided(prms)
+ case Some(x) => getFirstFailure(Stream.cons(x, Stream.empty)) match {
+ case Right((x,r)) => r.addArg(Arg(g.label,x,0,x))
+ case Left((x,r)) => 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(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)))
+
+}
diff --git a/src/scalacheck/org/scalacheck/Properties.scala b/src/scalacheck/org/scalacheck/Properties.scala
new file mode 100644
index 0000000000..bb2fe77c47
--- /dev/null
+++ b/src/scalacheck/org/scalacheck/Properties.scala
@@ -0,0 +1,76 @@
+/*-------------------------------------------------------------------------*\
+** ScalaCheck **
+** Copyright (c) 2007-2010 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
+
+/** 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>
+ *
+ * <p>
+ * <code>
+ * object MyProps extends Properties("MyProps") {
+ * property("myProp1") = forAll { (n:Int, m:Int) =&gt;
+ * n+m == m+n
+ * }
+ *
+ * property("myProp2") = ((0/1) throws classOf[ArithmeticException])
+ * }
+ */
+class Properties(val name: String) extends Prop {
+
+ import Test.cmdLineParser.{Success, NoSuccess}
+
+ 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: Prop.Params) = 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 <code>check</code> methods in <code>Test</code>
+ * instead. */
+ override def check(prms: Test.Params): Unit = Test.checkProperties(
+ prms copy (testCallback = 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 <code>check</code> methods in <code>Test</code> instead. */
+ override def check: Unit = check(Test.Params())
+
+ /** Convenience method that makes it possible to use a this instance
+ * as an application that checks itself on execution */
+ override def main(args: Array[String]): Unit =
+ Test.cmdLineParser.parseParams(args) match {
+ case Success(params, _) => Test.checkProperties(params, this)
+ case e: NoSuccess =>
+ println("Incorrect options:"+"\n"+e+"\n")
+ Test.cmdLineParser.printHelp
+ }
+
+ /** 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:
+ * <code>property("myProp") = ...</code> */
+ class PropertySpecifier() {
+ def update(propName: String, p: Prop) = props += ((name+"."+propName, p))
+ }
+
+ lazy val property = new PropertySpecifier()
+}
diff --git a/src/scalacheck/org/scalacheck/Shrink.scala b/src/scalacheck/org/scalacheck/Shrink.scala
new file mode 100644
index 0000000000..70ab5f6d23
--- /dev/null
+++ b/src/scalacheck/org/scalacheck/Shrink.scala
@@ -0,0 +1,208 @@
+/*-------------------------------------------------------------------------*\
+** ScalaCheck **
+** Copyright (c) 2007-2010 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
+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 to streams */
+ private def interleave[T](xs: Stream[T], ys: Stream[T]): Stream[T] =
+ if(xs.isEmpty) ys
+ else if(ys.isEmpty) xs
+ else Stream(xs.head, ys.head) append 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] =>
+
+ def removeChunks(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)))
+ }
+
+ def shrinkOne(zs: Stream[T]): Stream[Stream[T]] =
+ if(zs.isEmpty) empty
+ else {
+ val x = zs.head
+ val xs = zs.tail
+ (for(y <- shrink(x)) yield cons(y,xs)) append
+ (for(ys <- shrinkOne(xs)) yield cons(x,ys))
+ }
+
+ val ys = v(xs)
+ val zs = ys.toStream
+ removeChunks(ys.size,zs).append(shrinkOne(zs)).map(b.fromIterable)
+
+ }
+
+ /** 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](implicit s: Shrink[T]): 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,T2](implicit
+ s1: Shrink[T1], s2: Shrink[T2]
+ ): Shrink[(T1,T2)] =
+ Shrink { case (t1,t2) =>
+ (for(x1 <- shrink(t1)) yield (x1, t2)) append
+ (for(x2 <- shrink(t2)) yield (t1, x2))
+ }
+
+ /** Shrink instance of 3-tuple */
+ implicit def shrinkTuple3[T1,T2,T3](implicit
+ s1: Shrink[T1], s2: Shrink[T2], s3: Shrink[T3]
+ ): Shrink[(T1,T2,T3)] =
+ Shrink { case (t1,t2,t3) =>
+ (for(x1 <- shrink(t1)) yield (x1, t2, t3)) append
+ (for(x2 <- shrink(t2)) yield (t1, x2, t3)) append
+ (for(x3 <- shrink(t3)) yield (t1, t2, x3))
+ }
+
+ /** Shrink instance of 4-tuple */
+ implicit def shrinkTuple4[T1,T2,T3,T4](implicit
+ s1: Shrink[T1], s2: Shrink[T2], s3: Shrink[T3], s4: Shrink[T4]
+ ): Shrink[(T1,T2,T3,T4)] =
+ Shrink { case (t1,t2,t3,t4) =>
+ (for(x1 <- shrink(t1)) yield (x1, t2, t3, t4)) append
+ (for(x2 <- shrink(t2)) yield (t1, x2, t3, t4)) append
+ (for(x3 <- shrink(t3)) yield (t1, t2, x3, t4)) append
+ (for(x4 <- shrink(t4)) yield (t1, t2, t3, x4))
+ }
+
+ /** Shrink instance of 5-tuple */
+ implicit def shrinkTuple5[T1,T2,T3,T4,T5](implicit
+ s1: Shrink[T1], s2: Shrink[T2], s3: Shrink[T3], s4: Shrink[T4],
+ s5: Shrink[T5]
+ ): Shrink[(T1,T2,T3,T4,T5)] =
+ Shrink { case (t1,t2,t3,t4,t5) =>
+ (for(x1 <- shrink(t1)) yield (x1, t2, t3, t4, t5)) append
+ (for(x2 <- shrink(t2)) yield (t1, x2, t3, t4, t5)) append
+ (for(x3 <- shrink(t3)) yield (t1, t2, x3, t4, t5)) append
+ (for(x4 <- shrink(t4)) yield (t1, t2, t3, x4, t5)) append
+ (for(x5 <- shrink(t5)) yield (t1, t2, t3, t4, x5))
+ }
+
+ /** Shrink instance of 6-tuple */
+ implicit def shrinkTuple6[T1,T2,T3,T4,T5,T6](implicit
+ s1: Shrink[T1], s2: Shrink[T2], s3: Shrink[T3], s4: Shrink[T4],
+ s5: Shrink[T5], s6: Shrink[T6]
+ ): Shrink[(T1,T2,T3,T4,T5,T6)] =
+ Shrink { case (t1,t2,t3,t4,t5,t6) =>
+ (for(x1 <- shrink(t1)) yield (x1, t2, t3, t4, t5, t6)) append
+ (for(x2 <- shrink(t2)) yield (t1, x2, t3, t4, t5, t6)) append
+ (for(x3 <- shrink(t3)) yield (t1, t2, x3, t4, t5, t6)) append
+ (for(x4 <- shrink(t4)) yield (t1, t2, t3, x4, t5, t6)) append
+ (for(x5 <- shrink(t5)) yield (t1, t2, t3, t4, x5, t6)) append
+ (for(x6 <- shrink(t6)) yield (t1, t2, t3, t4, t5, x6))
+ }
+
+ /** Shrink instance of 7-tuple */
+ implicit def shrinkTuple7[T1,T2,T3,T4,T5,T6,T7](implicit
+ s1: Shrink[T1], s2: Shrink[T2], s3: Shrink[T3], s4: Shrink[T4],
+ s5: Shrink[T5], s6: Shrink[T6], s7: Shrink[T7]
+ ): Shrink[(T1,T2,T3,T4,T5,T6,T7)] =
+ Shrink { case (t1,t2,t3,t4,t5,t6,t7) =>
+ (for(x1 <- shrink(t1)) yield (x1, t2, t3, t4, t5, t6, t7)) append
+ (for(x2 <- shrink(t2)) yield (t1, x2, t3, t4, t5, t6, t7)) append
+ (for(x3 <- shrink(t3)) yield (t1, t2, x3, t4, t5, t6, t7)) append
+ (for(x4 <- shrink(t4)) yield (t1, t2, t3, x4, t5, t6, t7)) append
+ (for(x5 <- shrink(t5)) yield (t1, t2, t3, t4, x5, t6, t7)) append
+ (for(x6 <- shrink(t6)) yield (t1, t2, t3, t4, t5, x6, t7)) append
+ (for(x7 <- shrink(t7)) yield (t1, t2, t3, t4, t5, t6, x7))
+ }
+
+ /** Shrink instance of 8-tuple */
+ implicit def shrinkTuple8[T1,T2,T3,T4,T5,T6,T7,T8](implicit
+ s1: Shrink[T1], s2: Shrink[T2], s3: Shrink[T3], s4: Shrink[T4],
+ s5: Shrink[T5], s6: Shrink[T6], s7: Shrink[T7], s8: Shrink[T8]
+ ): Shrink[(T1,T2,T3,T4,T5,T6,T7,T8)] =
+ Shrink { case (t1,t2,t3,t4,t5,t6,t7,t8) =>
+ (for(x1 <- shrink(t1)) yield (x1, t2, t3, t4, t5, t6, t7, t8)) append
+ (for(x2 <- shrink(t2)) yield (t1, x2, t3, t4, t5, t6, t7, t8)) append
+ (for(x3 <- shrink(t3)) yield (t1, t2, x3, t4, t5, t6, t7, t8)) append
+ (for(x4 <- shrink(t4)) yield (t1, t2, t3, x4, t5, t6, t7, t8)) append
+ (for(x5 <- shrink(t5)) yield (t1, t2, t3, t4, x5, t6, t7, t8)) append
+ (for(x6 <- shrink(t6)) yield (t1, t2, t3, t4, t5, x6, t7, t8)) append
+ (for(x7 <- shrink(t7)) yield (t1, t2, t3, t4, t5, t6, x7, t8)) append
+ (for(x8 <- shrink(t8)) yield (t1, t2, t3, t4, t5, t6, t7, x8))
+ }
+
+ /** Shrink instance of 9-tuple */
+ implicit def shrinkTuple9[T1,T2,T3,T4,T5,T6,T7,T8,T9](implicit
+ s1: Shrink[T1], s2: Shrink[T2], s3: Shrink[T3], s4: Shrink[T4],
+ s5: Shrink[T5], s6: Shrink[T6], s7: Shrink[T7], s8: Shrink[T8],
+ s9: Shrink[T9]
+ ): Shrink[(T1,T2,T3,T4,T5,T6,T7,T8,T9)] =
+ Shrink { case (t1,t2,t3,t4,t5,t6,t7,t8,t9) =>
+ (for(x1 <- shrink(t1)) yield (x1, t2, t3, t4, t5, t6, t7, t8, t9)) append
+ (for(x2 <- shrink(t2)) yield (t1, x2, t3, t4, t5, t6, t7, t8, t9)) append
+ (for(x3 <- shrink(t3)) yield (t1, t2, x3, t4, t5, t6, t7, t8, t9)) append
+ (for(x4 <- shrink(t4)) yield (t1, t2, t3, x4, t5, t6, t7, t8, t9)) append
+ (for(x5 <- shrink(t5)) yield (t1, t2, t3, t4, x5, t6, t7, t8, t9)) append
+ (for(x6 <- shrink(t6)) yield (t1, t2, t3, t4, t5, x6, t7, t8, t9)) append
+ (for(x7 <- shrink(t7)) yield (t1, t2, t3, t4, t5, t6, x7, t8, t9)) append
+ (for(x8 <- shrink(t8)) yield (t1, t2, t3, t4, t5, t6, t7, x8, t9)) append
+ (for(x9 <- shrink(t9)) yield (t1, t2, t3, t4, t5, t6, t7, t8, x9))
+ }
+
+}
diff --git a/src/scalacheck/org/scalacheck/Test.scala b/src/scalacheck/org/scalacheck/Test.scala
new file mode 100644
index 0000000000..82d9f679b6
--- /dev/null
+++ b/src/scalacheck/org/scalacheck/Test.scala
@@ -0,0 +1,312 @@
+/*-------------------------------------------------------------------------*\
+** ScalaCheck **
+** Copyright (c) 2007-2010 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
+
+object Test {
+
+ import util.FreqMap
+ import scala.collection.immutable
+ import Prop.FM
+ import util.CmdLineParser
+
+ /** Test parameters */
+ case class Params(
+ minSuccessfulTests: Int = 100,
+ maxDiscardedTests: Int = 500,
+ minSize: Int = 0,
+ maxSize: Int = Gen.Params().size,
+ rng: java.util.Random = Gen.Params().rng,
+ workers: Int = 1,
+ testCallback: TestCallback = new TestCallback {}
+ )
+
+ /** Test statistics */
+ case class Result(status: Status, succeeded: Int, discarded: Int, freqMap: FM) {
+ 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: Prop.Args) extends Status
+
+ /** The property was proved wrong with the given concrete arguments. */
+ sealed case class Failed(args: Prop.Args, 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. */
+ sealed case class PropException(args: Prop.Args, e: Throwable,
+ labels: Set[String]) extends Status
+
+ /** An exception was raised when trying to generate concrete arguments
+ * for evaluating the property. */
+ 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: Params) = {
+ import prms._
+ if(
+ minSuccessfulTests <= 0 ||
+ maxDiscardedTests < 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 => Right(e) }
+
+ private[scalacheck] lazy val cmdLineParser = new CmdLineParser {
+ object OptMinSuccess extends IntOpt {
+ val default = Test.Params().minSuccessfulTests
+ val names = Set("minSuccessfulTests", "s")
+ val help = "Number of tests that must succeed in order to pass a property"
+ }
+ object OptMaxDiscarded extends IntOpt {
+ val default = Test.Params().maxDiscardedTests
+ val names = Set("maxDiscardedTests", "d")
+ val help =
+ "Number of tests that can be discarded before ScalaCheck stops " +
+ "testing a property"
+ }
+ object OptMinSize extends IntOpt {
+ val default = Test.Params().minSize
+ val names = Set("minSize", "n")
+ val help = "Minimum data generation size"
+ }
+ object OptMaxSize extends IntOpt {
+ val default = Test.Params().maxSize
+ val names = Set("maxSize", "x")
+ val help = "Maximum data generation size"
+ }
+ object OptWorkers extends IntOpt {
+ val default = Test.Params().workers
+ val names = Set("workers", "w")
+ val help = "Number of threads to execute in parallel for testing"
+ }
+ object OptVerbosity extends IntOpt {
+ val default = 1
+ val names = Set("verbosity", "v")
+ val help = "Verbosity level"
+ }
+
+ val opts = Set[Opt[_]](
+ OptMinSuccess, OptMaxDiscarded, OptMinSize,
+ OptMaxSize, OptWorkers, OptVerbosity
+ )
+
+ def parseParams(args: Array[String]) = parseArgs(args) {
+ optMap => Test.Params(
+ optMap(OptMinSuccess),
+ optMap(OptMaxDiscarded),
+ optMap(OptMinSize),
+ optMap(OptMaxSize),
+ Test.Params().rng,
+ optMap(OptWorkers),
+ ConsoleReporter(optMap(OptVerbosity))
+ )
+ }
+ }
+
+ /** Tests a property with the given testing parameters, and returns
+ * the test results. */
+ def check(prms: Params, p: Prop): Result = {
+ import prms._
+ import actors.Futures.future
+
+ assertParams(prms)
+ if(workers > 1)
+ assert(!p.isInstanceOf[Commands], "Commands cannot be checked multi-threaded")
+
+ val iterations = minSuccessfulTests / workers
+ val sizeStep = (maxSize-minSize) / (minSuccessfulTests: Float)
+ var stop = false
+
+ def worker(workerdIdx: Int) = future {
+ var n = 0
+ var d = 0
+ var size = workerdIdx*sizeStep
+ var res: Result = null
+ var fm = FreqMap.empty[immutable.Set[Any]]
+ while(!stop && res == null && n < iterations) {
+ val propPrms = Prop.Params(Gen.Params(size.round, prms.rng), fm)
+ secure(p(propPrms)) match {
+ case Right(e) => res =
+ Result(GenException(e), n, d, FreqMap.empty[immutable.Set[Any]])
+ case Left(propRes) =>
+ fm =
+ if(propRes.collected.isEmpty) fm
+ else fm + propRes.collected
+ propRes.status match {
+ case Prop.Undecided =>
+ d += 1
+ testCallback.onPropEval("", workerdIdx, n, d)
+ if(d >= maxDiscardedTests) res = Result(Exhausted, n, d, fm)
+ case Prop.True =>
+ n += 1
+ testCallback.onPropEval("", workerdIdx, n, d)
+ case Prop.Proof =>
+ n += 1
+ res = Result(Proved(propRes.args), n, d, fm)
+ case Prop.False => res =
+ Result(Failed(propRes.args, propRes.labels), n, d, fm)
+ case Prop.Exception(e) => res =
+ Result(PropException(propRes.args, e, propRes.labels), n, d, fm)
+ }
+ }
+ size += sizeStep
+ }
+ if(res != null) stop = true
+ else res = Result(Passed, n, d, fm)
+ res
+ }
+
+ def mergeResults(r1: () => Result, r2: () => Result) = r1() match {
+ case Result(Passed, s1, d1, fm1) => r2() match {
+ case Result(Passed, s2, d2, fm2) if d1+d2 >= maxDiscardedTests =>
+ () => Result(Exhausted, s1+s2, d1+d2, fm1++fm2)
+ case Result(st, s2, d2, fm2) =>
+ () => Result(st, s1+s2, d1+d2, fm1++fm2)
+ }
+ case r => () => r
+ }
+
+ val results = for(i <- 0 until workers) yield worker(i)
+ val r = results.reduceLeft(mergeResults)()
+ stop = true
+ results foreach (_.apply())
+ prms.testCallback.onTestResult("", r)
+ r
+ }
+
+ def checkProperties(prms: Params, 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 copy (testCallback = testCallback), p)
+ (name,res)
+ }
+
+
+ // Deprecated methods //
+
+ /** Default testing parameters
+ * @deprecated Use <code>Test.Params()</code> instead */
+ @deprecated("Use Test.Params() instead")
+ val defaultParams = Params()
+
+ /** Property evaluation callback. Takes number of passed and
+ * discarded tests, respectively */
+ @deprecated("(v1.8)")
+ type PropEvalCallback = (Int,Int) => Unit
+
+ /** Property evaluation callback. Takes property name, and number of passed
+ * and discarded tests, respectively */
+ @deprecated("(v1.8)")
+ type NamedPropEvalCallback = (String,Int,Int) => Unit
+
+ /** Test callback. Takes property name, and test results. */
+ @deprecated("(v1.8)")
+ type TestResCallback = (String,Result) => Unit
+
+ /** @deprecated (v1.8) Use <code>check(prms.copy(testCallback = myCallback), p)</code> instead. */
+ @deprecated("(v1.8) Use check(prms.copy(testCallback = myCallback), p) instead")
+ def check(prms: Params, p: Prop, propCallb: PropEvalCallback): Result = {
+ val testCallback = new TestCallback {
+ override def onPropEval(n: String, t: Int, s: Int, d: Int) = propCallb(s,d)
+ }
+ check(prms copy (testCallback = testCallback), p)
+ }
+
+ /** Tests a property and prints results to the console. The
+ * <code>maxDiscarded</code> parameter specifies how many
+ * discarded tests that should be allowed before ScalaCheck
+ * @deprecated (v1.8) Use <code>check(Params(maxDiscardedTests = n, testCallback = ConsoleReporter()), p)</code> instead. */
+ @deprecated("(v1.8) Use check(Params(maxDiscardedTests = n, testCallback = ConsoleReporter()), p) instead.")
+ def check(p: Prop, maxDiscarded: Int): Result =
+ check(Params(maxDiscardedTests = maxDiscarded, testCallback = ConsoleReporter()), p)
+
+ /** Tests a property and prints results to the console
+ * @deprecated (v1.8) Use <code>check(Params(testCallback = ConsoleReporter()), p)</code> instead. */
+ @deprecated("(v1.8) Use check(Params(testCallback = ConsoleReporter()), p) instead.")
+ def check(p: Prop): Result = check(Params(testCallback = ConsoleReporter()), p)
+
+ /** Tests all properties with the given testing parameters, and returns
+ * the test results. <code>f</code> is a function which is called each
+ * time a property is evaluted. <code>g</code> is a function called each
+ * time a property has been fully tested.
+ * @deprecated (v1.8) Use <code>checkProperties(prms.copy(testCallback = myCallback), ps)</code> instead. */
+ @deprecated("(v1.8) Use checkProperties(prms.copy(testCallback = myCallback), ps) instead.")
+ def checkProperties(ps: Properties, prms: Params,
+ propCallb: NamedPropEvalCallback, testCallb: TestResCallback
+ ): Seq[(String,Result)] = {
+ val testCallback = new TestCallback {
+ override def onPropEval(n: String, t: Int, s: Int, d: Int) = propCallb(n,s,d)
+ override def onTestResult(n: String, r: Result) = testCallb(n,r)
+ }
+ checkProperties(prms copy (testCallback = testCallback), ps)
+ }
+
+ /** Tests all properties with the given testing parameters, and returns
+ * the test results.
+ * @deprecated (v1.8) Use checkProperties(prms, ps) instead */
+ @deprecated("(v1.8) Use checkProperties(prms, ps) instead")
+ def checkProperties(ps: Properties, prms: Params): Seq[(String,Result)] =
+ checkProperties(ps, prms, (n,s,d) => (), (n,s) => ())
+
+ /** Tests all properties with default testing parameters, and returns
+ * the test results. The results are also printed on the console during
+ * testing.
+ * @deprecated (v1.8) Use <code>checkProperties(Params(), ps)</code> instead. */
+ @deprecated("(v1.8) Use checkProperties(Params(), ps) instead.")
+ def checkProperties(ps: Properties): Seq[(String,Result)] =
+ checkProperties(Params(), ps)
+}
diff --git a/src/scalacheck/org/scalacheck/util/Buildable.scala b/src/scalacheck/org/scalacheck/util/Buildable.scala
new file mode 100644
index 0000000000..a41448ee94
--- /dev/null
+++ b/src/scalacheck/org/scalacheck/util/Buildable.scala
@@ -0,0 +1,63 @@
+/*-------------------------------------------------------------------------*\
+** ScalaCheck **
+** Copyright (c) 2007-2010 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._
+
+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()
+ }
+}
+
+object Buildable {
+
+ implicit def buildableList[T] = new Buildable[T,List] {
+ def builder = new mutable.ListBuffer[T]
+ }
+
+ implicit def buildableStream[T] = new Buildable[T,Stream] {
+ def builder = (new mutable.ListBuffer[T]).mapResult(_.toStream)
+ }
+
+ implicit def buildableArray[T](implicit cm: ClassManifest[T]) =
+ new Buildable[T,Array] {
+ def builder = mutable.ArrayBuilder.make[T]
+ }
+
+ implicit def buildableMutableSet[T] = new Buildable[T,mutable.Set] {
+ def builder = new mutable.SetBuilder(mutable.Set.empty[T])
+ }
+
+ implicit def buildableImmutableSet[T] = new Buildable[T,immutable.Set] {
+ def builder = new mutable.SetBuilder(immutable.Set.empty[T])
+ }
+
+ implicit def buildableSet[T] = new Buildable[T,Set] {
+ def builder = new mutable.SetBuilder(Set.empty[T])
+ }
+
+ 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
+ }
+ }
+
+}
diff --git a/src/scalacheck/org/scalacheck/util/CmdLineParser.scala b/src/scalacheck/org/scalacheck/util/CmdLineParser.scala
new file mode 100644
index 0000000000..5fb572ac2d
--- /dev/null
+++ b/src/scalacheck/org/scalacheck/util/CmdLineParser.scala
@@ -0,0 +1,94 @@
+/*-------------------------------------------------------------------------*\
+** ScalaCheck **
+** Copyright (c) 2007-2010 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.util.parsing.combinator.Parsers
+import scala.util.parsing.input.Reader
+import scala.util.parsing.input.Position
+import scala.collection.Set
+import org.scalacheck.Test
+
+trait CmdLineParser extends Parsers {
+
+ 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 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[_]]
+
+ private class ArgsReader(args: Array[String], i: Int) extends Reader[String] {
+ val pos = new Position {
+ val column = (args take i).foldLeft(1)(_ + _.length + 1)
+ val line = 1
+ val lineContents = args.mkString(" ")
+ }
+ val atEnd = i >= args.length
+ def first = if(atEnd) null else args(i)
+ def rest = if(atEnd) this else new ArgsReader(args, i+1)
+ }
+
+ private def getOpt(s: String) = {
+ if(s == null || s.length == 0 || s.charAt(0) != '-') None
+ else opts.find(_.names.contains(s.drop(1)))
+ }
+
+ private val opt: Parser[Opt[Any]] = accept("option name", {
+ case s if getOpt(s).isDefined => getOpt(s).get
+ })
+
+ private val strVal: Parser[String] = accept("string", {
+ case s if s != null => s
+ })
+
+ private val intVal: Parser[Int] = accept("integer", {
+ case s if s != null && s.length > 0 && s.forall(_.isDigit) => s.toInt
+ })
+
+ private case class OptVal[T](o: Opt[T], v: T)
+
+ private val optVal: Parser[OptVal[Any]] = opt into {
+ case o: Flag => success(OptVal(o, ()))
+ case o: IntOpt => intVal ^^ (v => OptVal(o, v))
+ case o: StrOpt => strVal ^^ (v => OptVal(o, v))
+ }
+
+ val options: Parser[OptMap] = rep(optVal) ^^ { xs =>
+ val map = new OptMap
+ xs.foreach { case OptVal(o,v) => map(o) = v }
+ map
+ }
+
+ def printHelp = {
+ println("Available options:")
+ opts.foreach { opt =>
+ println(" " + opt.names.map("-"+_).mkString(", ") + ": " + opt.help)
+ }
+ }
+
+ def parseArgs[T](args: Array[String])(f: OptMap => T) =
+ phrase(options map f)(new ArgsReader(args,0))
+}
diff --git a/src/scalacheck/org/scalacheck/util/FreqMap.scala b/src/scalacheck/org/scalacheck/util/FreqMap.scala
new file mode 100644
index 0000000000..11cdb3ec28
--- /dev/null
+++ b/src/scalacheck/org/scalacheck/util/FreqMap.scala
@@ -0,0 +1,65 @@
+/*-------------------------------------------------------------------------*\
+** ScalaCheck **
+** Copyright (c) 2007-2010 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/scalacheck/org/scalacheck/util/StdRand.scala b/src/scalacheck/org/scalacheck/util/StdRand.scala
new file mode 100644
index 0000000000..ccdbbea301
--- /dev/null
+++ b/src/scalacheck/org/scalacheck/util/StdRand.scala
@@ -0,0 +1,12 @@
+/*-------------------------------------------------------------------------*\
+** ScalaCheck **
+** Copyright (c) 2007-2010 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
+
+object StdRand extends java.util.Random
diff --git a/test/benchmarks/source.list b/test/benchmarks/source.list
index 88d2b257b2..9ca7a406dd 100644
--- a/test/benchmarks/source.list
+++ b/test/benchmarks/source.list
@@ -23,6 +23,7 @@ src/scala/collection/parallel/benchmarks/parallel_array/PatchHalf.scala
src/scala/collection/parallel/benchmarks/parallel_array/DiffHalf.scala
src/scala/collection/parallel/benchmarks/parallel_array/TakeMany.scala
src/scala/collection/parallel/benchmarks/parallel_array/PartialMapLight.scala
+src/scala/collection/parallel/benchmarks/parallel_array/ScanLight.scala
src/scala/collection/parallel/benchmarks/parallel_array/Reverse.scala
src/scala/collection/parallel/benchmarks/parallel_array/SpanLight.scala
src/scala/collection/parallel/benchmarks/parallel_array/PlusPlus.scala
@@ -62,7 +63,10 @@ src/scala/collection/parallel/benchmarks/generic/Dummy.scala
src/scala/collection/parallel/benchmarks/parallel_range/RangeBenches.scala
src/scala/collection/parallel/benchmarks/Bench.scala
src/scala/collection/parallel/benchmarks/hashtries/Foreach.scala
+src/scala/collection/parallel/benchmarks/hashtries/Combine.scala
+src/scala/collection/parallel/benchmarks/hashtries/MultipleCombine.scala
src/scala/collection/parallel/benchmarks/hashtries/Iterate.scala
src/scala/collection/parallel/benchmarks/hashtries/Construct.scala
src/scala/collection/parallel/benchmarks/hashtries/IntInit.scala
src/scala/collection/parallel/benchmarks/hashtries/Lookup.scala
+src/scala/collection/parallel/benchmarks/hashtries/ParallelHashTries.scala
diff --git a/test/benchmarks/src/scala/collection/parallel/Benchmarking.scala b/test/benchmarks/src/scala/collection/parallel/Benchmarking.scala
index 89b5696f9d..2cc3abaf27 100644
--- a/test/benchmarks/src/scala/collection/parallel/Benchmarking.scala
+++ b/test/benchmarks/src/scala/collection/parallel/Benchmarking.scala
@@ -99,6 +99,7 @@ trait BenchmarkRegister {
// parallel hash trie benchmarks
register(hashtries.RefParHashTrieBenches.Reduce)
register(hashtries.RefParHashTrieBenches.ReduceMedium)
+ register(hashtries.RefParHashTrieBenches.Reduce2)
register(hashtries.RefParHashTrieBenches.Map)
register(hashtries.RefParHashTrieBenches.Map2)
}
diff --git a/test/benchmarks/src/scala/collection/parallel/benchmarks/hashtries/ParallelHashTries.scala b/test/benchmarks/src/scala/collection/parallel/benchmarks/hashtries/ParallelHashTries.scala
index bec8ba6650..c68bce93b2 100644
--- a/test/benchmarks/src/scala/collection/parallel/benchmarks/hashtries/ParallelHashTries.scala
+++ b/test/benchmarks/src/scala/collection/parallel/benchmarks/hashtries/ParallelHashTries.scala
@@ -21,6 +21,7 @@ trait ParHashTrieBenches[K, V] extends StandardParIterableBench[(K, V), ParHashT
object Map2 extends IterableBenchCompanion {
override def defaultSize = 5000
+ override def comparisons = List("jhashtable", "hashtable")
def benchName = "map2";
def apply(sz: Int, p: Int, w: String) = new Map2(sz, p, w)
}
@@ -28,7 +29,7 @@ trait ParHashTrieBenches[K, V] extends StandardParIterableBench[(K, V), ParHashT
class Map2(val size: Int, val parallelism: Int, val runWhat: String)
extends IterableBench with StandardParIterableBench[(K, V), ParHashTrie[K, V]] {
var result: Int = 0
- def comparisonMap = collection.Map()
+ def comparisonMap = collection.Map("jhashtable" -> runjhashtable _, "hashtable" -> runhashtable _)
def runseq = {
val r = this.seqcoll.asInstanceOf[collection.immutable.HashMap[K, V]].map(operators.mapper2)
result = r.size
@@ -38,6 +39,29 @@ trait ParHashTrieBenches[K, V] extends StandardParIterableBench[(K, V), ParHashT
//println(collection.parallel.immutable.ParHashTrie.totalcombines)
//System.exit(1)
}
+ def runjhashtable = {
+ val jumap = new java.util.HashMap[K, V]()
+ val it = this.seqcoll.iterator
+ while (it.hasNext) {
+ val p = it.next
+ jumap.put(p._1, p._2)
+ }
+ result = jumap.size
+ }
+ def runhashtable = {
+ val smap = collection.mutable.HashMap[K, V]()
+ val it = this.seqcoll.iterator
+ while (it.hasNext) {
+ val p = it.next
+ smap.put(p._1, p._2)
+ }
+ result = smap.size
+ }
+ override def reset = runWhat match {
+ case "jhashtable" => this.seqcoll = createSequential(size, parallelism)
+ case "hashtable" => this.seqcoll = createSequential(size, parallelism)
+ case _ => super.reset
+ }
def companion = Map2
override def repetitionsPerRun = 50
override def printResults {
@@ -46,6 +70,29 @@ trait ParHashTrieBenches[K, V] extends StandardParIterableBench[(K, V), ParHashT
}
}
+ object Reduce2 extends IterableBenchCompanion {
+ override def defaultSize = 50000
+ override def comparisons = List("hashtable")
+ def benchName = "reduce2";
+ def apply(sz: Int, p: Int, w: String) = new Reduce2(sz, p, w)
+ }
+
+ class Reduce2(val size: Int, val parallelism: Int, val runWhat: String)
+ extends IterableBench with StandardParIterableBench[(K, V), ParHashTrie[K, V]] {
+ private var ht: collection.mutable.HashMap[K, V] = _
+ def comparisonMap = collection.Map("hashtable" -> runhashtable _)
+ def runseq = this.seqcoll.reduceLeft(operators.reducer)
+ def runpar = this.parcoll.reduce(operators.reducer)
+ def runhashtable = ht.reduceLeft(operators.reducer)
+ override def reset = runWhat match {
+ case "hashtable" => ht = createHashTable(size)
+ case _ => super.reset
+ }
+ def companion = Reduce2
+ }
+
+ def createHashTable(sz: Int): collection.mutable.HashMap[K, V]
+
}
@@ -118,4 +165,10 @@ object RefParHashTrieBenches extends ParHashTrieBenches[Dummy, Dummy] with NotBe
pht
}
+ def createHashTable(sz: Int) = {
+ val hm = collection.mutable.HashMap[Dummy, Dummy]()
+ for (i <- 0 until sz) hm.put(new Dummy(i), new Dummy(i))
+ hm
+ }
+
}
diff --git a/test/benchmarks/src/scala/collection/parallel/benchmarks/parallel_array/CountLight.scala b/test/benchmarks/src/scala/collection/parallel/benchmarks/parallel_array/CountLight.scala
index 87eb07452f..569b304660 100644
--- a/test/benchmarks/src/scala/collection/parallel/benchmarks/parallel_array/CountLight.scala
+++ b/test/benchmarks/src/scala/collection/parallel/benchmarks/parallel_array/CountLight.scala
@@ -19,3 +19,4 @@ extends Resettable(sz, p, what, new Cont(_), new Array[Any](_), classOf[Cont]) {
def runjsr = jsrarr.withFilter(Cont.predjsr).size
def comparisonMap = collection.Map("jsr" -> runjsr _)
}
+
diff --git a/tools/updatescalacheck b/tools/updatescalacheck
new file mode 100755
index 0000000000..46112cf29d
--- /dev/null
+++ b/tools/updatescalacheck
@@ -0,0 +1,12 @@
+#
+# Updates ScalaCheck sources from ScalaCheck nightly branch
+#
+
+# update sources
+rm -r -f ../src/scalacheck
+svn export https://scalacheck.googlecode.com/svn/branches/scalanightly/src/main/scala ../src/scalacheck
+
+# remove unneeded class
+rm ../src/scalacheck/org/scalacheck/ScalaCheckFramework.scala
+
+