I am trying to develop property-based tests for a matching algorithm and I need to generate two inputs sets of the same size to feed into the algorithm. My current attempt at a solution is the following.
case class Man(id: Long, quality: Long, ordering: Ordering[Woman])
case class Woman(id: Long, quality: Long, ordering: Ordering[Man])
val man: Gen[Man] = {
for {
id <- Gen.posNum[Long]
quality <- Gen.posNum[Long]
} yield Man(id, quality, Man.womanByQuality)
}
val woman: Gen[Woman] = {
for {
id <- Gen.posNum[Long]
quality <- Gen.posNum[Long]
} yield Woman(id, quality, Woman.manByQuality)
}
def setOfN[T](n: Int, g: Gen[T]): Gen[Set[T]] = {
Gen.containerOfN[Set, T](n, g)
}
def unMatched: Gen[(Set[Man], Set[Woman])] = Gen.sized {
n => setOfN(n, man).flatMap(ms => setOfN(ms.size, woman).map(ws => (ms, ws)))
}
This generates tuples of input sets as required, but they are not guaranteed to be the same size. When I run the test using...
property("all men and women are matched") = forAll(unMatched) {
case (ms, ws) =>
println((ms.size, ws.size))
val matches = DeferredAcceptance.weaklyStableMatching(ms, ws)
(matches.size == ms.size) && (matches.size == ws.size)
}
The console will print something like...
(0,0)
(1,1)
(2,2)
(3,2)
(1,2)
(0,2)
(0,1)
(0,0)
! marriage-market.all men and women are matched: Exception raised on proper
ty evaluation.
> ARG_0: (Set(),Set(Woman(1,1,scala.math.Ordering$$anon$10@3d8314f0)))
> ARG_0_ORIGINAL: (Set(Man(3,1,scala.math.Ordering$$anon$10@2bea5ab4), Man(
2,1,scala.math.Ordering$$anon$10@2bea5ab4), Man(2,3,scala.math.Ordering$$
anon$10@2bea5ab4)),Set(Woman(1,1,scala.math.Ordering$$anon$10@3d8314f0),
Woman(3,2,scala.math.Ordering$$anon$10@3d8314f0)))
> Exception: java.lang.IllegalArgumentException: requirement failed
scala.Predef$.require(Predef.scala:264)
org.economicsl.matching.DeferredAcceptance$.weaklyStableMatching(DeferredAc
ceptance.scala:97)
org.economicsl.matching.MarriageMarketSpecification$.$anonfun$new$2(Marriag
eMarketSpecification.scala:54)
org.economicsl.matching.MarriageMarketSpecification$.$anonfun$new$2$adapted
(MarriageMarketSpecification.scala:51)
org.scalacheck.Prop$.$anonfun$forAllShrink$2(Prop.scala:761)
Found 1 failing properties.
Process finished with exit code 1
The test fails because I have included a requirement that the two input sets must be of equal size. My intent is that the generator should supply valid input data.
Thoughts?