Skip to content

Scala.js: Add neg tests for bad uses of reflect.Selectable. #9611

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 2 commits into from
Aug 21, 2020
Merged
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
2 changes: 1 addition & 1 deletion .github/workflows/ci.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -93,7 +93,7 @@ jobs:

- name: Test
run: |
./project/scripts/sbt ";dotty-bootstrapped/compile ;dotty-bootstrapped/test;sjsSandbox/run;sjsSandbox/test;sjsJUnitTests/test ;configureIDE"
./project/scripts/sbt ";dotty-bootstrapped/compile ;dotty-bootstrapped/test;sjsSandbox/run;sjsSandbox/test;sjsJUnitTests/test;sjsCompilerTests/test ;configureIDE"
./project/scripts/bootstrapCmdTests

community_build:
Expand Down
1 change: 1 addition & 0 deletions build.sbt
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ val `community-build` = Build.`community-build`

val sjsSandbox = Build.sjsSandbox
val sjsJUnitTests = Build.sjsJUnitTests
val sjsCompilerTests = Build.sjsCompilerTests

val `sbt-dotty` = Build.`sbt-dotty`
val `vscode-dotty` = Build.`vscode-dotty`
Expand Down
6 changes: 6 additions & 0 deletions compiler/test/dotty/Properties.scala
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,9 @@ object Properties {
/** dotty-library jar */
def dottyLibrary: String = sys.props("dotty.tests.classes.dottyLibrary")

/** dotty-library-js jar */
def dottyLibraryJS: String = sys.props("dotty.tests.classes.dottyLibraryJS")

/** dotty-compiler jar */
def dottyCompiler: String = sys.props("dotty.tests.classes.dottyCompiler")

Expand All @@ -74,4 +77,7 @@ object Properties {

/** jline-reader jar */
def jlineReader: String = sys.props("dotty.tests.classes.jlineReader")

/** scalajs-library jar */
def scalaJSLibrary: String = sys.props("dotty.tests.classes.scalaJSLibrary")
}
7 changes: 7 additions & 0 deletions compiler/test/dotty/tools/vulpix/TestConfiguration.scala
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,11 @@ object TestConfiguration {
lazy val withTastyInspectorClasspath =
withCompilerClasspath + File.pathSeparator + mkClasspath(List(Properties.dottyTastyInspector))

lazy val scalaJSClasspath = mkClasspath(List(
Properties.scalaJSLibrary,
Properties.dottyLibraryJS
))

def mkClasspath(classpaths: List[String]): String =
classpaths.map({ p =>
val file = new java.io.File(p)
Expand All @@ -61,6 +66,8 @@ object TestConfiguration {
defaultOptions.withClasspath(withStagingClasspath).withRunClasspath(withStagingClasspath)
lazy val withTastyInspectorOptions =
defaultOptions.withClasspath(withTastyInspectorClasspath).withRunClasspath(withTastyInspectorClasspath)
lazy val scalaJSOptions =
defaultOptions.and("-scalajs").withClasspath(scalaJSClasspath)
val allowDeepSubtypes = defaultOptions without "-Yno-deep-subtypes"
val allowDoubleBindings = defaultOptions without "-Yno-double-bindings"
val picklingOptions = defaultOptions and (
Expand Down
25 changes: 22 additions & 3 deletions project/Build.scala
Original file line number Diff line number Diff line change
Expand Up @@ -174,6 +174,8 @@ object Build {
fork in Test := true,
parallelExecution in Test := false,

outputStrategy := Some(StdoutOutput),

// enable verbose exception messages for JUnit
testOptions in Test += Tests.Argument(TestFrameworks.JUnit, "-a", "-v"),
)
Expand Down Expand Up @@ -335,7 +337,6 @@ object Build {
)

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

def dottyDocSettings(implicit mode: Mode) = Seq(
connectInput in run := true,
outputStrategy := Some(StdoutOutput),

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

Expand Down Expand Up @@ -466,7 +466,6 @@ object Build {
lazy val commonDottyCompilerSettings = Seq(
// set system in/out for repl
connectInput in run := true,
outputStrategy := Some(StdoutOutput),

// Generate compiler.properties, used by sbt
resourceGenerators in Compile += Def.task {
Expand Down Expand Up @@ -1140,6 +1139,26 @@ object Build {
}
)

lazy val sjsCompilerTests = project.in(file("sjs-compiler-tests")).
dependsOn(`dotty-compiler` % "test->test").
settings(
commonNonBootstrappedSettings,

// Change the baseDirectory when running the tests
baseDirectory in Test := baseDirectory.value.getParentFile,

javaOptions ++= (javaOptions in `dotty-compiler`).value,
javaOptions ++= {
val externalJSDeps = (externalDependencyClasspath in (`dotty-library-bootstrappedJS`, Compile)).value
val dottyLibraryJSJar = (packageBin in (`dotty-library-bootstrappedJS`, Compile)).value.getAbsolutePath

Seq(
"-Ddotty.tests.classes.dottyLibraryJS=" + dottyLibraryJSJar,
"-Ddotty.tests.classes.scalaJSLibrary=" + findArtifactPath(externalJSDeps, "scalajs-library_2.13"),
)
},
)

lazy val `dotty-bench` = project.in(file("bench")).asDottyBench(NonBootstrapped)
lazy val `dotty-bench-bootstrapped` = project.in(file("bench")).asDottyBench(Bootstrapped)
lazy val `dotty-bench-run` = project.in(file("bench-run")).asDottyBench(Bootstrapped)
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
package dotty
package tools
package dotc

import org.junit.{ Test, BeforeClass, AfterClass }
import org.junit.experimental.categories.Category

import scala.concurrent.duration._
import vulpix._

@Category(Array(classOf[ScalaJSCompilationTests]))
class ScalaJSCompilationTests extends ParallelTesting {
import ParallelTesting._
import TestConfiguration._
import ScalaJSCompilationTests._
import CompilationTest.aggregateTests

// Test suite configuration --------------------------------------------------

def maxDuration = 60.seconds
def numberOfSlaves = 5
def safeMode = Properties.testsSafeMode
def isInteractive = SummaryReport.isInteractive
def testFilter = Properties.testsFilter
def updateCheckFiles: Boolean = Properties.testsUpdateCheckfile

// Negative tests ------------------------------------------------------------

@Test def negScalaJS: Unit = {
implicit val testGroup: TestGroup = TestGroup("negScalaJS")
aggregateTests(
compileFilesInDir("tests/neg-scalajs", scalaJSOptions),
).checkExpectedErrors()
}
}

object ScalaJSCompilationTests {
implicit val summaryReport: SummaryReporting = new SummaryReport
@AfterClass def cleanup(): Unit = summaryReport.echoSummary()
}
45 changes: 45 additions & 0 deletions tests/neg-scalajs/reflective-calls.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
import scala.reflect.{ClassTag, Selectable => ReflectSel}
import ReflectSel.reflectiveSelectable

object Test {
/* Make sure that an explicit desugaring of the legit cases actually compiles,
* ensuring that the error cases we test are actually testing the right things.
*/
def sanityCheck(): Unit = {
val receiver: Any = ???
reflectiveSelectable(receiver).selectDynamic("foo") // OK
reflectiveSelectable(receiver).applyDynamic("foo")() // OK
reflectiveSelectable(receiver).applyDynamic("foo", ClassTag(classOf[String]), ClassTag(classOf[List[_]]))("bar", Nil) // OK
}

def badReceider(): Unit = {
val receiver: ReflectSel = ???
receiver.selectDynamic("foo") // error
receiver.applyDynamic("foo")() // error
}

def nonLiteralMethodName(): Unit = {
val receiver: Any = ???
val methodName: String = "foo"
reflectiveSelectable(receiver).selectDynamic(methodName) // error
reflectiveSelectable(receiver).applyDynamic(methodName)() // error
}

def nonLiteralClassTag(): Unit = {
val receiver: Any = ???
val myClassTag: ClassTag[String] = ClassTag(classOf[String])
reflectiveSelectable(receiver).applyDynamic("foo", myClassTag, ClassTag(classOf[List[_]]))("bar", Nil) // error
}

def classTagVarArgs(): Unit = {
val receiver: Any = ???
val classTags: List[ClassTag[_]] = List(ClassTag(classOf[String]), ClassTag(classOf[List[_]]))
reflectiveSelectable(receiver).applyDynamic("foo", classTags: _*)("bar", Nil) // error
}

def argsVarArgs(): Unit = {
val receiver: Any = ???
val args: List[Any] = List("bar", Nil)
reflectiveSelectable(receiver).applyDynamic("foo", ClassTag(classOf[String]), ClassTag(classOf[List[_]]))(args: _*) // error
}
}