fthomas/refined

refined-scalacheck all values discarded

err0r500 opened this issue · 5 comments

Hello,
I couldn't find any documentation about how to use refined-scalacheck and I struggle with refinements when they become a bit too specific (looks like they act as a filter discarding all values)

I'm new to scala and I suspect that the implicit resolution is not what it should be but I couldn't figure out how to make it work.

import org.scalacheck.Properties
import org.scalacheck.Prop.forAll

import eu.timepit.refined.auto.autoUnwrap
import eu.timepit.refined.api.Refined
import eu.timepit.refined.predicates.string.StartsWith
import eu.timepit.refined.scalacheck.string.startsWithArbitrary
import eu.timepit.refined.scalacheck.any.arbitraryFromValidate // <- my main suspect

object StringSpecification extends Properties("String") {
  property("startsWith") = forAll { (str: String Refined StartsWith["a"]) =>
    str.charAt(0).equals("a")
  }
}

// result -> String.startsWith: Gave up after only 0 passed tests. 501 tests were discarded.

Any hint about how I'm supposed to use it ?

It works if you remove the arbitraryFromValidate import because startsWithArbitrary is already imported: https://scastie.scala-lang.org/3zOprdJ5R7CRdcckNGfFVQ

If your refinement becomes more complex, you probably won't have luck with arbitraryFromValidate because - as you already said - it is just a filter that discards not matching values.

thanks @fthomas !
I use scala3 and if I just switch the target from your example, it doesn't compile : https://scastie.scala-lang.org/1J4smLVBQ86ckV9qgvf9pg

with the error :

No given instance of type org.scalacheck.Arbitrary[
  eu.timepit.refined.api.Refined[String, 
    eu.timepit.refined.string.StartsWith[("a" : String)]
  ]
] was found for parameter a1 of method forAll in object Prop.
I found:

    org.scalacheck.Arbitrary.arbContainer2[eu.timepit.refined.api.Refined, String, 
      eu.timepit.refined.string.StartsWith[("a" : String)]
    ](
      org.scalacheck.Arbitrary.arbContainer2[Tuple2, String, 
        eu.timepit.refined.string.StartsWith[("a" : String)]
      ](
        org.scalacheck.Arbitrary.arbContainer[([T2] =>> (String, T2)), 
          eu.timepit.refined.string.StartsWith[("a" : String)]
        ](
          org.scalacheck.Arbitrary.arbContainer[eu.timepit.refined.string.StartsWith
            , 
          ("a" : String)](org.scalacheck.Arbitrary.arbEnum[A], ???, ???)
        , ???, ???)
      , ???, ???)
    , ???, ???)

But method arbEnum in trait ArbitraryLowPriority does not match type org.scalacheck.Arbitrary[("a" : String)].

One of the following imports might make progress towards fixing the problem:

  import eu.timepit.refined.scalacheck.any.arbitraryFromValidate
  import shapeless.~?>.idKeyWitness
  import shapeless.~?>.idValueWitness
  import shapeless.~?>.witness

That's the reason why I had to add the arbitraryFromValidate in my example. I guess I'm doing something wrong....

I guess I'm doing something wrong....

No, you are not. I just saw that startsWithArbitrary still uses shapeless.Witness but that doesn't work with Scala 3. The Scala 3 version of this instance needs to be changed to use ValueOf as is done here for example.

ok, I opened a PR for this.
Beware, I'm a 3-day-old scala dev :D

@err0r500 Your fix is has been released in 0.10.2 and your example is working now: https://scastie.scala-lang.org/bdbcLixJRjmP0JyMltq7CA