summaryrefslogtreecommitdiff
path: root/examples/scala-js/test-suite/src/test/scala/scala/scalajs/testsuite/jsinterop
diff options
context:
space:
mode:
Diffstat (limited to 'examples/scala-js/test-suite/src/test/scala/scala/scalajs/testsuite/jsinterop')
-rw-r--r--examples/scala-js/test-suite/src/test/scala/scala/scalajs/testsuite/jsinterop/ArrayTest.scala94
-rw-r--r--examples/scala-js/test-suite/src/test/scala/scala/scalajs/testsuite/jsinterop/AsyncTest.scala121
-rw-r--r--examples/scala-js/test-suite/src/test/scala/scala/scalajs/testsuite/jsinterop/DictionaryTest.scala79
-rw-r--r--examples/scala-js/test-suite/src/test/scala/scala/scalajs/testsuite/jsinterop/DynamicTest.scala187
-rw-r--r--examples/scala-js/test-suite/src/test/scala/scala/scalajs/testsuite/jsinterop/ExportsTest.scala1075
-rw-r--r--examples/scala-js/test-suite/src/test/scala/scala/scalajs/testsuite/jsinterop/FunctionTest.scala41
-rw-r--r--examples/scala-js/test-suite/src/test/scala/scala/scalajs/testsuite/jsinterop/MiscInteropTest.scala89
-rw-r--r--examples/scala-js/test-suite/src/test/scala/scala/scalajs/testsuite/jsinterop/RuntimeLongTest.scala140
-rw-r--r--examples/scala-js/test-suite/src/test/scala/scala/scalajs/testsuite/jsinterop/StrangeNamedTests.scala28
-rw-r--r--examples/scala-js/test-suite/src/test/scala/scala/scalajs/testsuite/jsinterop/ThisFunctionTest.scala70
-rw-r--r--examples/scala-js/test-suite/src/test/scala/scala/scalajs/testsuite/jsinterop/UndefOrTest.scala191
11 files changed, 2115 insertions, 0 deletions
diff --git a/examples/scala-js/test-suite/src/test/scala/scala/scalajs/testsuite/jsinterop/ArrayTest.scala b/examples/scala-js/test-suite/src/test/scala/scala/scalajs/testsuite/jsinterop/ArrayTest.scala
new file mode 100644
index 0000000..2ffd6b7
--- /dev/null
+++ b/examples/scala-js/test-suite/src/test/scala/scala/scalajs/testsuite/jsinterop/ArrayTest.scala
@@ -0,0 +1,94 @@
+/* __ *\
+** ________ ___ / / ___ __ ____ Scala.js Test Suite **
+** / __/ __// _ | / / / _ | __ / // __/ (c) 2013, LAMP/EPFL **
+** __\ \/ /__/ __ |/ /__/ __ |/_// /_\ \ http://scala-js.org/ **
+** /____/\___/_/ |_/____/_/ | |__/ /____/ **
+** |/____/ **
+\* */
+package scala.scalajs.testsuite.jsinterop
+
+import scala.scalajs.js
+import org.scalajs.jasminetest.JasmineTest
+
+object ArrayTest extends JasmineTest {
+
+ describe("scala.scalajs.js.Array") {
+
+ it("should provide implicit conversion from js.Array to ArrayOps - String") {
+ var propCount = 0
+ var propString = ""
+
+ for (item <- js.Array("Sc", "ala", ".", "js")) {
+ expect(item.isInstanceOf[String]).toBeTruthy
+ propCount += 1
+ propString += item
+ }
+
+ expect(propCount).toEqual(4)
+ expect(propString).toEqual("Scala.js")
+ }
+
+ it("should provide implicit conversion from js.Array to ArrayOps - Int") {
+ var propCount = 0
+ var propString = ""
+
+ for (item <- js.Array(7, 3, 5, 7)) {
+ expect(item.isInstanceOf[Int]).toBeTruthy
+ propCount += 1
+ propString += item
+ }
+
+ expect(propCount).toEqual(4)
+ expect(propString).toEqual("7357")
+ }
+
+ it("should provide implicit conversion from js.Array to ArrayOps - Char") {
+ var propCount = 0
+ var propString = ""
+
+ for (item <- js.Array('S', 'c', 'a', 'l', 'a')) {
+ expect(item.isInstanceOf[Char]).toBeTruthy
+ propCount += 1
+ propString += item
+ }
+
+ expect(propCount).toEqual(5)
+ expect(propString).toEqual("Scala")
+ }
+
+ it("should provide implicit conversion from js.Array to ArrayOps - value class") {
+ var propCount = 0
+ var propString = ""
+
+ for (item <- js.Array(new VC(5), new VC(-4))) {
+ expect(item.isInstanceOf[VC]).toBeTruthy
+ propCount += 1
+ propString += item
+ }
+
+ expect(propCount).toEqual(2)
+ expect(propString).toEqual("VC(5)VC(-4)")
+ }
+
+ }
+
+ describe("scala.scalajs.js.JSConverters.JSRichGenTraversableOnce") {
+
+ import js.JSConverters._
+
+ it("should provide toJSArray") {
+ expect(List("foo", "bar").toJSArray).toEqual(js.Array("foo", "bar"))
+ expect(Iterator(1, 2, 3).toJSArray).toEqual(js.Array(1, 2, 3))
+ expect(Array(0.3, 7.3, 8.9).toJSArray).toEqual(js.Array(0.3, 7.3, 8.9))
+ expect(None.toJSArray).toEqual(js.Array())
+ // The following fails on 2.10.x
+ //expect(Some("Hello World").toJSArray).toEqual(js.Array("Hello World"))
+ }
+
+ }
+
+ private class VC(val x: Int) extends AnyVal {
+ override def toString(): String = s"VC($x)"
+ }
+
+}
diff --git a/examples/scala-js/test-suite/src/test/scala/scala/scalajs/testsuite/jsinterop/AsyncTest.scala b/examples/scala-js/test-suite/src/test/scala/scala/scalajs/testsuite/jsinterop/AsyncTest.scala
new file mode 100644
index 0000000..e37c89e
--- /dev/null
+++ b/examples/scala-js/test-suite/src/test/scala/scala/scalajs/testsuite/jsinterop/AsyncTest.scala
@@ -0,0 +1,121 @@
+/* __ *\
+** ________ ___ / / ___ __ ____ Scala.js Test Suite **
+** / __/ __// _ | / / / _ | __ / // __/ (c) 2013, LAMP/EPFL **
+** __\ \/ /__/ __ |/ /__/ __ |/_// /_\ \ http://scala-js.org/ **
+** /____/\___/_/ |_/____/_/ | |__/ /____/ **
+** |/____/ **
+\* */
+package scala.scalajs.testsuite.jsinterop
+
+import scala.scalajs.js
+import scala.scalajs.js.JSConverters._
+
+import org.scalajs.jasminetest.JasmineTest
+
+import scala.concurrent.{Future, ExecutionContext}
+import scala.scalajs.concurrent.JSExecutionContext
+
+import scala.collection.mutable.ArrayBuffer
+
+import org.scalajs.jasmine.JasmineExpectation
+
+object AsyncTest extends JasmineTest {
+
+ def asyncTest(implicit executor: ExecutionContext) = {
+ val steps = new ArrayBuffer[String]
+
+ steps += "prep-future"
+
+ val f1 = Future {
+ steps += "future"
+ 1 + 2 + 3
+ }
+
+ steps += "prep-map"
+
+ val f2 = f1 map { x =>
+ steps += "map"
+ x * 2
+ }
+
+ steps += "prep-foreach"
+
+ f2 foreach { _ => steps += "foreach" }
+
+ steps += "done"
+
+ steps
+ }
+
+ def expect(abuf: ArrayBuffer[String]): JasmineExpectation =
+ expect(abuf.toJSArray)
+
+ describe("scala.scalajs.concurrent.JSExecutionContext.queue") {
+
+ beforeEach {
+ jasmine.Clock.useMock()
+ }
+
+ it("should correctly order future calls") {
+ val res = asyncTest(JSExecutionContext.queue)
+
+ expect(res).toEqual(js.Array(
+ "prep-future",
+ "prep-map",
+ "prep-foreach",
+ "done"))
+
+ jasmine.Clock.tick(1)
+
+ expect(res).toEqual(js.Array(
+ "prep-future",
+ "prep-map",
+ "prep-foreach",
+ "done",
+ "future",
+ "map",
+ "foreach"))
+ }
+
+ }
+
+ describe("scala.scalajs.concurrent.JSExecutionContext.runNow") {
+
+ it("should correctly order future calls") {
+ val res = asyncTest(JSExecutionContext.runNow)
+
+ expect(res).toEqual(js.Array(
+ "prep-future",
+ "future",
+ "prep-map",
+ "map",
+ "prep-foreach",
+ "foreach",
+ "done"))
+ }
+
+ }
+
+ describe("scala.concurrent.Future") {
+
+ it("should support map") {
+ implicit val ec = JSExecutionContext.runNow
+ val f = Future(3).map(x => x*2)
+ expect(f.value.get.get).toEqual(6)
+ }
+
+ it("should support flatMap") {
+ implicit val ec = JSExecutionContext.runNow
+ val f = Future(Future(3)).flatMap(x => x)
+ expect(f.value.get.get).toEqual(3)
+ }
+
+ it("should support sequence") {
+ implicit val ec = JSExecutionContext.runNow
+ val f = Future.sequence(Seq(Future(3), Future(5)))
+ expect(f.value.get.get.toJSArray).toEqual(js.Array(3, 5))
+ }
+
+ }
+
+}
diff --git a/examples/scala-js/test-suite/src/test/scala/scala/scalajs/testsuite/jsinterop/DictionaryTest.scala b/examples/scala-js/test-suite/src/test/scala/scala/scalajs/testsuite/jsinterop/DictionaryTest.scala
new file mode 100644
index 0000000..8b45395
--- /dev/null
+++ b/examples/scala-js/test-suite/src/test/scala/scala/scalajs/testsuite/jsinterop/DictionaryTest.scala
@@ -0,0 +1,79 @@
+/* __ *\
+** ________ ___ / / ___ __ ____ Scala.js Test Suite **
+** / __/ __// _ | / / / _ | __ / // __/ (c) 2013, LAMP/EPFL **
+** __\ \/ /__/ __ |/ /__/ __ |/_// /_\ \ http://scala-js.org/ **
+** /____/\___/_/ |_/____/_/ | |__/ /____/ **
+** |/____/ **
+\* */
+package scala.scalajs.testsuite.jsinterop
+
+import scala.scalajs.js
+import org.scalajs.jasminetest.JasmineTest
+
+object DictionaryTest extends JasmineTest {
+
+ describe("scala.scalajs.js.Dictionary") {
+
+ it("should provide an equivalent of the JS delete keyword - #255") {
+ val obj = js.Dictionary.empty[js.Any]
+ obj("foo") = 42
+ obj("bar") = "foobar"
+
+ expect(obj("foo")).toEqual(42)
+ expect(obj("bar")).toEqual("foobar")
+ obj.delete("foo")
+ expect(obj("foo")).toBeUndefined
+ expect(obj.asInstanceOf[js.Object].hasOwnProperty("foo")).toBeFalsy
+ expect(obj("bar")).toEqual("foobar")
+ }
+
+ // This doesn't work on Rhino due to lack of full strict mode support - #679
+ unless("rhino").
+ it("should behave as specified when deleting a non-configurable property - #461 - #679") {
+ val obj = js.Dictionary.empty[js.Any]
+ js.Object.defineProperty(obj.asInstanceOf[js.Object], "nonconfig",
+ js.Dynamic.literal(value = 4, writable = false).asInstanceOf[js.PropertyDescriptor])
+ expect(obj("nonconfig")).toEqual(4)
+ expect(() => obj.delete("nonconfig")).toThrow
+ expect(obj("nonconfig")).toEqual(4)
+ }
+
+ it("should provide `get`") {
+ val obj = js.Dictionary.empty[Int]
+ obj("hello") = 1
+
+ expect(obj.get("hello").isDefined).toBeTruthy
+ expect(obj.get("world").isDefined).toBeFalsy
+ }
+
+ it("should treat delete as a statement - #907") {
+ val obj = js.Dictionary("a" -> "A")
+ obj.delete("a")
+ }
+
+ it("should desugar arguments to delete statements - #908") {
+ val kh = js.Dynamic.literal( key = "a" ).asInstanceOf[KeyHolder]
+ val dict = js.Dictionary[String]("a" -> "A")
+ def a[T](foo: String) = dict.asInstanceOf[T]
+ a[js.Dictionary[String]]("foo").delete(kh.key)
+ }
+
+ }
+
+ trait KeyHolder extends js.Object {
+ def key: String = js.native
+ }
+
+ describe("scala.scalajs.js.JSConverters.JSRichGenMap") {
+
+ import js.JSConverters._
+
+ it("should provide toJSDictionary") {
+ expect(Map("a" -> 1, "b" -> 2).toJSDictionary).toEqual(
+ js.Dynamic.literal(a = 1, b = 2))
+ expect(Map("a" -> "foo", "b" -> "bar").toJSDictionary).toEqual(
+ js.Dynamic.literal(a = "foo", b = "bar"))
+ }
+
+ }
+}
diff --git a/examples/scala-js/test-suite/src/test/scala/scala/scalajs/testsuite/jsinterop/DynamicTest.scala b/examples/scala-js/test-suite/src/test/scala/scala/scalajs/testsuite/jsinterop/DynamicTest.scala
new file mode 100644
index 0000000..2b6942f
--- /dev/null
+++ b/examples/scala-js/test-suite/src/test/scala/scala/scalajs/testsuite/jsinterop/DynamicTest.scala
@@ -0,0 +1,187 @@
+/* __ *\
+** ________ ___ / / ___ __ ____ Scala.js Test Suite **
+** / __/ __// _ | / / / _ | __ / // __/ (c) 2013, LAMP/EPFL **
+** __\ \/ /__/ __ |/ /__/ __ |/_// /_\ \ http://scala-js.org/ **
+** /____/\___/_/ |_/____/_/ | |__/ /____/ **
+** |/____/ **
+\* */
+package scala.scalajs.testsuite.jsinterop
+
+import scala.scalajs.js
+import org.scalajs.jasminetest.JasmineTest
+
+import js.annotation.JSExport
+
+object DynamicTest extends JasmineTest {
+
+ describe("scala.scalajs.js.Dynamic") {
+
+ it("should workaround Scala 2.10 issue with implicit conversion for dynamic fields named x - #8") {
+ class Point(val x: Int, val y: Int)
+
+ def jsonToPoint(json: js.Dynamic) = {
+ new Point(json.x.toString.toInt, json.y.toString.toInt)
+ }
+
+ val json = js.eval("var dynamicTestPoint = { x: 1, y: 2 }; dynamicTestPoint;")
+ val point = jsonToPoint(json.asInstanceOf[js.Dynamic])
+
+ expect(point.x).toEqual(1)
+ expect(point.y).toEqual(2)
+ }
+
+ it("should allow to call functions with arguments named x") {
+ class A {
+ def a = 1
+ }
+
+ class B extends A {
+ @JSExport
+ def x(par: Int) = a + par // make sure `this` is bound correctly in JS
+ }
+
+ val b = (new B).asInstanceOf[js.Dynamic]
+
+ expect(b.x(10)).toEqual(11)
+ }
+
+ it("should allow instanciating JS classes dynamically - #10") {
+ val DynamicTestClass = js.eval("""
+ var DynamicTestClass = function(x) {
+ this.x = x;
+ };
+ DynamicTestClass;
+ """).asInstanceOf[js.Dynamic]
+ val obj = js.Dynamic.newInstance(DynamicTestClass)("Scala.js")
+ expect(obj.x).toEqual("Scala.js")
+ }
+
+ it("should allow instantiating JS classes dynamically with varargs - #708") {
+ val DynamicTestClassVarArgs = js.eval("""
+ var DynamicTestClassVarArgs = function() {
+ this.count = arguments.length;
+ for (var i = 0; i < arguments.length; i++)
+ this['elem'+i] = arguments[i];
+ };
+ DynamicTestClassVarArgs;
+ """).asInstanceOf[js.Dynamic]
+
+ val obj1 = js.Dynamic.newInstance(DynamicTestClassVarArgs)("Scala.js")
+ expect(obj1.count).toEqual(1)
+ expect(obj1.elem0).toEqual("Scala.js")
+
+ val obj2 = js.Dynamic.newInstance(DynamicTestClassVarArgs)(
+ "Scala.js", 42, true)
+ expect(obj2.count).toEqual(3)
+ expect(obj2.elem0).toEqual("Scala.js")
+ expect(obj2.elem1).toEqual(42)
+ expect(obj2.elem2).toEqual(true)
+
+ def obj3Args: Seq[js.Any] = Seq("Scala.js", 42, true)
+ val obj3 = js.Dynamic.newInstance(DynamicTestClassVarArgs)(obj3Args: _*)
+ expect(obj3.count).toEqual(3)
+ expect(obj3.elem0).toEqual("Scala.js")
+ expect(obj3.elem1).toEqual(42)
+ expect(obj3.elem2).toEqual(true)
+ }
+
+ it("should provide an object literal construction") {
+ import js.Dynamic.{ literal => obj }
+ val x = obj(foo = 3, bar = "foobar")
+ expect(x.foo).toEqual(3)
+ expect(x.bar).toEqual("foobar")
+ expect(x.unknown).toBeUndefined()
+
+ val y = obj(
+ inner = obj(name = "inner obj"),
+ fun = { () => 42 }
+ )
+ expect(y.inner.name).toEqual("inner obj")
+ expect(y.fun()).toEqual(42)
+
+ expect(obj().anything).toBeUndefined()
+ }
+
+ it("should provide object literal construction with dynamic naming") {
+ import js.Dynamic.{ literal => obj }
+ val x = obj("foo" -> 3, "bar" -> "foobar")
+ expect(x.foo).toEqual(3)
+ expect(x.bar).toEqual("foobar")
+ expect(x.unknown).toBeUndefined()
+
+ val tup1 = ("hello1", 3: js.Any)
+ val tup2 = ("hello2", 10: js.Any)
+
+ val y = obj(tup1, tup2)
+ expect(y.hello1).toEqual(3)
+ expect(y.hello2).toEqual(10)
+
+ var count = 0
+ val z = obj({ count += 1; ("foo", "bar")})
+ expect(z.foo).toEqual("bar")
+ expect(count).toEqual(1)
+ }
+
+ it("should allow to create an empty object with the literal syntax") {
+ import js.Dynamic.{ literal => obj }
+ val x = obj()
+ expect(x.isInstanceOf[js.Object]).toBeTruthy()
+ }
+
+ it("should properly encode object literal property names") {
+ import js.Dynamic.{ literal => obj }
+
+ val obj0 = obj("3-" -> 42)
+ expect(obj0.`3-`).toEqual(42)
+
+ val obj0Dict = obj0.asInstanceOf[js.Dictionary[js.Any]]
+ expect(obj0Dict("3-")).toEqual(42)
+
+ val checkEvilProperties = js.eval("""
+ function dynamicLiteralNameEncoding_checkEvilProperties(x) {
+ return x['.o[3√!|-pr()per7:3$];'] === ' such eval ';
+ }
+ dynamicLiteralNameEncoding_checkEvilProperties
+ """).asInstanceOf[js.Function1[js.Any, Boolean]]
+ val obj1 = obj(
+ ".o[3√!|-pr()per7:3$];" -> " such eval ").asInstanceOf[js.Dictionary[js.Any]]
+ expect(obj1(".o[3√!|-pr()per7:3$];")).toEqual(" such eval ")
+ expect(checkEvilProperties(obj1)).toEqual(true)
+
+ val checkQuotesProperty = js.eval("""
+ function dynamicLiteralNameEncoding_quote(x) {
+ return x["'" + '"'] === 7357;
+ }
+ dynamicLiteralNameEncoding_quote
+ """).asInstanceOf[js.Function1[js.Any, Boolean]]
+
+ val quote = '"'
+
+ Seq(
+ obj("'" + quote -> 7357),
+ obj(s"'$quote" -> 7357),
+ obj("'\"" -> 7357),
+ obj("'" + quote -> 7357)
+ ).foreach { o =>
+ val dict = o.asInstanceOf[js.Dictionary[js.Any]]
+ expect(dict("'\"")).toEqual(7357)
+ expect(dict("'" + quote)).toEqual(7357)
+ expect(dict(s"'$quote")).toEqual(7357)
+ expect(checkQuotesProperty(o)).toEqual(true)
+ }
+ }
+
+ it("should return subclasses of js.Object in literal construction - #783") {
+ import js.Dynamic.{ literal => obj }
+
+ val a: js.Object = obj(theValue = 1)
+ expect(a.hasOwnProperty("theValue")).toBeTruthy
+ expect(a.hasOwnProperty("noValue")).toBeFalsy
+
+ val b: js.Object = obj("theValue" -> 2)
+ expect(b.hasOwnProperty("theValue")).toBeTruthy
+ expect(b.hasOwnProperty("noValue")).toBeFalsy
+
+ }
+ }
+}
diff --git a/examples/scala-js/test-suite/src/test/scala/scala/scalajs/testsuite/jsinterop/ExportsTest.scala b/examples/scala-js/test-suite/src/test/scala/scala/scalajs/testsuite/jsinterop/ExportsTest.scala
new file mode 100644
index 0000000..d577d8d
--- /dev/null
+++ b/examples/scala-js/test-suite/src/test/scala/scala/scalajs/testsuite/jsinterop/ExportsTest.scala
@@ -0,0 +1,1075 @@
+/* __ *\
+** ________ ___ / / ___ __ ____ Scala.js Test Suite **
+** / __/ __// _ | / / / _ | __ / // __/ (c) 2013, LAMP/EPFL **
+** __\ \/ /__/ __ |/ /__/ __ |/_// /_\ \ http://scala-js.org/ **
+** /____/\___/_/ |_/____/_/ | |__/ /____/ **
+** |/____/ **
+\* */
+package scala.scalajs.testsuite.jsinterop
+
+import scala.scalajs.js
+import js.annotation._
+import org.scalajs.jasminetest.{JasmineTest, JasmineTestFramework}
+
+import scala.annotation.meta
+
+object ExportsTest extends JasmineTest {
+
+ /** This package in the JS (export) namespace */
+ val jsPackage = js.Dynamic.global.scala.scalajs.testsuite.jsinterop
+
+ describe("@JSExport") {
+
+ it("should offer exports for methods with implicit name") {
+ class Foo {
+ @JSExport
+ def bar(): Int = 42
+ @JSExport
+ def double(x: Int): Int = x*2
+ }
+
+ val foo = (new Foo).asInstanceOf[js.Dynamic]
+ expect(js.typeOf(foo.bar)).toBe("function")
+ expect(foo.bar()).toEqual(42)
+ expect(foo.double(3)).toEqual(6)
+ }
+
+ it("should offer exports for methods with explicit name") {
+ class Foo {
+ @JSExport("theAnswer")
+ def bar(): Int = 42
+ @JSExport("doubleTheParam")
+ def double(x: Int): Int = x*2
+ }
+
+ val foo = (new Foo).asInstanceOf[js.Dynamic]
+ expect(foo.bar).toBeUndefined
+ expect(js.typeOf(foo.theAnswer)).toBe("function")
+ expect(foo.theAnswer()).toEqual(42)
+ expect(foo.doubleTheParam(3)).toEqual(6)
+ }
+
+ it("should offer exports for methods with constant folded name") {
+ class Foo {
+ @JSExport(ExportNameHolder.methodName)
+ def bar(): Int = 42
+ }
+
+ val foo = (new Foo).asInstanceOf[js.Dynamic]
+ expect(foo.bar).toBeUndefined
+ expect(foo.myMethod()).toEqual(42)
+ }
+
+ it("should offer exports for protected methods") {
+ class Foo {
+ @JSExport
+ protected def bar(): Int = 42
+
+ @JSExport
+ protected[testsuite] def foo(): Int = 100
+ }
+
+ val foo = (new Foo).asInstanceOf[js.Dynamic]
+ expect(js.typeOf(foo.bar)).toBe("function")
+ expect(foo.bar()).toEqual(42)
+ expect(js.typeOf(foo.foo)).toBe("function")
+ expect(foo.foo()).toEqual(100)
+ }
+
+ it("should offer exports for properties with implicit name") {
+ class Foo {
+ private[this] var myY: String = "hello"
+ @JSExport
+ val answer: Int = 42
+ @JSExport
+ var x: Int = 3
+ @JSExport
+ def doubleX: Int = x*2
+ @JSExport
+ def y: String = myY + " get"
+ @JSExport
+ def y_=(v: String): Unit = myY = v + " set"
+ }
+
+ val foo = (new Foo).asInstanceOf[js.Dynamic]
+ expect(js.typeOf(foo.answer)).toBe("number")
+ expect(foo.answer).toEqual(42)
+ expect(foo.x).toEqual(3)
+ expect(foo.doubleX).toEqual(6)
+ foo.x = 23
+ expect(foo.x).toEqual(23)
+ expect(foo.doubleX).toEqual(46)
+ expect(foo.y).toEqual("hello get")
+ foo.y = "world"
+ expect(foo.y).toEqual("world set get")
+ }
+
+ it("should offer exports for properties with explicit name") {
+ class Foo {
+ private[this] var myY: String = "hello"
+ @JSExport("answer")
+ val answerScala: Int = 42
+ @JSExport("x")
+ var xScala: Int = 3
+ @JSExport("doubleX")
+ def doubleXScala: Int = xScala*2
+ @JSExport("y")
+ def yGetter: String = myY + " get"
+ @JSExport("y")
+ def ySetter_=(v: String): Unit = myY = v + " set"
+ }
+
+ val foo = (new Foo).asInstanceOf[js.Dynamic]
+ expect(foo.answerScala).toBeUndefined
+ expect(js.typeOf(foo.answer)).toBe("number")
+ expect(foo.answer).toEqual(42)
+ expect(foo.x).toEqual(3)
+ expect(foo.doubleX).toEqual(6)
+ foo.x = 23
+ expect(foo.x).toEqual(23)
+ expect(foo.doubleX).toEqual(46)
+ expect(foo.y).toEqual("hello get")
+ foo.y = "world"
+ expect(foo.y).toEqual("world set get")
+ }
+
+ it("should offer exports for protected properties") {
+ class Foo {
+ @JSExport
+ protected val x: Int = 42
+ @JSExport
+ protected[testsuite] val y: Int = 43
+ }
+
+ val foo = (new Foo).asInstanceOf[js.Dynamic]
+ expect(foo.x).toEqual(42)
+ expect(foo.y).toEqual(43)
+ }
+
+ it("should offer overloaded exports for methods") {
+ class Foo {
+ @JSExport("foobar")
+ def foo(): Int = 42
+ @JSExport("foobar")
+ def bar(x: Int): Int = x*2
+ }
+
+ val foo = (new Foo).asInstanceOf[js.Dynamic]
+ expect(js.typeOf(foo.foobar)).toBe("function")
+ expect(foo.foobar()).toEqual(42)
+ expect(foo.foobar(3)).toEqual(6)
+ }
+
+ it("should offer multiple exports for the same method") {
+ class Foo {
+ @JSExport
+ @JSExport("b")
+ @JSExport("c")
+ def a(): Int = 1
+ }
+
+ val foo = (new Foo).asInstanceOf[js.Dynamic]
+ expect(js.typeOf(foo.a)).toBe("function")
+ expect(js.typeOf(foo.b)).toBe("function")
+ expect(js.typeOf(foo.c)).toBe("function")
+
+ expect(foo.a()).toEqual(1)
+ expect(foo.b()).toEqual(1)
+ expect(foo.c()).toEqual(1)
+ }
+
+ it("should inherit exports from traits") {
+ trait Foo {
+ @JSExport
+ def x: Int
+
+ @JSExport
+ def method(x: Int): Int
+ }
+
+ class Bar extends Foo {
+ val x = 1
+ def method(x: Int) = 2 * x
+ }
+
+ val bar = (new Bar).asInstanceOf[js.Dynamic]
+ expect(bar.x).toEqual(1)
+ expect(js.typeOf(bar.method)).toBe("function")
+ expect(bar.method(2)).toEqual(4)
+ }
+
+ it("should offer overloading with inherited exports") {
+ class A {
+ @JSExport
+ def foo(x: Int) = 2*x
+ }
+
+ class B extends A{
+ @JSExport("foo")
+ def bar(x: String) = s"Hello $x"
+ }
+
+ val b = (new B).asInstanceOf[js.Dynamic]
+ expect(js.typeOf(b.foo)).toBe("function")
+ expect(b.foo(1)).toEqual(2)
+ expect(b.foo("World")).toEqual("Hello World")
+ }
+
+ it("should offer exports for generic methods") {
+ class Foo {
+ @JSExport
+ def gen[T <: AnyRef](x: T) = x
+ }
+
+ val x = (new Object).asInstanceOf[js.Any]
+
+ val foo = (new Foo).asInstanceOf[js.Dynamic]
+ expect(js.typeOf(foo.gen)).toBe("function")
+ expect(foo.gen(x)).toBe(x)
+ }
+
+ it("should offer exports for lambda return types") {
+ class Foo {
+ @JSExport
+ def lambda(x: Int) = (y: Int) => x + y
+ }
+
+ val foo = (new Foo).asInstanceOf[js.Dynamic]
+ expect(js.typeOf(foo.lambda)).toBe("function")
+
+ val lambda = foo.lambda(5).asInstanceOf[Function1[Int,Int]]
+
+ expect(lambda(4)).toEqual(9)
+ }
+
+ it("should offer exports for multi parameter lists") {
+ class Foo {
+ @JSExport
+ def multiParam(x: Int)(y: Int): Int = x + y
+ }
+
+ val foo = (new Foo).asInstanceOf[js.Dynamic]
+ expect(js.typeOf(foo.multiParam)).toBe("function")
+ expect(foo.multiParam(5,6)).toEqual(11)
+ }
+
+ it("should offer exports for default arguments") {
+ class Foo {
+ @JSExport
+ def defArg(x: Int = 1) = x
+ }
+
+ val foo = (new Foo).asInstanceOf[js.Dynamic]
+ expect(js.typeOf(foo.defArg)).toBe("function")
+ expect(foo.defArg(5)).toEqual(5)
+ }
+
+ it("should offer exports for weird stuff") {
+ class UhOh {
+ // Something no one should export
+ @JSExport
+ def ahem[T : Comparable](x: T)(implicit y: Int) = ???
+ }
+
+ val x = (new UhOh).asInstanceOf[js.Dynamic]
+ expect(js.typeOf(x.ahem)).toBe("function")
+ }
+
+ it("should offer exports with value class return types") {
+ class Foo {
+ @JSExport
+ def vc(x: Int) = new SomeValueClass(x)
+ }
+
+ val foo = (new Foo).asInstanceOf[js.Dynamic]
+ expect(js.typeOf(foo.vc)).toBe("function")
+
+ // The result should be a boxed SomeValueClass
+ val result = foo.vc(5)
+ expect(js.typeOf(result)).toEqual("object")
+ expect((result: Any).isInstanceOf[SomeValueClass]).toBeTruthy
+ expect((result: Any) == (new SomeValueClass(5))).toBeTruthy
+ }
+
+ it("should allow exports with Any as return type") {
+ class A
+ class Foo {
+ @JSExport
+ def foo(switch: Boolean): Any =
+ if (switch) 1 else new A
+ }
+
+ val foo = (new Foo).asInstanceOf[js.Dynamic]
+ expect(foo.foo(true).isInstanceOf[Int]).toBeTruthy
+ expect(foo.foo(false).isInstanceOf[A]).toBeTruthy
+ }
+
+ it("should accept boxed value classes as parameter") {
+ class Foo {
+ @JSExport
+ def vc(x: SomeValueClass) = x.i
+ }
+
+ val foo = (new Foo).asInstanceOf[js.Dynamic]
+ expect(js.typeOf(foo.vc)).toBe("function")
+
+ // The parameter should be a boxed SomeValueClass
+ val valueCls = new SomeValueClass(7)
+ val result = foo.vc(valueCls.asInstanceOf[js.Any])
+ expect(js.typeOf(result)).toEqual("number")
+ expect(result).toEqual(7)
+ }
+
+ it("should offer exports for overridden methods with refined return type") {
+ class A
+ class B extends A
+
+ class C1 {
+ @JSExport
+ def x: A = new A
+ }
+
+ class C2 extends C1 {
+ override def x: B = new B
+ }
+
+ val c2 = (new C2).asInstanceOf[js.Dynamic]
+ expect(c2.x.isInstanceOf[B]).toBeTruthy
+ }
+
+ it("should offer exports for methods with refined types as return type") {
+ class A {
+ @JSExport
+ def foo(x: String): js.Object with js.Dynamic =
+ js.Dynamic.literal(arg = x)
+ }
+
+ val a = (new A).asInstanceOf[js.Dynamic]
+ expect(a.foo("hello")).toEqual(js.Dynamic.literal(arg = "hello"))
+ }
+
+ it("should offer exports for variable argument methods - #393") {
+ class A {
+ @JSExport
+ def foo(i: String*) = i.mkString("|")
+ }
+
+ val a = (new A).asInstanceOf[js.Dynamic]
+
+ expect(a.foo()).toEqual("")
+ expect(a.foo("a", "b", "c")).toEqual("a|b|c")
+ expect(a.foo("a", "b", "c", "d")).toEqual("a|b|c|d")
+ }
+
+ it("should correctly overload in view of difficult repeated parameter lists") {
+ class A {
+ @JSExport
+ def foo(a: String, b: String, i: Int, c: String) = 1
+
+ @JSExport
+ def foo(a: String*) = 2
+
+ @JSExport
+ def foo(x: Int)(a: Int*) = x * 100000 + a.sum
+ }
+
+ val a = (new A).asInstanceOf[js.Dynamic]
+
+ expect(a.foo()).toEqual(2)
+ expect(a.foo("asdf")).toEqual(2)
+ expect(a.foo("asdf", "foo")).toEqual(2)
+ expect(a.foo("asdf", "foo", "bar")).toEqual(2)
+ expect(a.foo("asdf", "foo", 1, "bar")).toEqual(1)
+ expect(a.foo("asdf", "foo", "foo", "bar")).toEqual(2)
+ expect(a.foo(5, 1, 2, 3, 10)).toEqual(500016)
+ expect(a.foo(1)).toEqual(100000)
+ }
+
+ it("should offer exports with default arguments") {
+ class A {
+ var oneCount: Int = 0
+ def one = {
+ oneCount += 1
+ 1
+ }
+ @JSExport
+ def foo(a: Int = one)(b: Int = a + one)(c: Int = b + one) =
+ a + b + c
+ }
+
+ val a = new A
+ val jsa = a.asInstanceOf[js.Dynamic]
+
+ expect(jsa.foo()).toEqual(6)
+ expect(a.oneCount).toEqual(3)
+
+ expect(jsa.foo(2)).toEqual(9)
+ expect(a.oneCount).toEqual(5)
+
+ expect(jsa.foo(2,4)).toEqual(11)
+ expect(a.oneCount).toEqual(6)
+
+ expect(jsa.foo(2,4,10)).toEqual(16)
+ expect(a.oneCount).toEqual(6)
+
+ expect(jsa.foo((),4,10)).toEqual(15)
+ expect(a.oneCount).toEqual(7)
+
+ expect(jsa.foo((),4)).toEqual(10)
+ expect(a.oneCount).toEqual(9)
+ }
+
+ it("should correctly overload methods in presence of default parameters") {
+ class A {
+ @JSExport
+ def foo(a: Int)(b: Int = 5)(c: Int = 7) = 1000 + a + b + c
+
+ @JSExport
+ def foo(a: Int, b: String) = 2
+
+ @JSExport
+ def foo(a: Int, b: Int, c: String) = 3
+ }
+
+ val a = (new A).asInstanceOf[js.Dynamic]
+
+ expect(a.foo(1)).toEqual(1013)
+ expect(a.foo(1, 4)).toEqual(1012)
+ expect(a.foo(1, 4, 5)).toEqual(1010)
+ expect(a.foo(1, "foo")).toEqual(2)
+ expect(a.foo(1, 2, "foo")).toEqual(3)
+
+ }
+
+ it("should prefer overloads taking a js.Undefined over methods with default parameters") {
+ class A {
+ @JSExport
+ def foo(a: Int)(b: String = "asdf") = s"$a $b"
+
+ @JSExport
+ def foo(a: Int, b: js.prim.Undefined) = "woot"
+ }
+
+ val a = (new A).asInstanceOf[js.Dynamic]
+
+ expect(a.foo(1)).toEqual("1 asdf")
+ expect(a.foo(2, "omg")).toEqual("2 omg")
+ expect(a.foo(1, ())).toEqual("woot")
+
+ }
+
+ it("should correctly overload methods in presence of default parameters and repeated parameters") {
+ class A {
+ @JSExport
+ def foo(x: Int, y: Int = 1) = x + y
+ @JSExport
+ def foo(x: String*) = x.mkString("|")
+ }
+
+ val a = (new A).asInstanceOf[js.Dynamic]
+
+ expect(a.foo(1)).toEqual(2)
+ expect(a.foo(1, 2)).toEqual(3)
+ expect(a.foo()).toEqual("")
+ expect(a.foo("foo")).toEqual("foo")
+ expect(a.foo("foo","bar")).toEqual("foo|bar")
+
+ }
+
+ it("should correctly overload exports called `toString`") {
+ class A {
+ override def toString(): String = "no arg"
+ @JSExport
+ def toString(x: Int): String = s"with arg: $x"
+ }
+
+ val a = (new A).asInstanceOf[js.Dynamic]
+ expect(a.applyDynamic("toString")()).toEqual("no arg")
+ expect(a.applyDynamic("toString")(1)).toEqual("with arg: 1")
+ }
+
+ it("should allow to explicitly export toString") {
+ class A {
+ @JSExport("toString")
+ override def toString(): String = "called"
+ }
+
+ val a = (new A).asInstanceOf[js.Dynamic]
+ expect(a.applyDynamic("toString")()).toEqual("called")
+ }
+
+ it("should correctly box repeated parameter lists with value classes") {
+ class A {
+ @JSExport
+ def foo(vcs: SomeValueClass*) = vcs.map(_.i).sum
+ }
+
+ val vc1 = new SomeValueClass(1)
+ val vc2 = new SomeValueClass(2)
+ val a = (new A).asInstanceOf[js.Dynamic]
+
+ expect(a.foo(vc1.asInstanceOf[js.Any], vc2.asInstanceOf[js.Any])).toEqual(3)
+ }
+
+ it("should offer exports for objects with implicit name") {
+ val accessor = jsPackage.ExportedObject
+ expect(accessor).toBeDefined
+ expect(js.typeOf(accessor)).toEqual("function")
+ val obj = accessor()
+ expect(obj).toBeDefined
+ expect(js.typeOf(obj)).toEqual("object")
+ expect(obj.witness).toEqual("witness")
+ }
+
+ it("should offer exports for objects with explicit name") {
+ val accessor = js.Dynamic.global.TheExportedObject
+ expect(accessor).toBeDefined
+ expect(js.typeOf(accessor)).toEqual("function")
+ val obj = accessor()
+ expect(obj).toBeDefined
+ expect(js.typeOf(obj)).toEqual("object")
+ expect(obj.witness).toEqual("witness")
+ }
+
+ it("should offer exports for objects with qualified name") {
+ val accessor = js.Dynamic.global.qualified.testobject.ExportedObject
+ expect(accessor).toBeDefined
+ expect(js.typeOf(accessor)).toEqual("function")
+ val obj = accessor()
+ expect(obj).toBeDefined
+ expect(js.typeOf(obj)).toEqual("object")
+ expect(obj.witness).toEqual("witness")
+ }
+
+ it("should offer exports for objects with constant folded name") {
+ val accessor = js.Dynamic.global.ConstantFoldedObjectExport
+ expect(accessor).toBeDefined
+ expect(js.typeOf(accessor)).toEqual("function")
+ val obj = accessor()
+ expect(obj).toBeDefined
+ expect(js.typeOf(obj)).toEqual("object")
+ expect(obj.witness).toEqual("witness")
+ }
+
+ it("should offer exports for protected objects") {
+ val accessor = jsPackage.ProtectedExportedObject
+ expect(accessor).toBeDefined
+ expect(js.typeOf(accessor)).toEqual("function")
+ val obj = accessor()
+ expect(obj).toBeDefined
+ expect(js.typeOf(obj)).toEqual("object")
+ expect(obj.witness).toEqual("witness")
+ }
+
+ it("should offer exports for classes with implicit name") {
+ val constr = jsPackage.ExportedClass
+ expect(constr).toBeDefined
+ expect(js.typeOf(constr)).toEqual("function")
+ val obj = js.Dynamic.newInstance(constr)(5)
+ expect(obj.x).toEqual(5)
+ }
+
+ it("should offer exports for classes with explicit name") {
+ val constr = js.Dynamic.global.TheExportedClass
+ expect(constr).toBeDefined
+ expect(js.typeOf(constr)).toEqual("function")
+ val obj = js.Dynamic.newInstance(constr)(5)
+ expect(obj.x).toEqual(5)
+ }
+
+ it("should offer exports for classes with qualified name") {
+ val constr = js.Dynamic.global.qualified.testclass.ExportedClass
+ expect(constr).toBeDefined
+ expect(js.typeOf(constr)).toEqual("function")
+ val obj = js.Dynamic.newInstance(constr)(5)
+ expect(obj.x).toEqual(5)
+ }
+
+ it("should offer exports for classes with constant folded name") {
+ val constr = js.Dynamic.global.ConstantFoldedClassExport
+ expect(constr).toBeDefined
+ expect(js.typeOf(constr)).toEqual("function")
+ val obj = js.Dynamic.newInstance(constr)(5)
+ expect(obj.x).toEqual(5)
+ }
+
+ it("should offer exports for protected classes") {
+ val constr = jsPackage.ProtectedExportedClass
+ expect(constr).toBeDefined
+ expect(js.typeOf(constr)).toEqual("function")
+ val obj = js.Dynamic.newInstance(constr)(5)
+ expect(obj.x).toEqual(5)
+ }
+
+ it("should offer export for classes with repeated parameters in ctor") {
+ val constr = jsPackage.ExportedVarArgClass
+ expect(js.Dynamic.newInstance(constr)().result).toEqual("")
+ expect(js.Dynamic.newInstance(constr)("a").result).toEqual("a")
+ expect(js.Dynamic.newInstance(constr)("a", "b").result).toEqual("a|b")
+ expect(js.Dynamic.newInstance(constr)("a", "b", "c").result).toEqual("a|b|c")
+ expect(js.Dynamic.newInstance(constr)(5, "a").result).toEqual("Number: <5>|a")
+ }
+
+ it("should offer export for classes with default parameters in ctor") {
+ val constr = jsPackage.ExportedDefaultArgClass
+ expect(js.Dynamic.newInstance(constr)(1,2,3).result).toEqual(6)
+ expect(js.Dynamic.newInstance(constr)(1).result).toEqual(106)
+ expect(js.Dynamic.newInstance(constr)(1,2).result).toEqual(103)
+ }
+
+ it("should correctly disambiguate overloads involving longs") {
+
+ class Foo {
+ @JSExport
+ def foo(x: Int) = 1
+ @JSExport
+ def foo(x: Long) = 2
+ }
+
+ val foo = (new Foo).asInstanceOf[js.Dynamic]
+
+ // Create a long factory we can call dynamically to retrieve an unboxed
+ // long which is typed as a js.Any
+ object LongFactory {
+ @JSExport
+ def aLong = 1L
+ }
+ val trueJsLong = LongFactory.asInstanceOf[js.Dynamic].aLong
+
+ expect(foo.foo(1)).toEqual(1)
+ expect(foo.foo(trueJsLong)).toEqual(2)
+ }
+
+ it("should return boxed Chars") {
+ class Foo {
+ @JSExport
+ def bar(x: Int): Char = x.toChar
+ }
+ val foo = (new Foo).asInstanceOf[js.Dynamic]
+
+ val funs = js.eval("""
+ var funs = {
+ testIsChar: function(foo) { return JSUtils().isChar(foo.bar(65)); },
+ testCharValue: function(foo) { return JSUtils().charToString(foo.bar(65)); }
+ }; funs;
+ """).asInstanceOf[js.Dynamic]
+
+ expect(funs.testIsChar(foo)).toBeTruthy
+ expect(funs.testCharValue(foo)).toEqual("A")
+ }
+
+ it("should take boxed Chars as parameter") {
+ class Foo {
+ @JSExport
+ def bar(x: Char): Int = x.toInt
+ }
+ val foo = (new Foo).asInstanceOf[js.Dynamic]
+
+ val f = js.eval("""
+ var f = function(foo) { return foo.bar(JSUtils().stringToChar('e')); };
+ f;
+ """).asInstanceOf[js.Dynamic]
+
+ expect(f(foo)).toEqual('e'.toInt)
+ }
+
+ it("should be able to disambiguate an Int from a Char") {
+ class Foo {
+ @JSExport
+ def bar(x: Char): String = "char: "+x
+ @JSExport
+ def bar(x: Int): String = "int: "+x
+ }
+ val foo = (new Foo).asInstanceOf[js.Dynamic]
+
+ val funs = js.eval("""
+ var funs = {
+ testChar: function(foo) { return foo.bar(JSUtils().stringToChar('S')); },
+ testInt: function(foo) { return foo.bar(68); }
+ }; funs;
+ """).asInstanceOf[js.Dynamic]
+
+ expect(funs.testChar(foo)).toEqual("char: S")
+ expect(funs.testInt(foo)).toEqual("int: 68")
+ }
+
+ it("should support exporting constructor parameter fields - #970") {
+ class Foo(@(JSExport @meta.field) val x: Int)
+ val foo = (new Foo(1)).asInstanceOf[js.Dynamic]
+ expect(foo.x).toEqual(1)
+ }
+
+ it("should support exporting case class fields - #970") {
+ case class Foo(@(JSExport @meta.field) x: Int)
+ val foo = (new Foo(1)).asInstanceOf[js.Dynamic]
+ expect(foo.x).toEqual(1)
+ }
+
+ it("should support exporting lazy values - #977") {
+ class Foo {
+ @JSExport
+ lazy val x = 1
+ }
+ val foo = (new Foo).asInstanceOf[js.Dynamic]
+ expect(foo.x).toEqual(1)
+ }
+
+ it("should support exporting all members of a class") {
+ @JSExportAll
+ class Foo {
+ val a = 1
+
+ @JSExport // double annotation allowed
+ def b = 2
+
+ lazy val c = 3
+
+ class Bar // not exported, but should not fail
+ }
+
+ val foo = (new Foo).asInstanceOf[js.Dynamic]
+
+ expect(foo.a).toEqual(1)
+ expect(foo.b).toEqual(2)
+ expect(foo.c).toEqual(3)
+ }
+
+ it("should not export synthetic members with @JSExportAll - #1195") {
+ @JSExportAll
+ case class Foo(x: Int)
+
+ val foo = Foo(1).asInstanceOf[js.Dynamic]
+
+ expect(foo.x).toEqual(1)
+ expect(foo.copy).toBeUndefined
+ }
+
+ it("should allow mutliple equivalent JSExport annotations") {
+ class Foo {
+ @JSExport
+ @JSExport("a")
+ @JSExport
+ @JSExport("a")
+ def b = 1
+ }
+
+ val foo = (new Foo).asInstanceOf[js.Dynamic]
+
+ expect(foo.b).toEqual(1)
+ }
+
+ it("should support named exports") {
+ import js.Dynamic.{literal => lit}
+
+ class FooNamed {
+ @JSExportNamed("bar1")
+ def bar(x: Int, y: Int) = x + y
+
+ @JSExportNamed("bar2")
+ @JSExport
+ def bar(x: Int = 1)(y: Int = x)(z: Int = y) = x + y + z
+ }
+
+ val foo = (new FooNamed).asInstanceOf[js.Dynamic]
+
+ expect(foo.bar1(lit(x = 1, y = 2))).toEqual(3)
+ if (JasmineTestFramework.hasTag("compliant-asinstanceof"))
+ expect(() => foo.bar1(lit(x = 1))).toThrow // missing arg
+ expect(foo.bar2(lit())).toEqual(3)
+ expect(foo.bar2(lit(x = 2))).toEqual(6)
+ expect(foo.bar2(lit(y = 2))).toEqual(5)
+ expect(foo.bar2(lit(y = 2, z = 1))).toEqual(4)
+ expect(foo.bar(2)).toEqual(6)
+ expect(foo.bar(2,3)).toEqual(8)
+ }
+
+ it("should support named constructor exports") {
+ import js.Dynamic.{literal => lit}
+
+ val constr = jsPackage.ExportedNamedArgClass
+ expect(js.Dynamic.newInstance(constr)(lit(x = 2)).result).toEqual("22true")
+ expect(js.Dynamic.newInstance(constr)(lit(y = "foo")).result).toEqual("1foofalse")
+ expect(js.Dynamic.newInstance(constr)(lit(z = true, y = "foo")).result).toEqual("1footrue")
+ }
+
+ it("should support exporting under 'org' namespace - #364") {
+ val accessor = js.Dynamic.global.org.ExportedUnderOrgObject
+ expect(js.typeOf(accessor)).toEqual("function")
+ val obj = accessor()
+ expect(obj).toBe(ExportedUnderOrgObject.asInstanceOf[js.Any])
+ }
+
+ when("compliant-asinstanceof").
+ it("should reject bad values for arguments of primitive value type") {
+ class Foo {
+ @JSExport
+ def doBool(x: Boolean) = x
+ @JSExport
+ def doChar(x: Char) = x
+ @JSExport
+ def doByte(x: Byte) = x
+ @JSExport
+ def doShort(x: Short) = x
+ @JSExport
+ def doInt(x: Int) = x
+ @JSExport
+ def doLong(x: Long) = x
+ @JSExport
+ def doFloat(x: Float) = x
+ @JSExport
+ def doDouble(x: Double) = x
+ @JSExport
+ def doUnit(x: Unit) = x
+ }
+
+ val foo = (new Foo).asInstanceOf[js.Dynamic]
+
+ // Nulls
+ expect(() => foo.doBool(null)).toThrow
+ expect(() => foo.doChar(null)).toThrow
+ expect(() => foo.doByte(null)).toThrow
+ expect(() => foo.doShort(null)).toThrow
+ expect(() => foo.doInt(null)).toThrow
+ expect(() => foo.doLong(null)).toThrow
+ expect(() => foo.doFloat(null)).toThrow
+ expect(() => foo.doDouble(null)).toThrow
+ expect(() => foo.doUnit(null)).toThrow
+
+ // Class type
+ expect(() => foo.doBool(foo)).toThrow
+ expect(() => foo.doChar(foo)).toThrow
+ expect(() => foo.doByte(foo)).toThrow
+ expect(() => foo.doShort(foo)).toThrow
+ expect(() => foo.doInt(foo)).toThrow
+ expect(() => foo.doLong(foo)).toThrow
+ expect(() => foo.doFloat(foo)).toThrow
+ expect(() => foo.doDouble(foo)).toThrow
+ expect(() => foo.doUnit(foo)).toThrow
+
+ // Bad values
+ expect(() => foo.doBool(1)).toThrow
+ expect(() => foo.doBool("a")).toThrow
+
+ expect(() => foo.doChar(1)).toThrow
+ expect(() => foo.doChar("a")).toThrow
+
+ expect(() => foo.doByte(300)).toThrow
+ expect(() => foo.doByte("a")).toThrow
+
+ expect(() => foo.doShort(32768)).toThrow
+ expect(() => foo.doShort("a")).toThrow
+
+ expect(() => foo.doInt(3.2)).toThrow
+ expect(() => foo.doInt("a")).toThrow
+
+ expect(() => foo.doLong(3.2)).toThrow
+ expect(() => foo.doLong(3)).toThrow
+ expect(() => foo.doLong("a")).toThrow
+
+ expect(() => foo.doFloat("a")).toThrow
+ }
+
+ when("compliant-asinstanceof").
+ it("should reject bad values for arguments of value class type - #613") {
+ class Foo {
+ @JSExport
+ def doVC(x: SomeValueClass) = x
+ }
+
+ val foo = (new Foo).asInstanceOf[js.Dynamic]
+
+ expect(() => foo.doVC(null)).toThrow
+ expect(() => foo.doVC(foo)).toThrow
+ expect(() => foo.doVC(1)).toThrow
+ expect(() => foo.doVC("a")).toThrow
+ }
+
+ when("compliant-asinstanceof").
+ it("should reject bad values for arguments of class type") {
+ class A
+ class B
+
+ class Foo {
+ @JSExport
+ def doA(x: A) = x
+ }
+
+ val foo = (new Foo).asInstanceOf[js.Dynamic]
+
+ expect(() => foo.doA(1)).toThrow
+ expect(() => foo.doA((new B).asInstanceOf[js.Any])).toThrow
+ expect(() => foo.doA("a")).toThrow
+ }
+
+ it("should offer exports for classes ending in _= - #1090") {
+ val constr = jsPackage.ExportClassSetterNamed_=
+ val obj = js.Dynamic.newInstance(constr)()
+ expect(obj.x).toBe(1)
+ }
+
+ it("should offer exports for objects ending in _= - #1090") {
+ expect(jsPackage.ExportObjSetterNamed_=().x).toBe(1)
+ }
+
+ } // describe
+
+ describe("@JSExportDescendentObjects") {
+
+ it("should offer auto exports for objects extending a trait") {
+ val accessor =
+ js.Dynamic.global.scala.scalajs.testsuite.jsinterop.AutoExportedTraitObject
+ expect(accessor).toBeDefined
+ expect(js.typeOf(accessor)).toEqual("function")
+ val obj = accessor()
+ expect(obj).toBeDefined
+ expect(obj).toBe(AutoExportedTraitObject.asInstanceOf[js.Any])
+ }
+
+ it("should offer auto exports for objects extending a class") {
+ val accessor =
+ js.Dynamic.global.scala.scalajs.testsuite.jsinterop.AutoExportedClassObject
+ expect(accessor).toBeDefined
+ expect(js.typeOf(accessor)).toEqual("function")
+ val obj = accessor()
+ expect(obj).toBeDefined
+ expect(obj).toBe(AutoExportedClassObject.asInstanceOf[js.Any])
+ }
+
+ }
+
+ describe("@JSExportDescendentClasses") {
+
+ it("should offer auto exports for classes extending a trait") {
+ val ctor =
+ js.Dynamic.global.scala.scalajs.testsuite.jsinterop.AutoExportedTraitClass
+ expect(ctor).toBeDefined
+ expect(js.typeOf(ctor)).toEqual("function")
+
+ val obj1 = js.Dynamic.newInstance(ctor)()
+ expect(obj1).toBeDefined
+ expect(obj1.x).toBe(5)
+
+ val obj2 = js.Dynamic.newInstance(ctor)(100)
+ expect(obj2).toBeDefined
+ expect(obj2.x).toBe(100)
+ }
+
+ it("should offer auto exports for classes extending a class") {
+ val ctor =
+ js.Dynamic.global.scala.scalajs.testsuite.jsinterop.AutoExportedClassClass
+ expect(ctor).toBeDefined
+ expect(js.typeOf(ctor)).toEqual("function")
+
+ val obj1 = js.Dynamic.newInstance(ctor)()
+ expect(obj1).toBeDefined
+ expect(obj1.x).toBe(5)
+
+ val obj2 = js.Dynamic.newInstance(ctor)(100)
+ expect(obj2).toBeDefined
+ expect(obj2.x).toBe(100)
+ }
+
+ }
+
+}
+
+object ExportNameHolder {
+ final val className = "ConstantFoldedClassExport"
+ final val objectName = "ConstantFoldedObjectExport"
+ final val methodName = "myMethod"
+}
+
+@JSExport
+@JSExport("TheExportedObject")
+@JSExport("qualified.testobject.ExportedObject") // purposefully halfway the same as ExportedClass
+@JSExport(ExportNameHolder.objectName)
+object ExportedObject {
+ @JSExport
+ def witness: String = "witness"
+}
+
+@JSExport
+protected object ProtectedExportedObject {
+ @JSExport
+ def witness: String = "witness"
+}
+
+@JSExport
+@JSExport("TheExportedClass")
+@JSExport("qualified.testclass.ExportedClass") // purposefully halfway the same as ExportedObject
+@JSExport(ExportNameHolder.className)
+class ExportedClass(_x: Int) {
+ @JSExport
+ val x = _x
+}
+
+@JSExport
+protected class ProtectedExportedClass(_x: Int) {
+ @JSExport
+ val x = _x
+}
+
+@JSExport
+class ExportedVarArgClass(x: String*) {
+
+ @JSExport
+ def this(x: Int, y: String) = this(s"Number: <$x>", y)
+
+ @JSExport
+ def result = x.mkString("|")
+}
+
+@JSExport
+class ExportedDefaultArgClass(x: Int, y: Int, z: Int) {
+
+ @JSExport
+ def this(x: Int, y: Int = 5) = this(x, y, 100)
+
+ @JSExport
+ def result = x + y + z
+}
+
+@JSExport("org.ExportedUnderOrgObject")
+object ExportedUnderOrgObject
+
+@JSExportDescendentClasses
+@JSExportDescendentObjects
+trait AutoExportTrait
+
+object AutoExportedTraitObject extends AutoExportTrait
+class AutoExportedTraitClass(_x: Int) extends AutoExportTrait {
+ def this() = this(5)
+ @JSExport
+ def x: Int = _x
+}
+
+@JSExportDescendentClasses
+@JSExportDescendentObjects
+class AutoExportClass
+
+object AutoExportedClassObject extends AutoExportClass
+class AutoExportedClassClass(_x: Int) extends AutoExportTrait {
+ def this() = this(5)
+ @JSExport
+ def x: Int = _x
+}
+
+class SomeValueClass(val i: Int) extends AnyVal
+
+@JSExportNamed
+class ExportedNamedArgClass(x: Int = 1)(y: String = x.toString)(z: Boolean = y != "foo") {
+ @JSExport
+ val result = x + y + z
+}
+
+@JSExport
+class ExportClassSetterNamed_= {
+ @JSExport
+ val x = 1
+}
+
+@JSExport
+object ExportObjSetterNamed_= {
+ @JSExport
+ val x = 1
+}
diff --git a/examples/scala-js/test-suite/src/test/scala/scala/scalajs/testsuite/jsinterop/FunctionTest.scala b/examples/scala-js/test-suite/src/test/scala/scala/scalajs/testsuite/jsinterop/FunctionTest.scala
new file mode 100644
index 0000000..4973e64
--- /dev/null
+++ b/examples/scala-js/test-suite/src/test/scala/scala/scalajs/testsuite/jsinterop/FunctionTest.scala
@@ -0,0 +1,41 @@
+/* __ *\
+** ________ ___ / / ___ __ ____ Scala.js Test Suite **
+** / __/ __// _ | / / / _ | __ / // __/ (c) 2013, LAMP/EPFL **
+** __\ \/ /__/ __ |/ /__/ __ |/_// /_\ \ http://scala-js.org/ **
+** /____/\___/_/ |_/____/_/ | |__/ /____/ **
+** |/____/ **
+\* */
+package scala.scalajs.testsuite.jsinterop
+
+import scala.scalajs.js
+import org.scalajs.jasminetest.JasmineTest
+
+object FunctionTest extends JasmineTest {
+
+ import js.Dynamic.{literal => lit}
+
+ describe("scala.scalajs.js.Function") {
+
+ it("should support call() with expanded arguments") {
+ val f = js.eval("""
+ var f = function() { return arguments; }; f;
+ """).asInstanceOf[js.Function]
+
+ expect(f.call(null, 42, true)).toEqual(lit(
+ `0` = 42,
+ `1` = true))
+ }
+
+ it("should support call() with the :_* notation to expand a Seq") {
+ val f = js.eval("""
+ var f = function() { return arguments; }; f;
+ """).asInstanceOf[js.Function]
+
+ val args = Seq[js.Any](42, true)
+ expect(f.call(null, args: _*)).toEqual(lit(
+ `0` = 42,
+ `1` = true))
+ }
+
+ }
+}
diff --git a/examples/scala-js/test-suite/src/test/scala/scala/scalajs/testsuite/jsinterop/MiscInteropTest.scala b/examples/scala-js/test-suite/src/test/scala/scala/scalajs/testsuite/jsinterop/MiscInteropTest.scala
new file mode 100644
index 0000000..08211c3
--- /dev/null
+++ b/examples/scala-js/test-suite/src/test/scala/scala/scalajs/testsuite/jsinterop/MiscInteropTest.scala
@@ -0,0 +1,89 @@
+/* __ *\
+** ________ ___ / / ___ __ ____ Scala.js Test Suite **
+** / __/ __// _ | / / / _ | __ / // __/ (c) 2013, LAMP/EPFL **
+** __\ \/ /__/ __ |/ /__/ __ |/_// /_\ \ http://scala-js.org/ **
+** /____/\___/_/ |_/____/_/ | |__/ /____/ **
+** |/____/ **
+\* */
+package scala.scalajs.testsuite.jsinterop
+
+import scala.scalajs.js
+import org.scalajs.jasminetest.JasmineTest
+
+object MiscInteropTest extends JasmineTest {
+
+ describe("scala.scalajs.js.package") {
+
+ it("should provide an equivalent to `typeof x`") {
+ import js.typeOf
+ expect(typeOf(5)).toEqual("number")
+ expect(typeOf(false)).toEqual("boolean")
+ expect(typeOf("hello")).toEqual("string")
+ expect(typeOf(null)).toEqual("object")
+ expect(typeOf(new js.Object)).toEqual("object")
+ expect(typeOf(())).toEqual("undefined")
+ expect(typeOf(() => 42)).toEqual("function")
+ }
+ }
+
+ describe("scala.scalajs.js.Object") {
+
+ it("should provide an equivalent to `p in o`") {
+ import js.Object.{ hasProperty => hasProp }
+ val o = js.Dynamic.literal(foo = 5, bar = "foobar").asInstanceOf[js.Object]
+ expect(hasProp(o, "foo")).toBeTruthy
+ expect(hasProp(o, "foobar")).toBeFalsy
+ expect(hasProp(o, "toString")).toBeTruthy // in prototype
+ }
+
+ it("should respect evaluation order for `hasProperty`") {
+ import js.Object.{ hasProperty => hasProp }
+ var indicator = 3
+ def o() = {
+ indicator += 4
+ js.Dynamic.literal(x = 5).asInstanceOf[js.Object]
+ }
+ def p() = {
+ indicator *= 2
+ "x"
+ }
+ expect(hasProp(o(), p())).toBeTruthy
+ expect(indicator).toEqual(14)
+ }
+
+ it("should provide equivalent of JS for-in loop of {} - #13") {
+ val obj = js.eval("var dictionaryTest13 = { a: 'Scala.js', b: 7357 }; dictionaryTest13;")
+ val dict = obj.asInstanceOf[js.Dictionary[js.Any]]
+ var propCount = 0
+ var propString = ""
+
+ for (prop <- js.Object.properties(dict)) {
+ propCount += 1
+ propString += dict(prop)
+ }
+
+ expect(propCount).toEqual(2)
+ expect(propString).toEqual("Scala.js7357")
+ }
+
+ it("should provide equivalent of JS for-in loop of [] - #13") {
+ val obj = js.eval("var arrayTest13 = [ 7, 3, 5, 7 ]; arrayTest13;")
+ val array = obj.asInstanceOf[js.Dictionary[js.Any]]
+ var propCount = 0
+ var propString = ""
+
+ for (prop <- js.Object.properties(array)) {
+ propCount += 1
+ propString += array(prop)
+ }
+
+ expect(propCount).toEqual(4)
+ expect(propString).toEqual("7357")
+ }
+
+ it("should compile js.undefined") {
+ expect(() => js.undefined.asInstanceOf[js.prim.Number].toString(10)).toThrow
+ }
+ }
+
+}
diff --git a/examples/scala-js/test-suite/src/test/scala/scala/scalajs/testsuite/jsinterop/RuntimeLongTest.scala b/examples/scala-js/test-suite/src/test/scala/scala/scalajs/testsuite/jsinterop/RuntimeLongTest.scala
new file mode 100644
index 0000000..589f379
--- /dev/null
+++ b/examples/scala-js/test-suite/src/test/scala/scala/scalajs/testsuite/jsinterop/RuntimeLongTest.scala
@@ -0,0 +1,140 @@
+/* __ *\
+** ________ ___ / / ___ __ ____ Scala.js Test Suite **
+** / __/ __// _ | / / / _ | __ / // __/ (c) 2013, LAMP/EPFL **
+** __\ \/ /__/ __ |/ /__/ __ |/_// /_\ \ http://scala-js.org/ **
+** /____/\___/_/ |_/____/_/ | |__/ /____/ **
+** |/____/ **
+\* */
+package scala.scalajs.testsuite.jsinterop
+
+import scala.scalajs.runtime.RuntimeLong
+
+import org.scalajs.jasmine.JasmineExpectation
+import org.scalajs.jasminetest.JasmineTest
+
+import scala.util.Try
+
+/**
+ * test the runtime Long implementation directly
+ * does not depend on magic compiler Long rewriting
+ */
+object RuntimeLongTest extends JasmineTest {
+
+ import RuntimeLong.fromDouble
+
+ /** overload expect for long to add toString */
+ def expect(l: RuntimeLong): JasmineExpectation = expect(l.toHexString)
+
+ describe("scala.scalajs.runtime.RuntimeLong") {
+
+ def fromInt(x: Int): RuntimeLong = new RuntimeLong(x)
+
+ val maxInt = fromInt(Int.MaxValue)
+ val minInt = fromInt(Int.MinValue)
+ val one = fromInt(1)
+ val billion = fromInt(1000000000)
+
+ val `4503599627370510L` = new RuntimeLong( 14, 0, 256)
+ val `613354684553L` = new RuntimeLong( 639113, 146235, 0)
+ val `9863155567412L` = new RuntimeLong(2247476, 2351559, 0)
+ val `3632147899696541255L` = new RuntimeLong(1568327, 2954580, 206463)
+ val `7632147899696541255L` = new RuntimeLong(2616903, 1593290, 433837)
+
+ it("should correctly implement negation") {
+ expect(-fromInt(5)).toEqual("fffffffffffffffb")
+ expect(-fromInt(0)).toEqual("0")
+ expect(-minInt ).toEqual("80000000")
+ }
+
+ it("should correctly implement comparison") {
+ expect(fromInt(7) < fromInt(15)).toBe(true)
+ expect(fromInt(15) < fromInt(15)).toBe(false)
+ expect(fromInt(15) <= fromInt(15)).toBe(true)
+ expect(fromInt(14) <= fromInt(15)).toBe(true)
+ expect(fromInt(15) > fromInt(15)).toBe(false)
+ expect(fromInt(14) > fromInt(15)).toBe(false)
+ expect(fromInt(16) > fromInt(15)).toBe(true)
+ expect(fromInt(15) >= fromInt(15)).toBe(true)
+ expect(fromInt(14) >= fromInt(15)).toBe(false)
+ expect(fromInt(16) >= fromInt(15)).toBe(true)
+ }
+
+ it("should correctly implement addition") {
+ expect(fromInt(7) + fromInt(15)).toEqual("16")
+ expect( maxInt + maxInt ).toEqual("fffffffe")
+ expect( maxInt + one ).toEqual("80000000")
+ }
+
+ it("should correctly implement subtraction") {
+ expect(fromInt(7) - fromInt(15)).toEqual("fffffffffffffff8")
+ expect( maxInt - maxInt ).toEqual("0")
+ }
+
+ it("should correctly implement multiplication") {
+ expect(fromInt(7) * fromInt(15)).toEqual("69")
+ expect(fromInt(-7) * fromInt(15)).toEqual("ffffffffffffff97")
+ expect( maxInt * maxInt ).toEqual("3fffffff00000001")
+ expect(`4503599627370510L` * fromInt(-4)).toEqual("ffbfffffffffffc8")
+ }
+
+ it("should correctly implement division") {
+ expect( fromInt(7) / fromInt(15)).toEqual("0")
+ expect( fromInt(24) / fromInt(5) ).toEqual("4")
+ expect( fromInt(24) / fromInt(-5)).toEqual("fffffffffffffffc")
+ expect( maxInt / fromInt(-5)).toEqual("ffffffffe6666667")
+ expect( maxInt / billion ).toEqual("2")
+ expect((maxInt+one) / billion ).toEqual("2")
+ }
+
+ it("should correctly implement modulus") {
+ expect( fromInt(7) % fromInt(15)).toEqual("7")
+ expect( fromInt(24) % fromInt(5) ).toEqual("4")
+ expect( fromInt(24) % fromInt(-5)).toEqual("4")
+ expect( maxInt % billion ).toEqual("8ca6bff")
+ expect((maxInt+one) % billion ).toEqual("8ca6c00")
+ expect( maxInt % fromInt(-5)).toEqual("2")
+ }
+
+ it("should correctly implement toString") {
+ expect(maxInt.toString).toEqual("2147483647")
+ expect(fromInt(-50).toString).toEqual("-50")
+ expect(fromInt(-1000000000).toString).toEqual("-1000000000")
+ expect((maxInt+one).toString).toEqual("2147483648")
+ expect(minInt.toString).toEqual("-2147483648")
+ }
+
+ it("should correctly implement fromDouble") {
+ expect(fromDouble( 4.5)).toEqual("4")
+ expect(fromDouble(-4.5)).toEqual("fffffffffffffffc")
+ }
+
+ it("should correctly implement toDouble") {
+ expect(fromInt(5).toDouble).toEqual(5.0)
+ expect((maxInt+one).toDouble).toEqual(2147483648.0)
+ }
+
+ it("should correctly implement numberOfLeadingZeros") {
+ expect(fromInt( 0).numberOfLeadingZeros).toEqual(64)
+ expect(fromInt( 1).numberOfLeadingZeros).toEqual(63)
+ expect(fromInt(-1).numberOfLeadingZeros).toEqual(0)
+ expect(fromInt( 2).numberOfLeadingZeros).toEqual(62)
+ }
+
+ it("should implement hashCode() according to spec in j.l.Long") {
+ expect(fromInt(0 ).hashCode()).toEqual(0)
+ expect(fromInt(55 ).hashCode()).toEqual(55)
+ expect(fromInt(-12 ).hashCode()).toEqual(11)
+ expect(fromInt(10006548).hashCode()).toEqual(10006548)
+ expect(fromInt(-1098748).hashCode()).toEqual(1098747)
+
+ expect(`613354684553L` .hashCode()).toEqual(-825638905)
+ expect(`9863155567412L` .hashCode()).toEqual(1910653900)
+ expect(`3632147899696541255L`.hashCode()).toEqual(1735398658)
+ expect(`7632147899696541255L`.hashCode()).toEqual(-1689438124)
+ }
+
+ }
+
+}
+
+
diff --git a/examples/scala-js/test-suite/src/test/scala/scala/scalajs/testsuite/jsinterop/StrangeNamedTests.scala b/examples/scala-js/test-suite/src/test/scala/scala/scalajs/testsuite/jsinterop/StrangeNamedTests.scala
new file mode 100644
index 0000000..846c80b
--- /dev/null
+++ b/examples/scala-js/test-suite/src/test/scala/scala/scalajs/testsuite/jsinterop/StrangeNamedTests.scala
@@ -0,0 +1,28 @@
+/* __ *\
+** ________ ___ / / ___ __ ____ Scala.js Test Suite **
+** / __/ __// _ | / / / _ | __ / // __/ (c) 2013, LAMP/EPFL **
+** __\ \/ /__/ __ |/ /__/ __ |/_// /_\ \ http://scala-js.org/ **
+** /____/\___/_/ |_/____/_/ | |__/ /____/ **
+** |/____/ **
+\* */
+package scala.scalajs.testsuite.jsinterop
+
+import org.scalajs.jasminetest.JasmineTest
+
+object `1_TestName` extends JasmineTest {
+ describe("a test with name 1_TestName") {
+ it("should run") {}
+ }
+}
+
+object eval extends JasmineTest {
+ describe("a test with name eval") {
+ it("should run") {}
+ }
+}
+
+object `\u1f4a7` extends JasmineTest {
+ describe("a test with name \u1f4a9") {
+ it("should run") {}
+ }
+}
diff --git a/examples/scala-js/test-suite/src/test/scala/scala/scalajs/testsuite/jsinterop/ThisFunctionTest.scala b/examples/scala-js/test-suite/src/test/scala/scala/scalajs/testsuite/jsinterop/ThisFunctionTest.scala
new file mode 100644
index 0000000..4ac9058
--- /dev/null
+++ b/examples/scala-js/test-suite/src/test/scala/scala/scalajs/testsuite/jsinterop/ThisFunctionTest.scala
@@ -0,0 +1,70 @@
+/* __ *\
+** ________ ___ / / ___ __ ____ Scala.js Test Suite **
+** / __/ __// _ | / / / _ | __ / // __/ (c) 2013, LAMP/EPFL **
+** __\ \/ /__/ __ |/ /__/ __ |/_// /_\ \ http://scala-js.org/ **
+** /____/\___/_/ |_/____/_/ | |__/ /____/ **
+** |/____/ **
+\* */
+package scala.scalajs.testsuite.jsinterop
+
+import scala.scalajs.js
+import org.scalajs.jasminetest.JasmineTest
+
+object ThisFunctionTest extends JasmineTest {
+
+ describe("scala.scalajs.js.ThisFunctionN") {
+
+ it("should provide an implicit conversion from Scala function to js.ThisFunction") {
+ val g = js.eval("""
+ var g = function(f, x) { return f.call(x, 42, x.foo); }; g;
+ """).asInstanceOf[js.Function2[js.ThisFunction2[
+ js.Dynamic, Int, String, String], js.Dynamic, String]]
+
+ val f = { (thiz: js.Dynamic, v: Int, u: String) =>
+ expect(thiz).toBeTruthy()
+ expect(thiz.foobar).toEqual("foobar")
+ u + v
+ }
+ val obj = js.Object().asInstanceOf[js.Dynamic]
+ obj.foo = "foo"
+ obj.foobar = "foobar"
+ expect(g(f, obj)).toEqual("foo42")
+ }
+
+ it("should accept a lambda where a js.ThisFunction is expected") {
+ val g = js.eval("""
+ var g = function(f, x) { return f.call(x, 42, x.foo); }; g;
+ """).asInstanceOf[js.Function2[js.ThisFunction2[
+ js.Dynamic, Int, String, String], js.Dynamic, String]]
+
+ val obj = js.Object().asInstanceOf[js.Dynamic]
+ obj.foo = "foo"
+ obj.foobar = "foobar"
+ expect(g({ (thiz: js.Dynamic, v: Int, u: String) =>
+ expect(thiz).toBeTruthy()
+ expect(thiz.foobar).toEqual("foobar")
+ u + v
+ }, obj)).toEqual("foo42")
+ }
+
+ it("should bind the first argument to this when applying js.ThisFunctionN") {
+ val g = js.eval("""
+ var g = function(x) { return this.foo + ":" + x; }; g;
+ """).asInstanceOf[js.ThisFunction1[js.Dynamic, Int, String]]
+ val obj = js.Object().asInstanceOf[js.Dynamic]
+ obj.foo = "foo"
+ expect(g(obj, 42)).toEqual("foo:42")
+ }
+
+ it("should provide an implicit conversion from js.ThisFunction to Scala function") {
+ val g = js.eval("""
+ var g = function(x) { return this.foo + ":" + x; }; g;
+ """).asInstanceOf[js.ThisFunction1[js.Dynamic, Int, String]]
+ val f: scala.Function2[js.Dynamic, Int, String] = g
+ val obj = js.Object().asInstanceOf[js.Dynamic]
+ obj.foo = "foo"
+ expect(f(obj, 42)).toEqual("foo:42")
+ }
+
+ }
+}
diff --git a/examples/scala-js/test-suite/src/test/scala/scala/scalajs/testsuite/jsinterop/UndefOrTest.scala b/examples/scala-js/test-suite/src/test/scala/scala/scalajs/testsuite/jsinterop/UndefOrTest.scala
new file mode 100644
index 0000000..28eae15
--- /dev/null
+++ b/examples/scala-js/test-suite/src/test/scala/scala/scalajs/testsuite/jsinterop/UndefOrTest.scala
@@ -0,0 +1,191 @@
+/* __ *\
+** ________ ___ / / ___ __ ____ Scala.js Test Suite **
+** / __/ __// _ | / / / _ | __ / // __/ (c) 2013, LAMP/EPFL **
+** __\ \/ /__/ __ |/ /__/ __ |/_// /_\ \ http://scala-js.org/ **
+** /____/\___/_/ |_/____/_/ | |__/ /____/ **
+** |/____/ **
+\* */
+package scala.scalajs.testsuite.jsinterop
+
+import scala.scalajs.js
+import org.scalajs.jasminetest.JasmineTest
+
+import js.annotation.JSExport
+
+object UndefOrTest extends JasmineTest {
+
+ def some[A](v: A): js.UndefOr[A] = v
+ def none[A]: js.UndefOr[A] = js.undefined
+
+ describe("scala.scalajs.js.UndefOr[A]") {
+
+ it("convert A to js.UndefOr[A]") {
+ val x: js.UndefOr[Int] = 42
+ expect(x.isEmpty).toBeFalsy
+ expect(x.isDefined).toBeTruthy
+ expect(x.nonEmpty).toBeTruthy
+ expect(x.get).toEqual(42)
+ }
+
+ it("convert undefined to js.UndefOr[A]") {
+ val x: js.UndefOr[Int] = js.undefined
+ expect(x.isEmpty).toBeTruthy
+ expect(x.isDefined).toBeFalsy
+ expect(x.nonEmpty).toBeFalsy
+ expect(() => x.get).toThrow
+ }
+
+ it("convert to js.Any when A <% js.Any") {
+ val x: js.UndefOr[Int] = 42
+ expect(x).toEqual(42)
+
+ val y: js.UndefOr[String] = js.undefined
+ expect(y).toBeUndefined
+ }
+
+ it("getOrElse") {
+ expect(some("hello").getOrElse("ko")).toEqual("hello")
+ expect(none[String].getOrElse("ok")).toEqual("ok")
+
+ var defaultComputed = false
+ expect(some("test") getOrElse {
+ defaultComputed = true
+ "ko"
+ }).toEqual("test")
+ expect(defaultComputed).toBeFalsy
+ }
+
+ it("orNull") {
+ expect(some("hello").orNull).toEqual("hello")
+ expect(none[String].orNull).toBeNull
+ }
+
+ it("map") {
+ expect(some(62).map(_ / 3)).toEqual(62 / 3)
+ expect(none[Int].map(_ / 3)).toBeUndefined
+ }
+
+ it("fold") {
+ expect(some(3).fold(10)(_ * 2)).toEqual(6)
+ expect(none[Int].fold(10)(_ * 2)).toEqual(10)
+ }
+
+ it("flatMap") {
+ def f(x: Int): js.UndefOr[Int] = if (x > 0) x+3 else js.undefined
+ expect(some(6).flatMap(f)).toEqual(9)
+ expect(some(-6).flatMap(f)).toBeUndefined
+ expect(none[Int].flatMap(f)).toBeUndefined
+ }
+
+ it("flatten") {
+ expect(some(some(7)).flatten.isDefined).toBeTruthy
+ expect(some(some(7)).flatten.get).toEqual(7)
+ expect(some(none[Int]).flatten.isDefined).toBeFalsy
+ expect(none[js.UndefOr[Int]].flatten.isDefined).toBeFalsy
+ }
+
+ it("filter") {
+ expect(some(7).filter(_ > 0).isDefined).toBeTruthy
+ expect(some(7).filter(_ > 0).get).toEqual(7)
+ expect(some(7).filter(_ < 0).isDefined).toBeFalsy
+ expect(none[Int].filter(_ < 0).isDefined).toBeFalsy
+ }
+
+ it("filterNot") {
+ expect(some(7).filterNot(_ < 0).isDefined).toBeTruthy
+ expect(some(7).filterNot(_ < 0).get).toEqual(7)
+ expect(some(7).filterNot(_ > 0).isDefined).toBeFalsy
+ expect(none[Int].filterNot(_ > 0).isDefined).toBeFalsy
+ }
+
+ it("exists") {
+ expect(some(7).exists(_ > 0)).toBeTruthy
+ expect(some(7).exists(_ < 0)).toBeFalsy
+ expect(none[Int].exists(_ > 0)).toBeFalsy
+ }
+
+ it("forall") {
+ expect(some(7).forall(_ > 0)).toBeTruthy
+ expect(some(7).forall(_ < 0)).toBeFalsy
+ expect(none[Int].forall(_ > 0)).toBeTruthy
+ }
+
+ it("foreach") {
+ var witness1 = 3
+ some(42).foreach(witness1 = _)
+ expect(witness1).toEqual(42)
+
+ var witness2 = 3
+ none[Int].foreach(witness2 = _)
+ expect(witness2).toEqual(3)
+ }
+
+ it("collect") {
+ expect(some("hello") collect {
+ case "hello" => "ok"
+ }).toEqual("ok")
+ expect(some("hello") collect {
+ case "notthis" => "ko"
+ }).toBeUndefined
+ expect(none[String] collect {
+ case "hello" => "ko"
+ }).toBeUndefined
+ }
+
+ it("collect should call guard at most once") {
+ var witness = 0
+ def guard(x: String) = {
+ witness += 1
+ true
+ }
+ expect(some("hello") collect {
+ case x @ "hello" if guard(x) => "ok"
+ }).toEqual("ok")
+ expect(witness).toEqual(1)
+ }
+
+ it("orElse") {
+ expect(some(true) orElse some(false)).toBeTruthy
+ expect(some("ok") orElse none).toEqual("ok")
+ expect(none orElse some("yes")).toEqual("yes")
+ expect(none orElse none).toBeUndefined
+ }
+
+ it("toList") {
+ import scala.scalajs.js.JSConverters._
+
+ expect(some("hello").toList.toJSArray).toEqual(js.Array("hello"))
+ expect(none[String].toList.toJSArray).toEqual(js.Array())
+ }
+
+ it("toLeft and toRight") {
+ expect(some("left").toLeft("right").isInstanceOf[Left[_, _]]).toBeTruthy
+ expect(none[String].toLeft("right").isInstanceOf[Right[_, _]]).toBeTruthy
+ expect(some("right").toRight("left").isInstanceOf[Right[_, _]]).toBeTruthy
+ expect(none[String].toRight("left").isInstanceOf[Left[_, _]]).toBeTruthy
+ }
+
+ it("toOption") {
+ expect(some("foo").toOption == Some("foo")).toBeTruthy
+ expect(none.toOption == None).toBeTruthy
+ }
+
+ }
+
+ describe("scala.scalajs.js.JSConverters.JSRichOption") {
+
+ import js.JSConverters._
+
+ it("should provide orUndefined") {
+ expect(Some("asdf").orUndefined).toEqual("asdf")
+ expect((None: Option[String]).orUndefined).toBeUndefined
+
+ // This doesn't work on 2.10, since it doesn't infer
+ // Nothing <:< js.Any to implicitly convert UndefOr[Nothing] to
+ // js.Any
+ // expect(None.orUndefined).toBeUndefined
+ }
+
+ }
+
+}