diff --git a/main-actions/src/main/scala/sbt/ForkTests.scala b/main-actions/src/main/scala/sbt/ForkTests.scala index 9bdfcc94a..a1380792a 100755 --- a/main-actions/src/main/scala/sbt/ForkTests.scala +++ b/main-actions/src/main/scala/sbt/ForkTests.scala @@ -37,6 +37,10 @@ import sbt.internal.WorkerConnection private[sbt] object ForkTests: val r = Random() + /** + * virtualClasspath can be controlled by setting + * Test / classLoaderLayeringStrategy to ClassLoaderLayeringStrategy.Raw. + */ def apply( runners: Map[TestFramework, Runner], opts: ProcessedOptions, @@ -46,6 +50,7 @@ private[sbt] object ForkTests: fork: ForkOptions, log: Logger, parallelism: Option[Int], + virtualClasspath: Boolean, tags: (Tag, Int)* ): Task[TestOutput] = { import std.TaskExtra.* @@ -57,44 +62,22 @@ private[sbt] object ForkTests: if opts.tests.isEmpty then constant(TestOutput(TestResult.Passed, Map.empty[String, SuiteResult], Iterable.empty)) else - mainTestTask(runners, opts, classpath, converter, fork, log, config.parallel, parallelism) - .tagw( - config.tags* - ) + mainTestTask( + runners = runners, + opts = opts, + classpath = classpath, + converter = converter, + fork = fork, + log = log, + parallel = config.parallel, + parallelism = parallelism, + virtualClasspath = virtualClasspath, + ).tagw(config.tags*) main.tagw(tags*).dependsOn(all(opts.setup)*) flatMap { results => all(opts.cleanup).join.map(_ => results) } } - def apply( - runners: Map[TestFramework, Runner], - tests: Vector[TestDefinition], - config: Execution, - classpath: Seq[HashedVirtualFileRef], - converter: FileConverter, - fork: ForkOptions, - log: Logger, - parallelism: Option[Int], - tags: (Tag, Int)* - ): Task[TestOutput] = { - val opts = processOptions(config, tests, log) - apply(runners, opts, config, classpath, converter, fork, log, parallelism, tags*) - } - - def apply( - runners: Map[TestFramework, Runner], - tests: Vector[TestDefinition], - config: Execution, - classpath: Seq[HashedVirtualFileRef], - converter: FileConverter, - fork: ForkOptions, - log: Logger, - parallelism: Option[Int], - tag: Tag - ): Task[TestOutput] = { - apply(runners, tests, config, classpath, converter, fork, log, parallelism, tag -> 1) - } - private def mainTestTask( runners: Map[TestFramework, Runner], opts: ProcessedOptions, @@ -103,7 +86,8 @@ private[sbt] object ForkTests: fork: ForkOptions, log: Logger, parallel: Boolean, - parallelism: Option[Int] + parallelism: Option[Int], + virtualClasspath: Boolean, ): Task[TestOutput] = std.TaskExtra.task { val testListeners = opts.testListeners.flatMap: @@ -131,8 +115,6 @@ private[sbt] object ForkTests: ArrayList(mainRunner.remoteArgs().toList.asJava) ) val g = WorkerMain.mkGson() - // virtualize classloading by using ClassLoader - val useClassLoader = true val cpList = ArrayList[FilePath]( (classpath .map: vf => @@ -146,7 +128,7 @@ private[sbt] object ForkTests: true, /* jvm */ RunInfo.JvmRunInfo( ArrayList(), - if useClassLoader then cpList else ArrayList(), + if virtualClasspath then cpList else ArrayList(), "", false /*connectInput*/, ), @@ -160,7 +142,7 @@ private[sbt] object ForkTests: testListeners.foreach(_.doInit()) val result = val ct = WorkerConnection.Tcp - val w = WorkerExchange.startWorker(fork, if useClassLoader then Nil else cpFiles, ct) + val w = WorkerExchange.startWorker(fork, if virtualClasspath then Nil else cpFiles, ct) val wl = React(randomId, log, opts.testListeners, resultsAcc, w.process) try WorkerExchange.registerListener(wl) diff --git a/main/src/main/scala/sbt/ClassLoaderLayeringStrategy.scala b/main/src/main/scala/sbt/ClassLoaderLayeringStrategy.scala index c1e1f7584..71a8a9284 100644 --- a/main/src/main/scala/sbt/ClassLoaderLayeringStrategy.scala +++ b/main/src/main/scala/sbt/ClassLoaderLayeringStrategy.scala @@ -77,6 +77,11 @@ object ClassLoaderLayeringStrategy { */ case object Flat extends ClassLoaderLayeringStrategy + /** + * Use the system loader. This applises only for forked tests. + */ + case object Raw extends ClassLoaderLayeringStrategy + /** * Add a layer for the scala library class loader. */ diff --git a/main/src/main/scala/sbt/Defaults.scala b/main/src/main/scala/sbt/Defaults.scala index 4c0ffe923..afc845b33 100644 --- a/main/src/main/scala/sbt/Defaults.scala +++ b/main/src/main/scala/sbt/Defaults.scala @@ -1573,6 +1573,7 @@ object Defaults extends BuildCommon { opts, s.log, forkedParallelism, + strategy != ClassLoaderLayeringStrategy.Raw, (Tags.ForkedTestGroup, 1) +: group.tags* ) case Tests.InProcess => diff --git a/main/src/main/scala/sbt/internal/ClassLoaders.scala b/main/src/main/scala/sbt/internal/ClassLoaders.scala index ae5a3afac..9a77c9658 100644 --- a/main/src/main/scala/sbt/internal/ClassLoaders.scala +++ b/main/src/main/scala/sbt/internal/ClassLoaders.scala @@ -159,7 +159,8 @@ private[sbt] object ClassLoaders { ): ClassLoader = { val cpFiles = fullCP.map(_._1) strategy match { - case Flat => new FlatLoader(cpFiles.urls, interfaceLoader, tmp, close, allowZombies, logger) + case Flat | Raw => + new FlatLoader(cpFiles.urls, interfaceLoader, tmp, close, allowZombies, logger) case _ => val layerDependencies = strategy match { case _: AllLibraryJars => true diff --git a/sbt-app/src/sbt-test/tests/fork-raw/build.sbt b/sbt-app/src/sbt-test/tests/fork-raw/build.sbt new file mode 100644 index 000000000..7fd48e96c --- /dev/null +++ b/sbt-app/src/sbt-test/tests/fork-raw/build.sbt @@ -0,0 +1,7 @@ +val munit = "org.scalameta" %% "munit" % "1.0.4" + +scalaVersion := "3.8.2" +libraryDependencies += munit % Test + +Test / fork := true +Test / classLoaderLayeringStrategy := ClassLoaderLayeringStrategy.Raw diff --git a/sbt-app/src/sbt-test/tests/fork-raw/changes/Good.scala b/sbt-app/src/sbt-test/tests/fork-raw/changes/Good.scala new file mode 100644 index 000000000..e7115a67b --- /dev/null +++ b/sbt-app/src/sbt-test/tests/fork-raw/changes/Good.scala @@ -0,0 +1,8 @@ +package testpkg + +import munit.* + +class ATest extends FunSuite: + test("sum"): + assert(1 + 1 == 2) +end ATest diff --git a/sbt-app/src/sbt-test/tests/fork-raw/src/test/scala/ATest.scala b/sbt-app/src/sbt-test/tests/fork-raw/src/test/scala/ATest.scala new file mode 100644 index 000000000..5023768df --- /dev/null +++ b/sbt-app/src/sbt-test/tests/fork-raw/src/test/scala/ATest.scala @@ -0,0 +1,8 @@ +package testpkg + +import munit.* + +class ATest extends FunSuite: + test("sum"): + assert(1 + 1 == 3) +end ATest diff --git a/sbt-app/src/sbt-test/tests/fork-raw/test b/sbt-app/src/sbt-test/tests/fork-raw/test new file mode 100644 index 000000000..ba0ee4d22 --- /dev/null +++ b/sbt-app/src/sbt-test/tests/fork-raw/test @@ -0,0 +1,4 @@ +-> testFull + +$ copy-file changes/Good.scala src/test/scala/ATest.scala +> testFull diff --git a/sbt-app/src/sbt-test/tests/munit/build.sbt b/sbt-app/src/sbt-test/tests/munit/build.sbt index 949e62eaa..4de5cd4df 100644 --- a/sbt-app/src/sbt-test/tests/munit/build.sbt +++ b/sbt-app/src/sbt-test/tests/munit/build.sbt @@ -1,9 +1,7 @@ -ThisBuild / scalaVersion := "2.12.21" +val munit = "org.scalameta" %% "munit" % "1.0.4" +scalaVersion := "3.8.2" -lazy val munit = "org.scalameta" %% "munit" % "0.7.22" - -lazy val root = (project in file(".")) +lazy val root = rootProject .settings( - Compile / scalacOptions += "-Yrangepos", libraryDependencies += munit % Test ) diff --git a/sbt-app/src/sbt-test/tests/munit/src/test/scala/ClueSuite.scala b/sbt-app/src/sbt-test/tests/munit/src/test/scala/ClueSuite.scala index f4e44be9a..d717bcbdb 100644 --- a/sbt-app/src/sbt-test/tests/munit/src/test/scala/ClueSuite.scala +++ b/sbt-app/src/sbt-test/tests/munit/src/test/scala/ClueSuite.scala @@ -1,8 +1,8 @@ package testpkg -import munit._ +import munit.* -class ClueSuite extends FunSuite { +class ClueSuite extends FunSuite: val x = 42 val y = 32 checkPrint( @@ -31,10 +31,10 @@ class ClueSuite extends FunSuite { options: TestOptions, clues: Clues, expected: String - )(implicit loc: Location): Unit = { + )(using loc: Location): Unit = { test(options) { val obtained = munitPrint(clues) assertNoDiff(obtained, expected) } } -} +end ClueSuite diff --git a/worker/src/main/java/sbt/internal/worker1/WorkerMain.java b/worker/src/main/java/sbt/internal/worker1/WorkerMain.java index 2a2ebf9c8..0caa6d04d 100644 --- a/worker/src/main/java/sbt/internal/worker1/WorkerMain.java +++ b/worker/src/main/java/sbt/internal/worker1/WorkerMain.java @@ -188,8 +188,13 @@ public final class WorkerMain { if (info.jvm) { RunInfo.JvmRunInfo jvmRunInfo = info.jvmRunInfo; ClassLoader parent = new ForkTestMain().getClass().getClassLoader(); - try (URLClassLoader cl = createClassLoader(jvmRunInfo, parent)) { - ForkTestMain.main(id, info, this.jsonOut, cl); + // empty virtual classpath means raw mode + if (jvmRunInfo.classpath.isEmpty()) { + ForkTestMain.main(id, info, this.jsonOut, parent); + } else { + try (URLClassLoader cl = createClassLoader(jvmRunInfo, parent)) { + ForkTestMain.main(id, info, this.jsonOut, cl); + } } } else { throw new RuntimeException("only jvm is supported");