Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
25 changes: 24 additions & 1 deletion build.mill
Original file line number Diff line number Diff line change
Expand Up @@ -112,6 +112,8 @@ object runner extends Cross[Runner](Scala.runnerScalaVersions)
with CrossScalaDefaultToRunner
object `test-runner` extends Cross[TestRunner](Scala.runnerScalaVersions)
with CrossScalaDefaultToRunner
object `java-test-runner` extends JavaTestRunner
with LocatedInModules
object `tasty-lib` extends Cross[TastyLib](Scala.scala3MainVersions)
with CrossScalaDefaultToInternal

Expand Down Expand Up @@ -452,12 +454,18 @@ trait Core extends ScalaCliCrossSbtModule
val runnerMainClass = build.runner(crossScalaVersion)
.mainClass()
.getOrElse(sys.error("No main class defined for runner"))
val javaTestRunnerMainClass = `java-test-runner`
.mainClass()
.getOrElse(sys.error("No main class defined for java-test-runner"))
val detailedVersionValue =
if (`local-repo`.developingOnStubModules) s"""Some("${vcsState()}")"""
else "None"
val testRunnerOrganization = `test-runner`(crossScalaVersion)
.pomSettings()
.organization
val javaTestRunnerOrganization = `java-test-runner`
.pomSettings()
.organization
val code =
s"""package scala.build.internal
|
Expand All @@ -479,6 +487,11 @@ trait Core extends ScalaCliCrossSbtModule
| def testRunnerVersion = "${`test-runner`(crossScalaVersion).publishVersion()}"
| def testRunnerMainClass = "$testRunnerMainClass"
|
| def javaTestRunnerOrganization = "$javaTestRunnerOrganization"
| def javaTestRunnerModuleName = "${`java-test-runner`.artifactName()}"
| def javaTestRunnerVersion = "${`java-test-runner`.publishVersion()}"
| def javaTestRunnerMainClass = "$javaTestRunnerMainClass"
|
| def runnerOrganization = "${build.runner(crossScalaVersion).pomSettings().organization}"
| def runnerModuleName = "${build.runner(crossScalaVersion).artifactName()}"
| def runnerVersion = "${build.runner(crossScalaVersion).publishVersion()}"
Expand Down Expand Up @@ -1323,6 +1336,16 @@ trait TestRunner extends CrossSbtModule
override def mainClass: T[Option[String]] = Some("scala.build.testrunner.DynamicTestRunner")
}

trait JavaTestRunner extends JavaModule
with ScalaCliPublishModule
with LocatedInModules {
override def mvnDeps: T[Seq[Dep]] = super.mvnDeps() ++ Seq(
Deps.asm,
Deps.testInterface
)
override def mainClass: T[Option[String]] = Some("scala.build.testrunner.JavaDynamicTestRunner")
}

trait TastyLib extends ScalaCliCrossSbtModule
with ScalaCliPublishModule
with ScalaCliScalafixModule
Expand Down Expand Up @@ -1357,7 +1380,7 @@ object `local-repo` extends LocalRepo {
def developingOnStubModules = false

override def stubsModules: Seq[PublishLocalNoFluff] =
Seq(runner(Scala.runnerScala3), `test-runner`(Scala.runnerScala3))
Seq(runner(Scala.runnerScala3), `test-runner`(Scala.runnerScala3), `java-test-runner`)

override def version: T[String] = runner(Scala.runnerScala3).publishVersion()
}
Expand Down
3 changes: 1 addition & 2 deletions modules/build/src/main/scala/scala/build/Build.scala
Original file line number Diff line number Diff line change
Expand Up @@ -1105,8 +1105,7 @@ object Build {
either {

val options0 =
// FIXME: don't add Scala to pure Java test builds (need to add pure Java test runner)
if sources.hasJava && !sources.hasScala && scope != Scope.Test
if sources.hasJava && !sources.hasScala
then
options.copy(
scalaOptions = options.scalaOptions.copy(
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
package scala.build.tests

import com.eed3si9n.expecty.Expecty.assert as expect

import scala.build.options.*

class JavaTestRunnerTests extends TestUtil.ScalaCliBuildSuite {

private def makeOptions(
scalaVersionOpt: Option[MaybeScalaVersion],
addTestRunner: Boolean
): BuildOptions =
BuildOptions(
scalaOptions = ScalaOptions(
scalaVersion = scalaVersionOpt
),
internalDependencies = InternalDependenciesOptions(
addTestRunnerDependencyOpt = Some(addTestRunner)
)
)

test("pure Java build has no scalaParams") {
val opts = makeOptions(Some(MaybeScalaVersion.none), addTestRunner = false)
val params = opts.scalaParams.toOption.flatten
expect(params.isEmpty, "Pure Java build should have no scalaParams")
}

test("Scala build has scalaParams") {
val opts = makeOptions(None, addTestRunner = false)
val params = opts.scalaParams.toOption.flatten
expect(params.isDefined, "Scala build should have scalaParams")
}

test("pure Java test build gets addJvmJavaTestRunner=true in Artifacts params") {
val opts = makeOptions(Some(MaybeScalaVersion.none), addTestRunner = true)
val isJava = opts.scalaParams.toOption.flatten.isEmpty
expect(isJava, "Expected pure Java build to have no scalaParams")
}

test("Scala test build gets addJvmTestRunner=true in Artifacts params") {
val opts = makeOptions(None, addTestRunner = true)
val isJava = opts.scalaParams.toOption.flatten.isEmpty
expect(!isJava, "Expected Scala build to have scalaParams")
}

test("mixed Scala+Java build still gets Scala test runner") {
val opts = makeOptions(None, addTestRunner = true)
val isJava = opts.scalaParams.toOption.flatten.isEmpty
expect(!isJava, "Mixed Scala+Java build should still use Scala test runner")
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -256,11 +256,16 @@ object Test extends ScalaCommand[TestOptions] {
testOnly.map(to => s"--test-only=$to").toSeq ++
Seq("--") ++ args

val testRunnerMainClass =
if build.artifacts.hasJavaTestRunner
then Constants.javaTestRunnerMainClass
else Constants.testRunnerMainClass

Runner.runJvm(
build.options.javaHome().value.javaCommand,
build.options.javaOptions.javaOpts.toSeq.map(_.value.value),
classPath,
Constants.testRunnerMainClass,
testRunnerMainClass,
extraArgs,
logger,
allowExecve = allowExecve
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2510,4 +2510,24 @@ abstract class RunTestDefinitions
processes.foreach { case (p, _) => expect(p.exitCode() == 0) }
}
}

test("pure Java run has no Scala on classpath") {
TestInputs(
os.rel / "Main.java" ->
"""public class Main {
| public static void main(String[] args) {
| try {
| Class.forName("scala.Predef");
| throw new RuntimeException("Scala should not be on the classpath");
| } catch (ClassNotFoundException e) {
| System.out.println("No Scala on classpath!");
| }
| }
|}
|""".stripMargin
).fromRoot { root =>
val res = os.proc(TestUtil.cli, "run", extraOptions, ".").call(cwd = root)
expect(res.out.text().contains("No Scala on classpath!"))
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -857,6 +857,63 @@ abstract class TestTestDefinitions extends ScalaCliSuite with TestScalaVersionAr
}
}

test("pure Java test with JUnit has no Scala on classpath") {
TestInputs(
os.rel / "test" / "MyTests.java" ->
"""//> using test.dep junit:junit:4.13.2
|//> using test.dep com.novocode:junit-interface:0.11
|import org.junit.Test;
|import static org.junit.Assert.assertEquals;
|
|public class MyTests {
| @Test
| public void foo() {
| try {
| Class.forName("scala.Predef");
| throw new AssertionError("Scala should not be on the classpath");
| } catch (ClassNotFoundException e) {
| // expected
| }
| assertEquals(4, 2 + 2);
| System.out.println("No Scala on classpath!");
| }
|}
|""".stripMargin
).fromRoot { root =>
val res = os.proc(TestUtil.cli, "test", extraOptions, ".").call(cwd = root)
expect(res.out.text().contains("No Scala on classpath!"))
}
}

test("pure Java test with JUnit and --server=false has no Scala on classpath") {
TestInputs(
os.rel / "test" / "MyTests.java" ->
"""//> using test.dep junit:junit:4.13.2
|//> using test.dep com.novocode:junit-interface:0.11
|import org.junit.Test;
|import static org.junit.Assert.assertEquals;
|
|public class MyTests {
| @Test
| public void foo() {
| try {
| Class.forName("scala.Predef");
| throw new AssertionError("Scala should not be on the classpath");
| } catch (ClassNotFoundException e) {
| // expected
| }
| assertEquals(4, 2 + 2);
| System.out.println("No Scala on classpath (no server)!");
| }
|}
|""".stripMargin
).fromRoot { root =>
val res =
os.proc(TestUtil.cli, "test", "--server=false", extraOptions, ".").call(cwd = root)
expect(res.out.text().contains("No Scala on classpath (no server)!"))
}
}

test(s"zio-test warning when zio-test-sbt was not passed") {
TestUtil.retryOnCi() {
val expectedMessage = "Hello from zio"
Expand Down
Loading
Loading