Skip to content

Commit 26be60a

Browse files
committed
Execute tests/run/ tests with Scala.js.
Tests that are not supposed to pass (because they have Java source files, use Java reflection, rely on NPEs being thrown, use `scala.Enumeration`, etc.) are moved `tests/run-jvm-only/`. Tests that did not work out of the box because of differences in `toString` or `getClass` were changed to be portable. Tests that require compliant semantics from the Scala.js linker are moved to `run-with-compliant-semantics`. The remaining tests are probably bugs, and are moved to `run-pending-js`. They should be further investigated.
1 parent 0632405 commit 26be60a

File tree

574 files changed

+331
-127
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

574 files changed

+331
-127
lines changed

compiler/test/dotty/tools/dotc/CompilationTests.scala

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -210,7 +210,10 @@ class CompilationTests {
210210
compileDir("tests/run-custom-args/Xmacro-settings/simple", defaultOptions.and("-Xmacro-settings:one,two,three")),
211211
compileDir("tests/run-custom-args/Xmacro-settings/compileTimeEnv", defaultOptions.and("-Xmacro-settings:a,b=1,c.b.a=x.y.z=1,myLogger.level=INFO")),
212212
compileFilesInDir("tests/run-deep-subtype", allowDeepSubtypes),
213-
compileFilesInDir("tests/run", defaultOptions.and("-Ysafe-init"))
213+
compileFilesInDir("tests/run", defaultOptions.and("-Ysafe-init")),
214+
compileFilesInDir("tests/run-with-compliant-semantics", defaultOptions.and("-Ysafe-init")),
215+
compileFilesInDir("tests/run-pending-js", defaultOptions.and("-Ysafe-init")),
216+
compileFilesInDir("tests/run-jvm-only", defaultOptions.and("-Ysafe-init")),
214217
).checkRuns()
215218
}
216219

