summaryrefslogtreecommitdiff
path: root/src/partest-extras/scala/org/scalacheck/Shrink.scala
diff options
context:
space:
mode:
Diffstat (limited to 'src/partest-extras/scala/org/scalacheck/Shrink.scala')
-rw-r--r--src/partest-extras/scala/org/scalacheck/Shrink.scala215
1 files changed, 215 insertions, 0 deletions
diff --git a/src/partest-extras/scala/org/scalacheck/Shrink.scala b/src/partest-extras/scala/org/scalacheck/Shrink.scala
new file mode 100644
index 0000000000..8ec28f4c4b
--- /dev/null
+++ b/src/partest-extras/scala/org/scalacheck/Shrink.scala
@@ -0,0 +1,215 @@
+/*-------------------------------------------------------------------------*\
+** ScalaCheck **
+** Copyright (c) 2007-2014 Rickard Nilsson. All rights reserved. **
+** http://www.scalacheck.org **
+** **
+** This software is released under the terms of the Revised BSD License. **
+** There is NO WARRANTY. See the file LICENSE for the full text. **
+\*------------------------------------------------------------------------ */
+
+package org.scalacheck
+
+import util.{Buildable,Buildable2}
+import scala.collection.{ JavaConversions => jcl }
+
+sealed abstract class Shrink[T] {
+ def shrink(x: T): Stream[T]
+}
+
+object Shrink {
+
+ import Stream.{cons, empty}
+ import scala.collection._
+ import java.util.ArrayList
+
+ /** Interleaves two streams */
+ private def interleave[T](xs: Stream[T], ys: Stream[T]): Stream[T] =
+ if(xs.isEmpty) ys
+ else if(ys.isEmpty) xs
+ else cons(xs.head, cons(ys.head, interleave(xs.tail, ys.tail)))
+
+ /** Shrink instance factory */
+ def apply[T](s: T => Stream[T]): Shrink[T] = new Shrink[T] {
+ override def shrink(x: T) = s(x)
+ }
+
+ /** Shrink a value */
+ def shrink[T](x: T)(implicit s: Shrink[T]): Stream[T] = s.shrink(x)
+
+ /** Default shrink instance */
+ implicit def shrinkAny[T]: Shrink[T] = Shrink(x => empty)
+
+ /** Shrink instance of container */
+ implicit def shrinkContainer[C[_],T](implicit v: C[T] => Traversable[T], s: Shrink[T],
+ b: Buildable[T,C]
+ ): Shrink[C[T]] = Shrink { xs: C[T] =>
+ val ys = v(xs)
+ val zs = ys.toStream
+ removeChunks(ys.size,zs).append(shrinkOne(zs)).map(b.fromIterable)
+ }
+
+ /** Shrink instance of container2 */
+ implicit def shrinkContainer2[C[_,_],T,U](implicit v: C[T,U] => Traversable[(T,U)], s: Shrink[(T,U)],
+ b: Buildable2[T,U,C]
+ ): Shrink[C[T,U]] = Shrink { xs: C[T,U] =>
+ val ys = v(xs)
+ val zs = ys.toStream
+ removeChunks(ys.size,zs).append(shrinkOne(zs)).map(b.fromIterable)
+ }
+
+ private def removeChunks[T](n: Int, xs: Stream[T]): Stream[Stream[T]] =
+ if (xs.isEmpty) empty
+ else if (xs.tail.isEmpty) cons(empty, empty)
+ else {
+ val n1 = n / 2
+ val n2 = n - n1
+ lazy val xs1 = xs.take(n1)
+ lazy val xs2 = xs.drop(n1)
+ lazy val xs3 =
+ for (ys1 <- removeChunks(n1, xs1) if !ys1.isEmpty) yield ys1 append xs2
+ lazy val xs4 =
+ for (ys2 <- removeChunks(n2, xs2) if !ys2.isEmpty) yield xs1 append ys2
+
+ cons(xs1, cons(xs2, interleave(xs3, xs4)))
+ }
+
+ private def shrinkOne[T : Shrink](zs: Stream[T]): Stream[Stream[T]] =
+ if (zs.isEmpty) empty
+ else {
+ val x = zs.head
+ val xs = zs.tail
+ shrink(x).map(cons(_,xs)).append(shrinkOne(xs).map(cons(x,_)))
+ }
+
+ /** Shrink instance of integer */
+ implicit lazy val shrinkInt: Shrink[Int] = Shrink { n =>
+
+ def halfs(n: Int): Stream[Int] =
+ if(n == 0) empty else cons(n, halfs(n/2))
+
+ if(n == 0) empty else {
+ val ns = halfs(n/2).map(n - _)
+ cons(0, interleave(ns, ns.map(-1 * _)))
+ }
+ }
+
+ /** Shrink instance of String */
+ implicit lazy val shrinkString: Shrink[String] = Shrink { s =>
+ shrinkContainer[List,Char].shrink(s.toList).map(_.mkString)
+ }
+
+ /** Shrink instance of Option */
+ implicit def shrinkOption[T : Shrink]: Shrink[Option[T]] = Shrink {
+ case None => empty
+ case Some(x) => cons(None, for(y <- shrink(x)) yield Some(y))
+ }
+
+ /** Shrink instance of 2-tuple */
+ implicit def shrinkTuple2[
+ T1:Shrink, T2:Shrink
+ ]: Shrink[(T1,T2)] =
+ Shrink { case (t1,t2) =>
+ shrink(t1).map((_,t2)) append
+ shrink(t2).map((t1,_))
+ }
+
+ /** Shrink instance of 3-tuple */
+ implicit def shrinkTuple3[
+ T1:Shrink, T2:Shrink, T3:Shrink
+ ]: Shrink[(T1,T2,T3)] =
+ Shrink { case (t1,t2,t3) =>
+ shrink(t1).map((_, t2, t3)) append
+ shrink(t2).map((t1, _, t3)) append
+ shrink(t3).map((t1, t2, _))
+ }
+
+ /** Shrink instance of 4-tuple */
+ implicit def shrinkTuple4[
+ T1:Shrink, T2:Shrink, T3:Shrink, T4:Shrink
+ ]: Shrink[(T1,T2,T3,T4)] =
+ Shrink { case (t1,t2,t3,t4) =>
+ shrink(t1).map((_, t2, t3, t4)) append
+ shrink(t2).map((t1, _, t3, t4)) append
+ shrink(t3).map((t1, t2, _, t4)) append
+ shrink(t4).map((t1, t2, t3, _))
+ }
+
+ /** Shrink instance of 5-tuple */
+ implicit def shrinkTuple5[
+ T1:Shrink, T2:Shrink, T3:Shrink, T4:Shrink, T5:Shrink
+ ]: Shrink[(T1,T2,T3,T4,T5)] =
+ Shrink { case (t1,t2,t3,t4,t5) =>
+ shrink(t1).map((_, t2, t3, t4, t5)) append
+ shrink(t2).map((t1, _, t3, t4, t5)) append
+ shrink(t3).map((t1, t2, _, t4, t5)) append
+ shrink(t4).map((t1, t2, t3, _, t5)) append
+ shrink(t5).map((t1, t2, t3, t4, _))
+ }
+
+ /** Shrink instance of 6-tuple */
+ implicit def shrinkTuple6[
+ T1:Shrink, T2:Shrink, T3:Shrink, T4:Shrink, T5:Shrink, T6:Shrink
+ ]: Shrink[(T1,T2,T3,T4,T5,T6)] =
+ Shrink { case (t1,t2,t3,t4,t5,t6) =>
+ shrink(t1).map((_, t2, t3, t4, t5, t6)) append
+ shrink(t2).map((t1, _, t3, t4, t5, t6)) append
+ shrink(t3).map((t1, t2, _, t4, t5, t6)) append
+ shrink(t4).map((t1, t2, t3, _, t5, t6)) append
+ shrink(t5).map((t1, t2, t3, t4, _, t6)) append
+ shrink(t6).map((t1, t2, t3, t4, t5, _))
+ }
+
+ /** Shrink instance of 7-tuple */
+ implicit def shrinkTuple7[
+ T1:Shrink, T2:Shrink, T3:Shrink, T4:Shrink, T5:Shrink, T6:Shrink, T7:Shrink
+ ]: Shrink[(T1,T2,T3,T4,T5,T6,T7)] =
+ Shrink { case (t1,t2,t3,t4,t5,t6,t7) =>
+ shrink(t1).map((_, t2, t3, t4, t5, t6, t7)) append
+ shrink(t2).map((t1, _, t3, t4, t5, t6, t7)) append
+ shrink(t3).map((t1, t2, _, t4, t5, t6, t7)) append
+ shrink(t4).map((t1, t2, t3, _, t5, t6, t7)) append
+ shrink(t5).map((t1, t2, t3, t4, _, t6, t7)) append
+ shrink(t6).map((t1, t2, t3, t4, t5, _, t7)) append
+ shrink(t7).map((t1, t2, t3, t4, t5, t6, _))
+ }
+
+ /** Shrink instance of 8-tuple */
+ implicit def shrinkTuple8[
+ T1:Shrink, T2:Shrink, T3:Shrink, T4:Shrink, T5:Shrink, T6:Shrink,
+ T7:Shrink, T8:Shrink
+ ]: Shrink[(T1,T2,T3,T4,T5,T6,T7,T8)] =
+ Shrink { case (t1,t2,t3,t4,t5,t6,t7,t8) =>
+ shrink(t1).map((_, t2, t3, t4, t5, t6, t7, t8)) append
+ shrink(t2).map((t1, _, t3, t4, t5, t6, t7, t8)) append
+ shrink(t3).map((t1, t2, _, t4, t5, t6, t7, t8)) append
+ shrink(t4).map((t1, t2, t3, _, t5, t6, t7, t8)) append
+ shrink(t5).map((t1, t2, t3, t4, _, t6, t7, t8)) append
+ shrink(t6).map((t1, t2, t3, t4, t5, _, t7, t8)) append
+ shrink(t7).map((t1, t2, t3, t4, t5, t6, _, t8)) append
+ shrink(t8).map((t1, t2, t3, t4, t5, t6, t7, _))
+ }
+
+ /** Shrink instance of 9-tuple */
+ implicit def shrinkTuple9[
+ T1:Shrink, T2:Shrink, T3:Shrink, T4:Shrink, T5:Shrink, T6:Shrink,
+ T7:Shrink, T8:Shrink, T9:Shrink
+ ]: Shrink[(T1,T2,T3,T4,T5,T6,T7,T8,T9)] =
+ Shrink { case (t1,t2,t3,t4,t5,t6,t7,t8,t9) =>
+ shrink(t1).map((_, t2, t3, t4, t5, t6, t7, t8, t9)) append
+ shrink(t2).map((t1, _, t3, t4, t5, t6, t7, t8, t9)) append
+ shrink(t3).map((t1, t2, _, t4, t5, t6, t7, t8, t9)) append
+ shrink(t4).map((t1, t2, t3, _, t5, t6, t7, t8, t9)) append
+ shrink(t5).map((t1, t2, t3, t4, _, t6, t7, t8, t9)) append
+ shrink(t6).map((t1, t2, t3, t4, t5, _, t7, t8, t9)) append
+ shrink(t7).map((t1, t2, t3, t4, t5, t6, _, t8, t9)) append
+ shrink(t8).map((t1, t2, t3, t4, t5, t6, t7, _, t9)) append
+ shrink(t9).map((t1, t2, t3, t4, t5, t6, t7, t8, _))
+ }
+
+ /** Transform a Shrink[T] to a Shrink[U] where T and U are two isomorphic types
+ * whose relationship is described by the provided transformation functions.
+ * (exponential functor map) */
+ def xmap[T, U](from: T => U, to: U => T)(implicit st: Shrink[T]): Shrink[U] = Shrink[U] { u: U ⇒
+ st.shrink(to(u)).map(from)
+ }
+}