From 5bb46359b520adbea1b051b5ecd53f465d79521f Mon Sep 17 00:00:00 2001 From: cheeseng Date: Wed, 26 Jun 2013 20:31:41 +0800 Subject: [PATCH] Change to use test-interface-1.0-SNAP7, and use ScalaTest 2.0.M6-SNAP26 which implemented test-interface-1.0-SNAP7. --- .../src/main/scala/sbt/ForkTests.scala | 19 ++- main/actions/src/main/scala/sbt/Tests.scala | 14 +- main/src/main/scala/sbt/Defaults.scala | 2 +- project/Sbt.scala | 4 +- .../sbt-test/tests/do-not-discover/build.sbt | 2 +- sbt/src/sbt-test/tests/done/build.sbt | 2 +- .../tests/nested-inproc-par/build.sbt | 2 +- .../tests/nested-inproc-seq/build.sbt | 2 +- .../sbt-test/tests/nested-subproc/build.sbt | 2 +- .../sbt-test/tests/single-runner/build.sbt | 2 +- .../tests/t543/project/Ticket543Test.scala | 4 +- sbt/src/sbt-test/tests/task/build.sbt | 2 +- testing/agent/src/main/java/sbt/ForkMain.java | 130 ++++++++---------- .../src/main/java/sbt/FrameworkWrapper.java | 55 +++++--- .../src/main/scala/sbt/TestFramework.scala | 31 +++-- 15 files changed, 148 insertions(+), 125 deletions(-) diff --git a/main/actions/src/main/scala/sbt/ForkTests.scala b/main/actions/src/main/scala/sbt/ForkTests.scala index d4421e7136..44aee82490 100755 --- a/main/actions/src/main/scala/sbt/ForkTests.scala +++ b/main/actions/src/main/scala/sbt/ForkTests.scala @@ -11,7 +11,7 @@ import Tests.{Output => TestOutput, _} import ForkMain._ private[sbt] object ForkTests { - def apply(runners: Map[TestFramework, Runner], tests: List[TestDefinition], config: Execution, classpath: Seq[File], fork: ForkOptions, log: Logger): Task[TestOutput] = { + def apply(runners: Map[TestFramework, Runner], tests: List[TestDefinition], config: Execution, loader: ClassLoader, classpath: Seq[File], fork: ForkOptions, log: Logger): Task[TestOutput] = { val opts = config.options.toList val listeners = opts flatMap { case Listeners(ls) => ls @@ -40,7 +40,22 @@ private[sbt] object ForkTests { case _: java.net.SocketException => return } val os = new ObjectOutputStream(socket.getOutputStream) - val is = new ObjectInputStream(socket.getInputStream) + // Make sure that ObjectInputStream use the passed in class loader + // ObjectInputStream class loading seems to be confusing, some old but useful links for reference: + // https://forums.oracle.com/thread/1151865 + // http://sourceforge.net/p/jpype/bugs/52/ + // http://tech-tauk.blogspot.com/2010/05/thread-context-classlaoder-in.html + val is = new ObjectInputStream(socket.getInputStream) { + override protected def resolveClass(desc: ObjectStreamClass): Class[_] = { + try { + val name = desc.getName + Class.forName(name, false, loader) + } + catch { + case e: ClassNotFoundException => super.resolveClass(desc) + } + } + } try { os.writeBoolean(log.ansiCodesSupported) diff --git a/main/actions/src/main/scala/sbt/Tests.scala b/main/actions/src/main/scala/sbt/Tests.scala index 36de6abc49..f3ade18a50 100644 --- a/main/actions/src/main/scala/sbt/Tests.scala +++ b/main/actions/src/main/scala/sbt/Tests.scala @@ -11,7 +11,7 @@ package sbt import xsbti.api.Definition import ConcurrentRestrictions.Tag - import testing.{AnnotatedFingerprint, Fingerprint, Framework, SubclassFingerprint, Runner, Task => TestTask} + import testing.{AnnotatedFingerprint, Fingerprint, Framework, SubclassFingerprint, Runner, TaskDef, SuiteSelector, Task => TestTask} import scala.annotation.tailrec import java.io.File @@ -123,9 +123,10 @@ object Tests } type TestRunnable = (String, TestFunction) - private def createNestedRunnables(name: String, loader: ClassLoader, testFun: TestFunction, nestedTasks: Seq[TestTask]): Seq[(String, TestFunction)] = + private def createNestedRunnables(loader: ClassLoader, testFun: TestFunction, nestedTasks: Seq[TestTask]): Seq[(String, TestFunction)] = nestedTasks.view.zipWithIndex map { case (nt, idx) => - (name, TestFramework.createTestFunction(loader, new TestDefinition(testFun.testDefinition.name + "-" + idx, testFun.testDefinition.fingerprint), testFun.runner, nt)) + val testFunDef = testFun.taskDef + (testFunDef.fullyQualifiedName, TestFramework.createTestFunction(loader, new TaskDef(testFunDef.fullyQualifiedName + "-" + idx, testFunDef.fingerprint, testFunDef.explicitlySpecified, testFunDef.selectors), testFun.runner, nt)) } def makeParallel(loader: ClassLoader, runnables: Iterable[TestRunnable], setupTasks: Task[Unit], tags: Seq[(Tag,Int)]): Task[Map[String,SuiteResult]] = @@ -142,7 +143,7 @@ object Tests val base = task { (name, fun.apply()) } val taggedBase = base.tagw(tags : _*).tag(fun.tags.map(ConcurrentRestrictions.Tag(_)) : _*) taggedBase flatMap { case (name, (result, nested)) => - val nestedRunnables = createNestedRunnables(fun.testDefinition.name, loader, fun, nested) + val nestedRunnables = createNestedRunnables(loader, fun, nested) toTasks(loader, nestedRunnables, tags).map( _.updated(name, result) ) } } @@ -155,7 +156,7 @@ object Tests case hd :: rst => val testFun = hd._2 val (result, nestedTasks) = testFun.apply() - val nestedRunnables = createNestedRunnables(testFun.testDefinition.name, loader, testFun, nestedTasks) + val nestedRunnables = createNestedRunnables(loader, testFun, nestedTasks) processRunnable(nestedRunnables.toList ::: rst, (hd._1, result) :: acc) case Nil => acc } @@ -202,7 +203,8 @@ object Tests defined(annotations, d.annotations, d.isModule) val discovered = Discovery(firsts(subclasses), firsts(annotations))(definitions) - val tests = for( (df, di) <- discovered; fingerprint <- toFingerprints(di) ) yield new TestDefinition(df.name, fingerprint) + // TODO: To pass in correct explicitlySpecified and selectors + val tests = for( (df, di) <- discovered; fingerprint <- toFingerprints(di) ) yield new TestDefinition(df.name, fingerprint, false, Array(new SuiteSelector)) val mains = discovered collect { case (df, di) if di.hasMain => df.name } (tests, mains.toSet) } diff --git a/main/src/main/scala/sbt/Defaults.scala b/main/src/main/scala/sbt/Defaults.scala index 6d758f09af..23165f9391 100755 --- a/main/src/main/scala/sbt/Defaults.scala +++ b/main/src/main/scala/sbt/Defaults.scala @@ -484,7 +484,7 @@ object Defaults extends BuildCommon case Tests.Group(name, tests, runPolicy) => runPolicy match { case Tests.SubProcess(opts) => - ForkTests(runners, tests.toList, config, cp.files, opts, s.log) tag Tags.ForkedTestGroup + ForkTests(runners, tests.toList, config, loader, cp.files, opts, s.log) tag Tags.ForkedTestGroup case Tests.InProcess => Tests(frameworks, loader, runners, tests, config, s.log) } diff --git a/project/Sbt.scala b/project/Sbt.scala index e857ed4374..82bb9d689d 100644 --- a/project/Sbt.scala +++ b/project/Sbt.scala @@ -79,10 +79,10 @@ object Sbt extends Build // Apache Ivy integration lazy val ivySub = baseProject(file("ivy"), "Ivy") dependsOn(interfaceSub, launchInterfaceSub, crossSub, logSub % "compile;test->test", ioSub % "compile;test->test", launchSub % "test->test") settings(ivy, jsch, testExclusive) // Runner for uniform test interface - lazy val testingSub = baseProject(file("testing"), "Testing") dependsOn(ioSub, classpathSub, logSub, launchInterfaceSub, testAgentSub) settings(libraryDependencies += "org.scalatest" % "test-interface" % "1.0-SNAP3") + lazy val testingSub = baseProject(file("testing"), "Testing") dependsOn(ioSub, classpathSub, logSub, launchInterfaceSub, testAgentSub) settings(libraryDependencies += "org.scalatest" % "test-interface" % "1.0-SNAP7") // Testing agent for running tests in a separate process. lazy val testAgentSub = project(file("testing/agent"), "Test Agent") settings( - libraryDependencies += "org.scalatest" % "test-interface" % "1.0-SNAP3" + libraryDependencies += "org.scalatest" % "test-interface" % "1.0-SNAP7" ) // Basic task engine diff --git a/sbt/src/sbt-test/tests/do-not-discover/build.sbt b/sbt/src/sbt-test/tests/do-not-discover/build.sbt index 2e8f50f5b3..597b2de1d3 100644 --- a/sbt/src/sbt-test/tests/do-not-discover/build.sbt +++ b/sbt/src/sbt-test/tests/do-not-discover/build.sbt @@ -1,5 +1,5 @@ scalaVersion := "2.10.1" -libraryDependencies += "org.scalatest" %% "scalatest" % "2.0.M6-SNAP15" +libraryDependencies += "org.scalatest" %% "scalatest" % "2.0.M6-SNAP26" testOptions in Test += Tests.Argument("-r", "custom.CustomReporter") \ No newline at end of file diff --git a/sbt/src/sbt-test/tests/done/build.sbt b/sbt/src/sbt-test/tests/done/build.sbt index 2e8f50f5b3..597b2de1d3 100644 --- a/sbt/src/sbt-test/tests/done/build.sbt +++ b/sbt/src/sbt-test/tests/done/build.sbt @@ -1,5 +1,5 @@ scalaVersion := "2.10.1" -libraryDependencies += "org.scalatest" %% "scalatest" % "2.0.M6-SNAP15" +libraryDependencies += "org.scalatest" %% "scalatest" % "2.0.M6-SNAP26" testOptions in Test += Tests.Argument("-r", "custom.CustomReporter") \ No newline at end of file diff --git a/sbt/src/sbt-test/tests/nested-inproc-par/build.sbt b/sbt/src/sbt-test/tests/nested-inproc-par/build.sbt index 0895fe82af..d63e1c9ee7 100644 --- a/sbt/src/sbt-test/tests/nested-inproc-par/build.sbt +++ b/sbt/src/sbt-test/tests/nested-inproc-par/build.sbt @@ -1,6 +1,6 @@ scalaVersion := "2.10.1" -libraryDependencies += "org.scalatest" %% "scalatest" % "2.0.M6-SNAP15" +libraryDependencies += "org.scalatest" %% "scalatest" % "2.0.M6-SNAP26" testOptions in Test += Tests.Argument("-r", "custom.CustomReporter") diff --git a/sbt/src/sbt-test/tests/nested-inproc-seq/build.sbt b/sbt/src/sbt-test/tests/nested-inproc-seq/build.sbt index dda0ba5dce..f5f53412cb 100644 --- a/sbt/src/sbt-test/tests/nested-inproc-seq/build.sbt +++ b/sbt/src/sbt-test/tests/nested-inproc-seq/build.sbt @@ -1,6 +1,6 @@ scalaVersion := "2.10.1" -libraryDependencies += "org.scalatest" %% "scalatest" % "2.0.M6-SNAP15" +libraryDependencies += "org.scalatest" %% "scalatest" % "2.0.M6-SNAP26" testOptions in Test += Tests.Argument("-r", "custom.CustomReporter") diff --git a/sbt/src/sbt-test/tests/nested-subproc/build.sbt b/sbt/src/sbt-test/tests/nested-subproc/build.sbt index f2336a77e3..ec7e0f18a7 100644 --- a/sbt/src/sbt-test/tests/nested-subproc/build.sbt +++ b/sbt/src/sbt-test/tests/nested-subproc/build.sbt @@ -1,6 +1,6 @@ scalaVersion := "2.10.1" -libraryDependencies += "org.scalatest" %% "scalatest" % "2.0.M6-SNAP15" +libraryDependencies += "org.scalatest" %% "scalatest" % "2.0.M6-SNAP26" testOptions in Test += Tests.Argument("-r", "custom.CustomReporter") diff --git a/sbt/src/sbt-test/tests/single-runner/build.sbt b/sbt/src/sbt-test/tests/single-runner/build.sbt index 2e8f50f5b3..597b2de1d3 100644 --- a/sbt/src/sbt-test/tests/single-runner/build.sbt +++ b/sbt/src/sbt-test/tests/single-runner/build.sbt @@ -1,5 +1,5 @@ scalaVersion := "2.10.1" -libraryDependencies += "org.scalatest" %% "scalatest" % "2.0.M6-SNAP15" +libraryDependencies += "org.scalatest" %% "scalatest" % "2.0.M6-SNAP26" testOptions in Test += Tests.Argument("-r", "custom.CustomReporter") \ No newline at end of file diff --git a/sbt/src/sbt-test/tests/t543/project/Ticket543Test.scala b/sbt/src/sbt-test/tests/t543/project/Ticket543Test.scala index ba9881ba04..cda602f1a7 100755 --- a/sbt/src/sbt-test/tests/t543/project/Ticket543Test.scala +++ b/sbt/src/sbt-test/tests/t543/project/Ticket543Test.scala @@ -15,9 +15,9 @@ object Ticket543Test extends Build { testListeners += new TestReportListener { def testEvent(event: TestEvent) { for (e <- event.detail.filter(_.status == sbt.testing.Status.Failure)) { - if (e.throwable ne null) { + if (e.throwable != null && e.throwable.isDefined) { val caw = new CharArrayWriter - e.throwable.printStackTrace(new PrintWriter(caw)) + e.throwable.get.printStackTrace(new PrintWriter(caw)) if (caw.toString.contains("Test.scala:")) marker.createNewFile() } diff --git a/sbt/src/sbt-test/tests/task/build.sbt b/sbt/src/sbt-test/tests/task/build.sbt index 2e8f50f5b3..597b2de1d3 100644 --- a/sbt/src/sbt-test/tests/task/build.sbt +++ b/sbt/src/sbt-test/tests/task/build.sbt @@ -1,5 +1,5 @@ scalaVersion := "2.10.1" -libraryDependencies += "org.scalatest" %% "scalatest" % "2.0.M6-SNAP15" +libraryDependencies += "org.scalatest" %% "scalatest" % "2.0.M6-SNAP26" testOptions in Test += Tests.Argument("-r", "custom.CustomReporter") \ No newline at end of file diff --git a/testing/agent/src/main/java/sbt/ForkMain.java b/testing/agent/src/main/java/sbt/ForkMain.java index 8ec30b7954..ff542ae521 100755 --- a/testing/agent/src/main/java/sbt/ForkMain.java +++ b/testing/agent/src/main/java/sbt/ForkMain.java @@ -63,68 +63,41 @@ static class ForkError extends Exception { public String getMessage() { return originalMessage; } public Exception getCause() { return cause; } } - static class ForkSelector extends Selector implements Serializable {} - static class ForkSuiteSelector extends ForkSelector {} - static class ForkTestSelector extends ForkSelector { - private String testName; - ForkTestSelector(TestSelector testSelector) { - this.testName = testSelector.getTestName(); - } - public String getTestName() { - return testName; - } - } - static class ForkNestedSuiteSelector extends ForkSelector { - private String suiteId; - ForkNestedSuiteSelector(NestedSuiteSelector nestedSuiteSelector) { - this.suiteId = nestedSuiteSelector.getSuiteId(); - } - public String getSuiteId() { - return suiteId; - } - } - static class ForkNestedTestSelector extends ForkSelector { - private String suiteId; - private String testName; - ForkNestedTestSelector(NestedTestSelector nestedTestSelector) { - this.suiteId = nestedTestSelector.getSuiteId(); - this.testName = nestedTestSelector.getTestName(); - } - public String getSuiteId() { - return suiteId; - } - public String getTestName() { - return testName; - } - } static class ForkEvent implements Event, Serializable { private String fullyQualifiedName; - private boolean isModule; - private ForkSelector selector; + private Fingerprint fingerprint; + private Selector selector; private Status status; - private Throwable throwable; + private OptionalThrowable throwable; + private long duration; ForkEvent(Event e) { fullyQualifiedName = e.fullyQualifiedName(); - isModule = e.isModule(); + Fingerprint rawFingerprint = e.fingerprint(); + if (rawFingerprint instanceof SubclassFingerprint) + this.fingerprint = new SubclassFingerscan((SubclassFingerprint) rawFingerprint); + else + this.fingerprint = new AnnotatedFingerscan((AnnotatedFingerprint) rawFingerprint); selector = forkSelector(e.selector()); status = e.status(); - if (e.throwable() != null) throwable = new ForkError(e.throwable()); + OptionalThrowable originalThrowable = e.throwable(); + if (originalThrowable.isDefined()) + this.throwable = new OptionalThrowable(new ForkError(originalThrowable.get())); + else + this.throwable = originalThrowable; + this.duration = e.duration(); } public String fullyQualifiedName() { return fullyQualifiedName; } - public boolean isModule() { return isModule; } + public Fingerprint fingerprint() { return fingerprint; } public Selector selector() { return selector; } public Status status() { return status; } - public Throwable throwable() { return throwable; } - protected ForkSelector forkSelector(Selector selector) { - if (selector instanceof SuiteSelector) - return new ForkSuiteSelector(); - else if (selector instanceof TestSelector) - return new ForkTestSelector((TestSelector) selector); - else if (selector instanceof NestedSuiteSelector) - return new ForkNestedSuiteSelector((NestedSuiteSelector) selector); + public OptionalThrowable throwable() { return throwable; } + public long duration() { return duration; } + protected Selector forkSelector(Selector selector) { + if (selector instanceof Serializable) + return selector; else - return new ForkNestedTestSelector((NestedTestSelector) selector); + throw new UnsupportedOperationException("Selector implementation must be Serializable."); } } public static void main(String[] args) throws Exception { @@ -172,8 +145,8 @@ void logError(ObjectOutputStream os, String message) { void logDebug(ObjectOutputStream os, String message) { write(os, new Object[]{ForkTags.Debug, message}); } - void writeEvents(ObjectOutputStream os, ForkTestDefinition test, ForkEvent[] events) { - write(os, new Object[]{test.name, events}); + void writeEvents(ObjectOutputStream os, TaskDef taskDef, ForkEvent[] events) { + write(os, new Object[]{taskDef.fullyQualifiedName(), events}); } void runTests(ObjectInputStream is, final ObjectOutputStream os) throws Exception { final boolean ansiCodesSupported = is.readBoolean(); @@ -212,15 +185,18 @@ void runTests(ObjectInputStream is, final ObjectOutputStream os) throws Exceptio if (framework == null) continue; - ArrayList filteredTests = new ArrayList(); + ArrayList filteredTests = new ArrayList(); for (Fingerprint testFingerprint : framework.fingerprints()) { for (ForkTestDefinition test : tests) { - if (matches(testFingerprint, test.fingerprint)) filteredTests.add(test); + // TODO: To pass in correct explicitlySpecified and selectors + if (matches(testFingerprint, test.fingerprint)) + filteredTests.add(new TaskDef(test.name, test.fingerprint, false, new Selector[] { new SuiteSelector() })); } } final Runner runner = framework.runner(frameworkArgs, remoteFrameworkArgs, getClass().getClassLoader()); - for (ForkTestDefinition test : filteredTests) - runTestSafe(test, runner, loggers, os); + Task[] tasks = runner.tasks(filteredTests.toArray(new TaskDef[filteredTests.size()])); + for (Task task : tasks) + runTestSafe(task, runner, loggers, os); runner.done(); } write(os, ForkTags.Done); @@ -240,21 +216,19 @@ public Task getTask() { return task; } } - void runTestSafe(ForkTestDefinition test, Runner runner, Logger[] loggers, ObjectOutputStream os) { + void runTestSafe(Task task, Runner runner, Logger[] loggers, ObjectOutputStream os) { + TaskDef taskDef = task.taskDef(); try { - // TODO: To pass in correct explicitlySpecified and selectors - Task task = runner.task(test.name, test.fingerprint, false, new Selector[] { new SuiteSelector() }); - List nestedTasks = new ArrayList(); - for (Task nt : runTest(test, task, loggers, os)) - nestedTasks.add(new NestedTask(test.name, nt)); + for (Task nt : runTest(taskDef, task, loggers, os)) + nestedTasks.add(new NestedTask(taskDef.fullyQualifiedName(), nt)); while (true) { List newNestedTasks = new ArrayList(); int nestedTasksLength = nestedTasks.size(); for (int i = 0; i < nestedTasksLength; i++) { NestedTask nestedTask = nestedTasks.get(i); String nestedParentName = nestedTask.getParentName() + "-" + i; - for (Task nt : runTest(new ForkTestDefinition(nestedParentName, test.fingerprint), nestedTask.getTask(), loggers, os)) { + for (Task nt : runTest(nestedTask.getTask().taskDef(), nestedTask.getTask(), loggers, os)) { newNestedTasks.add(new NestedTask(nestedParentName, nt)); } } @@ -265,10 +239,10 @@ void runTestSafe(ForkTestDefinition test, Runner runner, Logger[] loggers, Objec } } } catch (Throwable t) { - writeEvents(os, test, new ForkEvent[] { testError(os, test, "Uncaught exception when running " + test.name + ": " + t.toString(), t) }); + writeEvents(os, taskDef, new ForkEvent[] { testError(os, taskDef, "Uncaught exception when running " + taskDef.fullyQualifiedName() + ": " + t.toString(), t) }); } } - Task[] runTest(ForkTestDefinition test, Task task, Logger[] loggers, ObjectOutputStream os) { + Task[] runTest(TaskDef taskDef, Task task, Logger[] loggers, ObjectOutputStream os) { ForkEvent[] events; Task[] nestedTasks; try { @@ -279,9 +253,9 @@ Task[] runTest(ForkTestDefinition test, Task task, Logger[] loggers, ObjectOutpu } catch (Throwable t) { nestedTasks = new Task[0]; - events = new ForkEvent[] { testError(os, test, "Uncaught exception when running " + test.name + ": " + t.toString(), t) }; + events = new ForkEvent[] { testError(os, taskDef, "Uncaught exception when running " + taskDef.fullyQualifiedName() + ": " + t.toString(), t) }; } - writeEvents(os, test, events); + writeEvents(os, taskDef, events); return nestedTasks; } void run(ObjectInputStream is, ObjectOutputStream os) throws Exception { @@ -301,23 +275,33 @@ void run(ObjectInputStream is, ObjectOutputStream os) throws Exception { void internalError(Throwable t) { System.err.println("Internal error when running tests: " + t.toString()); } - ForkEvent testEvent(final String fullyQualifiedName, final Fingerprint fingerprint, final Selector selector, final Status r, final Throwable err) { + ForkEvent testEvent(final String fullyQualifiedName, final Fingerprint fingerprint, final Selector selector, final Status r, final Throwable err, final long duration) { + final OptionalThrowable throwable; + if (err == null) + throwable = new OptionalThrowable(); + else + throwable = new OptionalThrowable(err); return new ForkEvent(new Event() { public String fullyQualifiedName() { return fullyQualifiedName; } - public boolean isModule() { return fingerprint instanceof SubclassFingerprint ? ((SubclassFingerprint) fingerprint).isModule() : ((AnnotatedFingerprint) fingerprint).isModule(); } + public Fingerprint fingerprint() { return fingerprint; } public Selector selector() { return selector; } public Status status() { return r; } - public Throwable throwable() { return err; } + public OptionalThrowable throwable() { + return throwable; + } + public long duration() { + return duration; + } }); } - ForkEvent testError(ObjectOutputStream os, ForkTestDefinition test, String message) { + ForkEvent testError(ObjectOutputStream os, TaskDef taskDef, String message) { logError(os, message); - return testEvent(test.name, test.fingerprint, new SuiteSelector(), Status.Error, null); + return testEvent(taskDef.fullyQualifiedName(), taskDef.fingerprint(), new SuiteSelector(), Status.Error, null, 0); } - ForkEvent testError(ObjectOutputStream os, ForkTestDefinition test, String message, Throwable t) { + ForkEvent testError(ObjectOutputStream os, TaskDef taskDef, String message, Throwable t) { logError(os, message); write(os, t); - return testEvent(test.name, test.fingerprint, new SuiteSelector(), Status.Error, t); + return testEvent(taskDef.fullyQualifiedName(), taskDef.fingerprint(), new SuiteSelector(), Status.Error, t, 0); } } } diff --git a/testing/agent/src/main/java/sbt/FrameworkWrapper.java b/testing/agent/src/main/java/sbt/FrameworkWrapper.java index 55d978025f..21b9cc4b5d 100644 --- a/testing/agent/src/main/java/sbt/FrameworkWrapper.java +++ b/testing/agent/src/main/java/sbt/FrameworkWrapper.java @@ -88,16 +88,16 @@ class EventHandlerWrapper implements org.scalatools.testing.EventHandler { private EventHandler newEventHandler; private String fullyQualifiedName; - private boolean isModule; + private Fingerprint fingerprint; - public EventHandlerWrapper(EventHandler newEventHandler, String fullyQualifiedName, boolean isModule) { + public EventHandlerWrapper(EventHandler newEventHandler, String fullyQualifiedName, Fingerprint fingerprint) { this.newEventHandler = newEventHandler; this.fullyQualifiedName = fullyQualifiedName; - this.isModule = isModule; + this.fingerprint = fingerprint; } public void handle(org.scalatools.testing.Event oldEvent) { - newEventHandler.handle(new EventWrapper(oldEvent, fullyQualifiedName, isModule)); + newEventHandler.handle(new EventWrapper(oldEvent, fullyQualifiedName, fingerprint)); } } @@ -105,20 +105,26 @@ class EventWrapper implements Event { private org.scalatools.testing.Event oldEvent; private String className; - private boolean classIsModule; + private Fingerprint fingerprint; + private OptionalThrowable throwable; - public EventWrapper(org.scalatools.testing.Event oldEvent, String className, boolean classIsModule) { + public EventWrapper(org.scalatools.testing.Event oldEvent, String className, Fingerprint fingerprint) { this.oldEvent = oldEvent; this.className = className; - this.classIsModule = classIsModule; + this.fingerprint = fingerprint; + Throwable oldThrowable = oldEvent.error(); + if (oldThrowable == null) + throwable = new OptionalThrowable(); + else + throwable = new OptionalThrowable(oldThrowable); } public String fullyQualifiedName() { return className; } - public boolean isModule() { - return classIsModule; + public Fingerprint fingerprint() { + return fingerprint; } public Selector selector() { @@ -140,10 +146,13 @@ public Status status() { } } - public Throwable throwable() { - return oldEvent.error(); + public OptionalThrowable throwable() { + return throwable; } + public long duration() { + return 0; // Just return 0 as old event does not have duration. + } } class RunnerWrapper implements Runner { @@ -157,8 +166,19 @@ public RunnerWrapper(org.scalatools.testing.Framework oldFramework, ClassLoader this.testClassLoader = testClassLoader; this.args = args; } + + public Task[] tasks(TaskDef[] taskDefs) { + int length = taskDefs.length; + Task[] tasks = new Task[length]; + for (int i = 0; i < length; i++) { + TaskDef taskDef = taskDefs[i]; + tasks[i] = createTask(taskDef.fullyQualifiedName(), taskDef.fingerprint(), taskDef.explicitlySpecified(), taskDef.selectors()); + } + return tasks; + } - public Task task(final String fullyQualifiedName, final Fingerprint fingerprint, boolean explicitlySpecified, Selector[] selectors) { + public Task createTask(final String fullyQualifiedName, final Fingerprint fingerprint, boolean explicitlySpecified, Selector[] selectors) { + final TaskDef taskDef = new TaskDef(fullyQualifiedName, fingerprint, explicitlySpecified, selectors); return new Task() { public String[] tags() { return new String[0]; // Old framework does not support tags @@ -183,19 +203,17 @@ private void runRunner(org.scalatools.testing.Runner runner, Fingerprint fingerp public boolean isModule() { return subclassFingerprint.isModule(); } public String superClassName() { return subclassFingerprint.superclassName(); } }; - runner.run(fullyQualifiedName, oldFingerprint, new EventHandlerWrapper(eventHandler, fullyQualifiedName, subclassFingerprint.isModule()), args); + runner.run(fullyQualifiedName, oldFingerprint, new EventHandlerWrapper(eventHandler, fullyQualifiedName, subclassFingerprint), args); } private void runRunner2(org.scalatools.testing.Runner2 runner, Fingerprint fingerprint, EventHandler eventHandler) { org.scalatools.testing.Fingerprint oldFingerprint = null; - boolean isModule = false; if (fingerprint instanceof SubclassFingerprint) { final SubclassFingerprint subclassFingerprint = (SubclassFingerprint) fingerprint; oldFingerprint = new org.scalatools.testing.SubclassFingerprint() { public boolean isModule() { return subclassFingerprint.isModule(); } public String superClassName() { return subclassFingerprint.superclassName(); } }; - isModule = subclassFingerprint.isModule(); } else { final AnnotatedFingerprint annotatedFingerprint = (AnnotatedFingerprint) fingerprint; @@ -203,9 +221,8 @@ private void runRunner2(org.scalatools.testing.Runner2 runner, Fingerprint finge public boolean isModule() { return annotatedFingerprint.isModule(); } public String annotationName() { return annotatedFingerprint.annotationName(); } }; - isModule = annotatedFingerprint.isModule(); } - runner.run(fullyQualifiedName, oldFingerprint, new EventHandlerWrapper(eventHandler, fullyQualifiedName, isModule), args); + runner.run(fullyQualifiedName, oldFingerprint, new EventHandlerWrapper(eventHandler, fullyQualifiedName, fingerprint), args); } public Task[] execute(EventHandler eventHandler, Logger[] loggers) { @@ -224,6 +241,10 @@ public Task[] execute(EventHandler eventHandler, Logger[] loggers) { } return new Task[0]; } + + public TaskDef taskDef() { + return taskDef; + } }; } diff --git a/testing/src/main/scala/sbt/TestFramework.scala b/testing/src/main/scala/sbt/TestFramework.scala index ec3c4ef6a2..ffe7f24e37 100644 --- a/testing/src/main/scala/sbt/TestFramework.scala +++ b/testing/src/main/scala/sbt/TestFramework.scala @@ -51,7 +51,7 @@ case class TestFramework(val implClassNames: String*) def create(loader: ClassLoader, log: Logger): Option[Framework] = createFramework(loader, log, implClassNames.toList) } -final class TestDefinition(val name: String, val fingerprint: Fingerprint) +final class TestDefinition(val name: String, val fingerprint: Fingerprint, val explicitlySpecified: Boolean, val selectors: Array[Selector]) { override def toString = "Test " + name + " : " + TestFramework.toString(fingerprint) override def equals(t: Any) = @@ -65,13 +65,15 @@ final class TestDefinition(val name: String, val fingerprint: Fingerprint) final class TestRunner(delegate: Runner, listeners: Seq[TestReportListener], log: Logger) { - final def task(testDefinition: TestDefinition): TestTask = - delegate.task(testDefinition.name, testDefinition.fingerprint, false, Array(new SuiteSelector)) // TODO: To pass in correct explicitlySpecified and selectors + final def tasks(testDefs: Set[TestDefinition]): Array[TestTask] = + delegate.tasks(testDefs.map(df => new TaskDef(df.name, df.fingerprint, df.explicitlySpecified, df.selectors)).toArray) - final def run(testDefinition: TestDefinition, testTask: TestTask): (SuiteResult, Seq[TestTask]) = + final def run(taskDef: TaskDef, testTask: TestTask): (SuiteResult, Seq[TestTask]) = { - log.debug("Running " + testDefinition) + val testDefinition = new TestDefinition(taskDef.fullyQualifiedName, taskDef.fingerprint, taskDef.explicitlySpecified, taskDef.selectors) + log.debug("Running " + taskDef) val name = testDefinition.name + def runTest() = { // here we get the results! here is where we'd pass in the event listener @@ -186,8 +188,8 @@ object TestFramework def pickOne(prints: Seq[Fingerprint]): Fingerprint = frameworkPrints.find(prints.toSet) getOrElse prints.head val uniqueDefs = - for( (name, defs) <- tests.groupBy(_.name) ) yield - new TestDefinition(name, pickOne(defs.map(_.fingerprint))) + for( ((name, explicitlySpecified, selectors), defs) <- tests.groupBy(t => (t.name, t.explicitlySpecified, t.selectors)) ) yield + new TestDefinition(name, pickOne(defs.map(_.fingerprint)), explicitlySpecified, selectors) uniqueDefs.toSet } @@ -203,11 +205,10 @@ object TestFramework val testTasks = tests flatMap { case (framework, (testDefinitions, testArgs)) => val runner = runners(framework) - for(testDefinition <- testDefinitions) yield - { - val testTask = withContextLoader(loader) { runner.task(testDefinition) } - val testFunction = createTestFunction(loader, testDefinition, runner, testTask) - (testDefinition.name, testFunction) + val testTasks = withContextLoader(loader) { runner.tasks(testDefinitions) } + for (testTask <- testTasks) yield { + val taskDef = testTask.taskDef + (taskDef.fullyQualifiedName, createTestFunction(loader, taskDef, runner, testTask)) } } @@ -229,11 +230,11 @@ object TestFramework val main = ClasspathUtilities.makeLoader(classpath, dual, scalaInstance, tempDir) ClasspathUtilities.filterByClasspath(interfaceJar +: classpath, main) } - def createTestFunction(loader: ClassLoader, testDefinition: TestDefinition, runner:TestRunner, testTask: TestTask): TestFunction = - new TestFunction(testDefinition, runner, (r: TestRunner) => withContextLoader(loader) { r.run(testDefinition, testTask) }) { def tags = testTask.tags } + def createTestFunction(loader: ClassLoader, taskDef: TaskDef, runner:TestRunner, testTask: TestTask): TestFunction = + new TestFunction(taskDef, runner, (r: TestRunner) => withContextLoader(loader) { r.run(taskDef, testTask) }) { def tags = testTask.tags } } -abstract class TestFunction(val testDefinition: TestDefinition, val runner: TestRunner, fun: (TestRunner) => (SuiteResult, Seq[TestTask])) { +abstract class TestFunction(val taskDef: TaskDef, val runner: TestRunner, fun: (TestRunner) => (SuiteResult, Seq[TestTask])) { def apply(): (SuiteResult, Seq[TestTask]) = fun(runner)