-
Notifications
You must be signed in to change notification settings - Fork 35
Open
Description
Failing generators are really bad now that we have non-constant arbitrary functions in ScalaCheck 1.13. Here's an example of a place this comes up in this library (derived from an example by @nrinaudo):
import org.scalacheck._, Shapeless._
sealed trait Foo; case object Bar extends Foo
val prop = Prop.forAll { (f: Int => Foo) => f(0); true }And:
scala> prop.check
! Exception raised on property evaluation.
> ARG_0: <function1>
> Exception: org.scalacheck.Gen$RetrievalError: couldn't generate value
org.scalacheck.Gen.loop$1(Gen.scala:57)
org.scalacheck.Gen.doPureApply(Gen.scala:58)
...I've taken a shot at a diagnosis here, but in short it looks like something like this in MkCoproductArbitrary.ccons would work:
Arbitrary {
Gen.sized {
case size =>
val sig = math.signum(size)
try {
Gen.frequency(
1 -> Gen.resize(size - sig, Gen.lzy(headArbitrary.value.arbitrary)).map(Inl(_)),
n() -> Gen.resize(size - sig, Gen.lzy(tailArbitrary.arbitrary.arbitrary)).map(Inr(_))
)
} catch {
case _: StackOverflowError => Gen.fail
}
}
}(I'd also just use math.min(0, size - 1) instead of the signum stuff, but that's not really relevant.)
Catching the stack overflow is an awful hack, but it avoids the Gen.fail on size == 0 for non-recursive ADTs while still not stack-overflowing for recursive ones.
ScalaWilliam
Metadata
Metadata
Assignees
Labels
No labels