Skip to content

Commit 1fb07cb

Browse files
authored
Merge pull request #9611 from dotty-staging/sjs-neg-tests-infrastructure
Scala.js: Add neg tests for bad uses of `reflect.Selectable`.
2 parents 212b8af + eb54a18 commit 1fb07cb

File tree

7 files changed

+122
-4
lines changed

7 files changed

+122
-4
lines changed

.github/workflows/ci.yaml

+1-1
Original file line numberDiff line numberDiff line change
@@ -93,7 +93,7 @@ jobs:
9393

9494
- name: Test
9595
run: |
96-
./project/scripts/sbt ";dotty-bootstrapped/compile ;dotty-bootstrapped/test;sjsSandbox/run;sjsSandbox/test;sjsJUnitTests/test ;configureIDE"
96+
./project/scripts/sbt ";dotty-bootstrapped/compile ;dotty-bootstrapped/test;sjsSandbox/run;sjsSandbox/test;sjsJUnitTests/test;sjsCompilerTests/test ;configureIDE"
9797
./project/scripts/bootstrapCmdTests
9898
9999
community_build:

build.sbt

+1
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@ val `community-build` = Build.`community-build`
3030

3131
val sjsSandbox = Build.sjsSandbox
3232
val sjsJUnitTests = Build.sjsJUnitTests
33+
val sjsCompilerTests = Build.sjsCompilerTests
3334

3435
val `sbt-dotty` = Build.`sbt-dotty`
3536
val `vscode-dotty` = Build.`vscode-dotty`

compiler/test/dotty/Properties.scala

