Hi Kevin,
On 04/20/2015 09:01 PM, Kevin Meredith wrote:
> I wrote a ScalaCheck property:
>
> Imports
>
> |scala> import org.scalacheck.{Properties, Arbitrary, Gen}
> import org.scalacheck.{Properties, Arbitrary, Gen}
>
> scala> import org.scalacheck.Prop.forAll
> import org.scalacheck.Prop.forAll
>
> scala> import org.scalacheck.Prop._
> import org.scalacheck.Prop._
>
> scala> import org.scalacheck.Arbitrary._
> import org.scalacheck.Arbitrary._|
>
> Making a Gen and Arbitrary for |Foo|
>
> |scala> case class Foo(x: Any)
> definedclass Foo
>
> scala> val fooGen: Gen[Foo] = arbitrary[Int].map(Foo(_))
> fooGen: org.scalacheck.Gen[Foo] = org.scalacheck.Gen$$anon$6@74da2066
>
> scala> implicit val arbitraryFoo: Arbitrary[Foo] = Arbitrary(fooGen)
> arbitraryFoo: org.scalacheck.Arbitrary[Foo] = org.scalacheck.Arbitrary$$anon$3@6f4c397e
>
> scala> forAll{ _: Foo => (true == true) }
> res2: org.scalacheck.Prop = Prop|
>
> However, I'd like to specify that this property holds for a |Double| too.
>
> So I added another |Gen[Foo]| and |Arbitrary[Foo]|:
>
> |scala> val fooGenDouble: Gen[Foo] = arbitrary[Double].map(Foo(_))
> fooGenDouble: org.scalacheck.Gen[Foo] = org.scalacheck.Gen$$anon$6@31d5eb6c
>
> scala> implicit val arbitraryFooDouble: Arbitrary[Foo] = Arbitrary(fooGenDouble)
> arbitraryFooDouble: org.scalacheck.Arbitrary[Foo] = org.scalacheck.Arbitrary$$anon$3@6a43082d|
>
> But, when I try to define another property, I get an ambiguous implicit:
>
> |scala> forAll{ _: Foo => (true == true) }
> <console>:22: error: ambiguousimplicit values:
> both value arbitraryFoo oftype => org.scalacheck.Arbitrary[Foo]
> and value arbitraryFooDouble oftype => org.scalacheck.Arbitrary[Foo]
> match expectedtype org.scalacheck.Arbitrary[Foo]
> forAll{ _: Foo => (true == true) }
> ^|
>
> How is this typically handled in a Scalacheck test?
First of all, in the general case you can always skip using Arbitrary
and simply specify your generator explicitly like this:
forAll(fooGenDouble) { foo => ... }
I actually recommend using this approach as soon as you start dealing
with more than a single generator for your type. Multiple Arbitrary
instances for the same type doesn't really make sense, and using an
explicit generator in a forAll call actually makes it clearer exactly
what the property specifies. This might be a matter of taste, though.
In your specific case, I'm actually not sure what you want to achieve,
having two properties for different actual types of `x`. Since Foo.x
will always be of type Any (if you don't cast it), neither the property
or the "real" code using Foo can behave differently if x is Int or Double.
If you would add a type parameter to your class, it would at least be
possible to define two Arbitrary instances for it, like this:
case class Foo[T](x: T)
implicit val arbitraryFooInt: Arbitrary[Foo[Int]]
implicit val arbitraryFooDouble: Arbitrary[Foo[Double]]
And you could write specific properties that could specify different
things depending on the actual type:
forAll(genFooInt) { foo => ... } // foo.x : Int
forAll(genFooDouble) { foo => ... } // foo.x : Double
/ Rickard
> --
> You received this message because you are subscribed to the Google
> Groups "scalacheck" group.
> To unsubscribe from this group and stop receiving emails from it, send
> an email to
scalacheck+...@googlegroups.com
> <mailto:
scalacheck+...@googlegroups.com>.
> To post to this group, send email to
scala...@googlegroups.com
> <mailto:
scala...@googlegroups.com>.
> Visit this group at
http://groups.google.com/group/scalacheck.
> For more options, visit
https://groups.google.com/d/optout.