Fix random Analysis generator for ScalaCheck

Unit tests in incremental-compiler subproject use a generator to
create random Analysis objects. This generator was unfortunately
not working properly and generated only empty Analyses (it failed
to generate any non-empty Analysis because of a bug in the `unique`
generator).
This commit is contained in:
Martin Duhem 2014-09-03 23:10:22 +02:00
parent 68602278d5
commit c55ae4fd18
2 changed files with 39 additions and 5 deletions

View File

@ -65,7 +65,9 @@ object AnalysisTest extends Properties("Analysis") {
// Merge and split large, generated examples.
// Mustn't shrink, as the default Shrink[Int] doesn't respect the lower bound of choose(), which will cause
// a divide-by-zero error masking the original error.
property("Complex Merge and Split") = forAllNoShrink(genAnalysis, choose(1, 10)) { (analysis: Analysis, numSplits: Int) =>
// Note that the generated Analyses have nameHashing = false (Grouping of Analyses with name hashing enabled
// is not supported right now)
property("Complex Merge and Split") = forAllNoShrink(genAnalysis(nameHashing = false), choose(1, 10)) { (analysis: Analysis, numSplits: Int) =>
val grouped: Map[Int, Analysis] = analysis.groupBy({ f: File => abs(f.hashCode()) % numSplits })
def getGroup(i: Int): Analysis = grouped.getOrElse(i, Analysis.empty(false))
val splits = (Range(0, numSplits) map getGroup).toList

View File

@ -25,9 +25,18 @@ object TestCaseGenerators {
// Ensure that we generate unique class names and file paths every time.
// Using repeated strings may lead to all sorts of undesirable interactions.
val used = scala.collection.mutable.Set.empty[String]
val used1 = scala.collection.mutable.Set.empty[String]
val used2 = scala.collection.mutable.Set.empty[String]
def unique[T](g: Gen[T]) = g retryUntil { o: T => used.add(o.toString) }
// When using `retryUntil`, the condition is actually tested twice (see implementation in ScalaCheck),
// which is why we need to insert twice the element.
// If the element is present in both sets, then it has already been used.
def unique[T](g: Gen[T]) = g retryUntil { o: T =>
if (used1.add(o.toString))
true
else
used2.add(o.toString)
}
def identifier: Gen[String] = sized { size =>
resize(Math.max(size, 3), Gen.identifier)
@ -134,6 +143,18 @@ object TestCaseGenerators {
external <- someOf(src.external.all.toList)
} yield Relations.makeSource(Relation.empty ++ internal, Relation.empty ++ external)
def genRSourceDependencies(srcs: List[File]): Gen[Relations.SourceDependencies] = for {
internal <- listOfN(srcs.length, someOf(srcs))
external <- genStringRelation(srcs)
} yield Relations.makeSourceDependencies(
Relation.reconstruct((srcs zip (internal map { _.toSet }) map { case (a, b) => (a, b - a) }).toMap),
external)
def genSubRSourceDependencies(src: Relations.SourceDependencies): Gen[Relations.SourceDependencies] = for {
internal <- someOf(src.internal.all.toList)
external <- someOf(src.external.all.toList)
} yield Relations.makeSourceDependencies(Relation.empty ++ internal, Relation.empty ++ external)
def genRelations: Gen[Relations] = for {
numSrcs <- choose(0, maxSources)
srcs <- listOfN(numSrcs, genFile)
@ -145,8 +166,19 @@ object TestCaseGenerators {
} yield Relations.make(srcProd, binaryDep, direct, publicInherited, classes)
def genAnalysis: Gen[Analysis] = for {
rels <- genRelations
def genRelationsNameHashing: Gen[Relations] = for {
numSrcs <- choose(0, maxSources)
srcs <- listOfN(numSrcs, genFile)
srcProd <- genFileRelation(srcs)
binaryDep <- genFileRelation(srcs)
memberRef <- genRSourceDependencies(srcs)
inheritance <- genSubRSourceDependencies(memberRef)
classes <- genStringRelation(srcs)
names <- genStringRelation(srcs)
} yield Relations.make(srcProd, binaryDep, memberRef, inheritance, classes, names)
def genAnalysis(nameHashing: Boolean): Gen[Analysis] = for {
rels <- if (nameHashing) genRelationsNameHashing else genRelations
stamps <- genStamps(rels)
apis <- genAPIs(rels)
} yield new MAnalysis(stamps, apis, rels, SourceInfos.empty, Compilations.empty)