+6
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,9 @@ object Properties {
4848
/** dotty-library jar */
4949
def dottyLibrary: String = sys.props("dotty.tests.classes.dottyLibrary")
5050

51+
/** dotty-library-js jar */
52+
def dottyLibraryJS: String = sys.props("dotty.tests.classes.dottyLibraryJS")
53+
5154
/** dotty-compiler jar */
5255
def dottyCompiler: String = sys.props("dotty.tests.classes.dottyCompiler")
5356

@@ -74,4 +77,7 @@ object Properties {
7477

7578
/** jline-reader jar */
7679
def jlineReader: String = sys.props("dotty.tests.classes.jlineReader")
80+
81+
/** scalajs-library jar */
82+
def scalaJSLibrary: String = sys.props("dotty.tests.classes.scalaJSLibrary")
7783
}

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

+7
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,11 @@ object TestConfiguration {
4444
lazy val withTastyInspectorClasspath =
4545
withCompilerClasspath + File.pathSeparator + mkClasspath(List(Properties.dottyTastyInspector))
4646

47+
lazy val scalaJSClasspath = mkClasspath(List(
48+
Properties.scalaJSLibrary,
49+
Properties.dottyLibraryJS
50+
))
51+
4752
def mkClasspath(classpaths: List[String]): String =
4853
classpaths.map({ p =>
4954
val file = new java.io.File(p)
@@ -61,6 +66,8 @@ object TestConfiguration {
6166
defaultOptions.withClasspath(withStagingClasspath).withRunClasspath(withStagingClasspath)
6267
lazy val withTastyInspectorOptions =
6368
defaultOptions.withClasspath(withTastyInspectorClasspath).withRunClasspath(withTastyInspectorClasspath)
69+
lazy val scalaJSOptions =
70+
defaultOptions.and("-scalajs").withClasspath(scalaJSClasspath)
6471
val allowDeepSubtypes = defaultOptions without "-Yno-deep-subtypes"
6572
val allowDoubleBindings = defaultOptions without "-Yno-double-bindings"
6673
val picklingOptions = defaultOptions and (

project/Build.scala

+22-3
Original file line numberDiff line numberDiff line change
@@ -174,6 +174,8 @@ object Build {
174174
fork in Test := true,
175175
parallelExecution in Test := false,
176176

177+
outputStrategy := Some(StdoutOutput),
178+
177179
// enable verbose exception messages for JUnit
178180
testOptions in Test += Tests.Argument(TestFrameworks.JUnit, "-a", "-v"),
179181
)
@@ -335,7 +337,6 @@ object Build {
335337
)
336338

337339
lazy val commonBenchmarkSettings = Seq(
338-
outputStrategy := Some(StdoutOutput),
339340
mainClass in (Jmh, run) := Some("dotty.tools.benchmarks.Bench"), // custom main for jmh:run
340341
javaOptions += "-DBENCH_COMPILER_CLASS_PATH=" + Attributed.data((fullClasspath in (`dotty-bootstrapped`, Compile)).value).mkString("", File.pathSeparator, ""),
341342
javaOptions += "-DBENCH_CLASS_PATH=" + Attributed.data((fullClasspath in (`dotty-library-bootstrapped`, Compile)).value).mkString("", File.pathSeparator, "")
@@ -404,7 +405,6 @@ object Build {
404405

405406
def dottyDocSettings(implicit mode: Mode) = Seq(
406407
connectInput in run := true,
407-
outputStrategy := Some(StdoutOutput),
408408

409409
javaOptions ++= (javaOptions in `dotty-compiler`).value,
410410

@@ -466,7 +466,6 @@ object Build {
466466
lazy val commonDottyCompilerSettings = Seq(
467467
// set system in/out for repl
468468
connectInput in run := true,
469-
outputStrategy := Some(StdoutOutput),
470469

471470
// Generate compiler.properties, used by sbt
472471
resourceGenerators in Compile += Def.task {
@@ -1140,6 +1139,26 @@ object Build {
11401139
}
11411140
)
11421141

1142+
lazy val sjsCompilerTests = project.in(file("sjs-compiler-tests")).
1143+
dependsOn(`dotty-compiler` % "test->test").
1144+
settings(
1145+
commonNonBootstrappedSettings,
1146+
1147+
// Change the baseDirectory when running the tests
1148+
baseDirectory in Test := baseDirectory.value.getParentFile,
1149+
1150+
javaOptions ++= (javaOptions in `dotty-compiler`).value,
1151+
javaOptions ++= {
1152+
val externalJSDeps = (externalDependencyClasspath in (`dotty-library-bootstrappedJS`, Compile)).value
1153+
val dottyLibraryJSJar = (packageBin in (`dotty-library-bootstrappedJS`, Compile)).value.getAbsolutePath
1154+
1155+
Seq(
1156+
"-Ddotty.tests.classes.dottyLibraryJS=" + dottyLibraryJSJar,
1157+
"-Ddotty.tests.classes.scalaJSLibrary=" + findArtifactPath(externalJSDeps, "scalajs-library_2.13"),
1158+
)
1159+
},
1160+
)
1161+
11431162
lazy val `dotty-bench` = project.in(file("bench")).asDottyBench(NonBootstrapped)
11441163
lazy val `dotty-bench-bootstrapped` = project.in(file("bench")).asDottyBench(Bootstrapped)
11451164
lazy val `dotty-bench-run` = project.in(file("bench-run")).asDottyBench(Bootstrapped)
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
package dotty
2+
package tools
3+
package dotc
4+
5+
import org.junit.{ Test, BeforeClass, AfterClass }
6+
import org.junit.experimental.categories.Category
7+
8+
import scala.concurrent.duration._
9+
import vulpix._
10+
11+
@Category(Array(classOf[ScalaJSCompilationTests]))
12+
class ScalaJSCompilationTests extends ParallelTesting {
13+
import ParallelTesting._
14+
import TestConfiguration._
15+
import ScalaJSCompilationTests._
16+
import CompilationTest.aggregateTests
17+
18+
// Test suite configuration --------------------------------------------------
19+
20+
def maxDuration = 60.seconds
21+
def numberOfSlaves = 5
22+
def safeMode = Properties.testsSafeMode
23+
def isInteractive = SummaryReport.isInteractive
24+
def testFilter = Properties.testsFilter
25+
def updateCheckFiles: Boolean = Properties.testsUpdateCheckfile
26+
27+
// Negative tests ------------------------------------------------------------
28+
29+
@Test def negScalaJS: Unit = {
30+
implicit val testGroup: TestGroup = TestGroup("negScalaJS")
31+
aggregateTests(
32+
compileFilesInDir("tests/neg-scalajs", scalaJSOptions),
33+
).checkExpectedErrors()
34+
}
35+
}
36+
37+
object ScalaJSCompilationTests {
38+
implicit val summaryReport: SummaryReporting = new SummaryReport
39+
@AfterClass def cleanup(): Unit = summaryReport.echoSummary()
40+
}
+45
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
import scala.reflect.{ClassTag, Selectable => ReflectSel}
2+
import ReflectSel.reflectiveSelectable
3+
4+
object Test {
5+
/* Make sure that an explicit desugaring of the legit cases actually compiles,
6+
* ensuring that the error cases we test are actually testing the right things.
7+
*/
8+
def sanityCheck(): Unit = {
9+
val receiver: Any = ???
10+
reflectiveSelectable(receiver).selectDynamic("foo") // OK
11+
reflectiveSelectable(receiver).applyDynamic("foo")() // OK
12+
reflectiveSelectable(receiver).applyDynamic("foo", ClassTag(classOf[String]), ClassTag(classOf[List[_]]))("bar", Nil) // OK
13+
}
14+
15+
def badReceider(): Unit = {
16+
val receiver: ReflectSel = ???
17+
receiver.selectDynamic("foo") // error
18+
receiver.applyDynamic("foo")() // error
19+
}
20+
21+
def nonLiteralMethodName(): Unit = {
22+
val receiver: Any = ???
23+
val methodName: String = "foo"
24+
reflectiveSelectable(receiver).selectDynamic(methodName) // error
25+
reflectiveSelectable(receiver).applyDynamic(methodName)() // error
26+
}
27+
28+
def nonLiteralClassTag(): Unit = {
29+
val receiver: Any = ???
30+
val myClassTag: ClassTag[String] = ClassTag(classOf[String])
31+
reflectiveSelectable(receiver).applyDynamic("foo", myClassTag, ClassTag(classOf[List[_]]))("bar", Nil) // error
32+
}
33+
34+
def classTagVarArgs(): Unit = {
35+
val receiver: Any = ???
36+
val classTags: List[ClassTag[_]] = List(ClassTag(classOf[String]), ClassTag(classOf[List[_]]))
37+
reflectiveSelectable(receiver).applyDynamic("foo", classTags: _*)("bar", Nil) // error
38+
}
39+
40+
def argsVarArgs(): Unit = {
41+
val receiver: Any = ???
42+
val args: List[Any] = List("bar", Nil)
43+
reflectiveSelectable(receiver).applyDynamic("foo", ClassTag(classOf[String]), ClassTag(classOf[List[_]]))(args: _*) // error
44+
}
45+
}

0 commit comments

Comments
 (0)