diff --git a/src/main/scala/com/buransky/plugins/scoverage/pathcleaner/BruteForceSequenceMatcher.scala b/src/main/scala/com/buransky/plugins/scoverage/pathcleaner/BruteForceSequenceMatcher.scala index 458e4e8..ebc2628 100644 --- a/src/main/scala/com/buransky/plugins/scoverage/pathcleaner/BruteForceSequenceMatcher.scala +++ b/src/main/scala/com/buransky/plugins/scoverage/pathcleaner/BruteForceSequenceMatcher.scala @@ -20,12 +20,16 @@ package com.buransky.plugins.scoverage.pathcleaner import java.io.File + import org.apache.commons.io.FileUtils import BruteForceSequenceMatcher._ import com.buransky.plugins.scoverage.util.PathUtil + import scala.collection.JavaConversions._ import org.sonar.api.utils.log.Loggers +import scala.annotation.tailrec + object BruteForceSequenceMatcher { val extensions = Array[String]("java", "scala") @@ -48,40 +52,53 @@ object BruteForceSequenceMatcher { */ class BruteForceSequenceMatcher(baseDir: File, sourcePath: String) extends PathSanitizer { - private val sourceDir = initSourceDir() - require(sourceDir.isAbsolute) - require(sourceDir.isDirectory) + private val sourceDirs = initSourceDir() private val log = Loggers.get(classOf[BruteForceSequenceMatcher]) - private val sourcePathLength = PathUtil.splitPath(sourceDir.getAbsolutePath).size + //private val sourcePathLength = private val filesMap = initFilesMap() def getSourceRelativePath(reportPath: PathSeq): Option[PathSeq] = { - // match with file system map of files - val relPathOption = for { - absPathCandidates <- filesMap.get(reportPath.last) - path <- absPathCandidates.find(absPath => absPath.endsWith(reportPath)) - } yield path.drop(sourcePathLength) + getSourceRelativePathInner(filesMap, reportPath) + } - relPathOption + @tailrec + final def getSourceRelativePathInner(elements:Seq[(Int, Map[String, Seq[PathSeq]])], reportPath: PathSeq): Option[PathSeq]= { + elements match { + case Nil => None + case (sourcePathLength, head) :: rest => + val relPathOption = for { + absPathCandidates <- head.get(reportPath.last) + path <- absPathCandidates.find(absPath => absPath.endsWith(reportPath)) + } yield { + path.drop(sourcePathLength) + } + relPathOption match { + case None => getSourceRelativePathInner(rest, reportPath) + case v => v + } + } } // mock able helpers that allow us to remove the dependency to the real file system during tests - private[pathcleaner] def initSourceDir(): File = { - sourcePath.split(",").headOption.map { first => + private[pathcleaner] def initSourceDir(): Seq[File] = { + sourcePath.split(",").map { first => val sourceDir = new File(baseDir, first) + require(sourceDir.isAbsolute) + require(sourceDir.isDirectory) sourceDir - }.getOrElse(null) + } } - private[pathcleaner] def initFilesMap(): Map[String, Seq[PathSeq]] = { - val srcFiles = FileUtils.iterateFiles(sourceDir, extensions, true) - val paths = srcFiles.map(file => PathUtil.splitPath(file.getAbsolutePath)).toSeq - - // group them by filename, in case multiple files have the same name - paths.groupBy(path => path.last) + private[pathcleaner] def initFilesMap(): List[(Int, Map[String, Seq[PathSeq]])] = { + sourceDirs.map { sourceDir => + val srcFiles = FileUtils.iterateFiles(sourceDir, extensions, true) + val paths = srcFiles.map(file => PathUtil.splitPath(file.getAbsolutePath)).toSeq + // group them by filename, in case multiple files have the same name + (PathUtil.splitPath(sourceDir.getAbsolutePath).size, paths.groupBy(path => path.last)) + }.toList } } diff --git a/src/main/scala/com/buransky/plugins/scoverage/sensor/ScoverageSensor.scala b/src/main/scala/com/buransky/plugins/scoverage/sensor/ScoverageSensor.scala index 3e3c414..30b84ee 100644 --- a/src/main/scala/com/buransky/plugins/scoverage/sensor/ScoverageSensor.scala +++ b/src/main/scala/com/buransky/plugins/scoverage/sensor/ScoverageSensor.scala @@ -19,6 +19,8 @@ */ package com.buransky.plugins.scoverage.sensor +import java.io.File + import com.buransky.plugins.scoverage.language.Scala import com.buransky.plugins.scoverage.measure.ScalaMetrics import com.buransky.plugins.scoverage.pathcleaner.{BruteForceSequenceMatcher, PathSanitizer} @@ -248,12 +250,27 @@ class ScoverageSensor(settings: Settings, pathResolver: PathResolver, fileSystem new Measure(ScalaMetrics.coveredStatements, coveredStatements.toDouble, 0) private def appendFilePath(src: String, name: String) = { - val result = src match { + def whyDoWeMakeThisAssumption(elems:List[String]):Option[String] = { + elems match { + case Nil => None + case elem :: rest => + val f = new File(elem) + val n = new File(f, name) + n.exists match { + case true => Some(elem + java.io.File.separator + name) + case false => whyDoWeMakeThisAssumption(rest) + } + } + } + src match { case java.io.File.separator => java.io.File.separator case empty if empty.isEmpty => "" - case other => other + java.io.File.separator + case other => + val omg = src.split(",").toList + whyDoWeMakeThisAssumption(omg) match { + case None => other + java.io.File.separator + name + case Some(real) => real + } } - - result + name } } diff --git a/src/test/scala/com/buransky/plugins/scoverage/pathcleaner/BruteForceSequenceMatcherSpec.scala b/src/test/scala/com/buransky/plugins/scoverage/pathcleaner/BruteForceSequenceMatcherSpec.scala index 5fec3f6..9a6a55c 100644 --- a/src/test/scala/com/buransky/plugins/scoverage/pathcleaner/BruteForceSequenceMatcherSpec.scala +++ b/src/test/scala/com/buransky/plugins/scoverage/pathcleaner/BruteForceSequenceMatcherSpec.scala @@ -26,6 +26,8 @@ import org.scalatest.FlatSpec import com.buransky.plugins.scoverage.pathcleaner.BruteForceSequenceMatcher.PathSeq import org.scalatest.Matchers import java.io.File + +import com.buransky.plugins.scoverage.util.PathUtil import org.mockito.Mockito._ @RunWith(classOf[JUnitRunner]) @@ -111,7 +113,7 @@ class BruteForceSequenceMatcherSpec extends FlatSpec with Matchers with MockitoS dir } - override private[pathcleaner] def initSourceDir(): File = srcDir - override private[pathcleaner] def initFilesMap(): Map[String, Seq[PathSeq]] = filesMap + override private[pathcleaner] def initSourceDir(): Seq[File] = List(srcDir) + override private[pathcleaner] def initFilesMap(): List[(Int, Map[String, Seq[PathSeq]])] = List((PathUtil.splitPath(srcDir.getAbsolutePath).size, filesMap)) } }