From de1c5a4aedd27bb880e33e519d636e2607b35412 Mon Sep 17 00:00:00 2001 From: Grzegorz Kossakowski Date: Sun, 24 Nov 2013 23:27:54 +0100 Subject: [PATCH] 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. --- .../xsbt/ScalaCompilerForUnitTesting.scala | 53 ++++++++++++++++--- 1 file changed, 46 insertions(+), 7 deletions(-) diff --git a/compile/interface/src/test/scala/xsbt/ScalaCompilerForUnitTesting.scala b/compile/interface/src/test/scala/xsbt/ScalaCompilerForUnitTesting.scala index 8b4d67d23..61fb08078 100644 --- a/compile/interface/src/test/scala/xsbt/ScalaCompilerForUnitTesting.scala +++ b/compile/interface/src/test/scala/xsbt/ScalaCompilerForUnitTesting.scala @@ -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]]) +}