diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index d23d3cb69f4..53ae2583afd 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -57,6 +57,7 @@ jobs: sbt, maven, gradle, + scalacli, mill, feature, cross, @@ -89,6 +90,10 @@ jobs: command: bin/test.sh 'slow/testOnly -- tests.mill.*' name: Mill integration os: ubuntu-latest + - type: scalacli + command: bin/test.sh 'slow/testOnly -- tests.scalacli.*' + name: Scala CLI integration + os: ubuntu-latest - type: feature command: bin/test.sh 'slow/testOnly -- tests.feature.*' name: LSP integration tests diff --git a/project/V.scala b/project/V.scala index 54a4ff155d0..6cc478c1267 100644 --- a/project/V.scala +++ b/project/V.scala @@ -34,7 +34,7 @@ object V { val pprint = "0.7.3" val sbtBloop = bloop val sbtJdiTools = "1.1.1" - val scalaCli = "0.2.1" + val scalaCli = "1.0.1" val scalafix = "0.11.0" val scalafmt = "3.7.4" val scalameta = "4.7.8" diff --git a/tests/slow/src/main/scala/tests/scalacli/BaseScalaCLIActionSuite.scala b/tests/slow/src/main/scala/tests/scalacli/BaseScalaCLIActionSuite.scala new file mode 100644 index 00000000000..2db12d19a3f --- /dev/null +++ b/tests/slow/src/main/scala/tests/scalacli/BaseScalaCLIActionSuite.scala @@ -0,0 +1,62 @@ +package tests.scalacli + +import munit.Location +import munit.TestOptions +import org.eclipse.lsp4j.CodeAction +import tests.codeactions.BaseCodeActionLspSuite + +class BaseScalaCLIActionSuite(name: String) + extends BaseCodeActionLspSuite(name) { + + def checkScalaCLI( + name: TestOptions, + input: String, + expectedActions: String, + expectedCode: String, + selectedActionIndex: Int = 0, + expectNoDiagnostics: Boolean = true, + kind: List[String] = Nil, + scalafixConf: String = "", + scalacOptions: List[String] = Nil, + scalaCliOptions: List[String] = Nil, + configuration: => Option[String] = None, + scalaVersion: String = scalaVersion, + renamePath: Option[String] = None, + extraOperations: => Unit = (), + fileName: String = "A.scala", + changeFile: String => String = identity, + expectError: Boolean = false, + filterAction: CodeAction => Boolean = _ => true, + )(implicit loc: Location): Unit = { + + val path = toPath(fileName) + val layout = Some( + s"""/.bsp/scala-cli.json + |${BaseScalaCliSuite.scalaCliBspJsonContent(scalaCliOptions)} + |/.scala-build/ide-inputs.json + |${BaseScalaCliSuite.scalaCliIdeInputJson(".")} + |/$path + |$input""".stripMargin + ) + super.check( + name, + input, + expectedActions, + expectedCode, + selectedActionIndex, + expectNoDiagnostics, + kind, + scalafixConf, + scalacOptions, + configuration, + scalaVersion, + renamePath, + extraOperations, + fileName, + changeFile, + expectError, + filterAction, + overrideLayout = layout, + ) + } +} diff --git a/tests/slow/src/main/scala/tests/scalacli/BaseScalaCliSuite.scala b/tests/slow/src/main/scala/tests/scalacli/BaseScalaCliSuite.scala new file mode 100644 index 00000000000..927f3ea140d --- /dev/null +++ b/tests/slow/src/main/scala/tests/scalacli/BaseScalaCliSuite.scala @@ -0,0 +1,166 @@ +package tests.scalacli + +import java.io.File +import java.nio.file.Files +import java.util.concurrent.Executors +import java.util.concurrent.TimeoutException + +import scala.concurrent.Future +import scala.concurrent.Promise +import scala.concurrent.duration._ + +import scala.meta.internal.metals.BuildInfo +import scala.meta.internal.metals.Messages +import scala.meta.internal.metals.scalacli.ScalaCli + +import ch.epfl.scala.bsp4j.MessageType +import org.eclipse.lsp4j.InitializeResult +import org.eclipse.lsp4j.MessageActionItem +import tests.BaseLspSuite +import tests.ScriptsAssertions + +abstract class BaseScalaCliSuite(protected val scalaVersion: String) + extends BaseLspSuite(s"scala-cli-$scalaVersion") + with ScriptsAssertions { + + private val scheduler = Executors.newSingleThreadScheduledExecutor() + + private def timeout( + message: String, + duration: FiniteDuration, + ): Future[Unit] = { + val p = Promise[Unit]() + val r: Runnable = { () => + p.failure(new TimeoutException(message)) + } + scheduler.schedule(r, duration.length, duration.unit) + p.future + } + + override def afterAll(): Unit = { + super.afterAll() + scheduler.shutdown() + } + + override def munitIgnore: Boolean = + !isValidScalaVersionForEnv(scalaVersion) + + private var importedPromise = Promise[Unit]() + + override def newServer(workspaceName: String): Unit = { + super.newServer(workspaceName) + val previousShowMessageHandler = server.client.showMessageHandler + server.client.showMessageHandler = { params => + if (params == Messages.ImportScalaScript.ImportedScalaCli) + importedPromise.success(()) + else if ( + params.getType == MessageType.ERROR && params.getMessage.startsWith( + "Error importing Scala CLI project " + ) + ) + importedPromise.failure( + new Exception(s"Error importing project: $params") + ) + else + previousShowMessageHandler(params) + } + val previousShowMessageRequestHandler = + server.client.showMessageRequestHandler + server.client.showMessageRequestHandler = { params => + def useBsp = Files.exists( + server.server.folder + .resolve(".bsp/scala-cli.json") + .toNIO + ) + if (params == Messages.ImportScalaScript.params()) + Some( + new MessageActionItem( + if (useBsp) + Messages.ImportScalaScript.dismiss + else + Messages.ImportScalaScript.doImportScalaCli + ) + ) + else if (params == Messages.ImportAllScripts.params()) + Some( + new MessageActionItem( + if (useBsp) + Messages.ImportAllScripts.dismiss + else + Messages.ImportAllScripts.importAll + ) + ) + else + previousShowMessageRequestHandler(params) + } + } + + protected def manualLayout: String = + s"""/metals.json + |{ + | "a": { + | "scalaVersion": "$scalaVersion" + | } + |} + | + |""".stripMargin + + protected def bspLayout: String = + s"""/.bsp/scala-cli.json + |${BaseScalaCliSuite.scalaCliBspJsonContent()} + | + |/.scala-build/ide-inputs.json + |${BaseScalaCliSuite.scalaCliIdeInputJson(".")} + | + |""".stripMargin + + protected def scalaCliInitialize( + useBsp: Boolean + )(layout: String): Future[InitializeResult] = { + if (!useBsp) + importedPromise = Promise[Unit]() + initialize( + (if (useBsp) bspLayout else manualLayout) + layout + ) + } + + protected def waitForImport(useBsp: Boolean): Future[Unit] = + if (useBsp) Future.successful(()) + else + Future + .firstCompletedOf( + List( + importedPromise.future, + timeout("import timeout", 180.seconds), + ) + ) + +} + +object BaseScalaCliSuite { + def scalaCliBspJsonContent(args: List[String] = Nil): String = { + val argv = List( + ScalaCli.javaCommand, + "-cp", + ScalaCli.scalaCliClassPath().mkString(File.pathSeparator), + ScalaCli.scalaCliMainClass, + "bsp", + ".", + ) ++ args + val bsjJson = ujson.Obj( + "name" -> "scala-cli", + "argv" -> argv, + "version" -> BuildInfo.scalaCliVersion, + "bspVersion" -> "2.0.0", + "languages" -> List("scala", "java"), + ) + ujson.write(bsjJson) + } + + def scalaCliIdeInputJson(args: String*): String = { + val ideInputJson = ujson.Obj( + "args" -> args + ) + ujson.write(ideInputJson) + } +} diff --git a/tests/slow/src/main/scala/tests/scalacli/ScalaCliBuildLayout.scala b/tests/slow/src/main/scala/tests/scalacli/ScalaCliBuildLayout.scala new file mode 100644 index 00000000000..ee4241c5759 --- /dev/null +++ b/tests/slow/src/main/scala/tests/scalacli/ScalaCliBuildLayout.scala @@ -0,0 +1,17 @@ +package tests.scalacli + +import tests.BuildToolLayout + +object ScalaCliBuildLayout extends BuildToolLayout { + override def apply( + sourceLayout: String, + scalaVersion: String, + ): String = { + s"""/.bsp/scala-cli.json + |${BaseScalaCliSuite.scalaCliBspJsonContent(List("-S", scalaVersion))} + |/.scala-build/ide-inputs.json + |${BaseScalaCliSuite.scalaCliIdeInputJson(".")} + |$sourceLayout + |""".stripMargin + } +} diff --git a/tests/slow/src/test/scala/tests/feature/CrossCodeLensLspSuite.scala b/tests/slow/src/test/scala/tests/feature/CrossCodeLensLspSuite.scala index 363a9cec13e..1d489ad5488 100644 --- a/tests/slow/src/test/scala/tests/feature/CrossCodeLensLspSuite.scala +++ b/tests/slow/src/test/scala/tests/feature/CrossCodeLensLspSuite.scala @@ -3,7 +3,6 @@ package tests.feature import scala.meta.internal.metals.{BuildInfo => V} import tests.BaseCodeLensLspSuite -import tests.ScalaCliBuildLayout class CrossCodeLensLspSuite extends BaseCodeLensLspSuite("cross-code-lens") { @@ -118,32 +117,4 @@ class CrossCodeLensLspSuite extends BaseCodeLensLspSuite("cross-code-lens") { } yield () } - test("run-main-annotation-with-script") { - cleanWorkspace() - val path = "main.sc" - for { - _ <- initialize( - ScalaCliBuildLayout( - s"""|/$path - |val x = 3 - | - |@main def main() = { - | println("annotation") - |}""".stripMargin, - V.scala3, - ) - ) - _ <- server.didOpen(path) - _ <- assertCodeLenses( - path, - """|<><> - |val x = 3 - | - |<><> - |@main def main() = { - | println("annotation") - |}""".stripMargin, - ) - } yield () - } } diff --git a/tests/unit/src/test/scala/tests/debug/BreakpointScalaCliDapSuite.scala b/tests/slow/src/test/scala/tests/scalacli/BreakpointScalaCliDapSuite.scala similarity index 96% rename from tests/unit/src/test/scala/tests/debug/BreakpointScalaCliDapSuite.scala rename to tests/slow/src/test/scala/tests/scalacli/BreakpointScalaCliDapSuite.scala index 2ca6a23472e..9f32911a12e 100644 --- a/tests/unit/src/test/scala/tests/debug/BreakpointScalaCliDapSuite.scala +++ b/tests/slow/src/test/scala/tests/scalacli/BreakpointScalaCliDapSuite.scala @@ -1,11 +1,10 @@ -package tests.debug +package tests.scalacli import scala.meta.internal.metals.DebugUnresolvedMainClassParams import scala.meta.internal.metals.JsonParser._ import tests.BaseDapSuite import tests.QuickBuildInitializer -import tests.ScalaCliBuildLayout class BreakpointScalaCliDapSuite extends BaseDapSuite( diff --git a/tests/slow/src/test/scala/tests/scalacli/CodeLensesScalaCliSuite.scala b/tests/slow/src/test/scala/tests/scalacli/CodeLensesScalaCliSuite.scala new file mode 100644 index 00000000000..6fd27408f4f --- /dev/null +++ b/tests/slow/src/test/scala/tests/scalacli/CodeLensesScalaCliSuite.scala @@ -0,0 +1,38 @@ +package tests.scalacli + +import scala.meta.internal.metals.{BuildInfo => V} + +import tests.BaseCodeLensLspSuite + +class CodeLensesScalaCliSuite + extends BaseCodeLensLspSuite("cross-code-lens-scalacli") { + + test("run-main-annotation-with-script") { + cleanWorkspace() + val path = "main.sc" + for { + _ <- initialize( + ScalaCliBuildLayout( + s"""|/$path + |val x = 3 + | + |def main() = { + | println("annotation") + |}""".stripMargin, + V.scala3, + ) + ) + _ <- server.didOpen(path) + _ <- assertCodeLenses( + path, + """|<><> + |val x = 3 + | + |def main() = { + | println("annotation") + |}""".stripMargin, + ) + } yield () + } + +} diff --git a/tests/unit/src/test/scala/tests/codeactions/MillifyScalaCliDependencyCodeActionSuite.scala b/tests/slow/src/test/scala/tests/scalacli/MillifyScalaCliDependencyCodeActionSuite.scala similarity index 85% rename from tests/unit/src/test/scala/tests/codeactions/MillifyScalaCliDependencyCodeActionSuite.scala rename to tests/slow/src/test/scala/tests/scalacli/MillifyScalaCliDependencyCodeActionSuite.scala index 10e0caba0e9..ebdaea59e98 100644 --- a/tests/unit/src/test/scala/tests/codeactions/MillifyScalaCliDependencyCodeActionSuite.scala +++ b/tests/slow/src/test/scala/tests/scalacli/MillifyScalaCliDependencyCodeActionSuite.scala @@ -1,16 +1,16 @@ -package tests.codeactions +package tests.scalacli import scala.meta.internal.metals.BuildInfo class MillifyScalaCliDependencyCodeActionSuite - extends BaseCodeActionLspSuite("millifyScalaCliDependency") { + extends BaseScalaCLIActionSuite("millifyScalaCliDependency") { val sbtStyleDependency = """"org.scalameta" %% "munit" % "0.7.26"""" val convertedDependency = """"org.scalameta::munit:0.7.26"""" val convertTo: String = s"""//> using lib $convertedDependency""" - check( + checkScalaCLI( "convert-dependency", s"""|//> <<>>using lib $sbtStyleDependency | @@ -27,13 +27,12 @@ class MillifyScalaCliDependencyCodeActionSuite |""".stripMargin, scalaCliOptions = List("--actions", "-S", scalaVersion), expectNoDiagnostics = false, - scalaCliLayout = true, ) val sbtStyleDependencyMultiSpace = """ "org.scalameta" %% "munit" % "0.7.26"""" - check( + checkScalaCLI( "convert-dependency-multiple-whitespace", s"""|//> <<>>using lib $sbtStyleDependencyMultiSpace | @@ -48,12 +47,10 @@ class MillifyScalaCliDependencyCodeActionSuite | println("Hello") |} |""".stripMargin, - scalaCliOptions = List("--actions", "-S", scalaVersion), expectNoDiagnostics = false, - scalaCliLayout = true, ) - check( + checkScalaCLI( "convert-dependency-multiple", s"""|//> using scala "${BuildInfo.scala213}" |//> <<>>using lib $sbtStyleDependencyMultiSpace @@ -70,9 +67,7 @@ class MillifyScalaCliDependencyCodeActionSuite | println("Hello") |} |""".stripMargin, - scalaCliOptions = List("--actions", "-S", scalaVersion), expectNoDiagnostics = false, - scalaCliLayout = true, ) } diff --git a/tests/unit/src/test/scala/tests/codeactions/ScalaCliActionsSuite.scala b/tests/slow/src/test/scala/tests/scalacli/ScalaCliActionsSuite.scala similarity index 92% rename from tests/unit/src/test/scala/tests/codeactions/ScalaCliActionsSuite.scala rename to tests/slow/src/test/scala/tests/scalacli/ScalaCliActionsSuite.scala index 51e34820635..8534289ae90 100644 --- a/tests/unit/src/test/scala/tests/codeactions/ScalaCliActionsSuite.scala +++ b/tests/slow/src/test/scala/tests/scalacli/ScalaCliActionsSuite.scala @@ -1,4 +1,4 @@ -package tests.codeactions +package tests.scalacli import scala.meta.internal.metals.BuildInfo import scala.meta.internal.metals.codeactions.CreateNewSymbol @@ -9,7 +9,7 @@ import scala.meta.internal.mtags.CoursierComplete import coursier.version.Version class ScalaCliActionsSuite - extends BaseCodeActionLspSuite("actionableDiagnostic") { + extends BaseScalaCLIActionSuite("actionableDiagnostic") { val oldOsLibVersion: Version = Version("0.7.8") val coursierComplete = new CoursierComplete(scalaCompilerVersion) @@ -18,7 +18,7 @@ class ScalaCliActionsSuite .headOption .getOrElse("0.8.1") - check( + checkScalaCLI( "actionable-diagnostic-update", s"""|//> <<>>using lib "com.lihaoyi::os-lib:${oldOsLibVersion.repr}" | @@ -35,10 +35,9 @@ class ScalaCliActionsSuite |""".stripMargin, scalaCliOptions = List("--actions", "-S", scalaVersion), expectNoDiagnostics = false, - scalaCliLayout = true, ) - check( + checkScalaCLI( "auto-import", s"""|//> using scala "${BuildInfo.scala213}" |//> using lib "org.typelevel::cats-core:2.9.0" @@ -61,7 +60,6 @@ class ScalaCliActionsSuite |""".stripMargin, scalaCliOptions = List("--actions", "-S", scalaVersion), expectNoDiagnostics = false, - scalaCliLayout = true, fileName = "A.sc", ) diff --git a/tests/slow/src/test/scala/tests/scalacli/ScalaCliCodeLensesSuite.scala b/tests/slow/src/test/scala/tests/scalacli/ScalaCliCodeLensesSuite.scala new file mode 100644 index 00000000000..1da30aa2e4f --- /dev/null +++ b/tests/slow/src/test/scala/tests/scalacli/ScalaCliCodeLensesSuite.scala @@ -0,0 +1,53 @@ +package tests.scalacli + +import tests.BaseCodeLensLspSuite + +class ScalaCliCodeLensesSuite + extends BaseCodeLensLspSuite("scala-cli-code-lenses") { + + private val scalaCliScriptPath = "a/src/main/scala/a/main.sc" + test("run-script") { + cleanWorkspace() + for { + + _ <- initialize( + s"""/.bsp/scala-cli.json + |${BaseScalaCliSuite.scalaCliBspJsonContent()} + |/.scala-build/ide-inputs.json + |${BaseScalaCliSuite.scalaCliIdeInputJson(".")} + |/$scalaCliScriptPath + |print("oranges are nice")""".stripMargin + ) + _ <- server.didOpen(scalaCliScriptPath) + _ <- assertCodeLenses( + scalaCliScriptPath, + """|<><> + |print("oranges are nice") + |""".stripMargin, + ) + } yield () + } + + private val scalaCliScriptPathTop = "main.sc" + test("run-script-top") { + cleanWorkspace() + for { + + _ <- initialize( + s"""/.bsp/scala-cli.json + |${BaseScalaCliSuite.scalaCliBspJsonContent()} + |/.scala-build/ide-inputs.json + |${BaseScalaCliSuite.scalaCliIdeInputJson(".")} + |/$scalaCliScriptPathTop + |print("oranges are nice")""".stripMargin + ) + _ <- server.didOpen(scalaCliScriptPathTop) + _ <- assertCodeLenses( + scalaCliScriptPathTop, + """|<><> + |print("oranges are nice") + |""".stripMargin, + ) + } yield () + } +} diff --git a/tests/slow/src/test/scala/tests/scalacli/ScalaCliDebugSuite.scala b/tests/slow/src/test/scala/tests/scalacli/ScalaCliDebugSuite.scala new file mode 100644 index 00000000000..a497e1d855b --- /dev/null +++ b/tests/slow/src/test/scala/tests/scalacli/ScalaCliDebugSuite.scala @@ -0,0 +1,45 @@ +package tests.scalacli + +import java.util.concurrent.TimeUnit + +import scala.meta.internal.metals.DebugDiscoveryParams +import scala.meta.internal.metals.JsonParser._ + +import tests.BaseDapSuite +import tests.QuickBuildInitializer + +class ScalaCliDebugSuite + extends BaseDapSuite( + "scala-cli-debug", + QuickBuildInitializer, + ScalaCliBuildLayout, + ) { + + private val scalaCliScriptPath = "a/src/main/scala/a/main.sc" + test("run-scala-cli-script") { + for { + _ <- initialize( + s"""/.bsp/scala-cli.json + |${BaseScalaCliSuite.scalaCliBspJsonContent()} + |/.scala-build/ide-inputs.json + |${BaseScalaCliSuite.scalaCliIdeInputJson(".")} + |/$scalaCliScriptPath + |print("oranges are nice")""".stripMargin + ) + _ <- server.didOpen(scalaCliScriptPath) + _ <- server.waitFor(TimeUnit.SECONDS.toMillis(10)) + debugger <- server.startDebuggingUnresolved( + DebugDiscoveryParams( + server.toPath(scalaCliScriptPath).toURI.toString, + "run", + ).toJson + ) + _ <- debugger.initialize + _ <- debugger.launch + _ <- debugger.configurationDone + _ <- debugger.shutdown + output <- debugger.allOutput + } yield assertNoDiff(output, "oranges are nice") + } + +} diff --git a/tests/unit/src/main/scala/tests/BaseScalaCliSuite.scala b/tests/slow/src/test/scala/tests/scalacli/ScalaCliSuite.scala similarity index 51% rename from tests/unit/src/main/scala/tests/BaseScalaCliSuite.scala rename to tests/slow/src/test/scala/tests/scalacli/ScalaCliSuite.scala index 8b91701dc5a..5020b25ef7f 100644 --- a/tests/unit/src/main/scala/tests/BaseScalaCliSuite.scala +++ b/tests/slow/src/test/scala/tests/scalacli/ScalaCliSuite.scala @@ -1,193 +1,15 @@ -package tests - -import java.io.File -import java.nio.file.Files -import java.util.concurrent.Executors -import java.util.concurrent.TimeoutException +package tests.scalacli import scala.concurrent.Future -import scala.concurrent.Promise -import scala.concurrent.duration._ -import scala.meta.internal.metals.BuildInfo -import scala.meta.internal.metals.Messages import scala.meta.internal.metals.ServerCommands -import scala.meta.internal.metals.scalacli.ScalaCli - -import ch.epfl.scala.bsp4j.MessageType -import org.eclipse.lsp4j.InitializeResult -import org.eclipse.lsp4j.MessageActionItem - -abstract class BaseScalaCliSuite(scalaVersion: String) - extends BaseLspSuite(s"scala-cli-$scalaVersion") - with ScriptsAssertions { - - private val scheduler = Executors.newSingleThreadScheduledExecutor() - - private def timeout( - message: String, - duration: FiniteDuration, - ): Future[Unit] = { - val p = Promise[Unit]() - val r: Runnable = { () => - p.failure(new TimeoutException(message)) - } - scheduler.schedule(r, duration.length, duration.unit) - p.future - } - - override def afterAll(): Unit = { - super.afterAll() - scheduler.shutdown() - } +import scala.meta.internal.metals.{BuildInfo => V} - override def munitIgnore: Boolean = - !isValidScalaVersionForEnv(scalaVersion) +import tests.FileLayout - private var importedPromise = Promise[Unit]() - - override def newServer(workspaceName: String): Unit = { - super.newServer(workspaceName) - val previousShowMessageHandler = server.client.showMessageHandler - server.client.showMessageHandler = { params => - if (params == Messages.ImportScalaScript.ImportedScalaCli) - importedPromise.success(()) - else if ( - params.getType == MessageType.ERROR && params.getMessage.startsWith( - "Error importing Scala CLI project " - ) - ) - importedPromise.failure( - new Exception(s"Error importing project: $params") - ) - else - previousShowMessageHandler(params) - } - val previousShowMessageRequestHandler = - server.client.showMessageRequestHandler - server.client.showMessageRequestHandler = { params => - def useBsp = Files.exists( - server.server.folder - .resolve(".bsp/scala-cli.json") - .toNIO - ) - if (params == Messages.ImportScalaScript.params()) - Some( - new MessageActionItem( - if (useBsp) - Messages.ImportScalaScript.dismiss - else - Messages.ImportScalaScript.doImportScalaCli - ) - ) - else if (params == Messages.ImportAllScripts.params()) - Some( - new MessageActionItem( - if (useBsp) - Messages.ImportAllScripts.dismiss - else - Messages.ImportAllScripts.importAll - ) - ) - else - previousShowMessageRequestHandler(params) - } - } - - private def manualLayout = - s"""/metals.json - |{ - | "a": { - | "scalaVersion": "$scalaVersion" - | } - |} - | - |""".stripMargin - private def bspLayout = - s"""/.bsp/scala-cli.json - |${BaseScalaCliSuite.scalaCliBspJsonContent()} - | - |/.scala-build/ide-inputs.json - |${BaseScalaCliSuite.scalaCliIdeInputJson(".")} - | - |""".stripMargin - - private def scalaCliInitialize( - useBsp: Boolean - )(layout: String): Future[InitializeResult] = { - if (!useBsp) - importedPromise = Promise[Unit]() - initialize( - (if (useBsp) bspLayout else manualLayout) + layout - ) - } - - private def waitForImport(useBsp: Boolean): Future[Unit] = - if (useBsp) Future.successful(()) - else - Future - .firstCompletedOf( - List( - importedPromise.future, - timeout("import timeout", 180.seconds), - ) - ) - - for (useBsp <- Seq(true, false)) { - val message = if (useBsp) "BSP" else "manual" - test(s"simple file $message") { - simpleFileTest(useBsp) - } - test(s"simple script $message") { - simpleScriptTest(useBsp) - } - } - - private val simpleFileLayout = - s"""|/MyTests.scala - |//> using scala "$scalaVersion" - |//> using lib "com.lihaoyi::utest::0.7.9" - |//> using lib "com.lihaoyi::pprint::0.6.4" - | - |import foo.Foo - |import utest._ - | - |object MyTests extends TestSuite { - | pprint.log(2) - | val tests = Tests { - | test("foo") { - | assert(2 + 2 == 4) - | } - | test("nope") { - | assert(2 + 2 == (new Foo).value) - | } - | } - |} - | - |/foo.sc - |class Foo { - | def value = 5 - |} - |""".stripMargin +class ScalaCliSuite extends BaseScalaCliSuite(V.scala3) { - test("connecting-scalacli") { - cleanWorkspace() - for { - _ <- server.initialize() - _ <- server.initialized() - _ = FileLayout.fromString(simpleFileLayout, workspace) - _ = FileLayout.fromString(bspLayout, workspace) - _ <- server.server.indexingPromise.future - _ <- server.didOpen("MyTests.scala") - _ <- assertDefinitionAtLocation( - "MyTests.scala", - "val tests = Test@@s", - "utest/Tests.scala", - ) - } yield () - } - - def simpleFileTest(useBsp: Boolean): Future[Unit] = + private def simpleFileTest(useBsp: Boolean): Future[Unit] = for { _ <- scalaCliInitialize(useBsp)(simpleFileLayout) _ <- server.didOpen("MyTests.scala") @@ -226,18 +48,18 @@ abstract class BaseScalaCliSuite(scalaVersion: String) } yield () - def simpleScriptTest(useBsp: Boolean): Future[Unit] = + private def simpleScriptTest(useBsp: Boolean): Future[Unit] = for { _ <- scalaCliInitialize(useBsp)( s"""/MyTests.sc |#!/usr/bin/env -S scala-cli shebang --java-opt -Xms256m --java-opt -XX:MaxRAMPercentage=80 |//> using scala "$scalaVersion" - |//> using lib "com.lihaoyi::utest::0.7.9" - |//> using lib "com.lihaoyi::pprint::0.6.4" + |//> using lib "com.lihaoyi::utest::0.7.10" + |//> using lib "com.lihaoyi::pprint::0.6.6" | |import foo.Foo |import utest._ - | + | |pprint.log(2) // top-level statement should be fine in a script | |object MyTests extends TestSuite { @@ -301,13 +123,73 @@ abstract class BaseScalaCliSuite(scalaVersion: String) } yield () + private val simpleFileLayout = + s"""|/MyTests.scala + |//> using scala "$scalaVersion" + |//> using lib "com.lihaoyi::utest::0.7.10" + |//> using lib "com.lihaoyi::pprint::0.6.6" + | + |import foo.Foo + |import utest._ + | + |object MyTests extends TestSuite { + | pprint.log(2) + | val tests = Tests { + | test("foo") { + | assert(2 + 2 == 4) + | } + | test("nope") { + | assert(2 + 2 == (new Foo).value) + | } + | } + |} + | + |/foo.sc + |class Foo { + | def value = 5 + |} + |""".stripMargin + + test(s"simple-file-bsp") { + simpleFileTest(useBsp = true) + } + + test(s"simple-file-manual") { + simpleFileTest(useBsp = false) + } + + test(s"simple-script-bsp") { + simpleScriptTest(useBsp = true) + } + + test(s"simple-script-manual") { + simpleScriptTest(useBsp = false) + } + + test("connecting-scalacli") { + cleanWorkspace() + for { + _ <- server.initialize() + _ <- server.initialized() + _ = FileLayout.fromString(simpleFileLayout, workspace) + _ = FileLayout.fromString(bspLayout, workspace) + _ <- server.server.indexingPromise.future + _ <- server.didOpen("MyTests.scala") + _ <- assertDefinitionAtLocation( + "MyTests.scala", + "val tests = Test@@s", + "utest/Tests.scala", + ) + } yield () + } + test("relative-semanticdb-root") { for { _ <- scalaCliInitialize(useBsp = false)( s"""/scripts/MyTests.scala |//> using scala "$scalaVersion" - |//> using lib "com.lihaoyi::utest::0.7.9" - |//> using lib "com.lihaoyi::pprint::0.6.4" + |//> using lib "com.lihaoyi::utest::0.7.10" + |//> using lib "com.lihaoyi::pprint::0.6.6" | |import foo.Foo |import utest._ @@ -342,32 +224,5 @@ abstract class BaseScalaCliSuite(scalaVersion: String) ) } yield () } -} -object BaseScalaCliSuite { - def scalaCliBspJsonContent(args: List[String] = Nil): String = { - val argv = List( - ScalaCli.javaCommand, - "-cp", - ScalaCli.scalaCliClassPath().mkString(File.pathSeparator), - ScalaCli.scalaCliMainClass, - "bsp", - ".", - ) ++ args - val bsjJson = ujson.Obj( - "name" -> "scala-cli", - "argv" -> argv, - "version" -> BuildInfo.scalaCliVersion, - "bspVersion" -> "2.0.0", - "languages" -> List("scala", "java"), - ) - ujson.write(bsjJson) - } - - def scalaCliIdeInputJson(args: String*): String = { - val ideInputJson = ujson.Obj( - "args" -> args - ) - ujson.write(ideInputJson) - } } diff --git a/tests/unit/src/main/scala/tests/BuildServerLayout.scala b/tests/unit/src/main/scala/tests/BuildServerLayout.scala index 3aa49922e31..1f4b7aea8bf 100644 --- a/tests/unit/src/main/scala/tests/BuildServerLayout.scala +++ b/tests/unit/src/main/scala/tests/BuildServerLayout.scala @@ -2,7 +2,7 @@ package tests import scala.meta.internal.metals.{BuildInfo => V} -sealed trait BuildToolLayout { +trait BuildToolLayout { def apply(sourceLayout: String, scalaVersion: String): String } @@ -20,20 +20,6 @@ object QuickBuildLayout extends BuildToolLayout { } } -object ScalaCliBuildLayout extends BuildToolLayout { - override def apply( - sourceLayout: String, - scalaVersion: String, - ): String = { - s"""/.bsp/scala-cli.json - |${BaseScalaCliSuite.scalaCliBspJsonContent(List("-S", scalaVersion))} - |/.scala-build/ide-inputs.json - |${BaseScalaCliSuite.scalaCliIdeInputJson(".")} - |$sourceLayout - |""".stripMargin - } -} - object SbtBuildLayout extends BuildToolLayout { val commonSbtSettings: String = """|import scala.concurrent.duration._ diff --git a/tests/unit/src/main/scala/tests/codeactions/BaseCodeActionLspSuite.scala b/tests/unit/src/main/scala/tests/codeactions/BaseCodeActionLspSuite.scala index 0e3c2b2a863..5d59d19dbfb 100644 --- a/tests/unit/src/main/scala/tests/codeactions/BaseCodeActionLspSuite.scala +++ b/tests/unit/src/main/scala/tests/codeactions/BaseCodeActionLspSuite.scala @@ -9,7 +9,6 @@ import munit.Location import munit.TestOptions import org.eclipse.lsp4j.CodeAction import tests.BaseLspSuite -import tests.BaseScalaCliSuite import tests.FileLayout abstract class BaseCodeActionLspSuite( @@ -39,6 +38,8 @@ abstract class BaseCodeActionLspSuite( ) } + protected def toPath(fileName: String): String = + s"a/src/main/scala/a/$fileName" def check( name: TestOptions, input: String, @@ -49,7 +50,6 @@ abstract class BaseCodeActionLspSuite( kind: List[String] = Nil, scalafixConf: String = "", scalacOptions: List[String] = Nil, - scalaCliOptions: List[String] = Nil, configuration: => Option[String] = None, scalaVersion: String = scalaVersion, renamePath: Option[String] = None, @@ -58,28 +58,20 @@ abstract class BaseCodeActionLspSuite( changeFile: String => String = identity, expectError: Boolean = false, filterAction: CodeAction => Boolean = _ => true, - scalaCliLayout: Boolean = false, + overrideLayout: Option[String] = None, )(implicit loc: Location): Unit = { val scalacOptionsJson = if (scalacOptions.nonEmpty) s""""scalacOptions": ["${scalacOptions.mkString("\",\"")}"],""" else "" - val path = s"a/src/main/scala/a/$fileName" + val path = toPath(fileName) - val layout = { - if (scalaCliLayout) - s"""/.bsp/scala-cli.json - |${BaseScalaCliSuite.scalaCliBspJsonContent(scalaCliOptions)} - |/.scala-build/ide-inputs.json - |${BaseScalaCliSuite.scalaCliIdeInputJson(".")} - |/$path - |$input""".stripMargin - else - s"""/metals.json - |{"a":{$scalacOptionsJson "scalaVersion" : "$scalaVersion"}} - |$scalafixConf - |/$path - |$input""".stripMargin + val layout = overrideLayout.getOrElse { + s"""/metals.json + |{"a":{$scalacOptionsJson "scalaVersion" : "$scalaVersion"}} + |$scalafixConf + |/$path + |$input""".stripMargin } checkEdit( diff --git a/tests/unit/src/test/scala/tests/CodeLensLspSuite.scala b/tests/unit/src/test/scala/tests/CodeLensLspSuite.scala index b65bf518e18..d43028ed34b 100644 --- a/tests/unit/src/test/scala/tests/CodeLensLspSuite.scala +++ b/tests/unit/src/test/scala/tests/CodeLensLspSuite.scala @@ -165,52 +165,6 @@ class CodeLensLspSuite extends BaseCodeLensLspSuite("codeLenses") { } yield () } - private val scalaCliScriptPath = "a/src/main/scala/a/main.sc" - test("run-script") { - cleanWorkspace() - for { - - _ <- initialize( - s"""/.bsp/scala-cli.json - |${BaseScalaCliSuite.scalaCliBspJsonContent()} - |/.scala-build/ide-inputs.json - |${BaseScalaCliSuite.scalaCliIdeInputJson(".")} - |/$scalaCliScriptPath - |print("oranges are nice")""".stripMargin - ) - _ <- server.didOpen(scalaCliScriptPath) - _ <- assertCodeLenses( - scalaCliScriptPath, - """|<><> - |print("oranges are nice") - |""".stripMargin, - ) - } yield () - } - - private val scalaCliScriptPathTop = "main.sc" - test("run-script-top") { - cleanWorkspace() - for { - - _ <- initialize( - s"""/.bsp/scala-cli.json - |${BaseScalaCliSuite.scalaCliBspJsonContent()} - |/.scala-build/ide-inputs.json - |${BaseScalaCliSuite.scalaCliIdeInputJson(".")} - |/$scalaCliScriptPathTop - |print("oranges are nice")""".stripMargin - ) - _ <- server.didOpen(scalaCliScriptPathTop) - _ <- assertCodeLenses( - scalaCliScriptPathTop, - """|<><> - |print("oranges are nice") - |""".stripMargin, - ) - } yield () - } - // Tests, whether main class in one project does not affect other class with same name in other project test("run-multi-module") { cleanWorkspace() diff --git a/tests/unit/src/test/scala/tests/DebugDiscoverySuite.scala b/tests/unit/src/test/scala/tests/DebugDiscoverySuite.scala index 2279db63864..cf5c181cdbb 100644 --- a/tests/unit/src/test/scala/tests/DebugDiscoverySuite.scala +++ b/tests/unit/src/test/scala/tests/DebugDiscoverySuite.scala @@ -24,7 +24,6 @@ class DebugDiscoverySuite private val fooPath = "a/src/main/scala/a/Foo.scala" private val barPath = "a/src/main/scala/a/Bar.scala" private val altTargetPath = "b/src/main/scala/b/Main.scala" - private val scalaCliScriptPath = "a/src/main/scala/a/main.sc" test("run") { for { @@ -92,32 +91,6 @@ class DebugDiscoverySuite } yield assertNoDiff(output, "oranges are nice") } - test("run-scala-cli-script") { - for { - _ <- initialize( - s"""/.bsp/scala-cli.json - |${BaseScalaCliSuite.scalaCliBspJsonContent()} - |/.scala-build/ide-inputs.json - |${BaseScalaCliSuite.scalaCliIdeInputJson(".")} - |/$scalaCliScriptPath - |print("oranges are nice")""".stripMargin - ) - _ <- server.didOpen(scalaCliScriptPath) - _ <- server.waitFor(TimeUnit.SECONDS.toMillis(10)) - debugger <- server.startDebuggingUnresolved( - DebugDiscoveryParams( - server.toPath(scalaCliScriptPath).toURI.toString, - "run", - ).toJson - ) - _ <- debugger.initialize - _ <- debugger.launch - _ <- debugger.configurationDone - _ <- debugger.shutdown - output <- debugger.allOutput - } yield assertNoDiff(output, "oranges are nice") - } - test("run-file-test") { for { _ <- initialize( diff --git a/tests/unit/src/test/scala/tests/ScalaCliSuite.scala b/tests/unit/src/test/scala/tests/ScalaCliSuite.scala deleted file mode 100644 index d39105d8d71..00000000000 --- a/tests/unit/src/test/scala/tests/ScalaCliSuite.scala +++ /dev/null @@ -1,5 +0,0 @@ -package tests - -import scala.meta.internal.metals.{BuildInfo => V} - -class ScalaCliSuite extends tests.BaseScalaCliSuite(V.scala213)