mirror of https://github.com/sbt/sbt.git
drop compilation tests
1. overlapped with integration tests 2. slower than integration tests 3. more fragile than integration tests
This commit is contained in:
parent
e2b5ce374c
commit
3f12f2eb9f
|
|
@ -1,142 +0,0 @@
|
||||||
package xsbt.api
|
|
||||||
|
|
||||||
import java.io.File
|
|
||||||
import java.net.URLClassLoader
|
|
||||||
import org.specs.Specification
|
|
||||||
import sbt.WithFiles
|
|
||||||
import sbt.compiler.{CallbackTest,TestCompile}
|
|
||||||
|
|
||||||
/** Verifies that the analyzer plugin properly detects main methods. The main method must be
|
|
||||||
* public with the right signature and be defined on a public, top-level module.*/
|
|
||||||
object ApplicationsTest extends Specification
|
|
||||||
{
|
|
||||||
val sourceContent =
|
|
||||||
"""
|
|
||||||
object Main { def main(args: Array[String]) {} }
|
|
||||||
""" :: """
|
|
||||||
class Main2 { def main(args: Array[String]) {} }
|
|
||||||
""" :: """
|
|
||||||
object Main3 { private def main(args: Array[String]) {} }
|
|
||||||
private object Main3b extends Main2
|
|
||||||
object Main3c { private def main(args: Array[String]) {} }
|
|
||||||
protected object Main3d { def main(args: Array[String]) {} }
|
|
||||||
object Main3e {
|
|
||||||
protected def main(args: Array[String]) {}
|
|
||||||
}
|
|
||||||
package a {
|
|
||||||
object Main3f { private[a] def main(args: Array[String]) {} }
|
|
||||||
object Main3g { protected[a] def main(args: Array[String]) {} }
|
|
||||||
}
|
|
||||||
""" ::"""
|
|
||||||
object Main4 extends Main2
|
|
||||||
""" :: """
|
|
||||||
trait Main5 { def main(args: Array[String]) {} }; trait Main5b extends Main5; trait Main5c extends Main2; abstract class Main5d { def main(args: Array[String]) {} };
|
|
||||||
trait Main5e[T] { def main(args: Array[T]) {} }
|
|
||||||
trait Main5f[T <: String] { def main(args: Array[T]) {} }
|
|
||||||
""" :: """
|
|
||||||
object Main6a { var main = () }
|
|
||||||
object Main6b { var main = (args: Array[String]) => () }
|
|
||||||
""" :: """
|
|
||||||
object Main7 { object Main7b extends Main2 }
|
|
||||||
""" :: """
|
|
||||||
object Main8 extends Main2 { object Main7b extends Main2 }
|
|
||||||
""" :: """
|
|
||||||
object Main9 {
|
|
||||||
def main() {}
|
|
||||||
def main(i: Int) {}
|
|
||||||
def main(args: Array[String]) {}
|
|
||||||
}
|
|
||||||
""" :: """
|
|
||||||
object MainA {
|
|
||||||
def main() {}
|
|
||||||
def main(i: Int) {}
|
|
||||||
def main(args: Array[String], other: String) {}
|
|
||||||
def main(i: Array[Int]) {}
|
|
||||||
}
|
|
||||||
object MainA2 {
|
|
||||||
def main[T](args: Array[T]) {}
|
|
||||||
}
|
|
||||||
""" :: """
|
|
||||||
object MainB extends Main2 {
|
|
||||||
def main() {}
|
|
||||||
def main(i: Int) {}
|
|
||||||
}
|
|
||||||
""" :: """
|
|
||||||
object MainC1 {
|
|
||||||
def main(args: Array[String]) = 3
|
|
||||||
}
|
|
||||||
object MainC2 {
|
|
||||||
def main1(args: Array[String]) {}
|
|
||||||
}
|
|
||||||
""" :: """
|
|
||||||
object MainD1 {
|
|
||||||
val main = ()
|
|
||||||
}
|
|
||||||
object MainD2 {
|
|
||||||
val main = (args: Array[String]) => ()
|
|
||||||
}
|
|
||||||
""" :: """
|
|
||||||
object MainE1 {
|
|
||||||
type T = String
|
|
||||||
def main(args: Array[T]) {}
|
|
||||||
}
|
|
||||||
object MainE2 {
|
|
||||||
type AT = Array[String]
|
|
||||||
def main(args: AT) {}
|
|
||||||
}
|
|
||||||
object MainE3 {
|
|
||||||
type U = Unit
|
|
||||||
type T = String
|
|
||||||
def main(args: Array[T]): U = ()
|
|
||||||
}
|
|
||||||
object MainE4 {
|
|
||||||
def main[T](args: Array[String]) {}
|
|
||||||
}
|
|
||||||
object MainE5 {
|
|
||||||
type A[T] = Array[String]
|
|
||||||
def main[T](args: A[T]) {}
|
|
||||||
}
|
|
||||||
object MainE6 extends Main5e[String]
|
|
||||||
object MainE7 extends Main5e[Int]
|
|
||||||
object MainE8 extends Main5f[String]
|
|
||||||
""" :: """
|
|
||||||
object MainF1 extends Application { var x = 3; x = 5 }
|
|
||||||
object MainF2 { def main(args: Array[java.lang.String]) {} }
|
|
||||||
trait MainF3 { def main(args: Array[String]) {} }
|
|
||||||
object MainF4 extends MainF3 { }
|
|
||||||
""" ::
|
|
||||||
Nil
|
|
||||||
val sources = for((source, index) <- sourceContent.zipWithIndex) yield new File("Main" + (index+1) + ".scala") -> source
|
|
||||||
|
|
||||||
"Analysis plugin should detect applications" in {
|
|
||||||
WithFiles(sources : _*) { case files @ Seq(main, main2, main3, main4, main5, main6, main7, main8, main9, mainA, mainB, mainC, mainD, mainE, mainF) =>
|
|
||||||
for(scalaVersion <- TestCompile.allVersions)
|
|
||||||
CallbackTest.full(scalaVersion, files) { (callback, file, scalaInstance, log) =>
|
|
||||||
val expected = Set( main -> "Main", main4 -> "Main4", main8 -> "Main8", main9 -> "Main9", mainB -> "MainB",
|
|
||||||
mainE -> "MainE1", mainE -> "MainE2", mainE -> "MainE3", mainE -> "MainE4", mainE -> "MainE5", mainE -> "MainE6", mainE -> "MainE8",
|
|
||||||
mainF -> "MainF1", mainF -> "MainF2", mainF -> "MainF4")
|
|
||||||
// the source signature is valid for the following, but the binary signature is not, so they can't actually be run.
|
|
||||||
// these are then known discrepancies between detected and actual entry points
|
|
||||||
val erased = Set( mainE -> "MainE6", mainE -> "MainE8" )
|
|
||||||
val actual = applications(callback).toSet
|
|
||||||
(actual -- expected) must beEmpty
|
|
||||||
(expected -- actual) must beEmpty
|
|
||||||
val loader = new URLClassLoader(Array(file.toURI.toURL), scalaInstance.loader)
|
|
||||||
for( (_, className) <- expected filterNot erased) testRun(loader, className)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
def applications(callback: xsbti.TestCallback): Seq[(File, String)] =
|
|
||||||
for( (file, api) <- CallbackTest.apis(callback);
|
|
||||||
x = println("\n" + file + ":\n" + (api.definitions.flatMap { case c: xsbti.api.ClassLike => c.structure.inherited.filter(_.name == "main"); case _ => Nil }).map(xsbt.api.DefaultShowAPI.apply).mkString("\n"));
|
|
||||||
application <- applications(api))
|
|
||||||
yield (file, application)
|
|
||||||
def applications(src: xsbti.api.SourceAPI): Seq[String] =
|
|
||||||
Discovery.applications(src.definitions) collect { case (definition, Discovered(_, _, true, _)) => definition.name }
|
|
||||||
|
|
||||||
private def testRun(loader: ClassLoader, className: String)
|
|
||||||
{
|
|
||||||
val obj = Class.forName(className, true, loader)
|
|
||||||
obj.getMethod("main", classOf[Array[String]]).invoke(null, new Array[String](0))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,68 +0,0 @@
|
||||||
package sbt
|
|
||||||
package compiler
|
|
||||||
|
|
||||||
import java.io.File
|
|
||||||
import org.specs.Specification
|
|
||||||
|
|
||||||
object CheckBasicAPI extends Specification
|
|
||||||
{
|
|
||||||
val basicName = new File("Basic.scala")
|
|
||||||
val basicSource =
|
|
||||||
"""
|
|
||||||
package org.example {
|
|
||||||
trait Parent[A] { def x: A }
|
|
||||||
abstract class Child extends Parent[String]
|
|
||||||
class S {
|
|
||||||
def x = new { def y = new S { def z = new Child { def x = "asdf" } } }
|
|
||||||
final val xconst = 3
|
|
||||||
private[this] def zz: Seq[_] = Nil
|
|
||||||
type L[M[_], P >: Int <: Int] = M[P]
|
|
||||||
type Q = L[Option, Int]
|
|
||||||
}
|
|
||||||
object Basic
|
|
||||||
trait Out {
|
|
||||||
trait In
|
|
||||||
def t: In
|
|
||||||
}
|
|
||||||
}
|
|
||||||
package org.example3 {
|
|
||||||
trait A extends Iterator[Int]
|
|
||||||
}
|
|
||||||
package org.example2 {
|
|
||||||
trait ZZ[S] {
|
|
||||||
val p: S
|
|
||||||
val q: ZZZ[S] { val what: S }
|
|
||||||
class A extends ZZZ[S] {
|
|
||||||
val p = error("")
|
|
||||||
val q = error("")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
trait ZZZ[T] extends ZZ[List[T]]
|
|
||||||
trait ZZZZ extends ZZZ[Int]
|
|
||||||
trait Z extends ZZZZ
|
|
||||||
trait P[S] {
|
|
||||||
trait Q
|
|
||||||
def x(s: S): S
|
|
||||||
def q(v: Q): Q
|
|
||||||
val u: Q
|
|
||||||
val p: S
|
|
||||||
}
|
|
||||||
trait Out { self: P[String] =>
|
|
||||||
trait In
|
|
||||||
def z = p
|
|
||||||
def t(i: In): In
|
|
||||||
def y(q: Q): Q
|
|
||||||
}
|
|
||||||
}
|
|
||||||
"""
|
|
||||||
|
|
||||||
"Compiling should succeed" in {
|
|
||||||
WithFiles(basicName -> basicSource){ files =>
|
|
||||||
for(scalaVersion <- TestCompile.allVersions)
|
|
||||||
{
|
|
||||||
TestCompile(scalaVersion, files){ loader => Class.forName("org.example.Basic", false, loader) }
|
|
||||||
true must beTrue // don't know how to just check that previous line completes without exception
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,43 +0,0 @@
|
||||||
package sbt
|
|
||||||
package compiler
|
|
||||||
|
|
||||||
import java.io.File
|
|
||||||
import org.specs.Specification
|
|
||||||
|
|
||||||
object CheckBasic extends Specification
|
|
||||||
{
|
|
||||||
val basicName = new File("Basic.scala")
|
|
||||||
val basicSource = "package org.example { /** A comment */ object Basic }"
|
|
||||||
|
|
||||||
"Compiling basic file should succeed" in {
|
|
||||||
WithFiles(basicName -> basicSource){ files =>
|
|
||||||
for(scalaVersion <- TestCompile.allVersions)
|
|
||||||
{
|
|
||||||
TestCompile(scalaVersion, files){ loader => Class.forName("org.example.Basic", false, loader) }
|
|
||||||
true must beTrue // don't know how to just check that previous line completes without exception
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
"Scaladoc on basic file should succeed" in {
|
|
||||||
WithFiles(basicName -> basicSource){ files =>
|
|
||||||
for(scalaVersion <- TestCompile.allVersions)
|
|
||||||
{
|
|
||||||
IO.withTemporaryDirectory { outputDirectory =>
|
|
||||||
WithCompiler(scalaVersion) { (compiler, log) =>
|
|
||||||
compiler.doc(files.toSeq, Nil, outputDirectory, Nil, 5, log)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
true must beTrue // don't know how to just check that previous line completes without exception
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
"Analyzer plugin should send source begin and end" in {
|
|
||||||
WithFiles(basicName -> basicSource) { files =>
|
|
||||||
for(scalaVersion <- TestCompile.allVersions)
|
|
||||||
CallbackTest.simple(scalaVersion, files) { callback =>
|
|
||||||
(callback.beganSources) must haveTheSameElementsAs(files)
|
|
||||||
(callback.endedSources) must haveTheSameElementsAs(files)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,97 +0,0 @@
|
||||||
package sbt
|
|
||||||
package compiler
|
|
||||||
|
|
||||||
import java.io.File
|
|
||||||
import IO.withTemporaryDirectory
|
|
||||||
import org.specs._
|
|
||||||
|
|
||||||
object CompileTest extends Specification
|
|
||||||
{
|
|
||||||
"Analysis compiler" should {
|
|
||||||
"compile basic sources" in {
|
|
||||||
WithCompiler( "2.9.1" )(testCompileAnalysis)
|
|
||||||
WithCompiler( "2.9.0-1" )(testCompileAnalysis)
|
|
||||||
WithCompiler( "2.8.0" )(testCompileAnalysis)
|
|
||||||
WithCompiler( "2.8.1" )(testCompileAnalysis)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
"Raw compiler" should {
|
|
||||||
"Properly handle classpaths" in {
|
|
||||||
testClasspath("2.9.1")
|
|
||||||
testClasspath("2.9.0-1")
|
|
||||||
testClasspath("2.8.1")
|
|
||||||
testClasspath("2.8.0")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private def testCompileAnalysis(compiler: AnalyzingCompiler, log: Logger)
|
|
||||||
{
|
|
||||||
WithFiles( new File("Test.scala") -> "object Test" ) { sources =>
|
|
||||||
withTemporaryDirectory { temp =>
|
|
||||||
val callback = new xsbti.TestCallback
|
|
||||||
compiler(sources, noChanges, Nil, temp, Nil, callback, 10, CompilerCache.fresh, log)
|
|
||||||
(callback.beganSources) must haveTheSameElementsAs(sources)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
val noChanges = new xsbti.compile.DependencyChanges {
|
|
||||||
def isEmpty = true
|
|
||||||
def modifiedBinaries = Array()
|
|
||||||
def modifiedClasses = Array()
|
|
||||||
}
|
|
||||||
|
|
||||||
val UsingCompiler = "object Test { classOf[scala.tools.nsc.Global] }"
|
|
||||||
|
|
||||||
private def shouldFail(act: => Unit) =
|
|
||||||
{
|
|
||||||
val success = try { act; true } catch { case t if expectedException(t) => false }
|
|
||||||
if(success) error("Expected exception not thrown")
|
|
||||||
}
|
|
||||||
private def expectedException(t: Throwable) =
|
|
||||||
t match
|
|
||||||
{
|
|
||||||
case e: Exception => true
|
|
||||||
case t if isMissingRequirementError(t) => true
|
|
||||||
case _ => false
|
|
||||||
}
|
|
||||||
private def shouldSucceed(act: => Unit) =
|
|
||||||
try { act } catch { case c: xsbti.CompileFailed => error(c.toString) }
|
|
||||||
|
|
||||||
private def isMissingRequirementError(t: Throwable) = t.getClass.getName == "scala.tools.nsc.MissingRequirementError"
|
|
||||||
private def testClasspath(scalaVersion: String) =
|
|
||||||
WithCompiler.launcher { (launch, log) =>
|
|
||||||
def compiler(bootLibrary: Boolean, compilerOnClasspath: Boolean): RawCompiler =
|
|
||||||
new RawCompiler(ScalaInstance(scalaVersion, launch), new ClasspathOptions(bootLibrary, compilerOnClasspath, true, true, bootLibrary), log)
|
|
||||||
|
|
||||||
val callback = new xsbti.TestCallback
|
|
||||||
|
|
||||||
val standard = compiler(true, true)
|
|
||||||
val noCompiler = compiler(true, false)
|
|
||||||
val fullExplicit = compiler(false, false)
|
|
||||||
|
|
||||||
val fullBoot = "-bootclasspath" :: fullExplicit.compilerArguments.createBootClasspath(true) :: Nil
|
|
||||||
val withCompiler = noCompiler.scalaInstance.compilerJar :: Nil
|
|
||||||
val withLibrary = noCompiler.scalaInstance.libraryJar :: Nil
|
|
||||||
val withLibraryCompiler = withLibrary ++ withCompiler
|
|
||||||
|
|
||||||
WithFiles( new File("Test.scala") -> "object Test", new File("Test2.scala") -> UsingCompiler ) { case Seq(plain, useCompiler) =>
|
|
||||||
val plainSrcs = Seq[File](plain)
|
|
||||||
val compSrcs = Seq[File](useCompiler)
|
|
||||||
withTemporaryDirectory { out =>
|
|
||||||
shouldSucceed( standard(plainSrcs, Nil, out, Nil) )
|
|
||||||
shouldSucceed( standard(compSrcs, Nil, out, Nil) )
|
|
||||||
|
|
||||||
shouldSucceed( noCompiler(plainSrcs, Nil, out, Nil) )
|
|
||||||
shouldFail( noCompiler(compSrcs, Nil, out, Nil) )
|
|
||||||
shouldSucceed( noCompiler(compSrcs, withCompiler, out, Nil) )
|
|
||||||
|
|
||||||
shouldFail( fullExplicit(plainSrcs, Nil, out, Nil) )
|
|
||||||
shouldFail( fullExplicit(compSrcs, Nil, out, Nil) )
|
|
||||||
shouldSucceed( fullExplicit(plainSrcs, withLibrary, out, fullBoot) )
|
|
||||||
shouldSucceed( fullExplicit(compSrcs, withLibraryCompiler, out, fullBoot) )
|
|
||||||
true must beTrue
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,61 +0,0 @@
|
||||||
package xsbt.api
|
|
||||||
|
|
||||||
import sbt.WithFiles
|
|
||||||
import sbt.compiler.{CallbackTest,TestCompile}
|
|
||||||
import java.io.File
|
|
||||||
import org.specs.Specification
|
|
||||||
|
|
||||||
object DetectAnnotations extends Specification
|
|
||||||
{
|
|
||||||
val sources =
|
|
||||||
("c/A.scala" -> "package c; class A(x: Int, y: Int) extends Annotation") ::
|
|
||||||
("B.scala" -> "class B extends Annotation") ::
|
|
||||||
("d/C.scala" -> "package d; class C extends Annotation") ::
|
|
||||||
("a/Super1.scala" -> "package a; trait Super1") ::
|
|
||||||
("a/Super2.scala" -> "package a; @c.A(3,4) trait Super2") ::
|
|
||||||
("Super3.scala" -> "@B class Super3") ::
|
|
||||||
("a/Super4.scala" -> "package a; trait Super4 { @d.C def test = () }") ::
|
|
||||||
("b/Middle.scala" -> "package y.w; trait Mid extends a.Super2") ::
|
|
||||||
("b/Sub1.scala" -> "class Sub1 extends Super3 with y.w.Mid") ::
|
|
||||||
("b/Sub2.scala" -> "final class Sub2 extends a.Super1") ::
|
|
||||||
("b/Sub3.scala" -> "@B @c.A(3,4) final class Sub3 extends a.Super1") ::
|
|
||||||
("d/Sub4.scala" -> "@B private class Sub4 extends a.Super1") ::
|
|
||||||
("d/Sub5.scala" -> "@B protected class Sub5 extends a.Super1") ::
|
|
||||||
("d/Sub6.scala" -> "@B abstract class Sub6 extends a.Super1") ::
|
|
||||||
("d/Sub7.scala" -> "class Sub7 extends a.Super4") ::
|
|
||||||
("d/Sub8.scala" -> "class Sub8 { @c.A(5,6) def test(s: Int) = s }") ::
|
|
||||||
("d/Sub9.scala" -> "object Sub9 { @B def test(s: String) = s }") ::
|
|
||||||
("d/SubA.scala" -> "object SubA { @c.A(3,3) def test = () }\nclass SubA { @B private def test = 6 }") ::
|
|
||||||
("d/SubB.scala" -> "object SubB { @c.A(3,3) def test = 3 }\nclass SubB { @d.C def test = () }") ::
|
|
||||||
Nil
|
|
||||||
|
|
||||||
"Analysis plugin should detect annotations" in {
|
|
||||||
WithFiles(sources.map{case (file, content) => (new File(file), content)} : _*)
|
|
||||||
{
|
|
||||||
case files @ Seq(a, b, c, sup1File, sup2File, sup3File, sup4File, midFile, sub1File, sub2File, sub3File, sub4File, sub5File, sub6File, sub7File, sub8File, sub9File, subAFile, subBFile) =>
|
|
||||||
for(scalaVersion <- TestCompile.allVersions)
|
|
||||||
CallbackTest.simple(scalaVersion, files) { callback =>
|
|
||||||
val expected =
|
|
||||||
(sup3File, "Super3", Set("B"), false) ::
|
|
||||||
(sub3File, "Sub3", Set("B", "c.A"), false) ::
|
|
||||||
(sub7File, "Sub7", Set("d.C"), false) ::
|
|
||||||
(sub8File, "Sub8", Set("c.A"), false) ::
|
|
||||||
(sub9File, "Sub9", Set("B"), true) ::
|
|
||||||
(subAFile, "SubA", Set("c.A"), true) ::
|
|
||||||
(subBFile, "SubB", Set("c.A"), true) ::
|
|
||||||
(subBFile, "SubB", Set("d.C"), false) ::
|
|
||||||
Nil
|
|
||||||
val actual = subclasses(callback).toSet
|
|
||||||
val actualOnly = (actual -- expected)
|
|
||||||
val expectedOnly = (expected.toSet -- actual)
|
|
||||||
expectedOnly must beEmpty
|
|
||||||
actualOnly must beEmpty
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
def subclasses(callback: xsbti.TestCallback): Seq[(File, String, Set[String], Boolean)] =
|
|
||||||
for( (file, src) <- CallbackTest.apis(callback); (definition, discovered) <- Discovery(Set.empty, annotationNames)(src.definitions) if !discovered.isEmpty ) yield
|
|
||||||
(file, definition.name, discovered.annotations, discovered.isModule)
|
|
||||||
|
|
||||||
def annotationNames = Set("c.A", "B", "d.C")
|
|
||||||
}
|
|
||||||
|
|
@ -1,43 +0,0 @@
|
||||||
package xsbt.api
|
|
||||||
|
|
||||||
import sbt.WithFiles
|
|
||||||
import sbt.compiler.{CallbackTest,TestCompile}
|
|
||||||
import java.io.File
|
|
||||||
import org.specs.Specification
|
|
||||||
|
|
||||||
object DetectSubclasses extends Specification
|
|
||||||
{
|
|
||||||
val sources =
|
|
||||||
("a/Super.scala" -> "package a; trait Super") ::
|
|
||||||
("a/Super2.scala" -> "class Super2") ::
|
|
||||||
("b/Middle.scala" -> "package y.w; trait Mid extends a.Super") ::
|
|
||||||
("b/Sub1.scala" -> "package a; class Sub1 extends y.w.Mid") ::
|
|
||||||
("b/Sub2.scala" -> "final class Sub2 extends a.Super") ::
|
|
||||||
("Sub3.scala" -> "private class F extends a.Super; package c { object Sub3 extends Super2 }") ::
|
|
||||||
Nil
|
|
||||||
|
|
||||||
"Analysis plugin should detect subclasses" in {
|
|
||||||
WithFiles(sources.map{case (file, content) => (new File(file), content)} : _*)
|
|
||||||
{
|
|
||||||
case files @ Seq(supFile, sup2File, midFile, sub1File, sub2File, sub3File) =>
|
|
||||||
for(scalaVersion <- TestCompile.allVersions)
|
|
||||||
CallbackTest.simple(scalaVersion, files) { callback =>
|
|
||||||
val expected =
|
|
||||||
(sub1File, "a.Sub1", Set("a.Super"), false) ::
|
|
||||||
(sub2File, "Sub2", Set("a.Super"), false) ::
|
|
||||||
(sup2File, "Super2", Set("Super2"), false) ::
|
|
||||||
(sub3File, "c.Sub3", Set("Super2"), true) ::
|
|
||||||
Nil
|
|
||||||
val actual = subclasses(callback).toSet
|
|
||||||
val actualOnly = actual -- expected
|
|
||||||
val expectedOnly = expected.toSet -- actual
|
|
||||||
actualOnly must beEmpty
|
|
||||||
expectedOnly must beEmpty
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
def subclasses(callback: xsbti.TestCallback): Seq[(File, String, Set[String], Boolean)] =
|
|
||||||
for( (file, src) <- CallbackTest.apis(callback); (definition, discovered) <- Discovery(subclassNames, Set.empty)(src.definitions) if !discovered.isEmpty ) yield
|
|
||||||
(file, definition.name, discovered.baseClasses, discovered.isModule)
|
|
||||||
def subclassNames = Set( "a.Super", "Super2", "x.Super3", "Super4")
|
|
||||||
}
|
|
||||||
|
|
@ -1,38 +0,0 @@
|
||||||
package sbt
|
|
||||||
package compiler
|
|
||||||
|
|
||||||
import java.io.File
|
|
||||||
import java.net.URLClassLoader
|
|
||||||
import xsbti.TestCallback
|
|
||||||
import IO.withTemporaryDirectory
|
|
||||||
|
|
||||||
object TestCompile
|
|
||||||
{
|
|
||||||
def allVersions = List("2.8.1", "2.9.0-1", "2.8.0", "2.9.1")
|
|
||||||
/** Tests running the compiler interface with the analyzer plugin with a test callback. The test callback saves all information
|
|
||||||
* that the plugin sends it for post-compile analysis by the provided function.*/
|
|
||||||
def apply[T](scalaVersion: String, sources: Seq[File], outputDirectory: File, options: Seq[String])
|
|
||||||
(f: (TestCallback, xsbti.compile.ScalaInstance, Logger) => T): T =
|
|
||||||
{
|
|
||||||
val testCallback = new TestCallback
|
|
||||||
WithCompiler(scalaVersion) { (compiler, log) =>
|
|
||||||
compiler(sources, CompileTest.noChanges, Nil, outputDirectory, options, testCallback, 5, CompilerCache.fresh, log)
|
|
||||||
f(testCallback, compiler.scalaInstance, log)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
/** Tests running the compiler interface with the analyzer plugin. The provided function is given a ClassLoader that can
|
|
||||||
* load the compiled classes..*/
|
|
||||||
def apply[T](scalaVersion: String, sources: Seq[File])(f: ClassLoader => T): T =
|
|
||||||
CallbackTest.full(scalaVersion, sources){ case (_, outputDir, _, _) => f(new URLClassLoader(Array(outputDir.toURI.toURL))) }
|
|
||||||
}
|
|
||||||
object CallbackTest
|
|
||||||
{
|
|
||||||
def simple[T](scalaVersion: String, sources: Seq[File])(f: TestCallback => T): T =
|
|
||||||
full(scalaVersion, sources){ case (callback, _, _, _) => f(callback) }
|
|
||||||
def full[T](scalaVersion: String, sources: Seq[File])(f: (TestCallback, File, xsbti.compile.ScalaInstance, Logger) => T): T =
|
|
||||||
withTemporaryDirectory { outputDir =>
|
|
||||||
TestCompile(scalaVersion, sources, outputDir, Nil) { case (callback, instance, log) => f(callback, outputDir, instance, log) }
|
|
||||||
}
|
|
||||||
def apis(callback: xsbti.TestCallback) =
|
|
||||||
callback.apis.toSeq map { case (src, api) => (src, xsbt.api.APIUtil.minimize(api)) }
|
|
||||||
}
|
|
||||||
|
|
@ -1,39 +0,0 @@
|
||||||
package sbt
|
|
||||||
package compiler
|
|
||||||
|
|
||||||
import xsbt.boot
|
|
||||||
import java.io.File
|
|
||||||
import IO.withTemporaryDirectory
|
|
||||||
|
|
||||||
object WithCompiler
|
|
||||||
{
|
|
||||||
def apply[T](scalaVersion: String)(f: (AnalyzingCompiler, Logger) => T): T =
|
|
||||||
{
|
|
||||||
launcher { (launch, log) =>
|
|
||||||
withTemporaryDirectory { componentDirectory =>
|
|
||||||
val manager = new ComponentManager(xsbt.boot.Locks, new boot.ComponentProvider(componentDirectory, true), None, log)
|
|
||||||
val compiler = new AnalyzingCompiler(ScalaInstance(scalaVersion, launch), manager, log)
|
|
||||||
compiler.newComponentCompiler(log).clearCache(ComponentCompiler.compilerInterfaceID)
|
|
||||||
define(manager, ComponentCompiler.compilerInterfaceSrcID, getResource("CompilerInterface.scala"), getClassResource(classOf[jline.Completor]))
|
|
||||||
define(manager, ComponentCompiler.xsbtiID, getClassResource(classOf[xsbti.AnalysisCallback]))
|
|
||||||
f(compiler, log)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
def launcher[T](f: (xsbti.Launcher, Logger) => T): T =
|
|
||||||
TestLogger { log =>
|
|
||||||
boot.LaunchTest.withLauncher { launch => f(launch, log) }
|
|
||||||
}
|
|
||||||
|
|
||||||
def getClassResource(resource: Class[_]): File = IO.classLocationFile(resource)
|
|
||||||
def getResource(resource: String): File =
|
|
||||||
{
|
|
||||||
val src = getClass.getClassLoader.getResource(resource)
|
|
||||||
if(src ne null) IO.asFile(src) else error("Resource not found: " + resource)
|
|
||||||
}
|
|
||||||
def define(manager: ComponentManager, id: String, files: File*)
|
|
||||||
{
|
|
||||||
manager.clearCache(id)
|
|
||||||
manager.define(id, files)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Loading…
Reference in New Issue