diff options
Diffstat (limited to 'src/scalacheck')
-rw-r--r-- | src/scalacheck/org/scalacheck/Arbitrary.scala | 83 | ||||
-rw-r--r-- | src/scalacheck/org/scalacheck/Arg.scala | 2 | ||||
-rw-r--r-- | src/scalacheck/org/scalacheck/Commands.scala | 6 | ||||
-rw-r--r-- | src/scalacheck/org/scalacheck/ConsoleReporter.scala | 2 | ||||
-rw-r--r-- | src/scalacheck/org/scalacheck/Gen.scala | 41 | ||||
-rw-r--r-- | src/scalacheck/org/scalacheck/Pretty.scala | 4 | ||||
-rw-r--r-- | src/scalacheck/org/scalacheck/Prop.scala | 81 | ||||
-rw-r--r-- | src/scalacheck/org/scalacheck/Properties.scala | 30 | ||||
-rw-r--r-- | src/scalacheck/org/scalacheck/ScalaCheckFramework.scala | 92 | ||||
-rw-r--r-- | src/scalacheck/org/scalacheck/Shrink.scala | 2 | ||||
-rw-r--r-- | src/scalacheck/org/scalacheck/Test.scala | 207 | ||||
-rw-r--r-- | src/scalacheck/org/scalacheck/util/Buildable.scala | 5 | ||||
-rw-r--r-- | src/scalacheck/org/scalacheck/util/CmdLineParser.scala | 4 | ||||
-rw-r--r-- | src/scalacheck/org/scalacheck/util/FreqMap.scala | 2 | ||||
-rw-r--r-- | src/scalacheck/org/scalacheck/util/StdRand.scala | 2 |
15 files changed, 439 insertions, 124 deletions
diff --git a/src/scalacheck/org/scalacheck/Arbitrary.scala b/src/scalacheck/org/scalacheck/Arbitrary.scala index 8c43cdaafe..db4163c8af 100644 --- a/src/scalacheck/org/scalacheck/Arbitrary.scala +++ b/src/scalacheck/org/scalacheck/Arbitrary.scala @@ -1,6 +1,6 @@ /*-------------------------------------------------------------------------*\ ** ScalaCheck ** -** Copyright (c) 2007-2011 Rickard Nilsson. All rights reserved. ** +** Copyright (c) 2007-2013 Rickard Nilsson. All rights reserved. ** ** http://www.scalacheck.org ** ** ** ** This software is released under the terms of the Revised BSD License. ** @@ -10,49 +10,44 @@ package org.scalacheck import util.{FreqMap,Buildable} -import scala.reflect.ClassTag sealed abstract class Arbitrary[T] { val arbitrary: Gen[T] } -/** Defines implicit <code>Arbitrary</code> instances for common types. +/** Defines implicit [[org.scalacheck.Arbitrary]] 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 + * uses implicit [[org.scalacheck.Arbitrary]] instances when creating properties + * out of functions with the `Prop.property` method, and when + * the `Arbitrary.arbitrary` method is used. For example, the * following code requires that there exists an implicit - * <code>Arbitrary[MyClass]</code> instance: + * `Arbitrary[MyClass]` instance: * </p> * - * <p> - * <code> - * val myProp = Prop.forAll { myClass: MyClass =><br /> - * ...<br /> - * }<br /> + * {{{ + * val myProp = Prop.forAll { myClass: MyClass => + * ... + * } * * 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>. + * The factory method `Arbitrary(...)` takes a generator of type + * `Gen[T]` and returns an instance of `Arbitrary[T]`. * </p> * * <p> - * The <code>Arbitrary</code> module defines implicit <code>Arbitrary</code> + * The `Arbitrary` module defines implicit [[org.scalacheck.Arbitrary]] * instances for common types, for convenient use in your properties and * generators. * </p> @@ -93,7 +88,7 @@ object Arbitrary { /** Arbitrary instance of Long */ implicit lazy val arbLong: Arbitrary[Long] = Arbitrary( - Gen.chooseNum(Long.MinValue / 2, Long.MaxValue / 2) + Gen.chooseNum(Long.MinValue, Long.MaxValue) ) /** Arbitrary instance of Float */ @@ -182,7 +177,13 @@ object Arbitrary { mc <- mcGen limit <- value(if(mc == UNLIMITED) 0 else math.max(x.abs.toString.length - mc.getPrecision, 0)) scale <- Gen.chooseNum(Int.MinValue + limit , Int.MaxValue) - } yield BigDecimal(x, scale, mc) + } yield { + try { + BigDecimal(x, scale, mc) + } catch { + case ae: java.lang.ArithmeticException => BigDecimal(x, scale, UNLIMITED) // Handle the case where scale/precision conflict + } + } Arbitrary(bdGen) } @@ -213,23 +214,43 @@ object Arbitrary { )) } - /** Arbitrary instance of test params */ + /** Arbitrary instance of test params + * @deprecated (in 1.10.0) Use `arbTestParameters` instead. + */ + @deprecated("Use 'arbTestParameters' instead", "1.10.0") implicit lazy val arbTestParams: Arbitrary[Test.Params] = Arbitrary(for { minSuccTests <- choose(10,200) - maxDiscardRatio <- choose(0.2f,10f) - minSize <- choose(0,500) + maxDiscTests <- choose(100,500) + mnSize <- choose(0,500) sizeDiff <- choose(0,500) - maxSize <- choose(minSize, minSize + sizeDiff) + mxSize <- choose(mnSize, mnSize + sizeDiff) ws <- choose(1,4) } yield Test.Params( minSuccessfulTests = minSuccTests, - maxDiscardRatio = maxDiscardRatio, - minSize = minSize, - maxSize = maxSize, + maxDiscardedTests = maxDiscTests, + minSize = mnSize, + maxSize = mxSize, workers = ws )) + /** Arbitrary instance of test parameters */ + implicit lazy val arbTestParameters: Arbitrary[Test.Parameters] = + Arbitrary(for { + _minSuccTests <- choose(10,200) + _maxDiscardRatio <- choose(0.2f,10f) + _minSize <- choose(0,500) + sizeDiff <- choose(0,500) + _maxSize <- choose(_minSize, _minSize + sizeDiff) + _workers <- choose(1,4) + } yield new Test.Parameters.Default { + override val minSuccessfulTests = _minSuccTests + override val maxDiscardRatio = _maxDiscardRatio + override val minSize = _minSize + override val maxSize = _maxSize + override val workers = _workers + }) + /** Arbitrary instance of gen params */ implicit lazy val arbGenParams: Arbitrary[Gen.Params] = Arbitrary(for { @@ -278,7 +299,7 @@ object Arbitrary { ): Arbitrary[C[T]] = Arbitrary(containerOf[C,T](arbitrary[T])) /** Arbitrary instance of any array. */ - implicit def arbArray[T](implicit a: Arbitrary[T], c: ClassTag[T] + implicit def arbArray[T](implicit a: Arbitrary[T], c: ClassManifest[T] ): Arbitrary[Array[T]] = Arbitrary(containerOf[Array,T](arbitrary[T])) diff --git a/src/scalacheck/org/scalacheck/Arg.scala b/src/scalacheck/org/scalacheck/Arg.scala index 8959211f09..4961c78a26 100644 --- a/src/scalacheck/org/scalacheck/Arg.scala +++ b/src/scalacheck/org/scalacheck/Arg.scala @@ -1,6 +1,6 @@ /*-------------------------------------------------------------------------*\ ** ScalaCheck ** -** Copyright (c) 2007-2011 Rickard Nilsson. All rights reserved. ** +** Copyright (c) 2007-2013 Rickard Nilsson. All rights reserved. ** ** http://www.scalacheck.org ** ** ** ** This software is released under the terms of the Revised BSD License. ** diff --git a/src/scalacheck/org/scalacheck/Commands.scala b/src/scalacheck/org/scalacheck/Commands.scala index 88ef8ae2a1..604b68cb36 100644 --- a/src/scalacheck/org/scalacheck/Commands.scala +++ b/src/scalacheck/org/scalacheck/Commands.scala @@ -1,6 +1,6 @@ /*-------------------------------------------------------------------------*\ ** ScalaCheck ** -** Copyright (c) 2007-2011 Rickard Nilsson. All rights reserved. ** +** Copyright (c) 2007-2013 Rickard Nilsson. All rights reserved. ** ** http://www.scalacheck.org ** ** ** ** This software is released under the terms of the Revised BSD License. ** @@ -53,7 +53,7 @@ trait Commands extends Prop { * 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 scala.collection.mutable.ListBuffer[State => Boolean] + val preConditions = new collection.mutable.ListBuffer[State => Boolean] /** Returns all postconditions merged into a single function */ def postCondition: (State,State,Any) => Prop = (s0,s1,r) => all(postConditions.map(_.apply(s0,s1,r)): _*) @@ -65,7 +65,7 @@ trait Commands extends Prop { * 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 scala.collection.mutable.ListBuffer[(State,State,Any) => Prop] + val postConditions = new collection.mutable.ListBuffer[(State,State,Any) => Prop] } /** A command that binds its result for later use */ diff --git a/src/scalacheck/org/scalacheck/ConsoleReporter.scala b/src/scalacheck/org/scalacheck/ConsoleReporter.scala index 93f1dc222e..d565322d99 100644 --- a/src/scalacheck/org/scalacheck/ConsoleReporter.scala +++ b/src/scalacheck/org/scalacheck/ConsoleReporter.scala @@ -1,6 +1,6 @@ /*-------------------------------------------------------------------------*\ ** ScalaCheck ** -** Copyright (c) 2007-2011 Rickard Nilsson. All rights reserved. ** +** Copyright (c) 2007-2013 Rickard Nilsson. All rights reserved. ** ** http://www.scalacheck.org ** ** ** ** This software is released under the terms of the Revised BSD License. ** diff --git a/src/scalacheck/org/scalacheck/Gen.scala b/src/scalacheck/org/scalacheck/Gen.scala index 64bb61c2d3..aec67159f1 100644 --- a/src/scalacheck/org/scalacheck/Gen.scala +++ b/src/scalacheck/org/scalacheck/Gen.scala @@ -1,6 +1,6 @@ /*-------------------------------------------------------------------------*\ ** ScalaCheck ** -** Copyright (c) 2007-2011 Rickard Nilsson. All rights reserved. ** +** Copyright (c) 2007-2013 Rickard Nilsson. All rights reserved. ** ** http://www.scalacheck.org ** ** ** ** This software is released under the terms of the Revised BSD License. ** @@ -23,7 +23,7 @@ object Choose { implicit val chooseLong: Choose[Long] = new Choose[Long] { def choose(low: Long, high: Long) = - if(low > high || (high-low < 0)) fail + if (low > high) fail else parameterized(prms => value(prms.choose(low,high))) } @@ -204,9 +204,17 @@ object Gen { /** @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 l + math.abs(rng.nextLong % (d+1)) + if (h < l) throw new IllegalArgumentException("Invalid range") + val d = h - l + 1 + if (d <= 0) { + var n = rng.nextLong + while (n < l || n > h) { + n = rng.nextLong + } + n + } else { + l + math.abs(rng.nextLong % d) + } } /** @throws IllegalArgumentException if l is greater than h, or if @@ -225,8 +233,11 @@ object Gen { 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> */ + /* Convenience method for using the `frequency` method like this: + * {{{ + * frequency((1, "foo"), (3, "bar")) + * }}} + */ implicit def freqTuple[T](t: (Int, T)): (Int, Gen[T]) = (t._1, value(t._2)) @@ -308,9 +319,9 @@ object Gen { //// List Generators //// /** Generates a container of any type for which there exists an implicit - * <code>Buildable</code> instance. The elements in the container will + * [[org.scalacheck.util.Buildable]] 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>. */ + * is given by `n`. */ 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]] { @@ -321,14 +332,14 @@ object Gen { }) /** 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 + * [[org.scalacheck.util.Buildable]] instance. The elements in the container + * will be generated by the given generator. The size of the container is * bounded by the size parameter used when generating values. */ def containerOf[C[_],T](g: Gen[T])(implicit 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 + * implicit [[org.scalacheck.util.Buildable]] instance. The elements in the container * will be generated by the given generator. The size of the container is * bounded by the size parameter used when generating values. */ def containerOf1[C[_],T](g: Gen[T])(implicit b: Buildable[T,C]): Gen[C[T]] = @@ -336,16 +347,16 @@ object Gen { /** 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>. */ + * `containerOf[List,T](g)`. */ def listOf[T](g: => Gen[T]) = containerOf[List,T](g) /** Generates a non-empty list of random length. The maximum length depends * on the size parameter. This method is equal to calling - * <code>containerOf1[List,T](g)</code>. */ + * `containerOf1[List,T](g)`. */ 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>. */ + * `containerOfN[List,T](n,g)`. */ def listOfN[T](n: Int, g: Gen[T]) = containerOfN[List,T](n,g) /** A generator that picks a random number of elements from a list */ diff --git a/src/scalacheck/org/scalacheck/Pretty.scala b/src/scalacheck/org/scalacheck/Pretty.scala index eeb5936086..3e8f6de5f6 100644 --- a/src/scalacheck/org/scalacheck/Pretty.scala +++ b/src/scalacheck/org/scalacheck/Pretty.scala @@ -1,6 +1,6 @@ /*-------------------------------------------------------------------------*\ ** ScalaCheck ** -** Copyright (c) 2007-2011 Rickard Nilsson. All rights reserved. ** +** Copyright (c) 2007-2013 Rickard Nilsson. All rights reserved. ** ** http://www.scalacheck.org ** ** ** ** This software is released under the terms of the Revised BSD License. ** @@ -96,7 +96,7 @@ object Pretty { } implicit def prettyTestRes(res: Test.Result) = Pretty { prms => - def labels(ls: scala.collection.immutable.Set[String]) = + def labels(ls: collection.immutable.Set[String]) = if(ls.isEmpty) "" else "> Labels of failing property: " / ls.mkString("\n") val s = res.status match { diff --git a/src/scalacheck/org/scalacheck/Prop.scala b/src/scalacheck/org/scalacheck/Prop.scala index dfd85a832a..38e00f260f 100644 --- a/src/scalacheck/org/scalacheck/Prop.scala +++ b/src/scalacheck/org/scalacheck/Prop.scala @@ -1,6 +1,6 @@ /*-------------------------------------------------------------------------*\ ** ScalaCheck ** -** Copyright (c) 2007-2011 Rickard Nilsson. All rights reserved. ** +** Copyright (c) 2007-2013 Rickard Nilsson. All rights reserved. ** ** http://www.scalacheck.org ** ** ** ** This software is released under the terms of the Revised BSD License. ** @@ -31,16 +31,27 @@ trait Prop { /** 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. */ + * from the test use the `check` methods in [[org.scalacheck.Test]] + * instead. + * @deprecated (in 1.10.0) Use `check(Test.Parameters)` instead. + */ + @deprecated("Use 'check(Test.Parameters)' instead", "1.10.0") def check(prms: Test.Params): Unit = Test.check( prms copy (testCallback = ConsoleReporter(1) chain prms.testCallback), this ) + /** 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 `check` methods in [[org.scalacheck.Test]] + * instead. */ + def check(prms: Test.Parameters): 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()) + * the `check` methods in [[org.scalacheck.Test]] instead. */ + def check: Unit = check(Test.Parameters.default) /** The logic for main, separated out to make it easier to * avoid System.exit calls. Returns exit code. @@ -60,7 +71,7 @@ trait Prop { /** Whether main should call System.exit with an exit code. * Defaults to true; override to change. */ - def mainCallsExit = false + def mainCallsExit = true /** Convenience method that makes it possible to use this property * as an application that checks itself on execution */ @@ -274,20 +285,51 @@ object Prop { def apply(r: Result): Prop = Prop(prms => r) + def apply(b: Boolean): Prop = if(b) proved else falsified - // Implicit defs + // Implicits + + /** A collection of property operators on [[Any]] values. + * Import [[Prop.AnyOperators]] to make the operators available. */ class ExtendedAny[T <% Pretty](x: => T) { + /** See [[Prop.imply]] */ def imply(f: PartialFunction[T,Prop]) = Prop.imply(x,f) + /** See [[Prop.iff]] */ def iff(f: PartialFunction[T,Prop]) = Prop.iff(x,f) - def throws[U <: Throwable](c: Class[U]) = Prop.throws(x, c) + @deprecated("Use 'Prop.throws' instead", "1.10.1") + def throws[U <: Throwable](c: Class[U]): Prop = Prop.throws(c)(x) + /** See [[Prop.?=]] */ def ?=(y: T) = Prop.?=(x, y) + /** See [[Prop.=?]] */ def =?(y: T) = Prop.=?(x, y) } + /** A collection of property operators on [[Boolean]] values. + * Import [[Prop.BooleanOperators]] to make the operators available. */ + class ExtendedBoolean(b: => Boolean) { + /** See [[Prop.==>]] */ + def ==>(p: => Prop) = Prop(b) ==> p + } + + /** Implicit method that makes a number of property operators on values of + * type [[Any]] available in the current scope. See [[Prop.ExtendedAny]] for + * documentation on the operators. */ + @deprecated("Use 'Prop.AnyOperators' instead", "1.10.1") implicit def extendedAny[T <% Pretty](x: => T) = new ExtendedAny[T](x) - implicit def propBoolean(b: Boolean): Prop = if(b) proved else falsified + /** Implicit method that makes a number of property operators on values of + * type [[Any]] available in the current scope. See [[Prop.ExtendedAny]] for + * documentation on the operators. */ + implicit def AnyOperators[T <% Pretty](x: => T) = new ExtendedAny[T](x) + + /** Implicit method that makes a number of property operators on boolean + * values available in the current scope. See [[Prop.ExtendedBoolean]] for + * documentation on the operators. */ + implicit def BooleanOperators(b: => Boolean) = new ExtendedBoolean(b) + + /** Implicit conversion of Boolean values to Prop values. */ + implicit def propBoolean(b: Boolean): Prop = Prop(b) // Private support functions @@ -318,6 +360,9 @@ object Prop { /** A property that denotes an exception */ lazy val exception: Prop = exception(null) + /** Create a property that compares to values. If the values aren't equal, + * the property will fail and report that first value doesn't match the + * expected (second) value. */ def ?=[T](x: T, y: T)(implicit pp: T => Pretty): Prop = if(x == y) proved else falsified :| { val exp = Pretty.pretty[T](y, Pretty.Params(0)) @@ -325,6 +370,9 @@ object Prop { "Expected "+exp+" but got "+act } + /** Create a property that compares to values. If the values aren't equal, + * the property will fail and report that second value doesn't match the + * expected (first) value. */ def =?[T](x: T, y: T)(implicit pp: T => Pretty): Prop = ?=(y, x) /** A property that depends on the generator size */ @@ -340,7 +388,7 @@ object 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 */ + * `x`, and returns a property that holds */ def iff[T](x: T, f: PartialFunction[T,Prop]): Prop = secure(if(f.isDefinedAt(x)) f(x) else falsified) @@ -365,9 +413,16 @@ object Prop { 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 + * @deprecated (in 1.10.1) Use `throws(...): Boolean` instead. + */ + @deprecated("Use 'throws(...): Boolean' instead", "1.10.1") + def throws[T <: Throwable](x: => Any, c: Class[T]): Prop = throws(c)(x) + + /** Returns true 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 } + def throws[T <: Throwable](c: Class[T])(x: => Any): Boolean = + try { x; false } catch { case e if c.isInstance(e) => true } /** Collect data for presentation in test report */ def collect[T, P <% Prop](f: T => P): T => Prop = t => Prop { prms => @@ -390,7 +445,7 @@ object Prop { /** Wraps and protects a property */ def secure[P <% Prop](p: => P): Prop = - try { p: Prop } catch { case e => exception(e) } + try { p: Prop } catch { case e: Throwable => exception(e) } /** Existential quantifier for an explicit generator. */ def exists[A,P](f: A => P)(implicit diff --git a/src/scalacheck/org/scalacheck/Properties.scala b/src/scalacheck/org/scalacheck/Properties.scala index 26059231d6..d4836d7420 100644 --- a/src/scalacheck/org/scalacheck/Properties.scala +++ b/src/scalacheck/org/scalacheck/Properties.scala @@ -1,6 +1,6 @@ /*-------------------------------------------------------------------------*\ ** ScalaCheck ** -** Copyright (c) 2007-2011 Rickard Nilsson. All rights reserved. ** +** Copyright (c) 2007-2013 Rickard Nilsson. All rights reserved. ** ** http://www.scalacheck.org ** ** ** ** This software is released under the terms of the Revised BSD License. ** @@ -14,15 +14,15 @@ package org.scalacheck * 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) => + * property("myProp1") = forAll { (n:Int, m:Int) => * n+m == m+n * } * * property("myProp2") = ((0/1) throws classOf[ArithmeticException]) * } + * }}} */ class Properties(val name: String) extends Prop { @@ -42,16 +42,27 @@ class Properties(val name: String) extends Prop { /** 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> + * from the test use the `check` methods in [[org.scalacheck.Test]] * instead. */ + override def check(prms: Test.Parameters): Unit = Test.checkProperties( + prms copy (_testCallback = ConsoleReporter(1) chain prms.testCallback), this + ) + + /** Convenience method that checks the properties with the given parameters + * and reports the result on the console. If you need to get the results + * from the test use the `check` methods in [[org.scalacheck.Test]] + * instead. + * @deprecated (in 1.10.0) Use `check(Test.Parameters)` instead. + */ + @deprecated("Use 'check(Test.Parameters)' instead", "1.10.0") 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()) + * the `check` methods in [[org.scalacheck.Test]] instead. */ + override def check: Unit = check(Test.Parameters.default) /** The logic for main, separated out to make it easier to * avoid System.exit calls. Returns exit code. @@ -73,7 +84,10 @@ class Properties(val name: String) extends Prop { def include(ps: Properties) = for((n,p) <- ps.properties) property(n) = p /** Used for specifying properties. Usage: - * <code>property("myProp") = ...</code> */ + * {{{ + * property("myProp") = ... + * }}} + */ class PropertySpecifier() { def update(propName: String, p: Prop) = props += ((name+"."+propName, p)) } diff --git a/src/scalacheck/org/scalacheck/ScalaCheckFramework.scala b/src/scalacheck/org/scalacheck/ScalaCheckFramework.scala new file mode 100644 index 0000000000..7764101844 --- /dev/null +++ b/src/scalacheck/org/scalacheck/ScalaCheckFramework.scala @@ -0,0 +1,92 @@ +/*-------------------------------------------------------------------------*\ +** ScalaCheck ** +** Copyright (c) 2007-2013 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. ** +\*------------------------------------------------------------------------ */ + +// vim: set ts=2 sw=2 et: + +package org.scalacheck + +import org.scalatools.testing._ + +class ScalaCheckFramework extends Framework { + + private case object PropFingerprint extends TestFingerprint { + val superClassName = "org.scalacheck.Prop" + val isModule = false + } + + private case object PropsFingerprint extends TestFingerprint { + val superClassName = "org.scalacheck.Properties" + val isModule = true + } + + val name = "ScalaCheck" + + val tests = Array[Fingerprint](PropsFingerprint, PropsFingerprint) + + def testRunner(loader: ClassLoader, loggers: Array[Logger]) = new Runner2 { + + private def asEvent(nr: (String, Test.Result)) = nr match { + case (n: String, r: Test.Result) => new Event { + val testName = n + val description = n + val result = r.status match { + case Test.Passed => Result.Success + case _:Test.Proved => Result.Success + case _:Test.Failed => Result.Failure + case Test.Exhausted => Result.Skipped + case _:Test.PropException | _:Test.GenException => Result.Error + } + val error = r.status match { + case Test.PropException(_, e, _) => e + case _:Test.Failed => new Exception(Pretty.pretty(r,Pretty.Params(0))) + case _ => null + } + } + } + + def run(testClassName: String, fingerprint: Fingerprint, handler: EventHandler, args: Array[String]) { + + val testCallback = new Test.TestCallback { + override def onPropEval(n: String, w: Int, s: Int, d: Int) = {} + + override def onTestResult(n: String, r: Test.Result) = { + for (l <- loggers) { + import Pretty._ + l.info( + (if (r.passed) "+ " else "! ") + n + ": " + pretty(r, Params(0)) + ) + } + handler.handle(asEvent((n,r))) + } + } + + import Test.cmdLineParser.{Success, NoSuccess} + val prms = Test.cmdLineParser.parseParams(args) match { + case Success(params, _) => + params.copy(_testCallback = testCallback, _customClassLoader = Some(loader)) + // TODO: Maybe handle this a bit better than throwing exception? + case e: NoSuccess => throw new Exception(e.toString) + } + + fingerprint match { + case fp: SubclassFingerprint => + if(fp.isModule) { + val obj = Class.forName(testClassName + "$", true, loader) + val ps = obj.getField("MODULE$").get(null).asInstanceOf[Properties] + Test.checkProperties(prms, ps) + } else { + val p = Class.forName(testClassName, true, loader).newInstance.asInstanceOf[Prop] + handler.handle(asEvent((testClassName, Test.check(prms, p)))) + } + } + } + + } + +} diff --git a/src/scalacheck/org/scalacheck/Shrink.scala b/src/scalacheck/org/scalacheck/Shrink.scala index ae15bd9616..4895171a35 100644 --- a/src/scalacheck/org/scalacheck/Shrink.scala +++ b/src/scalacheck/org/scalacheck/Shrink.scala @@ -1,6 +1,6 @@ /*-------------------------------------------------------------------------*\ ** ScalaCheck ** -** Copyright (c) 2007-2011 Rickard Nilsson. All rights reserved. ** +** Copyright (c) 2007-2013 Rickard Nilsson. All rights reserved. ** ** http://www.scalacheck.org ** ** ** ** This software is released under the terms of the Revised BSD License. ** diff --git a/src/scalacheck/org/scalacheck/Test.scala b/src/scalacheck/org/scalacheck/Test.scala index 4368184823..6e9b6b88fd 100644 --- a/src/scalacheck/org/scalacheck/Test.scala +++ b/src/scalacheck/org/scalacheck/Test.scala @@ -1,6 +1,6 @@ /*-------------------------------------------------------------------------*\ ** ScalaCheck ** -** Copyright (c) 2007-2011 Rickard Nilsson. All rights reserved. ** +** Copyright (c) 2007-2013 Rickard Nilsson. All rights reserved. ** ** http://www.scalacheck.org ** ** ** ** This software is released under the terms of the Revised BSD License. ** @@ -16,23 +16,120 @@ object Test { import Prop.FM import util.CmdLineParser - /** Test parameters */ + /** Test parameters used by the `Test.check` method. + */ + trait Parameters { + /** The minimum number of tests that must succeed for ScalaCheck to + * consider a property passed. */ + def minSuccessfulTests: Int + + /** The starting size given as parameter to the generators. */ + def minSize: Int + + /** The maximum size given as parameter to the generators. */ + def maxSize: Int + + /** The random numbe generator used. */ + def rng: java.util.Random + + /** The number of tests run in parallell. */ + def workers: Int + + /** A callback that ScalaCheck calls each time a test is executed. */ + def testCallback: TestCallback + + /** The maximum ratio between discarded and passed tests allowed before + * ScalaCheck gives up and discards the property. At least + * `minSuccesfulTests` will always be run, though. */ + def maxDiscardRatio: Float + + /** A custom class loader that should be used during test execution. */ + def customClassLoader: Option[ClassLoader] + + // private since we can't guarantee binary compatibility for this one + private[scalacheck] def copy( + _minSuccessfulTests: Int = Parameters.this.minSuccessfulTests, + _minSize: Int = Parameters.this.minSize, + _maxSize: Int = Parameters.this.maxSize, + _rng: java.util.Random = Parameters.this.rng, + _workers: Int = Parameters.this.workers, + _testCallback: TestCallback = Parameters.this.testCallback, + _maxDiscardRatio: Float = Parameters.this.maxDiscardRatio, + _customClassLoader: Option[ClassLoader] = Parameters.this.customClassLoader + ): Parameters = new Parameters { + val minSuccessfulTests: Int = _minSuccessfulTests + val minSize: Int = _minSize + val maxSize: Int = _maxSize + val rng: java.util.Random = _rng + val workers: Int = _workers + val testCallback: TestCallback = _testCallback + val maxDiscardRatio: Float = _maxDiscardRatio + val customClassLoader: Option[ClassLoader] = _customClassLoader + } + } + + /** Test parameters used by the `Test.check` method. + * + * To override default values, extend the + * [[org.scalacheck.Test.Parameters.Default]] trait: + * + * {{{ + * val myParams = new Parameters.Default { + * override val minSuccesfulTests = 600 + * override val maxDiscardRatio = 8 + * } + * }}} + */ + object Parameters { + /** Default test parameters trait. This can be overriden if you need to + * tweak the parameters. */ + trait Default extends Parameters { + val minSuccessfulTests: Int = 100 + val minSize: Int = 0 + val maxSize: Int = Gen.Params().size + val rng: java.util.Random = Gen.Params().rng + val workers: Int = 1 + val testCallback: TestCallback = new TestCallback {} + val maxDiscardRatio: Float = 5 + val customClassLoader: Option[ClassLoader] = None + } + + /** Default test parameters instance. */ + val default: Parameters = new Default {} + } + + /** Test parameters + * @deprecated (in 1.10.0) Use [[org.scalacheck.Test.Parameters]] instead. + */ + @deprecated("Use [[org.scalacheck.Test.Parameters]] instead", "1.10.0") case class Params( minSuccessfulTests: Int = 100, - - /** @deprecated Use maxDiscardRatio instead. */ - @deprecated("Use maxDiscardRatio instead.", "1.10") maxDiscardedTests: Int = -1, - minSize: Int = 0, maxSize: Int = Gen.Params().size, rng: java.util.Random = Gen.Params().rng, workers: Int = 1, - testCallback: TestCallback = new TestCallback {}, - maxDiscardRatio: Float = 5, - customClassLoader: Option[ClassLoader] = None + testCallback: TestCallback = new TestCallback {} ) + @deprecated("Use [[org.scalacheck.Test.Parameters]] instead", "1.10.0") + private def paramsToParameters(params: Params) = new Parameters { + val minSuccessfulTests = params.minSuccessfulTests + val minSize = params.minSize + val maxSize = params.maxSize + val rng = params.rng + val workers = params.workers + val testCallback = params.testCallback + + // maxDiscardedTests is deprecated, but if someone + // uses it let it override maxDiscardRatio + val maxDiscardRatio = + if(params.maxDiscardedTests < 0) Parameters.default.maxDiscardRatio + else (params.maxDiscardedTests: Float)/(params.minSuccessfulTests: Float) + + val customClassLoader = Parameters.default.customClassLoader + } + /** Test statistics */ case class Result(status: Status, succeeded: Int, discarded: Int, freqMap: FM, time: Long = 0) { def passed = status match { @@ -92,7 +189,7 @@ object Test { } } - private def assertParams(prms: Params) = { + private def assertParams(prms: Parameters) = { import prms._ if( minSuccessfulTests <= 0 || @@ -104,16 +201,24 @@ object Test { } private def secure[T](x: => T): Either[T,Throwable] = - try { Left(x) } catch { case e => Right(e) } + try { Left(x) } catch { case e: Throwable => Right(e) } private[scalacheck] lazy val cmdLineParser = new CmdLineParser { object OptMinSuccess extends IntOpt { - val default = Test.Params().minSuccessfulTests + val default = Parameters.default.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 = -1 + val names = Set("maxDiscardedTests", "d") + val help = + "Number of tests that can be discarded before ScalaCheck stops " + + "testing a property. NOTE: this option is deprecated, please use " + + "the option maxDiscardRatio (-r) instead." + } object OptMaxDiscardRatio extends FloatOpt { - val default = Test.Params().maxDiscardRatio + val default = Parameters.default.maxDiscardRatio val names = Set("maxDiscardRatio", "r") val help = "The maximum ratio between discarded and succeeded tests " + @@ -121,17 +226,17 @@ object Test { "least minSuccessfulTests will always be tested, though." } object OptMinSize extends IntOpt { - val default = Test.Params().minSize + val default = Parameters.default.minSize val names = Set("minSize", "n") val help = "Minimum data generation size" } object OptMaxSize extends IntOpt { - val default = Test.Params().maxSize + val default = Parameters.default.maxSize val names = Set("maxSize", "x") val help = "Maximum data generation size" } object OptWorkers extends IntOpt { - val default = Test.Params().workers + val default = Parameters.default.workers val names = Set("workers", "w") val help = "Number of threads to execute in parallel for testing" } @@ -142,54 +247,63 @@ object Test { } val opts = Set[Opt[_]]( - OptMinSuccess, OptMaxDiscardRatio, OptMinSize, + OptMinSuccess, OptMaxDiscarded, OptMaxDiscardRatio, OptMinSize, OptMaxSize, OptWorkers, OptVerbosity ) def parseParams(args: Array[String]) = parseArgs(args) { - optMap => Test.Params( - minSuccessfulTests = optMap(OptMinSuccess), - maxDiscardRatio = optMap(OptMaxDiscardRatio), - minSize = optMap(OptMinSize), - maxSize = optMap(OptMaxSize), - rng = Test.Params().rng, - workers = optMap(OptWorkers), - testCallback = ConsoleReporter(optMap(OptVerbosity)) + optMap => Parameters.default.copy( + _minSuccessfulTests = optMap(OptMinSuccess), + _maxDiscardRatio = + if (optMap(OptMaxDiscarded) < 0) optMap(OptMaxDiscardRatio) + else optMap(OptMaxDiscarded).toFloat / optMap(OptMinSuccess), + _minSize = optMap(OptMinSize), + _maxSize = optMap(OptMaxSize), + _workers = optMap(OptWorkers), + _testCallback = ConsoleReporter(optMap(OptVerbosity)) ) } } /** Tests a property with the given testing parameters, and returns - * the test results. */ + * the test results. + * @deprecated (in 1.10.0) Use + * `check(Parameters, Properties)` instead. + */ + @deprecated("Use 'checkProperties(Parameters, Properties)' instead", "1.10.0") def check(params: Params, p: Prop): Result = { + check(paramsToParameters(params), p) + } - // maxDiscardedTests is deprecated, but if someone - // uses it let it override maxDiscardRatio - val mdr = - if(params.maxDiscardedTests < 0) params.maxDiscardRatio - else (params.maxDiscardedTests: Float)/(params.minSuccessfulTests: Float) - val prms = params.copy( maxDiscardRatio = mdr) - - import prms._ - import scala.actors.Futures.future + /** Tests a property with the given testing parameters, and returns + * the test results. */ + def check(params: Parameters, p: Prop): Result = { + import params._ - assertParams(prms) - if(workers > 1) + assertParams(params) + if(workers > 1) { assert(!p.isInstanceOf[Commands], "Commands cannot be checked multi-threaded") + } val iterations = math.ceil(minSuccessfulTests / (workers: Double)) val sizeStep = (maxSize-minSize) / (iterations*workers) var stop = false - def worker(workerIdx: Int) = future { - params.customClassLoader.map(Thread.currentThread.setContextClassLoader(_)) + def worker(workerIdx: Int) = + if (workers < 2) () => workerFun(workerIdx) + else actors.Futures.future { + params.customClassLoader.map(Thread.currentThread.setContextClassLoader(_)) + workerFun(workerIdx) + } + + def workerFun(workerIdx: Int) = { var n = 0 // passed tests var d = 0 // discarded tests var res: Result = null var fm = FreqMap.empty[immutable.Set[Any]] while(!stop && res == null && n < iterations) { val size = (minSize: Double) + (sizeStep * (workerIdx + (workers*(n+d)))) - val propPrms = Prop.Params(Gen.Params(size.round.toInt, prms.rng), fm) + val propPrms = Prop.Params(Gen.Params(size.round.toInt, params.rng), fm) secure(p(propPrms)) match { case Right(e) => res = Result(GenException(e), n, d, FreqMap.empty[immutable.Set[Any]]) @@ -250,11 +364,20 @@ object Test { stop = true results foreach (_.apply()) val timedRes = r.copy(time = System.currentTimeMillis-start) - prms.testCallback.onTestResult("", timedRes) + params.testCallback.onTestResult("", timedRes) timedRes } + /** Check a set of properties. + * @deprecated (in 1.10.0) Use + * `checkProperties(Parameters, Properties)` instead. + */ + @deprecated("Use 'checkProperties(Parameters, Properties)' instead", "1.10.0") def checkProperties(prms: Params, ps: Properties): Seq[(String,Result)] = + checkProperties(paramsToParameters(prms), ps) + + /** Check a set of properties. */ + def checkProperties(prms: Parameters, ps: Properties): Seq[(String,Result)] = ps.properties.map { case (name,p) => val testCallback = new TestCallback { override def onPropEval(n: String, t: Int, s: Int, d: Int) = @@ -262,7 +385,7 @@ object Test { override def onTestResult(n: String, r: Result) = prms.testCallback.onTestResult(name,r) } - val res = check(prms copy (testCallback = testCallback), p) + val res = check(prms copy (_testCallback = testCallback), p) (name,res) } diff --git a/src/scalacheck/org/scalacheck/util/Buildable.scala b/src/scalacheck/org/scalacheck/util/Buildable.scala index 221b8a61c3..140c541a95 100644 --- a/src/scalacheck/org/scalacheck/util/Buildable.scala +++ b/src/scalacheck/org/scalacheck/util/Buildable.scala @@ -1,6 +1,6 @@ /*-------------------------------------------------------------------------*\ ** ScalaCheck ** -** Copyright (c) 2007-2011 Rickard Nilsson. All rights reserved. ** +** Copyright (c) 2007-2013 Rickard Nilsson. All rights reserved. ** ** http://www.scalacheck.org ** ** ** ** This software is released under the terms of the Revised BSD License. ** @@ -10,7 +10,6 @@ package org.scalacheck.util import scala.collection._ -import scala.reflect.ClassTag trait Buildable[T,C[_]] { def builder: mutable.Builder[T,C[T]] @@ -31,7 +30,7 @@ object Buildable { def builder = (new mutable.ListBuffer[T]).mapResult(_.toStream) } - implicit def buildableArray[T](implicit cm: ClassTag[T]) = + implicit def buildableArray[T](implicit cm: ClassManifest[T]) = new Buildable[T,Array] { def builder = mutable.ArrayBuilder.make[T] } diff --git a/src/scalacheck/org/scalacheck/util/CmdLineParser.scala b/src/scalacheck/org/scalacheck/util/CmdLineParser.scala index 4683c34a65..eb3a91fe59 100644 --- a/src/scalacheck/org/scalacheck/util/CmdLineParser.scala +++ b/src/scalacheck/org/scalacheck/util/CmdLineParser.scala @@ -1,6 +1,6 @@ /*-------------------------------------------------------------------------*\ ** ScalaCheck ** -** Copyright (c) 2007-2011 Rickard Nilsson. All rights reserved. ** +** Copyright (c) 2007-2013 Rickard Nilsson. All rights reserved. ** ** http://www.scalacheck.org ** ** ** ** This software is released under the terms of the Revised BSD License. ** @@ -30,7 +30,7 @@ trait CmdLineParser extends Parsers { trait StrOpt extends Opt[String] class OptMap { - private val opts = new scala.collection.mutable.HashMap[Opt[_], Any] + 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 diff --git a/src/scalacheck/org/scalacheck/util/FreqMap.scala b/src/scalacheck/org/scalacheck/util/FreqMap.scala index c7474d3b87..d0686aec72 100644 --- a/src/scalacheck/org/scalacheck/util/FreqMap.scala +++ b/src/scalacheck/org/scalacheck/util/FreqMap.scala @@ -1,6 +1,6 @@ /*-------------------------------------------------------------------------*\ ** ScalaCheck ** -** Copyright (c) 2007-2011 Rickard Nilsson. All rights reserved. ** +** Copyright (c) 2007-2013 Rickard Nilsson. All rights reserved. ** ** http://www.scalacheck.org ** ** ** ** This software is released under the terms of the Revised BSD License. ** diff --git a/src/scalacheck/org/scalacheck/util/StdRand.scala b/src/scalacheck/org/scalacheck/util/StdRand.scala index 317b0ccd10..7c1dc8dcc4 100644 --- a/src/scalacheck/org/scalacheck/util/StdRand.scala +++ b/src/scalacheck/org/scalacheck/util/StdRand.scala @@ -1,6 +1,6 @@ /*-------------------------------------------------------------------------*\ ** ScalaCheck ** -** Copyright (c) 2007-2011 Rickard Nilsson. All rights reserved. ** +** Copyright (c) 2007-2013 Rickard Nilsson. All rights reserved. ** ** http://www.scalacheck.org ** ** ** ** This software is released under the terms of the Revised BSD License. ** |