Skip to content

Commit 3cb4ff2

Browse files
committed
Add continuously growing collection Generators
1 parent 6ba8dbd commit 3cb4ff2

File tree

1 file changed

+86
-0
lines changed

1 file changed

+86
-0
lines changed

src/main/scala/org/scalacheck/Gen.scala

Lines changed: 86 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1001,6 +1001,70 @@ object Gen extends GenArities with GenVersionSpecific {
10011001
}
10021002
}
10031003

1004+
/** Generates a container of any Traversable type for which there exists an
1005+
* implicit [[org.scalacheck.util.Buildable]] instance. The elements in the
1006+
* container will be generated by the given generator. The generated container
1007+
* will continuously grow in size until the `fillCondition` returns true.
1008+
* If the given generator fails generating a value, the
1009+
* complete container generator will also fail. */
1010+
def buildableOfCond[C,T](fillCondition: C => Boolean, g: Gen[T], failureHint: Int= Integer.MAX_VALUE)(implicit
1011+
evb: Buildable[T,C], evt: C => Traversable[T]
1012+
): Gen[C] = {
1013+
new Gen[C] {
1014+
def doApply(p: P, seed0: Seed): R[C] = {
1015+
var seed: Seed = p.initialSeed.getOrElse(seed0)
1016+
val bldr = evb.builder
1017+
val allowedFailures = Gen.collectionRetries(failureHint)
1018+
var failures = 0
1019+
while (!fillCondition(bldr.result)) {
1020+
val res = g.doApply(p, seed)
1021+
res.retrieve match {
1022+
case Some(t) =>
1023+
bldr += t
1024+
case None =>
1025+
failures += 1
1026+
if (failures >= allowedFailures) return r(None, res.seed)
1027+
}
1028+
seed = res.seed
1029+
}
1030+
r(Some(bldr.result), seed)
1031+
}
1032+
}
1033+
}
1034+
1035+
/** Generates a container of any Traversable type for which there exists an
1036+
* implicit [[org.scalacheck.util.Buildable]] instance. The elements in the
1037+
* container will be generated by the given generator. The generated container
1038+
* will continuously frow in size until the `fillCondition` returns true.
1039+
* Unlike `buildableOfCond`, this version of the method lets you specify another
1040+
* collection Gen which helps in speeding up the process of growing the collection.
1041+
* If the given generator fails generating a value, the
1042+
* complete container generator will also fail. */
1043+
def buildableOfCollCond[C <: Traversable[T],T](cond: C => Boolean, g: Gen[C], failureHint: Int= Integer.MAX_VALUE)(implicit
1044+
evb: Buildable[T,C], evt: C => Traversable[T]
1045+
): Gen[C] = {
1046+
new Gen[C] {
1047+
def doApply(p: P, seed0: Seed): R[C] = {
1048+
var seed: Seed = p.initialSeed.getOrElse(seed0)
1049+
val bldr = evb.builder
1050+
val allowedFailures = Gen.collectionRetries(failureHint)
1051+
var failures = 0
1052+
while (!cond(bldr.result)) {
1053+
val res = g.doApply(p, seed)
1054+
res.retrieve match {
1055+
case Some(t) =>
1056+
bldr ++= t
1057+
case None =>
1058+
failures += 1
1059+
if (failures >= allowedFailures) return r(None, res.seed)
1060+
}
1061+
seed = res.seed
1062+
}
1063+
r(Some(bldr.result), seed)
1064+
}
1065+
}
1066+
}
1067+
10041068
/** Generates a container of any Traversable type for which there exists an
10051069
* implicit [[org.scalacheck.util.Buildable]] instance. The elements in the
10061070
* container will be generated by the given generator. The size of the
@@ -1042,6 +1106,18 @@ object Gen extends GenArities with GenVersionSpecific {
10421106
* `containerOf[List,T](g)`. */
10431107
def listOf[T](g: => Gen[T]) = buildableOf[List[T], T](g)
10441108

1109+
/** Generates a list that continuously grows in size until
1110+
* `finishCondition` returns true. */
1111+
def listOfCond[T](finishCondition: List[T] => Boolean, g: => Gen[T], failureHint: Int = Integer.MAX_VALUE) =
1112+
buildableOfCond[List[T], T](finishCondition, g, failureHint)
1113+
1114+
/** Generates a list that continuously grows in size until
1115+
* `finishCondition` returns true. Unlike `listOfCond` it
1116+
* accepts a list generator argument which lets you generate
1117+
* larger lists quicker */
1118+
def listOfFillCond[T](finishCondition: List[T] => Boolean, g: => Gen[List[T]], failureHint: Int = Integer.MAX_VALUE) =
1119+
buildableOfCollCond[List[T], T](finishCondition, g, failureHint)
1120+
10451121
/** Generates a non-empty list of random length. The maximum length depends
10461122
* on the size parameter. This method is equal to calling
10471123
* `nonEmptyContainerOf[List,T](g)`. */
@@ -1056,6 +1132,16 @@ object Gen extends GenArities with GenVersionSpecific {
10561132
* <code>containerOf[Map,(T,U)](g)</code>. */
10571133
def mapOf[T, U](g: => Gen[(T, U)]) = buildableOf[Map[T, U], (T, U)](g)
10581134

1135+
/** Generates a map that continuously grows in size until
1136+
* `finishCondition` returns true. */
1137+
def mapOfCond[T, U](cond: Map[T,U] => Boolean, g: => Gen[(T, U)], failureHint: Int = Integer.MAX_VALUE) = buildableOfCond[Map[T, U],(T, U)](cond, g, failureHint)
1138+
1139+
/** Generates a map that continuously grows in size until
1140+
* `finishCondition` returns true. Unlike `mapOfCond` it
1141+
* accepts a map generator argument which lets you generate
1142+
* larger maps quicker */
1143+
def mapOfFillCond[T, U](cond: Map[T,U] => Boolean, g: => Gen[Map[T, U]], failureHint: Int = Integer.MAX_VALUE) = buildableOfCollCond[Map[T, U],(T, U)](cond, g, failureHint)
1144+
10591145
/** Generates a non-empty map of random length. The maximum length depends
10601146
* on the size parameter. This method is equal to calling
10611147
* <code>nonEmptyContainerOf[Map,(T,U)](g)</code>. */

0 commit comments

Comments
 (0)