I have implemented the following function:
/**
* Returns a function h , which is the composition of the functions f and g.
*/
def compose[A, B, C](g: B => C, f: A => B): A => C = f.andThen(g)
And I'm trying to test it with ScalaCheck. I could generate the following tests, which compile and pass:
import org.scalatest.prop.PropertyChecks
import org.scalatest.{FlatSpec, Matchers}
class ComposeSpec extends FlatSpec with Matchers with PropertyChecks {
"Compose" should "return a function h , which is the composition of the
functions f and g" in {
forAll { (a: Int, g: Int => Int, f: Int => Int) =>
compose(g, f)(a) should be(g(f(a)))
}
forAll { (a: String, g: Double => Int, f: String => Double) =>
compose(g, f)(a) should be(g(f(a)))
}
}
}
But, as you see, I'm generating arbitrary functions with defined types, and also matching the type of the parameter a
with the type of the input of the function f
. What I want to do would be something like this:
forAll { (a: A, g: B => C, f: A => B) =>
compose(g, f)(a) should be(g(f(a)))
}
But I don't know the syntax for that, nor if it's possible. Could you help me?
The scalatest website has this to say about forAll
:
An implicit
Arbitrary
generator andShrink
object needs to be supplied for TheforAll
method will pass each row of data to each parameter type. ScalaCheck provides many implicitArbitrary
generators for common types such asInt
,String
,List[Float]
, etc., in itsorg.scalacheck.Arbitrary
companion object. So long as you use types for which ScalaCheck already provides implicitArbitrary
generators, you needn't worry about them. Same forShrink
objects, which are provided by ScalaCheck'sorg.scalacheck.Shrink
companion object. Most often you can simply pass a property function toforAll
, and the compiler will grab the implicit values provided by ScalaCheck.
So unfortunately you can't use forAll
to check every possible type, because there are no implicit Arbitrary
and Shrink
objects for every possible type. It seems pretty impossible to generate arbitrary objects of any type.
The best you could do would be something like:
def checkComposeForAll[A : Arbitrary : Shrink, B : Arbitrary : Shrink, C : Arbitrary : Shrink]() = {
forAll { (a: A, g: B => C, f: A => B) =>
compose(g, f)(a) should be(g(f(a)))
}
}
checkComposeForAll[Int, Int, Int]()
checkComposeForAll[String, String, String]()
checkComposeForAll[List[Int], Double, Int]()
// ... etc, check a bunch of types ...