Skip to content

Instantly share code, notes, and snippets.

@peri4n
Forked from davidallsopp/Shrinking.scala
Created July 20, 2018 20:29
Show Gist options
  • Save peri4n/6cccdf20c386093acbe04ca3a4ef8b4d to your computer and use it in GitHub Desktop.
Save peri4n/6cccdf20c386093acbe04ca3a4ef8b4d to your computer and use it in GitHub Desktop.
Solutions to the ScalaCheck problem that shrinking failing values may generate invalid values, because the constraints of the generator are not respected. This is for using ScalaCheck from within ScalaTest.
import org.scalatest._
import prop._
import org.scalacheck.Arbitrary._
import org.scalacheck.Gen
/**
* Solutions to the ScalaCheck problem that shrinking failing values may generate
* invalid values, because the constraints of the generator are not respected.
*
* See also http://stackoverflow.com/questions/20037900/scalacheck-wont-properly-report-the-failing-case
* and http://code.google.com/p/scalatest/issues/detail?id=14
*/
class Shrinking extends PropSpec with PropertyChecks with ShouldMatchers {
def odd(i: Int) = i % 2 == 1
// Old solution - use whenever{} clause within the property
val odds: Gen[Int] = for {
n <- arbitrary[Int]
if (odd(n))
} yield n
property("fails with big numbers") {
forAll(odds) { n =>
whenever(odd(n)) {
if (n % 2 == 0) throw new Exception("Argh") // should never happen
if (n > 1000) (n / 2 + n / 2 should be(n)) else n should be(n)
}
}
}
// New solution - use suchThat() postcondition on the generator
// See https://github.com/rickynils/scalacheck/commit/2d92eb6
val odds2: Gen[Int] = arbitrary[Int].suchThat(odd)
property("fails with big numbers v2") {
forAll(odds2) { n =>
if (n % 2 == 0) throw new Exception("Argh") // should never happen
if (n > 1000) (n / 2 + n / 2 should be(n)) else n should be(n)
}
}
// Alternative solution - disable shrinking entirely (for Ints)
// From http://blog.knutwalker.de/2014/01/fun-with-scalatests-propertychecks.html
// In pure ScalaCheck you can use forAllNoShrink() but this is not exposed in ScalaTest
{
import org.scalacheck.Shrink
implicit val noShrink: Shrink[Int] = Shrink.shrinkAny
property("fails with big numbers, shrinking disabled") {
forAll(odds) { n =>
if (n % 2 == 0) throw new Exception("Argh") // should never happen
if (n > 1000) (n / 2 + n / 2 should be(n)) else n should be(n)
}
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment