Skip to content
This repository was archived by the owner on Sep 8, 2022. It is now read-only.

Commit e9b4b5c

Browse files
committed
Integrate scala-partest-interface for sbt into scala-partest
It’s only a few lines of code, it ends up on the same ClassLoader in the Scala build, and we already have a dependency on sbt’s test-interface here anyway. The test framework class name changes from `scala.tools.partest.Framework` to `scala.tools.partest.sbt.Framework`.
1 parent 24059d8 commit e9b4b5c

File tree

2 files changed

+71
-9
lines changed

2 files changed

+71
-9
lines changed

src/main/scala/scala/tools/partest/nest/SBTRunner.scala

Lines changed: 1 addition & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -9,15 +9,7 @@
99
package scala.tools.partest
1010
package nest
1111

12-
import sbt.testing.EventHandler
13-
import sbt.testing.Logger
14-
import sbt.testing.Event
15-
import sbt.testing.Fingerprint
16-
import sbt.testing.Selector
17-
import sbt.testing.Status
18-
import sbt.testing.OptionalThrowable
19-
import sbt.testing.SuiteSelector
20-
import sbt.testing.TestSelector
12+
import _root_.sbt.testing._
2113
import java.net.URLClassLoader
2214
import TestState._
2315

Lines changed: 70 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,70 @@
1+
package scala.tools.partest.sbt
2+
3+
import scala.language.reflectiveCalls
4+
5+
import _root_.sbt.testing._
6+
import java.net.URLClassLoader
7+
import java.io.File
8+
9+
object Framework {
10+
// as partest is not driven by test classes discovered by sbt, need to add this marker fingerprint to definedTests
11+
val fingerprint = new AnnotatedFingerprint { def isModule = true; def annotationName = "partest" }
12+
13+
// TODO how can we export `fingerprint` so that a user can just add this to their build.sbt
14+
// definedTests in Test += new sbt.TestDefinition("partest", fingerprint, true, Array())
15+
}
16+
class Framework extends sbt.testing.Framework {
17+
def fingerprints: Array[Fingerprint] = Array(Framework.fingerprint)
18+
def name: String = "partest"
19+
20+
def runner(args: Array[String], remoteArgs: Array[String], testClassLoader: ClassLoader): sbt.testing.Runner =
21+
new Runner(args, remoteArgs, testClassLoader)
22+
}
23+
24+
/** Represents one run of a suite of tests.
25+
*/
26+
case class Runner(args: Array[String], remoteArgs: Array[String], testClassLoader: ClassLoader) extends sbt.testing.Runner {
27+
28+
def tasks(taskDefs: Array[TaskDef]): Array[sbt.testing.Task] = taskDefs map (SbtPartestTask(_, args): sbt.testing.Task)
29+
30+
/** Indicates the client is done with this <code>Runner</code> instance.
31+
*
32+
* @return a possibly multi-line summary string, or the empty string if no summary is provided -- TODO
33+
*/
34+
def done(): String = ""
35+
}
36+
37+
/** Run partest in this VM. Assumes we're running in a forked VM!
38+
*/
39+
case class SbtPartestTask(taskDef: TaskDef, args: Array[String]) extends Task {
40+
/** Executes this task, possibly returning to the client new tasks to execute. */
41+
def execute(eventHandler: EventHandler, loggers: Array[Logger]): Array[Task] = {
42+
val forkedCp = scala.util.Properties.javaClassPath
43+
val classLoader = new URLClassLoader(forkedCp.split(java.io.File.pathSeparator).map(new File(_).toURI.toURL))
44+
val runner = SBTRunner(Framework.fingerprint, eventHandler, loggers, "files", classLoader, null, null, Array.empty[String], args)
45+
46+
if (Runtime.getRuntime().maxMemory() / (1024*1024) < 800)
47+
loggers foreach (_.warn(s"""Low heap size detected (~ ${Runtime.getRuntime().maxMemory() / (1024*1024)}M). Please add the following to your build.sbt: javaOptions in Test += "-Xmx1G""""))
48+
49+
try runner.run
50+
catch {
51+
case ex: ClassNotFoundException =>
52+
loggers foreach { l => l.error("Please make sure partest is running in a forked VM by including the following line in build.sbt:\nfork in Test := true") }
53+
throw ex
54+
}
55+
56+
Array()
57+
}
58+
59+
type SBTRunner = { def run(): Unit }
60+
61+
// use reflection to instantiate scala.tools.partest.nest.SBTRunner,
62+
// casting to the structural type SBTRunner above so that method calls on the result will be invoked reflectively as well
63+
private def SBTRunner(partestFingerprint: Fingerprint, eventHandler: EventHandler, loggers: Array[Logger], srcDir: String, testClassLoader: URLClassLoader, javaCmd: File, javacCmd: File, scalacArgs: Array[String], args: Array[String]): SBTRunner = {
64+
val runnerClass = Class.forName("scala.tools.partest.nest.SBTRunner")
65+
runnerClass.getConstructors()(0).newInstance(partestFingerprint, eventHandler, loggers, srcDir, testClassLoader, javaCmd, javacCmd, scalacArgs, args).asInstanceOf[SBTRunner]
66+
}
67+
68+
/** A possibly zero-length array of string tags associated with this task. */
69+
def tags: Array[String] = Array()
70+
}

0 commit comments

Comments
 (0)