Add support for unit testing of extracted source dependencies.

Add `extractDependenciesFromSrcs` method to ScalaCompilerForUnitTest
class which allows us to unit test dependency extraction logic.

See the comment attached to the method that explain the details of
how it should be used.
This commit is contained in:
Grzegorz Kossakowski 2013-11-24 23:27:54 +01:00
parent 89914975e1
commit de1c5a4aed
1 changed files with 46 additions and 7 deletions

View File

@ -13,11 +13,13 @@ import xsbti.api.Def
import xsbt.api.SameAPI
import sbt.ConsoleLogger
import ScalaCompilerForUnitTesting.ExtractedSourceDependencies
/**
* Provides common functionality needed for unit tests that require compiling
* source code using Scala compiler.
*/
class ScalaCompilerForUnitTesting {
class ScalaCompilerForUnitTesting(memberRefAndInheritanceDeps: Boolean = false) {
/**
* Compiles given source code using Scala compiler and returns API representation
@ -28,6 +30,43 @@ class ScalaCompilerForUnitTesting {
analysisCallback.apis(tempSrcFile)
}
/**
* Compiles given source code snippets (passed as Strings) using Scala compiler and returns extracted
* dependencies between snippets. Source code snippets are identified by symbols. Each symbol should
* be associated with one snippet only.
*
* Symbols are used to express extracted dependencies between source code snippets. This way we have
* file system-independent way of testing dependencies between source code "files".
*/
def extractDependenciesFromSrcs(srcs: (Symbol, String)*): ExtractedSourceDependencies = {
val (symbolsForSrcs, rawSrcs) = srcs.unzip
assert(symbolsForSrcs.distinct.size == symbolsForSrcs.size,
s"Duplicate symbols for srcs detected: $symbolsForSrcs")
val (tempSrcFiles, testCallback) = compileSrcs(rawSrcs: _*)
val fileToSymbol = (tempSrcFiles zip symbolsForSrcs).toMap
val memberRefFileDeps = testCallback.sourceDependencies collect {
// false indicates that those dependencies are not introduced by inheritance
case (target, src, false) => (src, target)
}
val inheritanceFileDeps = testCallback.sourceDependencies collect {
// true indicates that those dependencies are introduced by inheritance
case (target, src, true) => (src, target)
}
def toSymbols(src: File, target: File): (Symbol, Symbol) = (fileToSymbol(src), fileToSymbol(target))
val memberRefDeps = memberRefFileDeps map { case (src, target) => toSymbols(src, target) }
val inheritanceDeps = inheritanceFileDeps map { case (src, target) => toSymbols(src, target) }
def pairsToMultiMap[A, B](pairs: Seq[(A, B)]): Map[A, Set[B]] = {
import scala.collection.mutable.{HashMap, MultiMap}
val emptyMultiMap = new HashMap[A, scala.collection.mutable.Set[B]] with MultiMap[A, B]
val multiMap = pairs.foldLeft(emptyMultiMap) { case (acc, (key, value)) =>
acc.addBinding(key, value)
}
// convert all collections to immutable variants
multiMap.toMap.mapValues(_.toSet).withDefaultValue(Set.empty)
}
ExtractedSourceDependencies(pairsToMultiMap(memberRefDeps), pairsToMultiMap(inheritanceDeps))
}
/**
* Compiles given source code snippets written to a temporary files. Each snippet is
* written to a separate temporary file.
@ -37,7 +76,7 @@ class ScalaCompilerForUnitTesting {
*/
private def compileSrcs(srcs: String*): (Seq[File], TestCallback) = {
withTemporaryDirectory { temp =>
val analysisCallback = new TestCallback
val analysisCallback = new TestCallback(memberRefAndInheritanceDeps)
val classesDir = new File(temp, "classes")
classesDir.mkdir()
val compiler = prepareCompiler(classesDir, analysisCallback)
@ -53,12 +92,8 @@ class ScalaCompilerForUnitTesting {
}
private def prepareSrcFile(baseDir: File, fileName: String, src: String): File = {
import java.io.FileWriter
val srcFile = new File(baseDir, fileName)
srcFile.createNewFile()
val fw = new FileWriter(srcFile)
fw.write(src)
fw.close()
sbt.IO.write(srcFile, src)
srcFile
}
@ -90,3 +125,7 @@ class ScalaCompilerForUnitTesting {
}
}
object ScalaCompilerForUnitTesting {
case class ExtractedSourceDependencies(memberRef: Map[Symbol, Set[Symbol]], inheritance: Map[Symbol, Set[Symbol]])
}