compiler/test/dotty/tools/vulpix/ParallelTesting.scala

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -739,7 +739,7 @@ trait ParallelTesting extends RunnerOrchestration { self =>
739739

740740
private def verifyOutput(checkFile: Option[JFile], dir: JFile, testSource: TestSource, warnings: Int, reporters: Seq[TestReporter], logger: LoggedRunnable) = {
741741
if (Properties.testsNoRun) addNoRunWarning()
742-
else runMain(testSource.runClassPath) match {
742+
else runMain(testSource.runClassPath, testSource.flags) match {
743743
case Success(output) => checkFile match {
744744
case Some(file) if file.exists => diffTest(testSource, file, output.linesIterator.toList, reporters, logger)
745745
case _ =>

compiler/test/dotty/tools/vulpix/RunnerOrchestration.scala

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -48,7 +48,7 @@ trait RunnerOrchestration {
4848
def safeMode: Boolean
4949

5050
/** Running a `Test` class's main method from the specified `dir` */
51-
def runMain(classPath: String)(implicit summaryReport: SummaryReporting): Status =
51+
def runMain(classPath: String, flags: TestFlags)(implicit summaryReport: SummaryReporting): Status =
5252
monitor.runMain(classPath)
5353

5454
/** Kill all processes */

compiler/test/dotty/tools/vulpix/TestConfiguration.scala

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -72,7 +72,7 @@ object TestConfiguration {
7272
lazy val withTastyInspectorOptions =
7373
defaultOptions.withClasspath(withTastyInspectorClasspath).withRunClasspath(withTastyInspectorClasspath)
7474
lazy val scalaJSOptions =
75-
defaultOptions.and("-scalajs").withClasspath(scalaJSClasspath)
75+
defaultOptions.and("-scalajs").withClasspath(scalaJSClasspath).withRunClasspath(scalaJSClasspath)
7676
val allowDeepSubtypes = defaultOptions without "-Yno-deep-subtypes"
7777
val allowDoubleBindings = defaultOptions without "-Yno-double-bindings"
7878
val picklingOptions = defaultOptions and (

compiler/test/dotty/tools/vulpix/TestFlags.scala

Lines changed: 12 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -8,22 +8,26 @@ final case class TestFlags(
88
defaultClassPath: String,
99
runClassPath: String, // class path that is used when running `run` tests (not compiling)
1010
options: Array[String],
11-
javacOptions: Array[String]) {
11+
javacOptions: Array[String],
12+
scalaJSCompliantSemantics: Boolean) {
1213

1314
def and(flags: String*): TestFlags =
14-
TestFlags(defaultClassPath, runClassPath, options ++ flags, javacOptions)
15+
TestFlags(defaultClassPath, runClassPath, options ++ flags, javacOptions, scalaJSCompliantSemantics)
1516

1617
def without(flags: String*): TestFlags =
17-
TestFlags(defaultClassPath, runClassPath, options diff flags, javacOptions)
18+
TestFlags(defaultClassPath, runClassPath, options diff flags, javacOptions, scalaJSCompliantSemantics)
1819

1920
def withClasspath(classPath: String): TestFlags =
20-
TestFlags(s"$defaultClassPath${JFile.pathSeparator}$classPath", runClassPath, options, javacOptions)
21+
TestFlags(s"$defaultClassPath${JFile.pathSeparator}$classPath", runClassPath, options, javacOptions, scalaJSCompliantSemantics)
2122

2223
def withRunClasspath(classPath: String): TestFlags =
23-
TestFlags(defaultClassPath, s"$runClassPath${JFile.pathSeparator}$classPath", options, javacOptions)
24+
TestFlags(defaultClassPath, s"$runClassPath${JFile.pathSeparator}$classPath", options, javacOptions, scalaJSCompliantSemantics)
2425

2526
def withJavacOnlyOptions(flags: String*): TestFlags =
26-
TestFlags(defaultClassPath, runClassPath, options, javacOptions ++ flags)
27+
TestFlags(defaultClassPath, runClassPath, options, javacOptions ++ flags, scalaJSCompliantSemantics)
28+
29+
def withScalaJSCompliantSemantics(compliantSemantics: Boolean): TestFlags =
30+
TestFlags(defaultClassPath, runClassPath, options, javacOptions, compliantSemantics)
2731

2832
def all: Array[String] = Array("-classpath", defaultClassPath) ++ options
2933

@@ -54,5 +58,6 @@ final case class TestFlags(
5458
}
5559

5660
object TestFlags {
57-
def apply(classPath: String, flags: Array[String]): TestFlags = TestFlags(classPath, classPath, flags, Array.empty)
61+
def apply(classPath: String, flags: Array[String]): TestFlags =
62+
TestFlags(classPath, classPath, flags, Array.empty, false)
5863
}

project/Build.scala

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1228,6 +1228,11 @@ object Build {
12281228
settings(
12291229
commonNonBootstrappedSettings,
12301230

1231+
libraryDependencies ++= Seq(
1232+
"org.scala-js" %% "scalajs-linker" % scalaJSVersion % Test cross CrossVersion.for3Use2_13,
1233+
"org.scala-js" %% "scalajs-env-nodejs" % "1.3.0" % Test cross CrossVersion.for3Use2_13,
1234+
),
1235+
12311236
// Change the baseDirectory when running the tests
12321237
Test / baseDirectory := baseDirectory.value.getParentFile,
12331238

Lines changed: 70 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,70 @@
1+
package dotty.tools.dotc
2+
3+
import scala.concurrent.duration.Duration
4+
import scala.concurrent.{Await, ExecutionContext}
5+
6+
import java.io.InputStream
7+
import java.nio.charset.StandardCharsets
8+
import java.nio.file.Path
9+
10+
import dotty.tools.vulpix.*
11+
12+
import org.scalajs.jsenv.*
13+
import org.scalajs.jsenv.nodejs.NodeJSEnv
14+
import org.scalajs.logging.*
15+
16+
object JSRun:
17+
def runJSCode(sjsCode: Path)(using ExecutionContext): Status =
18+
val logger = new ScalaConsoleLogger(Level.Warn)
19+
20+
var stdoutStream: Option[InputStream] = None
21+
var stderrStream: Option[InputStream] = None
22+
23+
val input = Input.Script(sjsCode) :: Nil
24+
val config = RunConfig()
25+
.withLogger(logger)
26+
.withInheritOut(false)
27+
.withInheritErr(false)
28+
.withOnOutputStream { (out, err) =>
29+
stdoutStream = out
30+
stderrStream = err
31+
}
32+
33+
val run = new NodeJSEnv().start(input, config)
34+
try
35+
val success = try {
36+
Await.result(run.future, Duration.Inf)
37+
true
38+
} catch {
39+
case _: Exception =>
40+
false
41+
}
42+
val output = readStreamFully(stderrStream) + readStreamFully(stdoutStream)
43+
if success then
44+
Success(output)
45+
else
46+
Failure(output)
47+
finally
48+
run.close()
49+
end runJSCode
50+
51+
private def readStreamFully(optStream: Option[InputStream]): String =
52+
optStream match
53+
case None =>
54+
""
55+
case Some(stream) =>
56+
try
57+
val result = new java.io.ByteArrayOutputStream()
58+
val buffer = new Array[Byte](1024)
59+
while ({
60+
val len = stream.read(buffer)
61+
len >= 0 && {
62+
result.write(buffer, 0, len)
63+
true
64+
}
65+
}) ()
66+
new String(result.toByteArray(), StandardCharsets.UTF_8)
67+
finally
68+
stream.close()
69+
end readStreamFully
70+
end JSRun

sjs-compiler-tests/test/scala/dotty/tools/dotc/ScalaJSCompilationTests.scala

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,29 @@ class ScalaJSCompilationTests extends ParallelTesting {
3232
compileFilesInDir("tests/neg-scalajs", scalaJSOptions),
3333
).checkExpectedErrors()
3434
}
35+
36+
// Run tests -----------------------------------------------------------------
37+
38+
override def runMain(classPath: String, flags: TestFlags)(implicit summaryReport: SummaryReporting): Status =
39+
import scala.concurrent.ExecutionContext.Implicits.global
40+
41+
try
42+
val sjsCode = ScalaJSLink.link(classPath, flags.scalaJSCompliantSemantics)
43+
JSRun.runJSCode(sjsCode)
44+
catch
45+
case t: Exception =>
46+
val writer = new java.io.StringWriter()
47+
t.printStackTrace(new java.io.PrintWriter(writer))
48+
Failure(writer.toString())
49+
end runMain
50+
51+
@Test def runScalaJS: Unit = {
52+
implicit val testGroup: TestGroup = TestGroup("runScalaJS")
53+
aggregateTests(
54+
compileFilesInDir("tests/run", scalaJSOptions),
55+
compileFilesInDir("tests/run-with-compliant-semantics", scalaJSOptions.withScalaJSCompliantSemantics(true)),
56+
).checkRuns()
57+
}
3558
}
3659

3760
object ScalaJSCompilationTests {
Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
package dotty.tools.dotc
2+
3+
import scala.concurrent.duration.Duration
4+
import scala.concurrent.{Await, ExecutionContext}
5+
6+
import java.io.File
7+
import java.nio.file.{Files, Path}
8+
9+
import com.google.common.jimfs.Jimfs
10+
11+
import org.scalajs.linker.*
12+
import org.scalajs.linker.interface.*
13+
import org.scalajs.logging.*
14+
15+
object ScalaJSLink:
16+
private val compliantSemantics: Semantics =
17+
Semantics.Defaults
18+
.withAsInstanceOfs(CheckedBehavior.Compliant)
19+
.withArrayIndexOutOfBounds(CheckedBehavior.Compliant)
20+
.withModuleInit(CheckedBehavior.Compliant)
21+
end compliantSemantics
22+
23+
def link(classPath: String, useCompliantSemantics: Boolean)(using ExecutionContext): Path =
24+
val cpEntries = classPath.split(File.pathSeparatorChar)
25+
26+
val logger = new ScalaConsoleLogger(Level.Warn)
27+
28+
val moduleInitializers = Seq(ModuleInitializer.mainMethodWithArgs(
29+
"Test", "main", Nil))
30+
31+
val semantics = if useCompliantSemantics then compliantSemantics else Semantics.Defaults
32+
33+
val linkerConfig = StandardConfig()
34+
.withCheckIR(true)
35+
.withSourceMap(false)
36+
.withBatchMode(true)
37+
.withSemantics(semantics)
38+
39+
val linker = StandardImpl.linker(linkerConfig)
40+
41+
val dir = Jimfs.newFileSystem().getPath("tmp")
42+
Files.createDirectory(dir)
43+
44+
val cache = StandardImpl.irFileCache().newCache
45+
val result = PathIRContainer
46+
.fromClasspath(cpEntries.toSeq.map(entry => new File(entry).toPath()))
47+
.map(_._1)
48+
.flatMap(cache.cached _)
49+
.flatMap(linker.link(_, moduleInitializers, PathOutputDirectory(dir), logger))
50+
51+
val report = Await.result(result, Duration.Inf)
52+
53+
if (report.publicModules.size != 1)
54+
throw new AssertionError(s"got other than 1 module: $report")
55+
56+
dir.resolve(report.publicModules.head.jsFileName)
57+
end link
58+
end ScalaJSLink
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.

0 commit comments

Comments
 (0)