diff options
author | Grzegorz Kossakowski <grzegorz.kossakowski@gmail.com> | 2014-12-05 14:19:00 +0100 |
---|---|---|
committer | Grzegorz Kossakowski <grzegorz.kossakowski@gmail.com> | 2014-12-05 14:19:00 +0100 |
commit | 124cf2f62f559caf37a5d5df7e15db7ba5958bcf (patch) | |
tree | 7cf981e5940bc70c8dfa2def557c631f8dc6c81e /test/junit | |
parent | 59832b0afedeaae8d0c1a48cf92d2b5f529ccd82 (diff) | |
parent | 35811876a3a089706951620e2434d171090ac0b0 (diff) | |
download | scala-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')
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 + } +} |