diff options
Diffstat (limited to 'test')
32 files changed, 1102 insertions, 397 deletions
diff --git a/test/files/neg/t5148.check b/test/files/neg/t5148.check index 0de4fe2d4c..286ed9e04a 100644 --- a/test/files/neg/t5148.check +++ b/test/files/neg/t5148.check @@ -1,6 +1,11 @@ error: missing or invalid dependency detected while loading class file 'Imports.class'. +Could not access type Wrapper in class scala.tools.nsc.interpreter.IMain.Request, +because it (or its dependencies) are missing. Check your build definition for +missing or conflicting dependencies. (Re-run with `-Ylog-classpath` to see the problematic classpath.) +A full rebuild may help if 'Imports.class' was compiled against an incompatible version of scala.tools.nsc.interpreter.IMain.Request. +error: missing or invalid dependency detected while loading class file 'Imports.class'. Could not access type Request in class scala.tools.nsc.interpreter.IMain, because it (or its dependencies) are missing. Check your build definition for missing or conflicting dependencies. (Re-run with `-Ylog-classpath` to see the problematic classpath.) A full rebuild may help if 'Imports.class' was compiled against an incompatible version of scala.tools.nsc.interpreter.IMain. -one error found +two errors found diff --git a/test/files/neg/t9008.check b/test/files/neg/t9008.check new file mode 100644 index 0000000000..c32bc41baf --- /dev/null +++ b/test/files/neg/t9008.check @@ -0,0 +1,4 @@ +t9008.scala:2: error: type M takes type parameters + def x: List[M forSome { type M[_] }] = ??? + ^ +one error found diff --git a/test/files/neg/t9008.scala b/test/files/neg/t9008.scala new file mode 100644 index 0000000000..c6a5389e42 --- /dev/null +++ b/test/files/neg/t9008.scala @@ -0,0 +1,3 @@ +object Test { + def x: List[M forSome { type M[_] }] = ??? +} diff --git a/test/files/neg/t9008b.check b/test/files/neg/t9008b.check new file mode 100644 index 0000000000..5e911fc138 --- /dev/null +++ b/test/files/neg/t9008b.check @@ -0,0 +1,4 @@ +t9008b.scala:2: error: type M takes type parameters + type T = M forSome { type M[_] } + ^ +one error found diff --git a/test/files/neg/t9008b.scala b/test/files/neg/t9008b.scala new file mode 100644 index 0000000000..58f9d0e8de --- /dev/null +++ b/test/files/neg/t9008b.scala @@ -0,0 +1,3 @@ +object Test { + type T = M forSome { type M[_] } +} diff --git a/test/files/pos/t7683-stop-after-parser/ThePlugin.scala b/test/files/pos/t7683-stop-after-parser/ThePlugin.scala new file mode 100644 index 0000000000..cd800781dc --- /dev/null +++ b/test/files/pos/t7683-stop-after-parser/ThePlugin.scala @@ -0,0 +1,31 @@ +package scala.test.plugins + +import scala.tools.nsc +import nsc.Global +import nsc.Phase +import nsc.plugins.Plugin +import nsc.plugins.PluginComponent + +class ThePlugin(val global: Global) extends Plugin { + import global._ + + val name = "timebomb" + val description = "Explodes if run. Maybe I haven't implemented it yet." + val components = List[PluginComponent](thePhase1) + + private object thePhase1 extends PluginComponent { + val global = ThePlugin.this.global + + val runsAfter = List[String]("parser") + override val runsBefore = List[String]("namer") + val phaseName = ThePlugin.this.name + + def newPhase(prev: Phase) = new ThePhase(prev) + } + + private class ThePhase(prev: Phase) extends Phase(prev) { + override def name = ThePlugin.this.name + override def run = ??? + } +} + diff --git a/test/files/pos/t7683-stop-after-parser/sample_2.flags b/test/files/pos/t7683-stop-after-parser/sample_2.flags new file mode 100644 index 0000000000..99672cdfd3 --- /dev/null +++ b/test/files/pos/t7683-stop-after-parser/sample_2.flags @@ -0,0 +1 @@ +-Xplugin:. -Xplugin-require:timebomb -Ystop-after:parser diff --git a/test/files/pos/t7683-stop-after-parser/sample_2.scala b/test/files/pos/t7683-stop-after-parser/sample_2.scala new file mode 100644 index 0000000000..7eb11b8204 --- /dev/null +++ b/test/files/pos/t7683-stop-after-parser/sample_2.scala @@ -0,0 +1,6 @@ + +package sample + +// just a sample that is compiled with the explosive plugin disabled +object Sample extends App { +} diff --git a/test/files/pos/t7683-stop-after-parser/scalac-plugin.xml b/test/files/pos/t7683-stop-after-parser/scalac-plugin.xml new file mode 100644 index 0000000000..2558d6fd03 --- /dev/null +++ b/test/files/pos/t7683-stop-after-parser/scalac-plugin.xml @@ -0,0 +1,5 @@ +<plugin> + <name>ignored</name> + <classname>scala.test.plugins.ThePlugin</classname> +</plugin> + diff --git a/test/files/pos/t9008.scala b/test/files/pos/t9008.scala new file mode 100644 index 0000000000..d11b8604f2 --- /dev/null +++ b/test/files/pos/t9008.scala @@ -0,0 +1,5 @@ +trait Monad[M[_]] + +object Test { + def x: Monad[M forSome { type M[_] }] = ??? +} diff --git a/test/files/pos/t9018.scala b/test/files/pos/t9018.scala new file mode 100644 index 0000000000..7fb4cf21b3 --- /dev/null +++ b/test/files/pos/t9018.scala @@ -0,0 +1,16 @@ +object TestObject { + + def m(i: Int): AnyRef = i match { + case 0 => new C() + case 1 => Some(E.A).getOrElse("") + } + + class C extends Ordered[C] { + def compare(that: C): Int = ??? + } + + object E extends Enumeration { + type CharacterClass = Value + val A = Value + } +} diff --git a/test/files/run/priorityQueue.scala b/test/files/run/priorityQueue.scala deleted file mode 100644 index 327d8bf137..0000000000 --- a/test/files/run/priorityQueue.scala +++ /dev/null @@ -1,373 +0,0 @@ - - - -import scala.collection.mutable.PriorityQueue - - - - - - -// populate a priority queue a few different ways and make sure they all seem equal -object Test { - - def main(args: Array[String]) { - // testInsertionsAndEqualities - // testIntensiveEnqueueDequeue - // testTails - // testInits - // testFilters - // testDrops - // testEquality - // testMisc - // testReverse - // testToList - // testForeach - } - - // def testInsertionsAndEqualities { - // import scala.util.Random.nextInt - // val pq1 = new PriorityQueue[String] - // val pq2 = new PriorityQueue[String] - // val pq3 = new PriorityQueue[String] - // val pq4 = new PriorityQueue[String] - - // val strings = (1 to 20).toList map (i => List.fill((Math.abs(nextInt % 20)) + 1)("x").mkString) - - // pq1 ++= strings - // pq2 ++= strings.reverse - // for (s <- strings) pq3 += s - // for (s <- strings.reverse) pq4 += s - - // val pqs = List(pq1, pq2, pq3, pq4, pq1.clone, pq2.clone) - - // for (queue1 <- pqs ; queue2 <- pqs) { - // val l1: List[String] = queue1.dequeueAll[String, List[String]] - // val l2: List[String] = queue2.dequeueAll[String, List[String]] - // assert(l1 == l2) - // assert(queue1.max == queue2.max) - // } - - // assertPriorityDestructive(pq1) - // } - - // not a sequence anymore, Mildred - // def testIndexing { - // val pq = new PriorityQueue[Char] - // "The quick brown fox jumps over the lazy dog".foreach(pq += _) - - // // val iter = pq.iterator - // // while (iter.hasNext) println("`" + iter.next + "`") - // assert(pq(0) == 'z') - // assert(pq(1) == 'y') - // assert(pq(2) == 'x') - // assert(pq(3) == 'w') - // assert(pq(4) == 'v') - // assert(pq(5) == 'u') - // assert(pq(7) == 't') - // assert(pq(8) == 's') - // assert(pq(9) == 'r') - // assert(pq(10) == 'r') - - // pq.clear - // "abcdefghijklmnopqrstuvwxyz".foreach(pq += _) - // for (i <- 0 until 26) assert(pq(i) == ('z' - i)) - - // val intpq = new PriorityQueue[Int] - // val intlst = new collection.mutable.ArrayBuffer ++ (0 until 100) - // val random = new util.Random(101) - // while (intlst.nonEmpty) { - // val idx = random.nextInt(intlst.size) - // intpq += intlst(idx) - // intlst.remove(idx) - // } - // for (i <- 0 until 100) assert(intpq(i) == (99 - i)) - // } - - // def testTails { - // val pq = new PriorityQueue[Int] - // for (i <- 0 until 10) pq += i * 4321 % 200 - - // assert(pq.size == 10) - // assert(pq.nonEmpty) - - // val tailpq = pq.tail - // // pq.printstate - // // tailpq.printstate - // assert(tailpq.size == 9) - // assert(tailpq.nonEmpty) - // assertPriorityDestructive(tailpq) - // } - - // def assertPriorityDestructive[A](pq: PriorityQueue[A])(implicit ord: Ordering[A]) { - // import ord._ - // var prev: A = null.asInstanceOf[A] - // while (pq.nonEmpty) { - // val curr = pq.dequeue - // if (prev != null) assert(curr <= prev) - // prev = curr - // } - // } - - // def testInits { - // val pq = new PriorityQueue[Long] - // for (i <- 0 until 20) pq += (i + 313) * 111 % 300 - - // assert(pq.size == 20) - - // val initpq = pq.init - // assert(initpq.size == 19) - // assertPriorityDestructive(initpq) - // } - - // def testFilters { - // val pq = new PriorityQueue[String] - // for (i <- 0 until 100) pq += "Some " + (i * 312 % 200) - - // val filpq = pq.filter(_.indexOf('0') != -1) - // assertPriorityDestructive(filpq) - // } - - // def testIntensiveEnqueueDequeue { - // val pq = new PriorityQueue[Int] - - // testIntensive(1000, pq) - // pq.clear - // testIntensive(200, pq) - // } - - // def testIntensive(sz: Int, pq: PriorityQueue[Int]) { - // val lst = new collection.mutable.ArrayBuffer[Int] ++ (0 until sz) - // val rand = new util.Random(7) - // while (lst.nonEmpty) { - // val idx = rand.nextInt(lst.size) - // pq.enqueue(lst(idx)) - // lst.remove(idx) - // if (rand.nextDouble < 0.25 && pq.nonEmpty) pq.dequeue - // assertPriority(pq) - // } - // } - - // def testDrops { - // val pq = new PriorityQueue[Int] - // pq ++= (0 until 100) - // val droppq = pq.drop(50) - // assertPriority(droppq) - - // pq.clear - // pq ++= droppq - // assertPriorityDestructive(droppq) - // assertPriority(pq) - // assertPriorityDestructive(pq) - // } - - // // your sequence days have ended, foul priority queue - // // def testUpdates { - // // val pq = new PriorityQueue[Int] - // // pq ++= (0 until 36) - // // assertPriority(pq) - - // // pq(0) = 100 - // // assert(pq(0) == 100) - // // assert(pq.dequeue == 100) - // // assertPriority(pq) - - // // pq.clear - - // // pq ++= (1 to 100) - // // pq(5) = 200 - // // assert(pq(0) == 200) - // // assert(pq(1) == 100) - // // assert(pq(2) == 99) - // // assert(pq(3) == 98) - // // assert(pq(4) == 97) - // // assert(pq(5) == 96) - // // assert(pq(6) == 94) - // // assert(pq(7) == 93) - // // assert(pq(98) == 2) - // // assert(pq(99) == 1) - // // assertPriority(pq) - - // // pq(99) = 450 - // // assert(pq(0) == 450) - // // assert(pq(1) == 200) - // // assert(pq(99) == 2) - // // assertPriority(pq) - - // // pq(1) = 0 - // // assert(pq(1) == 100) - // // assert(pq(99) == 0) - // // assertPriority(pq) - // // assertPriorityDestructive(pq) - // // } - - // def testEquality { - // val pq1 = new PriorityQueue[Int] - // val pq2 = new PriorityQueue[Int] - - // pq1 ++= (0 until 50) - // var i = 49 - // while (i >= 0) { - // pq2 += i - // i -= 1 - // } - // assert(pq1 == pq2) - // assertPriority(pq2) - - // pq1 += 100 - // assert(pq1 != pq2) - // pq2 += 100 - // assert(pq1 == pq2) - // pq2 += 200 - // assert(pq1 != pq2) - // pq1 += 200 - // assert(pq1 == pq2) - // assertPriorityDestructive(pq1) - // assertPriorityDestructive(pq2) - // } - - // def testMisc { - // val pq = new PriorityQueue[Int] - // pq ++= (0 until 100) - // assert(pq.size == 100) - - // val (p1, p2) = pq.partition(_ < 50) - // assertPriorityDestructive(p1) - // assertPriorityDestructive(p2) - - // val spq = pq.slice(25, 75) - // assertPriorityDestructive(spq) - - // pq.clear - // pq ++= (0 until 10) - // pq += 5 - // assert(pq.size == 11) - - // val ind = pq.lastIndexWhere(_ == 5) - // assert(ind == 5) - // assertPriorityDestructive(pq) - - // pq.clear - // pq ++= (0 until 10) - // assert(pq.lastIndexWhere(_ == 9) == 0) - // assert(pq.lastIndexOf(8) == 1) - // assert(pq.lastIndexOf(7) == 2) - - // pq += 5 - // pq += 9 - // assert(pq.lastIndexOf(9) == 1) - // assert(pq.lastIndexWhere(_ % 2 == 1) == 10) - // assert(pq.lastIndexOf(5) == 6) - - // val lst = pq.reverseIterator.toList - // for (i <- 0 until 5) assert(lst(i) == i) - // assert(lst(5) == 5) - // assert(lst(6) == 5) - // assert(lst(7) == 6) - // assert(lst(8) == 7) - // assert(lst(9) == 8) - // assert(lst(10) == 9) - // assert(lst(11) == 9) - - // pq.clear - // assert(pq.reverseIterator.toList.isEmpty) - - // pq ++= (50 to 75) - // assert(pq.lastIndexOf(70) == 5) - - // pq += 55 - // pq += 70 - // assert(pq.lastIndexOf(70) == 6) - // assert(pq.lastIndexOf(55) == 22) - // assert(pq.lastIndexOf(55, 21) == 21) - // assert(pq.lastIndexWhere(_ > 54) == 22) - // assert(pq.lastIndexWhere(_ > 54, 21) == 21) - // assert(pq.lastIndexWhere(_ > 69, 5) == 5) - // } - - // def testReverse { - // val pq = new PriorityQueue[(Int, Int)] - // pq ++= (for (i <- 0 until 10) yield (i, i * i % 10)) - - // assert(pq.reverse.size == pq.reverseIterator.toList.size) - // assert((pq.reverse zip pq.reverseIterator.toList).forall(p => p._1 == p._2)) - // assert(pq.reverse.sameElements(pq.reverseIterator.toSeq)) - // assert(pq.reverse(0)._1 == pq(9)._1) - // assert(pq.reverse(1)._1 == pq(8)._1) - // assert(pq.reverse(4)._1 == pq(5)._1) - // assert(pq.reverse(9)._1 == pq(0)._1) - - // pq += ((7, 7)) - // pq += ((7, 9)) - // pq += ((7, 8)) - // assert(pq.reverse.reverse == pq) - // assert(pq.reverse.lastIndexWhere(_._2 == 6) == 6) - // assertPriorityDestructive(pq.reverse.reverse) - - // val iq = new PriorityQueue[Int] - // iq ++= (0 until 50) - // assert(iq.reverse == iq.reverseIterator.toSeq) - // assert(iq.reverse.reverse == iq) - - // iq += 25 - // iq += 40 - // iq += 10 - // assert(iq.reverse == iq.reverseIterator.toList) - // assert(iq.reverse.reverse == iq) - // assert(iq.reverse.lastIndexWhere(_ == 10) == 11) - // assertPriorityDestructive(iq.reverse.reverse) - // } - - // def testToList { - // val pq = new PriorityQueue[Int] - - // pq += 1 - // pq += 4 - // pq += 0 - // pq += 5 - // pq += 3 - // pq += 2 - // assert(pq.toList == pq) - // assert(pq == List(5, 4, 3, 2, 1, 0)) - // assert(pq.reverse == List(0, 1, 2, 3, 4, 5)) - - // pq.clear - // for (i <- -50 until 50) pq += i - // assert(pq.toList == pq) - // assert(pq.toList == (-50 until 50).reverse) - // } - - // def testForeach { - // val pq = new PriorityQueue[Char] - - // pq += 't' - // pq += 'o' - // pq += 'b' - // pq += 'y' - // val sbf = new StringBuilder - // val sbi = new StringBuilder - // pq.foreach(sbf += _) - // pq.iterator.foreach(sbi += _) - // assert(sbf.toString == sbi.toString) - // assert(sbf.toString == "ytob") - // } - -} - - - - - - - - - - - - - - - - - - diff --git a/test/files/run/t6440.check b/test/files/run/t6440.check index 2358f08fcc..4d8618182b 100644 --- a/test/files/run/t6440.check +++ b/test/files/run/t6440.check @@ -1,5 +1,4 @@ -pos: source-newSource1.scala,line-9,offset=109 missing or invalid dependency detected while loading class file 'U.class'. -Could not access term pack1 in package <root>, -because it (or its dependencies) are missing. Check your build definition for -missing or conflicting dependencies. (Re-run with `-Ylog-classpath` to see the problematic classpath.) -A full rebuild may help if 'U.class' was compiled against an incompatible version of <root>. ERROR +pos: source-newSource1.scala,line-9,offset=109 reference to U is ambiguous; +it is imported twice in the same scope by +import pack2._ +and import X._ ERROR diff --git a/test/files/run/t6440.scala b/test/files/run/t6440.scala index 5a3a4150d9..94eda3642e 100644 --- a/test/files/run/t6440.scala +++ b/test/files/run/t6440.scala @@ -41,7 +41,7 @@ object Test extends StoreReporterDirectTest { assert(tClass.delete()) assert(pack1.delete()) - // bad symbolic reference error expected (but no stack trace!) + // should report ambiguous import, despite the fact that a parent of pack2.U is absent compileCode(app) println(filteredInfos.mkString("\n")) } diff --git a/test/files/run/t6502.scala b/test/files/run/t6502.scala index ced1b5812d..4ce034a482 100644 --- a/test/files/run/t6502.scala +++ b/test/files/run/t6502.scala @@ -1,6 +1,7 @@ -import scala.tools.partest._ -import java.io.File +import scala.tools.nsc.Settings import scala.tools.nsc.interpreter.ILoop +import scala.tools.nsc.settings.ClassPathRepresentationType +import scala.tools.partest._ object Test extends StoreReporterDirectTest { def code = ??? @@ -10,6 +11,14 @@ object Test extends StoreReporterDirectTest { compileString(newCompiler("-cp", classpath, "-d", s"${testOutput.path}/$jarFileName"))(code) } + // TODO flat classpath doesn't support the classpath invalidation yet so we force using the recursive one + // it's the only test which needed such a workaround + override def settings = { + val settings = new Settings + settings.YclasspathImpl.value = ClassPathRepresentationType.Recursive + settings + } + def app1 = """ package test @@ -41,7 +50,8 @@ object Test extends StoreReporterDirectTest { val jar = "test1.jar" compileCode(app1, jar) - val output = ILoop.run(List(s":require ${testOutput.path}/$jar", "test.Test.test()")) + val codeToRun = toCodeInSeparateLines(s":require ${testOutput.path}/$jar", "test.Test.test()") + val output = ILoop.run(codeToRun, settings) val lines = output.split("\n") val res1 = lines(4).contains("Added") && lines(4).contains("test1.jar") val res2 = lines(lines.length-3).contains("testing...") @@ -56,7 +66,8 @@ object Test extends StoreReporterDirectTest { val jar2 = "test2.jar" compileCode(app2, jar2) - val output = ILoop.run(List(s":require ${testOutput.path}/$jar1", s":require ${testOutput.path}/$jar2")) + val codeToRun = toCodeInSeparateLines(s":require ${testOutput.path}/$jar1", s":require ${testOutput.path}/$jar2") + val output = ILoop.run(codeToRun, settings) val lines = output.split("\n") val res1 = lines(4).contains("Added") && lines(4).contains("test1.jar") val res2 = lines(lines.length-3).contains("test2.jar") && lines(lines.length-3).contains("existing classpath entries conflict") @@ -71,7 +82,8 @@ object Test extends StoreReporterDirectTest { val jar3 = "test3.jar" compileCode(app3, jar3) - val output = ILoop.run(List(s":require ${testOutput.path}/$jar1", s":require ${testOutput.path}/$jar3", "test.Test3.test()")) + val codeToRun = toCodeInSeparateLines(s":require ${testOutput.path}/$jar1", s":require ${testOutput.path}/$jar3", "test.Test3.test()") + val output = ILoop.run(codeToRun, settings) val lines = output.split("\n") val res1 = lines(4).contains("Added") && lines(4).contains("test1.jar") val res2 = lines(lines.length-3).contains("new object in existing package") @@ -83,7 +95,8 @@ object Test extends StoreReporterDirectTest { def test4(): Unit = { // twice the same jar should be rejected val jar1 = "test1.jar" - val output = ILoop.run(List(s":require ${testOutput.path}/$jar1", s":require ${testOutput.path}/$jar1")) + val codeToRun = toCodeInSeparateLines(s":require ${testOutput.path}/$jar1", s":require ${testOutput.path}/$jar1") + val output = ILoop.run(codeToRun, settings) val lines = output.split("\n") val res1 = lines(4).contains("Added") && lines(4).contains("test1.jar") val res2 = lines(lines.length-3).contains("test1.jar") && lines(lines.length-3).contains("existing classpath entries conflict") @@ -98,4 +111,6 @@ object Test extends StoreReporterDirectTest { test3() test4() } + + def toCodeInSeparateLines(lines: String*): String = lines.map(_ + "\n").mkString } diff --git a/test/files/run/t6669.scala b/test/files/run/t6669.scala index e18f2514a9..27c4970d60 100644 --- a/test/files/run/t6669.scala +++ b/test/files/run/t6669.scala @@ -1,4 +1,5 @@ import java.io.{ByteArrayOutputStream, PrintStream} +import scala.reflect.io.File object Test extends App { val baos = new ByteArrayOutputStream() @@ -9,9 +10,11 @@ object Test extends App { scala.tools.scalap.Main.main(Array("-verbose", "java.lang.Object")) } + val currentLocationCpFragment = File.pathSeparator + "." + // now make sure we saw the '.' in the classpath val msg1 = baos.toString() - assert(msg1 contains "directory classpath: .", s"Did not see '.' in the default class path. Full results were:\n$msg1") + assert(msg1 contains currentLocationCpFragment, s"Did not see '.' in the default class path. Full results were:\n$msg1") // then test again with a user specified classpath baos.reset @@ -22,5 +25,5 @@ object Test extends App { // now make sure we did not see the '.' in the classpath val msg2 = baos.toString() - assert(!(msg2 contains "directory classpath: ."), s"Did saw '.' in the user specified class path. Full results were:\n$msg2") + assert(!(msg2 contains currentLocationCpFragment), s"Did saw '.' in the user specified class path. Full results were:\n$msg2") } diff --git a/test/files/run/t8502.scala b/test/files/run/t8502.scala new file mode 100644 index 0000000000..903e573711 --- /dev/null +++ b/test/files/run/t8502.scala @@ -0,0 +1,41 @@ +import scala.tools.partest._ +import java.io.File + +object Test extends StoreReporterDirectTest { + def code = ??? + + def compileCode(code: String) = { + val classpath = List(sys.props("partest.lib"), testOutput.path) mkString sys.props("path.separator") + compileString(newCompiler("-cp", classpath, "-d", testOutput.path))(code) + } + + def show(): Unit = { + compileCode(""" + object U { + def foo(log: vanishing.Vanishing) = () + } + + package vanishing { + class Vanishing + } + """) + assert(filteredInfos.isEmpty, filteredInfos) + deletePackage("vanishing") + compileCode(""" + class Test { + U + } + """) + assert(storeReporter.infos.isEmpty, storeReporter.infos.mkString("\n")) // Included a MissingRequirementError before. + } + + def deletePackage(name: String) { + val directory = new File(testOutput.path, name) + for (f <- directory.listFiles()) { + assert(f.getName.endsWith(".class")) + assert(f.delete()) + } + assert(directory.listFiles().isEmpty) + assert(directory.delete()) + } +} diff --git a/test/files/run/t9003.flags b/test/files/run/t9003.flags new file mode 100644 index 0000000000..49d036a887 --- /dev/null +++ b/test/files/run/t9003.flags @@ -0,0 +1 @@ +-optimize diff --git a/test/files/run/t9003.scala b/test/files/run/t9003.scala new file mode 100644 index 0000000000..4f24712201 --- /dev/null +++ b/test/files/run/t9003.scala @@ -0,0 +1,71 @@ +object Single { + var i = 0 + def isEmpty = false + def get = i + def unapply(a: Single.type) = this +} + +object Product { + var i = 0 + def _1: Int = i + def _2: String = ??? + def productArity = 2 + def unapply(a: Product.type) = this + def isEmpty = false + def get: this.type = this +} + +object Sequence { + var i = 0 + def apply(n: Int): Int = i + def length = 2 + def unapplySeq(a: Sequence.type) = this + def isEmpty = false + def get = this +} + +object Test { + def main(args: Array[String]): Unit = { + def assertZero(i: Int) = assert(i == 0) + + Single match { + case Single(i) => + Single.i = 1 + assertZero(i) // fails under -optimize + } + + Product match { + case Product(i, _) => + Product.i = 1 + assertZero(i) // fails under -optimize + } + + Sequence match { + case Sequence(i, _ @ _*) => + Sequence.i = 1 + assertZero(i) // okay + } + + Sequence.i = 0 + Sequence match { + case Sequence(_, i) => + Sequence.i = 1 + assertZero(i) // okay + } + + val buffer = collection.mutable.Buffer(0, 0) + buffer match { + case Seq(_, i) => + buffer(1) = 1 + assertZero(i) // failed + } + + case class CaseSequence(as: Int*) + val buffer1 = collection.mutable.Buffer(0, 0) + CaseSequence(buffer1: _*) match { + case CaseSequence(_, i) => + buffer1(1) = 1 + assertZero(i) // failed + } + } +} diff --git a/test/files/run/t9027.check b/test/files/run/t9027.check new file mode 100644 index 0000000000..3429254286 --- /dev/null +++ b/test/files/run/t9027.check @@ -0,0 +1,19 @@ +{ + { + val $buf = new _root_.scala.xml.NodeBuffer(); + $buf.$amp$plus(new _root_.scala.xml.Elem(null, "a", _root_.scala.xml.Null, $scope, true)); + $buf.$amp$plus(new _root_.scala.xml.Elem(null, "b", _root_.scala.xml.Null, $scope, true)); + $buf + }; + println("hello, world.") +} +{ + { + val $buf = new _root_.scala.xml.NodeBuffer(); + $buf.$amp$plus(new _root_.scala.xml.Elem(null, "a", _root_.scala.xml.Null, $scope, true)); + $buf.$amp$plus(new _root_.scala.xml.Elem(null, "b", _root_.scala.xml.Null, $scope, true)); + $buf.$amp$plus(new _root_.scala.xml.Elem(null, "c", _root_.scala.xml.Null, $scope, true)); + $buf + }; + println("hello, world.") +} diff --git a/test/files/run/t9027.scala b/test/files/run/t9027.scala new file mode 100644 index 0000000000..26238147da --- /dev/null +++ b/test/files/run/t9027.scala @@ -0,0 +1,15 @@ + +// used to be parsed as .println +object Test extends App { + import reflect.runtime._, universe._ + + val trees = List( + q"""<a/><b/> + println("hello, world.")""", + q"""<a/> + <b/> + <c/> + println("hello, world.")""" + ) + trees foreach println +} diff --git a/test/files/run/various-flat-classpath-types.check b/test/files/run/various-flat-classpath-types.check new file mode 100644 index 0000000000..401f707d0e --- /dev/null +++ b/test/files/run/various-flat-classpath-types.check @@ -0,0 +1,12 @@ +ZipBin() +JarBin() +DirBin() +ZipSrc() +JarSrc() +DirSrc() +NestedZipBin() +NestedJarBin() +NestedDirBin() +NestedZipSrc() +NestedJarSrc() +NestedDirSrc()
\ No newline at end of file diff --git a/test/files/run/various-flat-classpath-types.scala b/test/files/run/various-flat-classpath-types.scala new file mode 100644 index 0000000000..d39019e885 --- /dev/null +++ b/test/files/run/various-flat-classpath-types.scala @@ -0,0 +1,214 @@ +/* + * Copyright (c) 2014 Contributor. All rights reserved. + */ + +import java.io.{File => JFile, FileInputStream, FileOutputStream} +import java.util.zip.{ZipEntry, ZipOutputStream} +import scala.reflect.io.{Directory, File} +import scala.tools.nsc.classpath.FlatClassPath.RootPackage +import scala.tools.nsc.classpath.PackageNameUtils +import scala.tools.nsc.io.Jar + +/** + * Generates directories, jars and zip files containing sources and classes + * (the result of a compilation which is executed here) + * and use them as a class- and sourcepath during compilation and running + * created application. At the end everything is cleaned up. + * + * It can test also current, recursive classpath. Just right now we force + * flat classpath to test it also when the recursive one would be set as a default. + */ +object Test { + + private implicit class JFileOps(file: JFile) { + + def createDir(newDirName: String) = { + val newDir = new JFile(file, newDirName) + newDir.mkdir() + newDir + } + + def createSrcFile(newFileName: String) = createFile(newFileName + ".scala") + + def createFile(fullFileName: String) = { + val newFile = new JFile(file, fullFileName) + newFile.createNewFile() + newFile + } + + def writeAll(text: String): Unit = File(file) writeAll text + + def moveContentToZip(zipName: String): Unit = { + val newZip = zipsDir createFile s"$zipName.zip" + val outputStream = new ZipOutputStream(new FileOutputStream(newZip)) + + def addFileToZip(dirPrefix: String = "")(fileToAdd: JFile): Unit = + if (fileToAdd.isDirectory) { + val dirEntryName = fileToAdd.getName + "/" + outputStream.putNextEntry(new ZipEntry(dirEntryName)) + fileToAdd.listFiles() foreach addFileToZip(dirEntryName) + } else { + val inputStream = new FileInputStream(fileToAdd) + outputStream.putNextEntry(new ZipEntry(dirPrefix + fileToAdd.getName)) + + val buffer = new Array[Byte](1024) + var count = inputStream.read(buffer) + while (count > 0) { + outputStream.write(buffer, 0, count) + count = inputStream.read(buffer) + } + + inputStream.close() + } + + file.listFiles() foreach addFileToZip() + outputStream.close() + + cleanDir(file) + } + + def moveContentToJar(jarName: String): Unit = { + val newJar = jarsDir createFile s"$jarName.jar" + Jar.create(file = File(newJar), sourceDir = Directory(file), mainClass = "won't be used") + cleanDir(file) + } + + def path: String = file.getAbsolutePath + } + + private case class DirRep(name: String, nestedDirs: Seq[DirRep] = Nil, sourceFiles: Seq[String] = Nil) + + private val compiler = new scala.tools.nsc.MainClass + private val appRunner = new scala.tools.nsc.MainGenericRunner + private val classPathImplFlag = "-YclasspathImpl:flat" + private val javaClassPath = sys.props("java.class.path") + + // creates a test dir in a temporary dir containing compiled files of this test + // root dir will be automatically deleted after the end of test + private val rootDir = new JFile(sys.props("partest.output")) + private val testDir = rootDir createDir s"cp-tests-${System.currentTimeMillis()}" + + private val jarsDir = testDir createDir "jars" + private val zipsDir = testDir createDir "zips" + private val srcDir = testDir createDir "src" + private val binDir = testDir createDir "bin" + private val outDir = testDir createDir "out" + + def main(args: Array[String]): Unit = { + createClassesZipInZipsDir() + createClassesJarInJarsDir() + createClassesInBinDir() + createSourcesZipInZipsDir() + createSourcesJarInJarsDir() + createSourcesInSrcDir() + compileFinalApp() + runApp() + // at the end all created files will be deleted automatically + } + + private def createClassesZipInZipsDir(): Unit = { + val baseFileName = "ZipBin" + createStandardSrcHierarchy(baseFileName) + compileSrc(baseFileName) + outDir moveContentToZip "Bin" + cleanDir(srcDir) + } + + private def createClassesJarInJarsDir(): Unit = { + val baseFileName = "JarBin" + createStandardSrcHierarchy(baseFileName) + compileSrc(baseFileName) + outDir moveContentToJar "Bin" + cleanDir(srcDir) + } + + private def createClassesInBinDir(): Unit = { + val baseFileName = "DirBin" + createStandardSrcHierarchy(baseFileName) + compileSrc(baseFileName, destination = binDir) + cleanDir(srcDir) + } + + private def createSourcesZipInZipsDir(): Unit = { + createStandardSrcHierarchy(baseFileName = "ZipSrc") + srcDir moveContentToZip "Src" + } + + private def createSourcesJarInJarsDir(): Unit = { + createStandardSrcHierarchy(baseFileName = "JarSrc") + srcDir moveContentToJar "Src" + } + + private def createSourcesInSrcDir(): Unit = { + createStandardSrcHierarchy(baseFileName = "DirSrc") + + val appFile = srcDir createSrcFile "Main" + appFile writeAll s"""import nested._ + | object Main extends App { + | println(new ZipBin) + | println(new JarBin) + | println(new DirBin) + | println(new ZipSrc) + | println(new JarSrc) + | println(new DirSrc) + | + | println(new NestedZipBin) + | println(new NestedJarBin) + | println(new NestedDirBin) + | println(new NestedZipSrc) + | println(new NestedJarSrc) + | println(new NestedDirSrc) + | } + """.stripMargin + } + + private def compileFinalApp(): Unit = { + val classPath = mkPath(javaClassPath, binDir.path, zipsDir.path + "/Bin.zip", jarsDir.path + "/Bin.jar") + val sourcePath = mkPath(srcDir.path, zipsDir.path + "/Src.zip", jarsDir.path + "/Src.jar") + + compiler.process(Array(classPathImplFlag, "-cp", classPath, "-sourcepath", sourcePath, + "-d", outDir.path, s"${srcDir.path}/Main.scala")) + } + + private def runApp(): Unit = { + val classPath = mkPath(javaClassPath, outDir.path, binDir.path, zipsDir.path + "/Bin.zip", jarsDir.path + "/Bin.jar") + appRunner.process(Array(classPathImplFlag, "-cp", classPath, "Main")) + } + + private def createStandardSrcHierarchy(baseFileName: String): Unit = + createSources(RootPackage, srcDir, + DirRep("", + nestedDirs = Seq(DirRep("nested", sourceFiles = Seq("Nested" + baseFileName))), + sourceFiles = Seq(baseFileName) + ) + ) + + private def createSources(pkg: String, dirFile: JFile, dirRep: DirRep): Unit = { + dirRep.nestedDirs foreach { rep => + val nestedDir = dirFile createDir rep.name + val nestedPkg = PackageNameUtils.packagePrefix(pkg) + rep.name + createSources(nestedPkg, nestedDir, rep) + } + + val pkgHeader = if (pkg == RootPackage) "" else s"package $pkg\n\n" + dirRep.sourceFiles foreach { srcName => + val text = s"""${pkgHeader}case class $srcName(x: String = "")""" + val srcFile = dirFile createSrcFile srcName + srcFile writeAll text + } + } + + private def compileSrc(baseFileName: String, destination: JFile = outDir): Unit = { + val srcDirPath = srcDir.path + compiler.process(Array(classPathImplFlag, "-cp", javaClassPath, "-d", destination.path, + s"$srcDirPath/$baseFileName.scala", s"$srcDirPath/nested/Nested$baseFileName.scala")) + } + + private def cleanDir(dir: JFile): Unit = + dir.listFiles().foreach { file => + if (file.isDirectory) cleanDir(file) + file.delete() + } + + private def mkPath(pathEntries: String*) = pathEntries.mkString(File.pathSeparator) +} diff --git a/test/junit/scala/collection/immutable/ListTest.scala b/test/junit/scala/collection/immutable/ListTest.scala new file mode 100644 index 0000000000..1006801029 --- /dev/null +++ b/test/junit/scala/collection/immutable/ListTest.scala @@ -0,0 +1,49 @@ +package scala.collection.immutable + +import org.junit.{Assert, Test} +import org.junit.runner.RunWith +import org.junit.runners.JUnit4 + +import scala.ref.WeakReference + +@RunWith(classOf[JUnit4]) +class ListTest { + /** + * Test that empty iterator does not hold reference + * to complete List + */ + @Test + def testIteratorGC(): Unit = { + var num = 0 + var emptyIterators = Seq.empty[(Iterator[Int], WeakReference[List[Int]])] + + do { + val list = List.fill(10000)(num) + val ref = WeakReference(list) + + val i = list.iterator + + while (i.hasNext) i.next() + + emptyIterators = (i, ref) +: emptyIterators + + num+=1 + } while (emptyIterators.forall(_._2.get.isDefined) && num<1000) + + // check something is result to protect from JIT optimizations + for ((i, _) <- emptyIterators) { + Assert.assertTrue(i.isEmpty) + } + + // await gc up to ~5 seconds + var forceLoops = 50 + while (emptyIterators.forall(_._2.get.isDefined) && forceLoops>0) { + System.gc() + Thread.sleep(100) + forceLoops -= 1 + } + + // real assertion + Assert.assertTrue(emptyIterators.exists(_._2.get.isEmpty)) + } +} diff --git a/test/junit/scala/collection/immutable/PagedSeqTest.scala b/test/junit/scala/collection/immutable/PagedSeqTest.scala index 5f83cf6f31..2b576a3655 100644 --- a/test/junit/scala/collection/immutable/PagedSeqTest.scala +++ b/test/junit/scala/collection/immutable/PagedSeqTest.scala @@ -5,12 +5,24 @@ import org.junit.runners.JUnit4 import org.junit.Test import org.junit.Assert._ -/* Test for SI-6615 */ @RunWith(classOf[JUnit4]) class PagedSeqTest { + // should not NPE, and should equal the given Seq @Test - def rovingDoesNotNPE(): Unit = { - // should not NPE, and should equal the given Seq + def test_SI6615(): Unit = { assertEquals(Seq('a'), PagedSeq.fromStrings(List.fill(5000)("a")).slice(4096, 4097)) } + + // Slices shouldn't read outside where they belong + @Test + def test_SI6519 { + var readAttempt = 0 + val sideEffectingIterator = new Iterator[Int] { + def hasNext = readAttempt < 65536 + def next = { readAttempt += 1; readAttempt } + } + val s = PagedSeq.fromIterator(sideEffectingIterator).slice(0,2).mkString + assertEquals(s, "12") + assert(readAttempt <= 4096) + } } diff --git a/test/junit/scala/math/BigDecimalTest.scala b/test/junit/scala/math/BigDecimalTest.scala index d1ba96fcc8..c7a63da890 100644 --- a/test/junit/scala/math/BigDecimalTest.scala +++ b/test/junit/scala/math/BigDecimalTest.scala @@ -222,4 +222,10 @@ class BigDecimalTest { for (a <- different; b <- different if (a ne b)) assert(a != b, "BigDecimal representations of Double mistakenly conflated") } + + // Make sure hash code agrees with decimal representation of Double + @Test + def test_SI8970() { + assert((0.1).## == BigDecimal(0.1).##) + } } 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 + } +} diff --git a/test/script-tests/README b/test/script-tests/README index 3f5c2ce19c..7b3291c407 100755 --- a/test/script-tests/README +++ b/test/script-tests/README @@ -5,4 +5,9 @@ putting self-contained script tests in here to run some way that doesn't depend on all the platform stars aligning all the time. Feel free to join me. --- extempore, Nov 21 2011
\ No newline at end of file +-- extempore, Nov 21 2011 + +But there's a problem that probably nobody would run such tests so they would become outdated quite quickly. +And therefore they wouldn't work (and even compile) after some time - like this one existing currently. + +-- mpociecha, Oct 9 2014
\ No newline at end of file |