summaryrefslogtreecommitdiff
path: root/compiler/src/test/scala/scala/scalajs/compiler/test/JSExportTest.scala
diff options
context:
space:
mode:
Diffstat (limited to 'compiler/src/test/scala/scala/scalajs/compiler/test/JSExportTest.scala')
-rw-r--r--compiler/src/test/scala/scala/scalajs/compiler/test/JSExportTest.scala745
1 files changed, 745 insertions, 0 deletions
diff --git a/compiler/src/test/scala/scala/scalajs/compiler/test/JSExportTest.scala b/compiler/src/test/scala/scala/scalajs/compiler/test/JSExportTest.scala
new file mode 100644
index 0000000..c675420
--- /dev/null
+++ b/compiler/src/test/scala/scala/scalajs/compiler/test/JSExportTest.scala
@@ -0,0 +1,745 @@
+package scala.scalajs.compiler.test
+
+import scala.scalajs.compiler.test.util._
+import org.junit.Test
+import org.junit.Ignore
+
+class JSExportTest extends DirectTest with TestHelpers {
+
+ override def preamble =
+ """import scala.scalajs.js.annotation._
+ """
+
+ @Test
+ def noDoubleUnderscoreExport = {
+ // Normal exports
+ """
+ class A {
+ @JSExport(name = "__")
+ def foo = 1
+
+ @JSExport
+ def bar__(x: Int) = x
+ }
+
+ @JSExport
+ class B__
+ """ hasErrors
+ """
+ |newSource1.scala:4: error: An exported name may not contain a double underscore (`__`)
+ | @JSExport(name = "__")
+ | ^
+ |newSource1.scala:8: error: An exported name may not contain a double underscore (`__`)
+ | def bar__(x: Int) = x
+ | ^
+ |newSource1.scala:12: error: An exported name may not contain a double underscore (`__`)
+ | class B__
+ | ^
+ """
+
+ // Inherited exports (objects)
+ """
+ @JSExportDescendentObjects
+ trait A
+
+ package fo__o {
+ object B extends A
+ }
+ """ hasErrors
+ """
+ |newSource1.scala:7: error: B may not have a double underscore (`__`) in its fully qualified
+ |name, since it is forced to be exported by a @JSExportDescendentObjects on trait A
+ | object B extends A
+ | ^
+ """
+
+ // Inherited exports (classes)
+ """
+ @JSExportDescendentClasses
+ trait A
+
+ package fo__o {
+ class B(x: Int) extends A {
+ def this() = this(1)
+ private def this(s: String) = this(1)
+ }
+ }
+ """ hasErrors
+ """
+ |newSource1.scala:7: error: B may not have a double underscore (`__`) in its fully qualified
+ |name, since it is forced to be exported by a @JSExportDescendentClasses on trait A
+ | class B(x: Int) extends A {
+ | ^
+ |newSource1.scala:8: error: B may not have a double underscore (`__`) in its fully qualified
+ |name, since it is forced to be exported by a @JSExportDescendentClasses on trait A
+ | def this() = this(1)
+ | ^
+ """
+ }
+
+ @Test
+ def noConflictingExport = {
+ """
+ class Confl {
+ @JSExport("value")
+ def hello = "foo"
+
+ @JSExport("value")
+ def world = "bar"
+ }
+ """ fails() // No error test, Scala version dependent error messages
+
+ """
+ class Confl {
+ class Box[T](val x: T)
+
+ @JSExport
+ def ub(x: Box[String]): String = x.x
+ @JSExport
+ def ub(x: Box[Int]): Int = x.x
+ }
+ """ fails() // No error test, Scala version dependent error messages
+
+ """
+ class Confl {
+ @JSExport
+ def rtType(x: scala.scalajs.js.prim.Number) = x
+
+ @JSExport
+ def rtType(x: Double) = x
+ }
+ """ fails() // Error message depends on Scala version
+
+ """
+ class Confl {
+ @JSExport
+ def foo(x: Int)(ys: Int*) = x
+
+ @JSExport
+ def foo(x: Int*) = x
+ }
+ """ hasErrors
+ """
+ |newSource1.scala:7: error: Cannot disambiguate overloads for exported method $js$exported$meth$foo with types
+ | (x: Seq)Object
+ | (x: Int, ys: Seq)Object
+ | @JSExport
+ | ^
+ """
+
+ """
+ class Confl {
+ @JSExport
+ def foo(x: Int = 1) = x
+ @JSExport
+ def foo(x: String*) = x
+ }
+ """ hasErrors
+ """
+ |newSource1.scala:4: error: Cannot disambiguate overloads for exported method $js$exported$meth$foo with types
+ | (x: Int)Object
+ | (x: Seq)Object
+ | @JSExport
+ | ^
+ """
+
+ """
+ class Confl {
+ @JSExport
+ def foo(x: scala.scalajs.js.prim.Number, y: String)(z: Int = 1) = x
+ @JSExport
+ def foo(x: Double, y: String)(z: String*) = x
+ }
+ """ fails() // Error message depends on Scala version
+
+ """
+ class A {
+ @JSExport
+ def a(x: scala.scalajs.js.Any) = 1
+
+ @JSExport
+ def a(x: Any) = 2
+ }
+ """ fails() // Error message depends on Scala version
+
+ }
+
+ @Test
+ def noExportLocal = {
+ // Local class
+ """
+ class A {
+ def method = {
+ @JSExport
+ class A
+ }
+ }
+ """ hasErrors
+ """
+ |newSource1.scala:5: error: You may not export a local class
+ | @JSExport
+ | ^
+ """
+
+ // Local object
+ """
+ class A {
+ def method = {
+ @JSExport
+ object A
+ }
+ }
+ """ hasErrors
+ """
+ |newSource1.scala:5: error: You may not export a local object
+ | @JSExport
+ | ^
+ """
+
+ // Local method
+ """
+ class A {
+ def method = {
+ @JSExport
+ def foo = 1
+ }
+ }
+ """ hasErrors
+ """
+ |newSource1.scala:5: error: You may not export a local definition
+ | @JSExport
+ | ^
+ """
+
+ // Local val
+ """
+ class A {
+ def method = {
+ @JSExport
+ val x = 1
+ }
+ }
+ """ hasErrors
+ """
+ |newSource1.scala:5: error: You may not export a local definition
+ | @JSExport
+ | ^
+ """
+
+ // Local var
+ """
+ class A {
+ def method = {
+ @JSExport
+ var x = 1
+ }
+ }
+ """ hasErrors
+ """
+ |newSource1.scala:5: error: You may not export a local definition
+ | @JSExport
+ | ^
+ """
+
+ }
+
+ @Test
+ def infoExportLocal = {
+
+ """
+ class A(@JSExport val x: Int)
+ """ hasErrors
+ """
+ |newSource1.scala:3: error: You may not export a local definition. To export a (case) class field, use the meta-annotation scala.annotation.meta.field like this: @(JSExport @field).
+ | class A(@JSExport val x: Int)
+ | ^
+ """
+
+ }
+
+ @Test
+ def noMiddleVarArg = {
+
+ """
+ class A {
+ @JSExport
+ def method(xs: Int*)(ys: String) = 1
+ }
+ """ hasErrors
+ """
+ |newSource1.scala:4: error: In an exported method, a *-parameter must come last (through all parameter lists)
+ | @JSExport
+ | ^
+ """
+
+ }
+
+ @Test
+ def noMiddleDefaultParam = {
+
+ """
+ class A {
+ @JSExport
+ def method(x: Int = 1)(y: String) = 1
+ }
+ """ hasErrors
+ """
+ |newSource1.scala:4: error: In an exported method, all parameters with defaults must be at the end
+ | @JSExport
+ | ^
+ """
+
+ }
+
+ @Test
+ def noExportTrait = {
+
+ """
+ @JSExport
+ trait Test
+ """ hasErrors
+ """
+ |newSource1.scala:3: error: You may not export a trait
+ | @JSExport
+ | ^
+ """
+
+ }
+
+ @Test
+ def noExportNonPublicClassOrObject = {
+
+ """
+ @JSExport
+ private class A
+
+ @JSExport
+ protected[this] class B
+ """ hasErrors
+ """
+ |newSource1.scala:3: error: You may only export public and protected classes
+ | @JSExport
+ | ^
+ |newSource1.scala:6: error: You may only export public and protected classes
+ | @JSExport
+ | ^
+ """
+
+ """
+ @JSExport
+ private object A
+
+ @JSExport
+ protected[this] object B
+ """ hasErrors
+ """
+ |newSource1.scala:3: error: You may only export public and protected objects
+ | @JSExport
+ | ^
+ |newSource1.scala:6: error: You may only export public and protected objects
+ | @JSExport
+ | ^
+ """
+
+ }
+
+ @Test
+ def noExportNonPublicMember = {
+
+ """
+ class A {
+ @JSExport
+ private def foo = 1
+
+ @JSExport
+ protected[this] def bar = 2
+ }
+ """ hasErrors
+ """
+ |newSource1.scala:4: error: You may only export public and protected methods
+ | @JSExport
+ | ^
+ |newSource1.scala:7: error: You may only export public and protected methods
+ | @JSExport
+ | ^
+ """
+
+ }
+
+ @Test
+ def noExportNestedClass = {
+
+ """
+ class A {
+ @JSExport
+ class Nested
+ }
+ """ hasErrors
+ """
+ |newSource1.scala:4: error: You may not export a nested class. Create an exported factory method in the outer class to work around this limitation.
+ | @JSExport
+ | ^
+ """
+
+ """
+ object A {
+ @JSExport
+ class Nested
+ }
+ """ hasErrors
+ """
+ |newSource1.scala:4: error: You may not export a nested class. Create an exported factory method in the outer class to work around this limitation.
+ | @JSExport
+ | ^
+ """
+
+ }
+
+ @Test
+ def noExportNestedObject = {
+
+ """
+ class A {
+ @JSExport
+ object Nested
+ }
+ """ hasErrors
+ """
+ |newSource1.scala:4: error: You may not export a nested object
+ | @JSExport
+ | ^
+ """
+
+ """
+ object A {
+ @JSExport
+ object Nested
+ }
+ """ hasErrors
+ """
+ |newSource1.scala:4: error: You may not export a nested object
+ | @JSExport
+ | ^
+ """
+
+ }
+
+ @Test
+ def noExportJSRaw = {
+
+ """
+ import scala.scalajs.js
+
+ @JSExport
+ object A extends js.Object
+ """ hasErrors
+ """
+ |newSource1.scala:5: error: You may not export a class extending js.Any
+ | @JSExport
+ | ^
+ """
+
+ """
+ import scala.scalajs.js
+
+ @JSExport
+ class A extends js.Object
+ """ hasErrors
+ """
+ |newSource1.scala:5: error: You may not export a constructor of a subclass of js.Any
+ | @JSExport
+ | ^
+ """
+
+ }
+
+ @Test
+ def noExportJSRawMember = {
+
+ """
+ import scala.scalajs.js
+
+ class A extends js.Object {
+ @JSExport
+ def foo: Int = js.native
+ }
+ """ hasErrors
+ """
+ |newSource1.scala:6: error: You may not export a method of a subclass of js.Any
+ | @JSExport
+ | ^
+ """
+
+ }
+
+ @Test
+ def noBadSetterType = {
+
+ // Bad param list
+ """
+ class A {
+ @JSExport
+ def foo_=(x: Int, y: Int) = ()
+ }
+ """ hasErrors
+ """
+ |newSource1.scala:4: error: A method ending in _= will be exported as setter. But foo_= does not have the right signature to do so (single argument, unit return type).
+ | @JSExport
+ | ^
+ """
+
+ // Bad return type
+ """
+ class A {
+ @JSExport
+ def foo_=(x: Int) = "string"
+ }
+ """ hasErrors
+ """
+ |newSource1.scala:4: error: A method ending in _= will be exported as setter. But foo_= does not have the right signature to do so (single argument, unit return type).
+ | @JSExport
+ | ^
+ """
+
+ }
+
+ @Test
+ def noBadToStringExport = {
+
+ """
+ class A {
+ @JSExport("toString")
+ def a(): Int = 5
+ }
+ """ hasErrors
+ """
+ |newSource1.scala:4: error: You may not export a zero-argument method named other than 'toString' under the name 'toString'
+ | @JSExport("toString")
+ | ^
+ """
+
+ }
+
+ @Test
+ def noBadNameExportAll = {
+
+ """
+ @JSExportAll
+ class A {
+ val __f = 1
+ def a_= = 2
+ }
+ """ hasErrors
+ """
+ |newSource1.scala:5: error: An exported name may not contain a double underscore (`__`)
+ | val __f = 1
+ | ^
+ |newSource1.scala:3: error: A method ending in _= will be exported as setter. But a_= does not have the right signature to do so (single argument, unit return type).
+ | @JSExportAll
+ | ^
+ """
+
+ }
+
+ @Test
+ def noConflictingMethodAndProperty = {
+
+ // Basic case
+ """
+ class A {
+ @JSExport("a")
+ def bar() = 2
+
+ @JSExport("a")
+ val foo = 1
+ }
+ """ hasErrors
+ """
+ |newSource1.scala:7: error: Exported method a conflicts with A.$js$exported$prop$a
+ | @JSExport("a")
+ | ^
+ |newSource1.scala:4: error: Exported property a conflicts with A.$js$exported$meth$a
+ | @JSExport("a")
+ | ^
+ """
+
+ // Inherited case
+ """
+ class A {
+ @JSExport("a")
+ def bar() = 2
+ }
+
+ class B extends A {
+ @JSExport("a")
+ def foo_=(x: Int): Unit = ()
+
+ @JSExport("a")
+ val foo = 1
+ }
+ """ hasErrors
+ """
+ |newSource1.scala:4: error: Exported property a conflicts with A.$js$exported$meth$a
+ | @JSExport("a")
+ | ^
+ """
+
+ }
+
+ @Test
+ def noOverrideNamedExport = {
+
+ """
+ class A {
+ @JSExportNamed
+ def foo(x: Int, y: Int) = 1
+ }
+
+ class B extends A {
+ @JSExportNamed
+ override def foo(x: Int, y: Int) = 2
+ }
+ """ hasErrors
+ """
+ |newSource1.scala:9: error: overriding method $js$exported$meth$foo in class A of type (namedArgs: Any)Any;
+ | method $js$exported$meth$foo cannot override final member
+ | @JSExportNamed
+ | ^
+ """
+
+ }
+
+ @Test
+ def noConflictNamedExport = {
+
+ // Normal method
+ """
+ class A {
+ @JSExportNamed
+ def foo(x: Int, y: Int) = 1
+
+ @JSExport
+ def foo(x: scala.scalajs.js.Any) = 2
+ }
+ """ fails() // No error test, Scala version dependent error messages
+
+ // Ctors
+ """
+ class A {
+ @JSExportNamed
+ def this(x: Int) = this()
+
+ @JSExport
+ def this(x: scala.scalajs.js.Any) = this
+
+ @JSExportNamed
+ def this(x: Long) = this()
+ }
+ """ fails() // No error test, Scala version dependent error messages
+
+ }
+
+ @Test
+ def noNamedExportObject = {
+
+ """
+ @JSExportNamed
+ object A
+ """ hasErrors
+ """
+ |newSource1.scala:3: error: You may not use @JSNamedExport on an object
+ | @JSExportNamed
+ | ^
+ """
+
+ }
+
+ @Test
+ def noNamedExportVarArg = {
+
+ """
+ class A {
+ @JSExportNamed
+ def foo(a: Int*) = 1
+ }
+ """ hasErrors
+ """
+ |newSource1.scala:4: error: You may not name-export a method with a *-parameter
+ | @JSExportNamed
+ | ^
+ """
+
+ }
+
+ @Test
+ def noNamedExportProperty = {
+
+ // Getter
+ """
+ class A {
+ @JSExportNamed
+ def a = 1
+ }
+ """ hasErrors
+ """
+ |newSource1.scala:4: error: You may not export a getter or a setter as a named export
+ | @JSExportNamed
+ | ^
+ """
+
+
+ // Setter
+ """
+ class A {
+ @JSExportNamed
+ def a_=(x: Int) = ()
+ }
+ """ hasErrors
+ """
+ |newSource1.scala:4: error: You may not export a getter or a setter as a named export
+ | @JSExportNamed
+ | ^
+ """
+
+ }
+
+ @Test
+ def gracefulDoubleDefaultFail = {
+ // This used to blow up (i.e. not just fail), because PrepJSExports asked
+ // for the symbol of the default parameter getter of [[y]], and asserted its
+ // not overloaded. Since the Scala compiler only fails later on this, the
+ // assert got triggered and made the compiler crash
+ """
+ class A {
+ @JSExport
+ def foo(x: String, y: String = "hello") = x
+ def foo(x: Int, y: String = "bar") = x
+ }
+ """ fails()
+ }
+
+ @Test
+ def noNonLiteralExportNames = {
+
+ """
+ object A {
+ val a = "Hello"
+ final val b = "World"
+ }
+
+ class B {
+ @JSExport(A.a)
+ def foo = 1
+ @JSExport(A.b)
+ def bar = 1
+ }
+ """ hasErrors
+ """
+ |newSource1.scala:9: error: The argument to JSExport must be a literal string
+ | @JSExport(A.a)
+ | ^
+ """
+
+ }
+
+}