summaryrefslogtreecommitdiff
path: root/test/junit
diff options
context:
space:
mode:
authorGrzegorz Kossakowski <grzegorz.kossakowski@gmail.com>2014-12-05 14:19:00 +0100
committerGrzegorz Kossakowski <grzegorz.kossakowski@gmail.com>2014-12-05 14:19:00 +0100
commit124cf2f62f559caf37a5d5df7e15db7ba5958bcf (patch)
tree7cf981e5940bc70c8dfa2def557c631f8dc6c81e /test/junit
parent59832b0afedeaae8d0c1a48cf92d2b5f529ccd82 (diff)
parent35811876a3a089706951620e2434d171090ac0b0 (diff)
downloadscala-124cf2f62f559caf37a5d5df7e15db7ba5958bcf.tar.gz
scala-124cf2f62f559caf37a5d5df7e15db7ba5958bcf.tar.bz2
scala-124cf2f62f559caf37a5d5df7e15db7ba5958bcf.zip
Merge pull request #4176 from mpociecha/flat-classpath2
The alternative, flat representation of classpath elements
Diffstat (limited to 'test/junit')
-rw-r--r--test/junit/scala/tools/nsc/SampleTest.scala2
-rw-r--r--test/junit/scala/tools/nsc/classpath/AggregateFlatClassPathTest.scala208
-rw-r--r--test/junit/scala/tools/nsc/classpath/FlatClassPathResolverTest.scala159
-rw-r--r--test/junit/scala/tools/nsc/symtab/SymbolTableForUnitTesting.scala31
-rw-r--r--test/junit/scala/tools/nsc/util/ClassPathImplComparator.scala143
5 files changed, 538 insertions, 5 deletions
diff --git a/test/junit/scala/tools/nsc/SampleTest.scala b/test/junit/scala/tools/nsc/SampleTest.scala
index 810c88ef9d..60bb09e98f 100644
--- a/test/junit/scala/tools/nsc/SampleTest.scala
+++ b/test/junit/scala/tools/nsc/SampleTest.scala
@@ -11,6 +11,6 @@ import org.junit.runners.JUnit4
class SampleTest {
@Test
def testMath: Unit = {
- assert(2+2 == 4, "you didn't get the math right fellow")
+ assertTrue("you didn't get the math right fellow", 2 + 2 == 4)
}
}
diff --git a/test/junit/scala/tools/nsc/classpath/AggregateFlatClassPathTest.scala b/test/junit/scala/tools/nsc/classpath/AggregateFlatClassPathTest.scala
new file mode 100644
index 0000000000..9a004d5e0e
--- /dev/null
+++ b/test/junit/scala/tools/nsc/classpath/AggregateFlatClassPathTest.scala
@@ -0,0 +1,208 @@
+/*
+ * Copyright (c) 2014 Contributor. All rights reserved.
+ */
+package scala.tools.nsc.classpath
+
+import java.net.URL
+import org.junit.Assert._
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.junit.runners.JUnit4
+import scala.reflect.io.VirtualFile
+import scala.tools.nsc.io.AbstractFile
+
+/**
+ * Tests whether AggregateFlatClassPath returns correct entries taken from
+ * cp instances used during creating it and whether it preserves the ordering
+ * (in the case of the repeated entry for a class or a source it returns the first one).
+ */
+@RunWith(classOf[JUnit4])
+class AggregateFlatClassPathTest {
+
+ private class TestFlatClassPath extends FlatClassPath {
+ override def packages(inPackage: String): Seq[PackageEntry] = unsupported
+ override def sources(inPackage: String): Seq[SourceFileEntry] = unsupported
+ override def classes(inPackage: String): Seq[ClassFileEntry] = unsupported
+
+ override def list(inPackage: String): FlatClassPathEntries = unsupported
+ override def findClassFile(name: String): Option[AbstractFile] = unsupported
+
+ override def asClassPathStrings: Seq[String] = unsupported
+ override def asSourcePathString: String = unsupported
+ override def asURLs: Seq[URL] = unsupported
+ }
+
+ private case class TestClassPath(virtualPath: String, classesInPackage: EntryNamesInPackage*) extends TestFlatClassPath {
+
+ override def classes(inPackage: String): Seq[ClassFileEntry] =
+ for {
+ entriesWrapper <- classesInPackage if entriesWrapper.inPackage == inPackage
+ name <- entriesWrapper.names
+ } yield classFileEntry(virtualPath, inPackage, name)
+
+ override def sources(inPackage: String): Seq[SourceFileEntry] = Nil
+
+ // we'll ignore packages
+ override def list(inPackage: String): FlatClassPathEntries = FlatClassPathEntries(Nil, classes(inPackage))
+ }
+
+ private case class TestSourcePath(virtualPath: String, sourcesInPackage: EntryNamesInPackage*) extends TestFlatClassPath {
+
+ override def sources(inPackage: String): Seq[SourceFileEntry] =
+ for {
+ entriesWrapper <- sourcesInPackage if entriesWrapper.inPackage == inPackage
+ name <- entriesWrapper.names
+ } yield sourceFileEntry(virtualPath, inPackage, name)
+
+ override def classes(inPackage: String): Seq[ClassFileEntry] = Nil
+
+ // we'll ignore packages
+ override def list(inPackage: String): FlatClassPathEntries = FlatClassPathEntries(Nil, sources(inPackage))
+ }
+
+ private case class EntryNamesInPackage(inPackage: String)(val names: String*)
+
+ private val dir1 = "./dir1"
+ private val dir2 = "./dir2"
+ private val dir3 = "./dir3"
+ private val dir4 = ""
+
+ private val pkg1 = "pkg1"
+ private val pkg2 = "pkg2"
+ private val pkg3 = "pkg1.nested"
+ private val nonexistingPkg = "nonexisting"
+
+ private def unsupported = throw new UnsupportedOperationException
+
+ private def classFileEntry(pathPrefix: String, inPackage: String, fileName: String) =
+ ClassFileEntryImpl(classFile(pathPrefix, inPackage, fileName))
+
+ private def sourceFileEntry(pathPrefix: String, inPackage: String, fileName: String) =
+ SourceFileEntryImpl(sourceFile(pathPrefix, inPackage, fileName))
+
+ private def classFile(pathPrefix: String, inPackage: String, fileName: String) =
+ virtualFile(pathPrefix, inPackage, fileName, ".class")
+
+ private def sourceFile(pathPrefix: String, inPackage: String, fileName: String) =
+ virtualFile(pathPrefix, inPackage, fileName, ".scala")
+
+ private def virtualFile(pathPrefix: String, inPackage: String, fileName: String, extension: String) = {
+ val packageDirs =
+ if (inPackage == FlatClassPath.RootPackage) ""
+ else inPackage.split('.').mkString("/", "/", "")
+ new VirtualFile(fileName + extension, s"$pathPrefix$packageDirs/$fileName$extension")
+ }
+
+ private def createDefaultTestClasspath() = {
+ val partialClassPaths = Seq(TestSourcePath(dir1, EntryNamesInPackage(pkg1)("F", "A", "G")),
+ TestClassPath(dir2, EntryNamesInPackage(pkg1)("C", "B", "A"), EntryNamesInPackage(pkg2)("D", "A", "E")),
+ TestClassPath(dir3, EntryNamesInPackage(pkg1)("A", "D", "F")),
+ TestSourcePath(dir4, EntryNamesInPackage(pkg2)("A", "H", "I"), EntryNamesInPackage(pkg1)("A")),
+ TestSourcePath(dir2, EntryNamesInPackage(pkg3)("J", "K", "L"))
+ )
+
+ AggregateFlatClassPath(partialClassPaths)
+ }
+
+ @Test
+ def testGettingPackages: Unit = {
+ case class ClassPathWithPackages(packagesInPackage: EntryNamesInPackage*) extends TestFlatClassPath {
+ override def packages(inPackage: String): Seq[PackageEntry] =
+ packagesInPackage.find(_.inPackage == inPackage).map(_.names).getOrElse(Nil) map PackageEntryImpl
+ }
+
+ val partialClassPaths = Seq(ClassPathWithPackages(EntryNamesInPackage(pkg1)("pkg1.a", "pkg1.d", "pkg1.f")),
+ ClassPathWithPackages(EntryNamesInPackage(pkg1)("pkg1.c", "pkg1.b", "pkg1.a"),
+ EntryNamesInPackage(pkg2)("pkg2.d", "pkg2.a", "pkg2.e"))
+ )
+ val cp = AggregateFlatClassPath(partialClassPaths)
+
+ val packagesInPkg1 = Seq("pkg1.a", "pkg1.d", "pkg1.f", "pkg1.c", "pkg1.b")
+ assertEquals(packagesInPkg1, cp.packages(pkg1).map(_.name))
+
+ val packagesInPkg2 = Seq("pkg2.d", "pkg2.a", "pkg2.e")
+ assertEquals(packagesInPkg2, cp.packages(pkg2).map(_.name))
+
+ assertEquals(Seq.empty, cp.packages(nonexistingPkg))
+ }
+
+ @Test
+ def testGettingClasses: Unit = {
+ val cp = createDefaultTestClasspath()
+
+ val classesInPkg1 = Seq(classFileEntry(dir2, pkg1, "C"),
+ classFileEntry(dir2, pkg1, "B"),
+ classFileEntry(dir2, pkg1, "A"),
+ classFileEntry(dir3, pkg1, "D"),
+ classFileEntry(dir3, pkg1, "F")
+ )
+ assertEquals(classesInPkg1, cp.classes(pkg1))
+
+ val classesInPkg2 = Seq(classFileEntry(dir2, pkg2, "D"),
+ classFileEntry(dir2, pkg2, "A"),
+ classFileEntry(dir2, pkg2, "E")
+ )
+ assertEquals(classesInPkg2, cp.classes(pkg2))
+
+ assertEquals(Seq.empty, cp.classes(pkg3))
+ assertEquals(Seq.empty, cp.classes(nonexistingPkg))
+ }
+
+ @Test
+ def testGettingSources: Unit = {
+ val partialClassPaths = Seq(TestClassPath(dir1, EntryNamesInPackage(pkg1)("F", "A", "G")),
+ TestSourcePath(dir2, EntryNamesInPackage(pkg1)("C", "B", "A"), EntryNamesInPackage(pkg2)("D", "A", "E")),
+ TestSourcePath(dir3, EntryNamesInPackage(pkg1)("A", "D", "F")),
+ TestClassPath(dir4, EntryNamesInPackage(pkg2)("A", "H", "I")),
+ TestClassPath(dir2, EntryNamesInPackage(pkg3)("J", "K", "L"))
+ )
+ val cp = AggregateFlatClassPath(partialClassPaths)
+
+ val sourcesInPkg1 = Seq(sourceFileEntry(dir2, pkg1, "C"),
+ sourceFileEntry(dir2, pkg1, "B"),
+ sourceFileEntry(dir2, pkg1, "A"),
+ sourceFileEntry(dir3, pkg1, "D"),
+ sourceFileEntry(dir3, pkg1, "F")
+ )
+ assertEquals(sourcesInPkg1, cp.sources(pkg1))
+
+ val sourcesInPkg2 = Seq(sourceFileEntry(dir2, pkg2, "D"),
+ sourceFileEntry(dir2, pkg2, "A"),
+ sourceFileEntry(dir2, pkg2, "E")
+ )
+ assertEquals(sourcesInPkg2, cp.sources(pkg2))
+
+ assertEquals(Seq.empty, cp.sources(pkg3))
+ assertEquals(Seq.empty, cp.sources(nonexistingPkg))
+ }
+
+ @Test
+ def testList: Unit = {
+ val cp = createDefaultTestClasspath()
+
+ val classesAndSourcesInPkg1 = Seq(
+ ClassAndSourceFilesEntry(classFile(dir3, pkg1, "F"), sourceFile(dir1, pkg1, "F")),
+ ClassAndSourceFilesEntry(classFile(dir2, pkg1, "A"), sourceFile(dir1, pkg1, "A")),
+ sourceFileEntry(dir1, pkg1, "G"),
+ classFileEntry(dir2, pkg1, "C"),
+ classFileEntry(dir2, pkg1, "B"),
+ classFileEntry(dir3, pkg1, "D")
+ )
+ assertEquals(classesAndSourcesInPkg1, cp.list(pkg1).classesAndSources)
+
+ assertEquals(FlatClassPathEntries(Nil, Nil), cp.list(nonexistingPkg))
+ }
+
+ @Test
+ def testFindClass: Unit = {
+ val cp = createDefaultTestClasspath()
+
+ assertEquals(
+ Some(ClassAndSourceFilesEntry(classFile(dir2, pkg1, "A"), sourceFile(dir1, pkg1, "A"))),
+ cp.findClass(s"$pkg1.A")
+ )
+ assertEquals(Some(classFileEntry(dir3, pkg1, "D")), cp.findClass(s"$pkg1.D"))
+ assertEquals(Some(sourceFileEntry(dir2, pkg3, "L")), cp.findClass(s"$pkg3.L"))
+ assertEquals(None, cp.findClass("Nonexisting"))
+ }
+}
diff --git a/test/junit/scala/tools/nsc/classpath/FlatClassPathResolverTest.scala b/test/junit/scala/tools/nsc/classpath/FlatClassPathResolverTest.scala
new file mode 100644
index 0000000000..a37ba31b31
--- /dev/null
+++ b/test/junit/scala/tools/nsc/classpath/FlatClassPathResolverTest.scala
@@ -0,0 +1,159 @@
+/*
+ * Copyright (c) 2014 Contributor. All rights reserved.
+ */
+package scala.tools.nsc.classpath
+
+import java.io.File
+import org.junit.Assert._
+import org.junit._
+import org.junit.rules.TemporaryFolder
+import org.junit.runner.RunWith
+import org.junit.runners.JUnit4
+import scala.annotation.tailrec
+import scala.tools.nsc.io.AbstractFile
+import scala.tools.nsc.util.ClassPath
+import scala.tools.nsc.Settings
+import scala.tools.util.FlatClassPathResolver
+import scala.tools.util.PathResolver
+
+@RunWith(classOf[JUnit4])
+class FlatClassPathResolverTest {
+
+ val tempDir = new TemporaryFolder()
+
+ private val packagesToTest = List(FlatClassPath.RootPackage, "scala", "scala.reflect", "scala.reflect.io")
+ private val classFilesToFind = List("scala.tools.util.FlatClassPathResolver",
+ "scala.reflect.io.AbstractFile",
+ "scala.collection.immutable.List",
+ "scala.Option",
+ "scala.collection.immutable.Vector",
+ "scala.util.hashing.MurmurHash3",
+ "java.lang.Object",
+ "java.util.Date")
+
+ private val classesToFind = classFilesToFind ++ List("TestSourceInRootPackage",
+ "scala.reflect.io.TestScalaSource",
+ "scala.reflect.io.TestJavaSource")
+
+ private val settings = new Settings
+
+ @Before
+ def initTempDirAndSourcePath: Unit = {
+ // In Java TemporaryFolder in JUnit is managed automatically using @Rule.
+ // It would work also in Scala after adding and extending a class like
+ // TestWithTempFolder.java containing it. But in this case it doesn't work when running tests
+ // from the command line - java class is not compiled due to some, misterious reasons.
+ // That's why such dirs are here created and deleted manually.
+ tempDir.create()
+ tempDir.newFile("TestSourceInRootPackage.scala")
+ val ioDir = tempDir.newFolder("scala", "reflect", "io")
+ new File(ioDir, "AbstractFile.scala").createNewFile()
+ new File(ioDir, "ZipArchive.java").createNewFile()
+ new File(ioDir, "TestScalaSource.scala").createNewFile()
+ new File(ioDir, "TestJavaSource.java").createNewFile()
+
+ settings.usejavacp.value = true
+ settings.sourcepath.value = tempDir.getRoot.getAbsolutePath
+ }
+
+ @After
+ def deleteTempDir: Unit = tempDir.delete()
+
+ private def createFlatClassPath(settings: Settings) =
+ new FlatClassPathResolver(settings).result
+
+ @Test
+ def testEntriesFromListOperationAgainstSeparateMethods: Unit = {
+ val classPath = createFlatClassPath(settings)
+
+ def compareEntriesInPackage(inPackage: String): Unit = {
+ val packages = classPath.packages(inPackage)
+ val classes = classPath.classes(inPackage)
+ val sources = classPath.sources(inPackage)
+ val FlatClassPathEntries(packagesFromList, classesAndSourcesFromList) = classPath.list(inPackage)
+
+ val packageNames = packages.map(_.name).sorted
+ val packageNamesFromList = packagesFromList.map(_.name).sorted
+ assertEquals(s"Methods list and packages for package '$inPackage' should return the same packages",
+ packageNames, packageNamesFromList)
+
+ val classFileNames = classes.map(_.name).sorted
+ val classFileNamesFromList = classesAndSourcesFromList.filter(_.binary.isDefined).map(_.name).sorted
+ assertEquals(s"Methods list and classes for package '$inPackage' should return entries for the same class files",
+ classFileNames, classFileNamesFromList)
+
+ val sourceFileNames = sources.map(_.name).sorted
+ val sourceFileNamesFromList = classesAndSourcesFromList.filter(_.source.isDefined).map(_.name).sorted
+ assertEquals(s"Methods list and sources for package '$inPackage' should return entries for the same source files",
+ sourceFileNames, sourceFileNamesFromList)
+
+ val uniqueNamesOfClassAndSourceFiles = (classFileNames ++ sourceFileNames).toSet
+ assertEquals(s"Class and source entries with the same name obtained via list for package '$inPackage' should be merged into one containing both files",
+ uniqueNamesOfClassAndSourceFiles.size, classesAndSourcesFromList.length)
+ }
+
+ packagesToTest foreach compareEntriesInPackage
+ }
+
+ @Test
+ def testCreatedEntriesAgainstRecursiveClassPath: Unit = {
+ val flatClassPath = createFlatClassPath(settings)
+ val recursiveClassPath = new PathResolver(settings).result
+
+ def compareEntriesInPackage(inPackage: String): Unit = {
+
+ @tailrec
+ def traverseToPackage(packageNameParts: Seq[String], cp: ClassPath[AbstractFile]): ClassPath[AbstractFile] = {
+ packageNameParts match {
+ case Nil => cp
+ case h :: t =>
+ cp.packages.find(_.name == h) match {
+ case Some(nestedCp) => traverseToPackage(t, nestedCp)
+ case _ => throw new Exception(s"There's no package $inPackage in recursive classpath - error when searching for '$h'")
+ }
+ }
+ }
+
+ val packageNameParts = if (inPackage == FlatClassPath.RootPackage) Nil else inPackage.split('.').toList
+ val recursiveClassPathInPackage = traverseToPackage(packageNameParts, recursiveClassPath)
+
+ val flatCpPackages = flatClassPath.packages(inPackage).map(_.name)
+ val pkgPrefix = PackageNameUtils.packagePrefix(inPackage)
+ val recursiveCpPackages = recursiveClassPathInPackage.packages.map(pkgPrefix + _.name)
+ assertEquals(s"Packages in package '$inPackage' on flat cp should be the same as on the recursive cp",
+ recursiveCpPackages, flatCpPackages)
+
+ val flatCpSources = flatClassPath.sources(inPackage).map(_.name).sorted
+ val recursiveCpSources = recursiveClassPathInPackage.classes
+ .filter(_.source.nonEmpty)
+ .map(_.name).sorted
+ assertEquals(s"Source entries in package '$inPackage' on flat cp should be the same as on the recursive cp",
+ recursiveCpSources, flatCpSources)
+
+ val flatCpClasses = flatClassPath.classes(inPackage).map(_.name).sorted
+ val recursiveCpClasses = recursiveClassPathInPackage.classes
+ .filter(_.binary.nonEmpty)
+ .map(_.name).sorted
+ assertEquals(s"Class entries in package '$inPackage' on flat cp should be the same as on the recursive cp",
+ recursiveCpClasses, flatCpClasses)
+ }
+
+ packagesToTest foreach compareEntriesInPackage
+ }
+
+ @Test
+ def testFindClassFile: Unit = {
+ val classPath = createFlatClassPath(settings)
+ classFilesToFind foreach { className =>
+ assertTrue(s"File for $className should be found", classPath.findClassFile(className).isDefined)
+ }
+ }
+
+ @Test
+ def testFindClass: Unit = {
+ val classPath = createFlatClassPath(settings)
+ classesToFind foreach { className =>
+ assertTrue(s"File for $className should be found", classPath.findClass(className).isDefined)
+ }
+ }
+}
diff --git a/test/junit/scala/tools/nsc/symtab/SymbolTableForUnitTesting.scala b/test/junit/scala/tools/nsc/symtab/SymbolTableForUnitTesting.scala
index e4be42ac96..f0f20acf07 100644
--- a/test/junit/scala/tools/nsc/symtab/SymbolTableForUnitTesting.scala
+++ b/test/junit/scala/tools/nsc/symtab/SymbolTableForUnitTesting.scala
@@ -3,6 +3,9 @@ package symtab
import scala.reflect.ClassTag
import scala.reflect.internal.{Phase, NoPhase, SomePhase}
+import scala.tools.nsc.classpath.FlatClassPath
+import scala.tools.nsc.settings.ClassPathRepresentationType
+import scala.tools.util.FlatClassPathResolver
import scala.tools.util.PathResolver
import util.ClassPath
import io.AbstractFile
@@ -26,13 +29,28 @@ class SymbolTableForUnitTesting extends SymbolTable {
class LazyTreeCopier extends super.LazyTreeCopier with TreeCopier
override def isCompilerUniverse: Boolean = true
- def classPath = new PathResolver(settings).result
+
+ def classPath = platform.classPath
+ def flatClassPath: FlatClassPath = platform.flatClassPath
object platform extends backend.Platform {
val symbolTable: SymbolTableForUnitTesting.this.type = SymbolTableForUnitTesting.this
lazy val loaders: SymbolTableForUnitTesting.this.loaders.type = SymbolTableForUnitTesting.this.loaders
+
def platformPhases: List[SubComponent] = Nil
- val classPath: ClassPath[AbstractFile] = new PathResolver(settings).result
+
+ lazy val classPath: ClassPath[AbstractFile] = {
+ assert(settings.YclasspathImpl.value == ClassPathRepresentationType.Recursive,
+ "It's not possible to use the recursive classpath representation, when it's not the chosen classpath scanning method")
+ new PathResolver(settings).result
+ }
+
+ private[nsc] lazy val flatClassPath: FlatClassPath = {
+ assert(settings.YclasspathImpl.value == ClassPathRepresentationType.Flat,
+ "It's not possible to use the flat classpath representation, when it's not the chosen classpath scanning method")
+ new FlatClassPathResolver(settings).result
+ }
+
def isMaybeBoxed(sym: Symbol): Boolean = ???
def needCompile(bin: AbstractFile, src: AbstractFile): Boolean = ???
def externalEquals: Symbol = ???
@@ -50,7 +68,12 @@ class SymbolTableForUnitTesting extends SymbolTable {
class GlobalMirror extends Roots(NoSymbol) {
val universe: SymbolTableForUnitTesting.this.type = SymbolTableForUnitTesting.this
- def rootLoader: LazyType = new loaders.PackageLoader(classPath)
+
+ def rootLoader: LazyType = settings.YclasspathImpl.value match {
+ case ClassPathRepresentationType.Flat => new loaders.PackageLoaderUsingFlatClassPath(FlatClassPath.RootPackage, flatClassPath)
+ case ClassPathRepresentationType.Recursive => new loaders.PackageLoader(classPath)
+ }
+
override def toString = "compiler mirror"
}
@@ -60,7 +83,7 @@ class SymbolTableForUnitTesting extends SymbolTable {
rm.asInstanceOf[Mirror]
}
- def settings: Settings = {
+ lazy val settings: Settings = {
val s = new Settings
// initialize classpath using java classpath
s.usejavacp.value = true
diff --git a/test/junit/scala/tools/nsc/util/ClassPathImplComparator.scala b/test/junit/scala/tools/nsc/util/ClassPathImplComparator.scala
new file mode 100644
index 0000000000..f2926e3e17
--- /dev/null
+++ b/test/junit/scala/tools/nsc/util/ClassPathImplComparator.scala
@@ -0,0 +1,143 @@
+/*
+ * Copyright (c) 2014 Contributor. All rights reserved.
+ */
+package scala.tools.nsc.util
+
+import scala.reflect.io.AbstractFile
+import scala.tools.nsc.Settings
+import scala.tools.nsc.settings.ClassPathRepresentationType
+import scala.tools.util.PathResolverFactory
+
+/**
+ * Simple application to compare efficiency of the recursive and the flat classpath representations
+ */
+object ClassPathImplComparator {
+
+ private class TestSettings extends Settings {
+ val checkClasses = PathSetting("-checkClasses", "Specify names of classes which should be found separated with ;", "")
+ val requiredIterations = IntSetting("-requiredIterations",
+ "Repeat tests specified number of times (to check e.g. impact of caches)", 1, Some((1, Int.MaxValue)), (_: String) => None)
+ val cpCreationRepetitions = IntSetting("-cpCreationRepetitions",
+ "Repeat tests specified number of times (to check e.g. impact of caches)", 1, Some((1, Int.MaxValue)), (_: String) => None)
+ val cpLookupRepetitions = IntSetting("-cpLookupRepetitions",
+ "Repeat tests specified number of times (to check e.g. impact of caches)", 1, Some((1, Int.MaxValue)), (_: String) => None)
+ }
+
+ private class DurationStats(name: String) {
+ private var sum = 0L
+ private var iterations = 0
+
+ def noteMeasuredTime(millis: Long): Unit = {
+ sum += millis
+ iterations += 1
+ }
+
+ def printResults(): Unit = {
+ val avg = if (iterations == 0) 0 else sum.toDouble / iterations
+ println(s"$name - total duration: $sum ms; iterations: $iterations; avg: $avg ms")
+ }
+ }
+
+ private lazy val defaultClassesToFind = List(
+ "scala.collection.immutable.List",
+ "scala.Option",
+ "scala.Int",
+ "scala.collection.immutable.Vector",
+ "scala.util.hashing.MurmurHash3"
+ )
+
+ private val oldCpCreationStats = new DurationStats("Old classpath - create")
+ private val oldCpSearchingStats = new DurationStats("Old classpath - search")
+
+ private val flatCpCreationStats = new DurationStats("Flat classpath - create")
+ private val flatCpSearchingStats = new DurationStats("Flat classpath - search")
+
+ def main(args: Array[String]): Unit = {
+
+ if (args contains "-help")
+ usage()
+ else {
+ val oldCpSettings = loadSettings(args.toList, ClassPathRepresentationType.Recursive)
+ val flatCpSettings = loadSettings(args.toList, ClassPathRepresentationType.Flat)
+
+ val classesToCheck = oldCpSettings.checkClasses.value
+ val classesToFind =
+ if (classesToCheck.isEmpty) defaultClassesToFind
+ else classesToCheck.split(";").toList
+
+ def doTest(classPath: => ClassFileLookup[AbstractFile], cpCreationStats: DurationStats, cpSearchingStats: DurationStats,
+ cpCreationRepetitions: Int, cpLookupRepetitions: Int)= {
+
+ def createClassPaths() = (1 to cpCreationRepetitions).map(_ => classPath).last
+ def testClassLookup(cp: ClassFileLookup[AbstractFile]): Boolean = (1 to cpCreationRepetitions).foldLeft(true) {
+ case (a, _) => a && checkExistenceOfClasses(classesToFind)(cp)
+ }
+
+ val cp = withMeasuredTime("Creating classpath", createClassPaths(), cpCreationStats)
+ val result = withMeasuredTime("Searching for specified classes", testClassLookup(cp), cpSearchingStats)
+ println(s"The end of the test case. All expected classes found = $result \n")
+ }
+
+ (1 to oldCpSettings.requiredIterations.value) foreach { iteration =>
+ if (oldCpSettings.requiredIterations.value > 1)
+ println(s"Iteration no $iteration")
+
+ println("Recursive (old) classpath representation:")
+ doTest(PathResolverFactory.create(oldCpSettings).result, oldCpCreationStats, oldCpSearchingStats,
+ oldCpSettings.cpCreationRepetitions.value, oldCpSettings.cpLookupRepetitions.value)
+
+ println("Flat classpath representation:")
+ doTest(PathResolverFactory.create(flatCpSettings).result, flatCpCreationStats, flatCpSearchingStats,
+ flatCpSettings.cpCreationRepetitions.value, flatCpSettings.cpLookupRepetitions.value)
+ }
+
+ if (oldCpSettings.requiredIterations.value > 1) {
+ println("\nOld classpath - summary")
+ oldCpCreationStats.printResults()
+ oldCpSearchingStats.printResults()
+
+ println("\nFlat classpath - summary")
+ flatCpCreationStats.printResults()
+ flatCpSearchingStats.printResults()
+ }
+ }
+ }
+
+ /**
+ * Prints usage information
+ */
+ private def usage(): Unit =
+ println("""Use classpath and sourcepath options like in the case of e.g. 'scala' command.
+ | There are also two additional options:
+ | -checkClasses <semicolon separated class names> Specify names of classes which should be found
+ | -requiredIterations <int value> Repeat tests specified count of times (to check e.g. impact of caches)
+ | Note: Option -YclasspathImpl will be set automatically for each case.
+ """.stripMargin.trim)
+
+ private def loadSettings(args: List[String], implType: String) = {
+ val settings = new TestSettings()
+ settings.processArguments(args, processAll = true)
+ settings.YclasspathImpl.value = implType
+ if (settings.classpath.isDefault)
+ settings.classpath.value = sys.props("java.class.path")
+ settings
+ }
+
+ private def withMeasuredTime[T](operationName: String, f: => T, durationStats: DurationStats): T = {
+ val startTime = System.currentTimeMillis()
+ val res = f
+ val elapsed = System.currentTimeMillis() - startTime
+ durationStats.noteMeasuredTime(elapsed)
+ println(s"$operationName - elapsed $elapsed ms")
+ res
+ }
+
+ private def checkExistenceOfClasses(classesToCheck: Seq[String])(classPath: ClassFileLookup[AbstractFile]): Boolean =
+ classesToCheck.foldLeft(true) {
+ case (res, classToCheck) =>
+ val found = classPath.findClass(classToCheck).isDefined
+ if (!found)
+ println(s"Class $classToCheck not found") // of course in this case the measured time will be affected by IO operation
+ found
+ }
+}