Skip to content

Commit

Permalink
Add configurable scalaCheckInitialSeed
Browse files Browse the repository at this point in the history
  • Loading branch information
gabro committed Apr 1, 2020
1 parent 1abd10d commit 7857d0e
Show file tree
Hide file tree
Showing 3 changed files with 39 additions and 29 deletions.
21 changes: 13 additions & 8 deletions docs/integrations/scalacheck.md
Original file line number Diff line number Diff line change
Expand Up @@ -124,21 +124,26 @@ non-deterministically. This can happen due to the randomness of the input values
for each test run.

When this happens, you can deterministally reproduce a property failure by using
its seed. MUnit prints the property seed whenever a failure occurs in the form
of:
its seed. Whenever a failure occurs, MUnit prints the offending seed along with
a suggestion on how to reproduce it:

```
Failing seed: CTH6hXj8ViScMmsO78-k4_RytXHPK_wSJYNH2h4dCpB=
You can reproduce this failure by adding this to your suite:
override val scalaCheckInitialSeed = "CTH6hXj8ViScMmsO78-k4_RytXHPK_wSJYNH2h4dCpB="
```

To reproduce the exact same failure, you can override the test parameters and
provide the offending seed as the initial seed:
To reproduce the failure you can follow the suggestion to fix the seed:

```scala
override def scalaCheckTestParameters =
super.scalaCheckTestParameters.withInitialSeed(
"CTH6hXj8ViScMmsO78-k4_RytXHPK_wSJYNH2h4dCpB="
)
class MySuite extends ScalaCheckSuite {

override val scalaCheckInitialSeed = "CTH6hXj8ViScMmsO78-k4_RytXHPK_wSJYNH2h4dCpB="

// ...
}
```

Re-running the test will now fail deterministically, which allows you to work on
Expand Down
19 changes: 10 additions & 9 deletions munit-scalacheck/shared/src/main/scala/munit/ScalaCheckSuite.scala
Original file line number Diff line number Diff line change
Expand Up @@ -35,13 +35,7 @@ trait ScalaCheckSuite extends FunSuite {

protected def scalaCheckPrettyParameters = Pretty.defaultParams

// Allow specifying an initial seed in its Base64 encoded form
implicit class XtensionScalaCheckTestParameters(
params: ScalaCheckTest.Parameters
) {
def withInitialSeed(encodedSeed: String): ScalaCheckTest.Parameters =
params.withInitialSeed(Seed.fromBase64(encodedSeed).get)
}
protected def scalaCheckInitialSeed(): String = Seed.random().toBase64

private val scalaCheckPropTransform: TestTransform =
new TestTransform("ScalaCheck Prop", t => {
Expand All @@ -55,14 +49,21 @@ trait ScalaCheckSuite extends FunSuite {

private def propToTry(prop: Prop, test: Test): Try[Unit] = {
import ScalaCheckTest._
val seed = scalaCheckTestParameters.initialSeed.getOrElse(Seed.random())
val seed =
scalaCheckTestParameters.initialSeed.getOrElse(
Seed.fromBase64(scalaCheckInitialSeed()).get
)
val result = check(scalaCheckTestParameters, prop.useSeed(test.name, seed))
def renderResult(r: Result) = {
val resultMessage = Pretty.pretty(r, scalaCheckPrettyParameters)
if (r.passed) {
resultMessage
} else {
val seedMessage = s"Failing seed: ${seed.toBase64}\n"
val seedMessage = s"""|Failing seed: ${seed.toBase64}
|You can reproduce this failure by adding this to your suite:
|
| override val scalaCheckInitialSeed = "${seed.toBase64}"
|""".stripMargin
seedMessage + "\n" + resultMessage
}
}
Expand Down
28 changes: 16 additions & 12 deletions tests/shared/src/main/scala/munit/ScalaCheckFrameworkSuite.scala
Original file line number Diff line number Diff line change
Expand Up @@ -6,10 +6,8 @@ class ScalaCheckFrameworkSuite extends ScalaCheckSuite {

// NOTE(gabro): this is needed for making the test output stable for the failed test below.
// It also serves as a test for overriding these parameters.
override def scalaCheckTestParameters =
super.scalaCheckTestParameters.withInitialSeed(
"CTH6hXj8ViScMmsO78-k4_RytXHPK_wSJYNH2h4dCpB="
)
override val scalaCheckInitialSeed =
"CTH6hXj8ViScMmsO78-k4_RytXHPK_wSJYNH2h4dCpB="

property("boolean check (true)") {
forAll { (l1: List[Int], l2: List[Int]) =>
Expand Down Expand Up @@ -46,22 +44,25 @@ object ScalaCheckFrameworkSuite
extends FrameworkTest(
classOf[ScalaCheckFrameworkSuite],
"""|==> success munit.ScalaCheckFrameworkSuite.boolean check (true)
|==> failure munit.ScalaCheckFrameworkSuite.boolean check (false) - /scala/munit/ScalaCheckFrameworkSuite.scala:20
|19:
|20: property("boolean check (false)") {
|21: forAll { (n: Int) => scala.math.sqrt(n * n) == n }
|==> failure munit.ScalaCheckFrameworkSuite.boolean check (false) - /scala/munit/ScalaCheckFrameworkSuite.scala:18
|17:
|18: property("boolean check (false)") {
|19: forAll { (n: Int) => scala.math.sqrt(n * n) == n }
|
|Failing seed: CTH6hXj8ViScMmsO78-k4_RytXHPK_wSJYNH2h4dCpB=
|You can reproduce this failure by adding this to your suite:
|
| override val scalaCheckInitialSeed = "CTH6hXj8ViScMmsO78-k4_RytXHPK_wSJYNH2h4dCpB="
|
|Falsified after 0 passed tests.
|> ARG_0: -1
|> ARG_0_ORIGINAL: 2147483647
|==> success munit.ScalaCheckFrameworkSuite.tagged
|==> success munit.ScalaCheckFrameworkSuite.assertions (true)
|==> failure munit.ScalaCheckFrameworkSuite.assertions (false) - /scala/munit/ScalaCheckFrameworkSuite.scala:38
|37: assertEquals(n * 1, n)
|38: assertEquals(n * n, n)
|39: assertEquals(n + 0, n)
|==> failure munit.ScalaCheckFrameworkSuite.assertions (false) - /scala/munit/ScalaCheckFrameworkSuite.scala:36
|35: assertEquals(n * 1, n)
|36: assertEquals(n * n, n)
|37: assertEquals(n + 0, n)
|values are not the same
|=> Obtained
|1
Expand All @@ -70,6 +71,9 @@ object ScalaCheckFrameworkSuite
|+-1
|
|Failing seed: CTH6hXj8ViScMmsO78-k4_RytXHPK_wSJYNH2h4dCpB=
|You can reproduce this failure by adding this to your suite:
|
| override val scalaCheckInitialSeed = "CTH6hXj8ViScMmsO78-k4_RytXHPK_wSJYNH2h4dCpB="
|
|Falsified after 0 passed tests.
|> ARG_0: -1
Expand Down

0 comments on commit 7857d0e

Please sign in to comment.