typelevel / shapeless-contrib

Interoperability libraries for Shapeless
MIT License
77 stars 20 forks source link

"Gave up after only n tests." with heavily nested case classes #43

Open nevillelyh opened 7 years ago

nevillelyh commented 7 years ago

The following test fails with a message like "! Nested.nested: Gave up after only 7 passed tests. 501 tests were discarded.".

object NestedArbitrarySpec extends Properties("Nested") {
  private val ok = (_: Any) => true
  case class Mixed(longField: Long, doubleField: Double, stringField: String,
                   longFieldO: Option[Long], doubleFieldO: Option[Double], stringFieldO: Option[String],
                   longFieldR: List[Long], doubleFieldR: List[Double], stringFieldR: List[String])
  case class Nested(longField: Long, longFieldO: Option[Long], longFieldR: List[Long],
                    mixedField: Mixed, mixedFieldO: Option[Mixed], mixedFieldR: List[Mixed])
  property("nested") = {
    forAll(implicitly[Arbitrary[Nested]].arbitrary)(ok)
  }
}

I got it to work by removing the resizing logic. I can submit a PR for this but would like to understand better why it's there in the first place.

diff --git a/scalacheck/src/main/scala/package.scala b/scalacheck/src/main/scala/package.scala
index 4d84403..9e6bad5 100644
--- a/scalacheck/src/main/scala/package.scala
+++ b/scalacheck/src/main/scala/package.scala
@@ -13,15 +13,9 @@ object scalacheck {
       def emptyProduct = Arbitrary(Gen.const(HNil: HNil))

       def product[H, T <: HList](h: Arbitrary[H], t: Arbitrary[T]) =
-        Arbitrary(Gen.sized { size =>
-          if (size == 0)
-            Gen.fail
-          else {
-            val resizedH = Gen.resize(size.abs/2, h.arbitrary)
-            val resizedT = Gen.resize(size.abs - size.abs/2, t.arbitrary)
-            for { h <- resizedH; t <- resizedT }
-              yield h :: t
-          }})
+        Arbitrary {
+          for (h <- h.arbitrary; t <- t.arbitrary) yield h :: t
+        }

       def emptyCoproduct = Arbitrary[CNil](_emptyCoproduct)
nevillelyh commented 7 years ago

Just realized the workaround broke property("tree") with StackOverflowError. Maybe there can be some compromise between the 2.

larsrh commented 7 years ago

Resizing is absolutely crucial, otherwise you'll likely get "infinite" structures. Could you alternatively try scalacheck-shapeless?

nevillelyh commented 7 years ago

Yes I understand now after seeing the StackOverflowError. scalacheck-shapeless works for this case. Just curious if there is a way to make this lib work for both scenarios. :)

larsrh commented 7 years ago

In that case I would suggest using scalacheck-shapeless instead of shapeless-contrib. The former is actively maintained, the latter isn't (I'll merge PRs, but won't fix problems myself).

nevillelyh commented 7 years ago

Alright I'll let it rest then :)

larsrh commented 7 years ago

See also #33.

larsrh commented 7 years ago

@nevillelyh Thanks for reporting it anyway. I'll leave it open so that prospective users see immediately that they should prefer scalacheck-shapeless :smile: