diff options
Diffstat (limited to 'test-suite/src/test/scala/scala/scalajs/testsuite/compiler')
15 files changed, 2076 insertions, 0 deletions
diff --git a/test-suite/src/test/scala/scala/scalajs/testsuite/compiler/BooleanTest.scala b/test-suite/src/test/scala/scala/scalajs/testsuite/compiler/BooleanTest.scala new file mode 100644 index 0000000..8343244 --- /dev/null +++ b/test-suite/src/test/scala/scala/scalajs/testsuite/compiler/BooleanTest.scala @@ -0,0 +1,41 @@ +/* __ *\ +** ________ ___ / / ___ __ ____ Scala.js Test Suite ** +** / __/ __// _ | / / / _ | __ / // __/ (c) 2013, LAMP/EPFL ** +** __\ \/ /__/ __ |/ /__/ __ |/_// /_\ \ http://scala-js.org/ ** +** /____/\___/_/ |_/____/_/ | |__/ /____/ ** +** |/____/ ** +\* */ +package scala.scalajs.testsuite.compiler + +import org.scalajs.jasminetest.JasmineTest +import scala.scalajs.js + +object BooleanTest extends JasmineTest { + + describe("Boolean primitives") { + + it("&, | and ^ on booleans should return booleans") { + expect(js.typeOf(true & false)).toEqual("boolean") + expect(js.typeOf(true | false)).toEqual("boolean") + expect(js.typeOf(true ^ false)).toEqual("boolean") + } + + it("&, | and ^ on booleans should return correct results") { + expect(false & false).toBeFalsy + expect(false & true).toBeFalsy + expect(true & false).toBeFalsy + expect(true & true).toBeTruthy + + expect(false | false).toBeFalsy + expect(true | false).toBeTruthy + expect(false | true).toBeTruthy + expect(true | true).toBeTruthy + + expect(false ^ false).toBeFalsy + expect(true ^ false).toBeTruthy + expect(false ^ true).toBeTruthy + expect(true ^ true).toBeFalsy + } + + } +} diff --git a/test-suite/src/test/scala/scala/scalajs/testsuite/compiler/ByteTest.scala b/test-suite/src/test/scala/scala/scalajs/testsuite/compiler/ByteTest.scala new file mode 100644 index 0000000..9f48993 --- /dev/null +++ b/test-suite/src/test/scala/scala/scalajs/testsuite/compiler/ByteTest.scala @@ -0,0 +1,40 @@ +/* __ *\ +** ________ ___ / / ___ __ ____ Scala.js Test Suite ** +** / __/ __// _ | / / / _ | __ / // __/ (c) 2013, LAMP/EPFL ** +** __\ \/ /__/ __ |/ /__/ __ |/_// /_\ \ http://scala-js.org/ ** +** /____/\___/_/ |_/____/_/ | |__/ /____/ ** +** |/____/ ** +\* */ +package scala.scalajs.testsuite.compiler + +import org.scalajs.jasminetest.JasmineTest +import scala.scalajs.js + +object ByteTest extends JasmineTest { + + describe("Byte primitives") { + + it("should always be in their range") { + def test(x: Int, y: Byte): Unit = + expect(x.toByte).toEqual(y) + + test(0, 0) + test(127, 127) + test(128, -128) + test(-128, -128) + test(-500, 12) + test(-90000, 112) + test(123456789, 21) + test(-40000, -64) + test(65536, 0) + test(32768, 0) + + def testC(x: Char, y: Byte): Unit = + expect(x.toByte).toEqual(y) + + testC(-1.toChar, -1) + testC(200.toChar, -56) + } + + } +} diff --git a/test-suite/src/test/scala/scala/scalajs/testsuite/compiler/CharTest.scala b/test-suite/src/test/scala/scala/scalajs/testsuite/compiler/CharTest.scala new file mode 100644 index 0000000..edc2660 --- /dev/null +++ b/test-suite/src/test/scala/scala/scalajs/testsuite/compiler/CharTest.scala @@ -0,0 +1,40 @@ +/* __ *\ +** ________ ___ / / ___ __ ____ Scala.js Test Suite ** +** / __/ __// _ | / / / _ | __ / // __/ (c) 2013, LAMP/EPFL ** +** __\ \/ /__/ __ |/ /__/ __ |/_// /_\ \ http://scala-js.org/ ** +** /____/\___/_/ |_/____/_/ | |__/ /____/ ** +** |/____/ ** +\* */ +package scala.scalajs.testsuite.compiler + +import org.scalajs.jasminetest.JasmineTest +import scala.scalajs.js.Any.fromInt + +object CharTest extends JasmineTest { + + describe("Char primitives") { + + it("should always be positive (when coerced)") { + expect(-3.toByte.toChar.toInt).toEqual(65533) + expect(-100.toShort.toChar.toInt).toEqual(65436) + expect(-66000.toChar.toInt).toEqual(65072) + expect(-4567L.toChar.toInt).toEqual(60969) + expect(-5.3f.toChar.toInt).toEqual(65531) + expect(-7.9.toChar.toInt).toEqual(65529) + } + + it("should overflow (when coerced)") { + expect(347876543.toChar.toInt).toEqual(11455) + expect(34234567876543L.toChar.toInt).toEqual(57279) + } + + it("should overflow with *") { + def test(a: Char, b: Char, expected: Int): Unit = + expect(a * b).toEqual(expected) + + // note: expected values are constant-folded by the compiler on the JVM + test(Char.MaxValue, Char.MaxValue, Char.MaxValue * Char.MaxValue) + } + + } +} diff --git a/test-suite/src/test/scala/scala/scalajs/testsuite/compiler/FloatTest.scala b/test-suite/src/test/scala/scala/scalajs/testsuite/compiler/FloatTest.scala new file mode 100644 index 0000000..5eda04a --- /dev/null +++ b/test-suite/src/test/scala/scala/scalajs/testsuite/compiler/FloatTest.scala @@ -0,0 +1,73 @@ +/* __ *\ +** ________ ___ / / ___ __ ____ Scala.js Test Suite ** +** / __/ __// _ | / / / _ | __ / // __/ (c) 2013, LAMP/EPFL ** +** __\ \/ /__/ __ |/ /__/ __ |/_// /_\ \ http://scala-js.org/ ** +** /____/\___/_/ |_/____/_/ | |__/ /____/ ** +** |/____/ ** +\* */ +package scala.scalajs.testsuite.compiler + +import org.scalajs.jasminetest.JasmineTest + +object FloatTest extends JasmineTest { + + def froundNotInlined(x: Double): Float = { + val y = x // so you don't inline me + y.toFloat + } + + when("strict-floats"). + describe("Strict floats") { + + it("fround for special values") { + expect(froundNotInlined(Double.NaN).isNaN).toBeTruthy + expect(1 / froundNotInlined(0.0).toDouble).toBe(Double.PositiveInfinity) + expect(1 / froundNotInlined(-0.0).toDouble).toBe(Double.NegativeInfinity) + expect(froundNotInlined(Double.PositiveInfinity)).toBe(Float.PositiveInfinity) + expect(froundNotInlined(Double.NegativeInfinity)).toBe(Float.NegativeInfinity) + } + + it("fround overflows") { + expect(froundNotInlined(1e200)).toBe(Double.PositiveInfinity) + expect(froundNotInlined(-1e200)).toBe(Double.NegativeInfinity) + } + + it("fround underflows") { + expect(1 / froundNotInlined(1e-300).toDouble).toBe(Double.PositiveInfinity) + expect(1 / froundNotInlined(-1e-300).toDouble).toBe(Double.NegativeInfinity) + } + + it("fround normal cases") { + def test(input: Double, expected: Double): Unit = + expect(input.toFloat.toDouble).toBe(expected) + + // From MDN documentation + test(0.0, 0.0) + test(1.0, 1.0) + test(1.5, 1.5) + test(1.337, 1.3370000123977661) + test(-4.3, -4.300000190734863) + + // Some bounds + test(Float.MinPositiveValue.toDouble, Float.MinPositiveValue.toDouble) + test(Float.MaxValue.toDouble, Float.MaxValue.toDouble) + test(Float.MinValue.toDouble, Float.MinValue.toDouble) + + // Randomly generated Doubles + test(2.705609035558863E20, 2.7056090763400262E20) + test(-1.447710531503027E15, -1.447710532042752E15) + test(-5.1970024617732836E13, -5.1970022834176E13) + test(1.627661085098256E31, 1.6276610930768024E31) + test(-3.7731947682593834E-32, -3.7731946313230934E-32) + test(34.48229849163326, 34.4822998046875) + test(26.62034396181652, 26.620344161987305) + test(8.198435190113375E-24, 8.198434961596576E-24) + test(-6.079928908440255E-23, -6.079928963558556E-23) + test(3.3756949828462674E-13, 3.37569490589662E-13) + test(-1.2599049874324274E33, -1.2599049641449257E33) + test(6.08574575776438E-10, 6.085745796191588E-10) + test(1.973497969450596E-21, 1.973498047135062E-21) + } + + } +} diff --git a/test-suite/src/test/scala/scala/scalajs/testsuite/compiler/InstanceTestsHijackedBoxedClassesTest.scala b/test-suite/src/test/scala/scala/scalajs/testsuite/compiler/InstanceTestsHijackedBoxedClassesTest.scala new file mode 100644 index 0000000..1379b80 --- /dev/null +++ b/test-suite/src/test/scala/scala/scalajs/testsuite/compiler/InstanceTestsHijackedBoxedClassesTest.scala @@ -0,0 +1,98 @@ +/* __ *\ +** ________ ___ / / ___ __ ____ Scala.js Test Suite ** +** / __/ __// _ | / / / _ | __ / // __/ (c) 2013, LAMP/EPFL ** +** __\ \/ /__/ __ |/ /__/ __ |/_// /_\ \ http://scala-js.org/ ** +** /____/\___/_/ |_/____/_/ | |__/ /____/ ** +** |/____/ ** +\* */ +package scala.scalajs.testsuite.compiler + +import org.scalajs.jasminetest.JasmineTest +import scala.scalajs.js + +object InstanceTestsHijackedBoxedClassesTest extends JasmineTest { + + describe("Instance tests for hijacked boxed classes") { + + it("should support isInstanceOf (positive)") { + expect((() : Any).isInstanceOf[Unit] ).toBeTruthy + expect((false : Any).isInstanceOf[Boolean]).toBeTruthy + expect(('a' : Any).isInstanceOf[Char] ).toBeTruthy + expect((65.toByte : Any).isInstanceOf[Byte] ).toBeTruthy + expect((654.toShort: Any).isInstanceOf[Short] ).toBeTruthy + expect((-4321 : Any).isInstanceOf[Int] ).toBeTruthy + expect((684321L : Any).isInstanceOf[Long] ).toBeTruthy + expect((3.14f : Any).isInstanceOf[Float] ).toBeTruthy + expect((3.14 : Any).isInstanceOf[Double] ).toBeTruthy + } + + it("should support isInstanceOf (negative)") { + expect((12345: Any).isInstanceOf[Unit] ).toBeFalsy + expect((12345: Any).isInstanceOf[Boolean]).toBeFalsy + expect((12345: Any).isInstanceOf[Char] ).toBeFalsy + expect(('a' : Any).isInstanceOf[Byte] ).toBeFalsy + expect(('b' : Any).isInstanceOf[Short] ).toBeFalsy + expect(('c' : Any).isInstanceOf[Int] ).toBeFalsy + expect(('d' : Any).isInstanceOf[Long] ).toBeFalsy + expect(('f' : Any).isInstanceOf[Float] ).toBeFalsy + expect(('g' : Any).isInstanceOf[Double] ).toBeFalsy + } + + it("should support asInstanceOf (positive)") { + def swallow(x: Any): Unit = () + swallow((() : Any).asInstanceOf[Unit] ) + swallow((false : Any).asInstanceOf[Boolean]) + swallow(('a' : Any).asInstanceOf[Char] ) + swallow((65.toByte : Any).asInstanceOf[Byte] ) + swallow((654.toShort: Any).asInstanceOf[Short] ) + swallow((-4321 : Any).asInstanceOf[Int] ) + swallow((684321L : Any).asInstanceOf[Long] ) + swallow((3.14f : Any).asInstanceOf[Float] ) + swallow((3.14 : Any).asInstanceOf[Double] ) + } + + when("compliant-asinstanceof"). + it("should support asInstanceOf (negative)") { + expect(() => (12345: Any).asInstanceOf[Unit] ).toThrow + expect(() => (12345: Any).asInstanceOf[Boolean]).toThrow + expect(() => (12345: Any).asInstanceOf[Char] ).toThrow + expect(() => ('a' : Any).asInstanceOf[Byte] ).toThrow + expect(() => ('b' : Any).asInstanceOf[Short] ).toThrow + expect(() => ('c' : Any).asInstanceOf[Int] ).toThrow + expect(() => ('d' : Any).asInstanceOf[Long] ).toThrow + expect(() => ('f' : Any).asInstanceOf[Float] ).toThrow + expect(() => ('g' : Any).asInstanceOf[Double] ).toThrow + } + + it("should support isInstanceOf via java.lang.Class (positive)") { + def test(x: Any, clazz: Class[_]): Unit = + expect(clazz.isInstance(x)).toBeTruthy + + test(() , classOf[scala.runtime.BoxedUnit]) + test(false , classOf[java.lang.Boolean]) + test('a' , classOf[java.lang.Character]) + test(65.toByte , classOf[java.lang.Byte]) + test(654.toShort, classOf[java.lang.Short]) + test(-4321 , classOf[java.lang.Integer]) + test(684321L , classOf[java.lang.Long]) + test(3.14f , classOf[java.lang.Float]) + test(3.14 , classOf[java.lang.Double]) + } + + it("should support isInstanceOf via java.lang.Class (negative)") { + def test(x: Any, clazz: Class[_]): Unit = + expect(clazz.isInstance(x)).toBeFalsy + + test(12345, classOf[scala.runtime.BoxedUnit]) + test(12345, classOf[java.lang.Boolean]) + test(12345, classOf[java.lang.Character]) + test('a' , classOf[java.lang.Byte]) + test('b' , classOf[java.lang.Short]) + test('c' , classOf[java.lang.Integer]) + test('d' , classOf[java.lang.Long]) + test('e' , classOf[java.lang.Float]) + test('f' , classOf[java.lang.Double]) + } + + } +} diff --git a/test-suite/src/test/scala/scala/scalajs/testsuite/compiler/IntTest.scala b/test-suite/src/test/scala/scala/scalajs/testsuite/compiler/IntTest.scala new file mode 100644 index 0000000..60f8773 --- /dev/null +++ b/test-suite/src/test/scala/scala/scalajs/testsuite/compiler/IntTest.scala @@ -0,0 +1,206 @@ +/* __ *\ +** ________ ___ / / ___ __ ____ Scala.js Test Suite ** +** / __/ __// _ | / / / _ | __ / // __/ (c) 2013, LAMP/EPFL ** +** __\ \/ /__/ __ |/ /__/ __ |/_// /_\ \ http://scala-js.org/ ** +** /____/\___/_/ |_/____/_/ | |__/ /____/ ** +** |/____/ ** +\* */ +package scala.scalajs.testsuite.compiler + +import org.scalajs.jasminetest.JasmineTest + +object IntTest extends JasmineTest { + + /* General note on the way these tests are written: + * We leverage the constant folding applied by the Scala compiler to write + * sound tests. We always perform the same operation, on the same operands, + * once in a way constant folding understands, and once in a way it doesn't. + * Since constant folding is performed on the JVM, we know it has the right + * semantics. + */ + + // final val without type ascription to make sure these are constant-folded + final val MinVal = Int.MinValue + final val MaxVal = Int.MaxValue + final val AlmostMinVal = Int.MinValue + 43 + final val AlmostMaxVal = Int.MaxValue - 36 + + describe("Int primitives") { + + it("should support unary -") { + def test(a: Int, expected: Int): Unit = + expect(-a).toEqual(expected) + + test(56, -56) + test(0, 0) + test(-36, 36) + + test(MaxVal, -MaxVal) + test(MinVal, -MinVal) + test(-MaxVal, MaxVal) + test(AlmostMinVal, -AlmostMinVal) + test(AlmostMaxVal, -AlmostMaxVal) + } + + it("should support +") { + def test(a: Int, b: Int, expected: Int): Unit = + expect(a + b).toEqual(expected) + + test(56, 654, 56 + 654) + test(0, 25, 0 + 25) + test(-36, 13, -36 + 13) + + test(MaxVal, 1, MaxVal + 1) + test(MinVal, -1, MinVal - 1) + test(MaxVal, MinVal, MaxVal + MinVal) + test(AlmostMinVal, -100, AlmostMinVal - 100) + test(AlmostMaxVal, 123, AlmostMaxVal + 123) + } + + it("should support -") { + def test(a: Int, b: Int, expected: Int): Unit = + expect(a - b).toEqual(expected) + + test(56, 654, 56 - 654) + test(0, 25, 0 - 25) + test(-36, 13, -36 - 13) + + test(MaxVal, -1, MaxVal + 1) + test(MinVal, 1, MinVal - 1) + test(MaxVal, MinVal, MaxVal - MinVal) + test(AlmostMinVal, 100, AlmostMinVal - 100) + test(AlmostMaxVal, -123, AlmostMaxVal + 123) + } + + it("should support *") { + def test(a: Int, b: Int, expected: Int): Unit = + expect(a * b).toEqual(expected) + + test(56, 654, 56 * 654) + test(0, 25, 0 * 25) + test(-36, 13, -36 * 13) + test(-5, -6, -5 * -6) + + test(MinVal, 1, MinVal * 1) + test(MinVal, -1, MinVal * -1) + test(MaxVal, 1, MaxVal * 1) + test(MaxVal, -1, MaxVal * -1) + + test(MaxVal, MinVal, MaxVal * MinVal) + test(MaxVal, MaxVal, MaxVal * MaxVal) + test(MinVal, MaxVal, MinVal * MaxVal) + test(MinVal, MinVal, MinVal * MinVal) + + test(AlmostMaxVal, 2, AlmostMaxVal * 2) + test(AlmostMaxVal, 5, AlmostMaxVal * 5) + test(AlmostMaxVal, -7, AlmostMaxVal * -7) + test(AlmostMaxVal, -14, AlmostMaxVal * -14) + test(AlmostMinVal, 100, AlmostMinVal * 100) + test(AlmostMaxVal, -123, AlmostMaxVal * -123) + } + + it("should support /") { + def test(a: Int, b: Int, expected: Int): Unit = + expect(a / b).toEqual(expected) + + test(654, 56, 654 / 56) + test(0, 25, 0 / 25) + test(-36, 13, -36 / 13) + test(-55, -6, -55 / -6) + + test(MinVal, 1, MinVal / 1) + test(MinVal, -1, MinVal / -1) + test(MaxVal, 1, MaxVal / 1) + test(MaxVal, -1, MaxVal / -1) + + test(MaxVal, MinVal, MaxVal / MinVal) + test(MaxVal, MaxVal, MaxVal / MaxVal) + test(MinVal, MaxVal, MinVal / MaxVal) + test(MinVal, MinVal, MinVal / MinVal) + + test(AlmostMaxVal, 2, AlmostMaxVal / 2) + test(AlmostMaxVal, 5, AlmostMaxVal / 5) + test(AlmostMaxVal, -7, AlmostMaxVal / -7) + test(AlmostMaxVal, -14, AlmostMaxVal / -14) + test(AlmostMinVal, 100, AlmostMinVal / 100) + test(AlmostMaxVal, -123, AlmostMaxVal / -123) + } + + unless("phantomjs"). // see #593 + it("should support %") { + def test(a: Int, b: Int, expected: Int): Unit = + expect(a % b).toEqual(expected) + + test(654, 56, 654 % 56) + test(0, 25, 0 % 25) + test(-36, 13, -36 % 13) + test(-55, -6, -55 % -6) + + test(MinVal, 1, MinVal % 1) + test(MinVal, -1, MinVal % -1) + test(MaxVal, 1, MaxVal % 1) + test(MaxVal, -1, MaxVal % -1) + + test(MaxVal, MinVal, MaxVal % MinVal) + test(MaxVal, MaxVal, MaxVal % MaxVal) + test(MinVal, MaxVal, MinVal % MaxVal) + test(MinVal, MinVal, MinVal % MinVal) + + test(AlmostMaxVal, 2, AlmostMaxVal % 2) + test(AlmostMaxVal, 5, AlmostMaxVal % 5) + test(AlmostMaxVal, -7, AlmostMaxVal % -7) + test(AlmostMaxVal, -14, AlmostMaxVal % -14) + test(AlmostMinVal, 100, AlmostMinVal % 100) + test(AlmostMaxVal, -123, AlmostMaxVal % -123) + } + + it("should support <<") { + def test(a: Int, b: Int, expected: Int): Unit = + expect(a << b).toEqual(expected) + + test(0, 5, 0 << 5) + test(1, 5, 1 << 5) + test(13, 4, 13 << 4) + test(-35, 5, -35 << 5) + test(345, 0, 345 << 0) + + test(MinVal, 0, MinVal << 0) + test(MaxVal, 0, MaxVal << 0) + test(MinVal, 1, MinVal << 1) + test(MaxVal, 1, MaxVal << 1) + } + + it("should support >>") { + def test(a: Int, b: Int, expected: Int): Unit = + expect(a >> b).toEqual(expected) + + test(0, 5, 0 >> 5) + test(32, 5, 32 >> 5) + test(31, 4, 31 >> 4) + test(-355, 5, -355 >> 5) + test(345, 0, 345 >> 0) + + test(MinVal, 0, MinVal >> 0) + test(MaxVal, 0, MaxVal >> 0) + test(MinVal, 1, MinVal >> 1) + test(MaxVal, 1, MaxVal >> 1) + } + + it("should support >>>") { + def test(a: Int, b: Int, expected: Int): Unit = + expect(a >>> b).toEqual(expected) + + test(0, 5, 0 >>> 5) + test(32, 5, 32 >>> 5) + test(31, 4, 31 >>> 4) + test(-355, 5, -355 >>> 5) + test(345, 0, 345 >>> 0) + + test(MinVal, 0, MinVal >>> 0) + test(MaxVal, 0, MaxVal >>> 0) + test(MinVal, 1, MinVal >>> 1) + test(MaxVal, 1, MaxVal >>> 1) + } + + } +} diff --git a/test-suite/src/test/scala/scala/scalajs/testsuite/compiler/InteroperabilityTest.scala b/test-suite/src/test/scala/scala/scalajs/testsuite/compiler/InteroperabilityTest.scala new file mode 100644 index 0000000..594345a --- /dev/null +++ b/test-suite/src/test/scala/scala/scalajs/testsuite/compiler/InteroperabilityTest.scala @@ -0,0 +1,528 @@ +/* __ *\ +** ________ ___ / / ___ __ ____ Scala.js Test Suite ** +** / __/ __// _ | / / / _ | __ / // __/ (c) 2013, LAMP/EPFL ** +** __\ \/ /__/ __ |/ /__/ __ |/_// /_\ \ http://scala-js.org/ ** +** /____/\___/_/ |_/____/_/ | |__/ /____/ ** +** |/____/ ** +\* */ +package scala.scalajs.testsuite.compiler + +import scala.scalajs.js +import org.scalajs.jasminetest.{JasmineTest, JasmineTestFramework} +import scala.scalajs.js.annotation._ + +/* + * Based on examples in: + * http://lampwww.epfl.ch/~doeraene/scala-js/doc/js-interoperability.html + */ +object InteroperabilityTest extends JasmineTest { + + describe("JavaScript interoperability") { + + it("should support backquotes to escape Scala fields") { + val obj = js.eval(""" + var interoperabilityTestFieldEscape = { + def: 0, + val: function(x) { if (x) this.def = x; return this.def; } + }; + interoperabilityTestFieldEscape; + """).asInstanceOf[InteroperabilityTestFieldEscape] + + obj.`def` = 7357 + expect(obj.`def`).toEqual(7357) + expect(obj.`val`()).toEqual(7357) + expect(obj.`val`(42)).toEqual(42) + } + + it("should support @JSName to specify the JavaScript name for fields") { + val obj = js.eval(""" + var interoperabilityTestJSName = { + def: 42, + val: function(x) { if (x) this.def = x; return this.def; } + }; + interoperabilityTestJSName; + """).asInstanceOf[InteroperabilityTestJSName] + + expect(obj.value()).toEqual(42) + expect(obj.value(7357)).toEqual(7357) + } + + it("should translate explicit getter and setter names to field access") { + val obj = js.eval(""" + var interoperabilityTestProperty = { a: 1 }; + interoperabilityTestProperty; + """).asInstanceOf[InteroperabilityTestProperty] + + expect(obj.a).toEqual(1) + obj.a = 100 + expect(obj.a).toEqual(100) + } + + it("should support @JSName together with field access") { + val obj = js.eval(""" + var interoperabilityTestProperty = { b: 1 }; + interoperabilityTestProperty; + """).asInstanceOf[InteroperabilityTestPropertyNamed] + + expect(obj.a).toEqual(1) + obj.a = 100 + expect(obj.a).toEqual(100) + expect(obj.b).toEqual(100) + } + + it("should support @JSBracketAccess to specify access using []-subscription") { + val obj = js.eval(""" + var interoperabilityTestJSBracketAccess = [ 0, 1, 7357 ]; + interoperabilityTestJSBracketAccess; + """).asInstanceOf[InteroperabilityTestJSBracketAccess] + + expect(obj(2)).toEqual(7357) + obj(2) = 42 + expect(obj(2)).toEqual(42) + } + + it("should allow instanciation of JS classes inheriting from js.Object") { + js.eval(""" + var InteroperabilityTestInherit = { + Pattern: function(x) { + this.field = 42; + this.method = function() { + return '42'; + }; + this.getConstructorParam = function() { + return x; + }; + } + } + """) + + val obj = new InteroperabilityTestPattern("Scala.js") + expect(obj.field).toEqual(42) + expect(obj.method).toEqual("42") + expect(obj.getConstructorParam).toEqual("Scala.js") + } + + it("should acces top-level JS objects via Scala objects inheriting from js.Object") { + js.eval(""" + var InteroperabilityTestTopLevelObject = function(value) { + return { + value: value, + valueAsInt: function() { + return parseInt(value); + } + }; + } + """) + + // Use alias for convenience: see end of file for definition + val TopLevel = InteroperabilityTestTopLevel + + val obj = TopLevel("7357") + expect(obj.value).toEqual("7357") + expect(obj.valueAsInt).toEqual(7357) + } + + it("should allow to call JS methods with variadic parameters") { + val obj = js.eval(""" + var obj = { + foo: function() { + var args = new Array(arguments.length); + for (var i = 0; i < arguments.length; i++) + args[i] = arguments[i]; + return args; + } + }; + obj; + """) + + val elems = Seq[js.Any]("plop", 42, 51) + + val dyn = obj.asInstanceOf[js.Dynamic] + expect(dyn.foo()).toEqual(js.Array()) + expect(dyn.foo(3, 6)).toEqual(js.Array(3, 6)) + expect(dyn.foo("hello", false)).toEqual(js.Array("hello", false)) + expect(dyn.applyDynamic("foo")(elems: _*)).toEqual(js.Array("plop", 42, 51)) + + val stat = obj.asInstanceOf[InteroperabilityTestVariadicMethod] + expect(stat.foo()).toEqual(js.Array()) + expect(stat.foo(3, 6)).toEqual(js.Array(3, 6)) + expect(stat.foo("hello", false)).toEqual(js.Array("hello", false)) + expect(stat.foo(elems: _*)).toEqual(js.Array("plop", 42, 51)) + } + + it("should allow to call JS constructors with variadic parameters") { + import js.Dynamic.{newInstance => jsnew} + + js.eval(""" + var InteroperabilityTestVariadicCtor = function() { + var args = new Array(arguments.length); + for (var i = 0; i < arguments.length; i++) + args[i] = arguments[i]; + this.args = args; + }; + """) + + val elems = Seq[js.Any]("plop", 42, 51) + + val ctor = js.Dynamic.global.InteroperabilityTestVariadicCtor + expect(jsnew(ctor)().args).toEqual(js.Array()) + expect(jsnew(ctor)(3, 6).args).toEqual(js.Array(3, 6)) + expect(jsnew(ctor)("hello", false).args).toEqual(js.Array("hello", false)) + expect(jsnew(ctor)(elems: _*).args).toEqual(js.Array("plop", 42, 51)) + + import scala.scalajs.testsuite.compiler.{InteroperabilityTestVariadicCtor => C} + expect(new C().args).toEqual(js.Array()) + expect(new C(3, 6).args).toEqual(js.Array(3, 6)) + expect(new C("hello", false).args).toEqual(js.Array("hello", false)) + expect(new C(elems: _*).args).toEqual(js.Array("plop", 42, 51)) + } + + it("should acces top-level JS objects via Scala object inheriting from js.GlobalScope") { + js.eval(""" + var interoperabilityTestGlobalScopeValue = "7357"; + var interoperabilityTestGlobalScopeValueAsInt = function() { + return parseInt(interoperabilityTestGlobalScopeValue); + }; + """) + + // Use alias for convenience: see end of file for definition + val Global = InteroperabilityTestGlobalScope + + expect(Global.interoperabilityTestGlobalScopeValue).toEqual("7357") + expect(Global.interoperabilityTestGlobalScopeValueAsInt).toEqual(7357) + + Global.interoperabilityTestGlobalScopeValue = "42" + expect(Global.interoperabilityTestGlobalScopeValueAsInt).toEqual(42) + } + + it("should protect receiver of raw JS apply if it's a select - #804") { + val rawReceiver = js.eval(""" + var interoperabilityTestRawReceiver = { + member: 0xbad, + check: function(raw) { return this.member ? this.member : raw; } + }; + interoperabilityTestRawReceiver; + """).asInstanceOf[InteroperabilityTestRawReceiver] + + expect(rawReceiver.check(7357)).toEqual(7357) + + val check = rawReceiver.check + expect(check(0x600d)).toEqual(0x600d) + + class InScalaSelect(check: js.Function1[Int, Int]) { + @JSExport + val member: Int = 0xbad2 + def test(): Unit = expect(check(5894)).toEqual(5894) + } + new InScalaSelect(check).test() + } + + it("should properly handle default parameters") { + val obj = js.eval(""" + var interoperabilityTestDefaultParam = { + fun: function() { return arguments; } + }; + interoperabilityTestDefaultParam; + """).asInstanceOf[InteroperabilityTestDefaultParam] + + // Helpers + import js.Dynamic.{literal => args} + val undef = js.undefined + + expect(obj.simple(1)).toEqual(args(`0` = 1)) + expect(obj.simple(1,5)).toEqual(args(`0` = 1, `1` = 5)) + expect(obj.named(y = 5)).toEqual(args(`0` = undef, `1` = 5)) + expect(obj.named(x = 5)).toEqual(args(`0` = 5)) + expect(obj.multi()(1,2,3,4)()).toEqual(args( + `0` = undef, + `1` = 1, + `2` = 2, + `3` = 3, + `4` = 4)) + expect(obj.multi(2)()(5)).toEqual(args( + `0` = 2, + `1` = 5)) + } + + it("should properly handle default parameters for constructors - #791") { + js.eval(""" + var InteroperabilityTestCtor = function(x,y) { + this.values = Array(x || 6, y || 8) + } + """); + + expect(new InteroperabilityTestCtor().values).toEqual(js.Array(6,8)) + expect(new InteroperabilityTestCtor(y = 7).values).toEqual(js.Array(6,7)) + expect(new InteroperabilityTestCtor(3).values).toEqual(js.Array(3,8)) + expect(new InteroperabilityTestCtor(10, 2).values).toEqual(js.Array(10,2)) + } + + it("should generate exports for methods inherited from traits - #178") { + import js.annotation.JSExport + + trait Foo { + @JSExport + def theValue = 1 + } + class Bar extends Foo + + val x = (new Bar).asInstanceOf[js.Dynamic] + + // Call the export by using js.Dynamic + expect(x.theValue).toEqual(1) + } + + it("should allow constructor params that are vals/vars in facades - #1277") { + js.eval(""" + var InteroparabilityCtorInlineValue = function(x,y) { + this.x = x; + this.y = y; + } + """) + + val obj = new InteroparabilityCtorInlineValue(10, -1) + + expect(obj.x).toEqual(10) + expect(obj.y).toEqual(-1) + + obj.y = 100 + + expect(obj.x).toEqual(10) + expect(obj.y).toEqual(100) + } + + it("should unbox Chars received from calling a JS interop method") { + val obj = js.eval(""" + var obj = { + get: function() { return JSUtils().stringToChar('e'); } + }; + obj; + """).asInstanceOf[InteroperabilityTestCharResult] + + expect(obj.get().toInt).toEqual('e'.toInt) + } + + it("should box Chars given to a JS interop method") { + val obj = js.eval(""" + var obj = { + twice: function(c) { c = JSUtils().charToString(c); return c+c; } + }; + obj; + """).asInstanceOf[InteroperabilityTestCharParam] + + expect(obj.twice('x')).toEqual("xx") + } + + it("should unbox value classes received from calling a JS interop method") { + val obj = js.eval(""" + var obj = { + test: function(vc) { return vc; } + }; + obj; + """).asInstanceOf[InteroperabilityTestValueClassResult] + + val r = obj.test(new SomeValueClass(5)) + expect(r.i).toEqual(5) + } + + it("should box value classes given to a JS interop method") { + val obj = js.eval(""" + var obj = { + stringOf: function(vc) { return vc.toString(); } + }; + obj; + """).asInstanceOf[InteroperabilityTestValueClassParam] + + val vc = new SomeValueClass(7) + expect(obj.stringOf(vc)).toEqual("SomeValueClass(7)") + } + + it("should not unbox values received from JS method in statement position") { + /* To test this, we verify that a purposefully ill-typed facade does not + * throw a ClassCastException when called in statement position. + */ + val obj = js.eval(""" + var obj = { + test: function() { return 4; } // typed as String in the trait + }; + obj; + """).asInstanceOf[InteroperabilityTestNoUnboxResultInStatement] + obj.test() // in statement position, should not throw + if (JasmineTestFramework.hasTag("compliant-asinstanceof")) + expect(() => obj.test()).toThrow // in expression position, should throw + } + + when("compliant-asinstanceof"). + it("should protect conversions from JS types to Scala types") { + class Foo + val foo: Any = new Foo + + val invalidNumber: js.prim.Number = foo.asInstanceOf[js.prim.Number] + val nullNumber: js.prim.Number = null + expect(() => invalidNumber: Double).toThrow + expect(nullNumber: Double).toEqual(0) + + val invalidBoolean: js.prim.Boolean = foo.asInstanceOf[js.prim.Boolean] + val nullBoolean: js.prim.Boolean = null + expect(() => invalidBoolean: Boolean).toThrow + expect(nullBoolean: Boolean).toEqual(false) + + val invalidString: js.prim.String = foo.asInstanceOf[js.prim.String] + val nullString: js.prim.String = null + expect(() => invalidString: String).toThrow + expect(nullString: String).toBeNull + } + + when("compliant-asinstanceof"). + it("should asInstanceOf values received from calling a JS interop method") { + val obj = js.eval(""" + var obj = { + testChar: function() { return 5; }, + testInt: function() { return 6.4; }, + testShort: function() { return 60000; }, + testDouble: function() { return JSUtils().stringToChar('e'); }, + testString: function() { return {}; }, + testValueClass: function() { return "hello"; }, + testNormalClass: function() { return 45; }, + testAny: function() { return {}; } + }; + obj; + """).asInstanceOf[InteroperabilityTestAsInstanceOfResult] + + expect(() => obj.testChar()).toThrow + expect(() => obj.testInt()).toThrow + expect(() => obj.testShort()).toThrow + expect(() => obj.testDouble()).toThrow + expect(() => obj.testString()).toThrow + expect(() => obj.testValueClass()).toThrow + expect(() => obj.testNormalClass()).toThrow + expect(() => obj.testAny()).not.toThrow + } + + } + + trait InteroperabilityTestFieldEscape extends js.Object { + var `def`: Int = js.native + def `val`(): Int = js.native + def `val`(n: Int): Int = js.native + } + + trait InteroperabilityTestJSName extends js.Object { + @JSName("val") + def value(): Int = js.native + @JSName("val") + def value(n: Int): Int = js.native + } + + trait InteroperabilityTestProperty extends js.Object { + def a_=(x: Int): Unit = js.native + def a: Int = js.native + } + + trait InteroperabilityTestPropertyNamed extends js.Object { + @JSName("b") + def a_=(x: Int): Unit = js.native + @JSName("b") + def a: Int = js.native + def b: Int = js.native + } + + trait InteroperabilityTestJSBracketAccess extends js.Object { + @JSBracketAccess + def apply(index: Int): Int = js.native + @JSBracketAccess + def update(index: Int, v: Int): Unit = js.native + } + + trait InteroperabilityTestRawReceiver extends js.Object { + val check: js.Function1[Int, Int] = js.native + } + + /** Trait with different method signatures, all forwarded to the same + * JS raw function that returns the argument list for inspection + */ + trait InteroperabilityTestDefaultParam extends js.Object { + @JSName("fun") + def simple(x: Int, y: Int = 5): js.Any = js.native + @JSName("fun") + def named(x: Int = 1, y: Int = 1, z: Int = 1): js.Any = js.native + @JSName("fun") + def multi(x: Int = 1)(ys: Int*)(z: Int = 1): js.Any = js.native + } + + trait InteroperabilityTestCharResult extends js.Object { + def get(): Char = js.native + } + + trait InteroperabilityTestCharParam extends js.Object { + def twice(c: Char): String = js.native + } + + trait InteroperabilityTestValueClassResult extends js.Object { + def test(vc: Any): SomeValueClass = js.native + } + + trait InteroperabilityTestValueClassParam extends js.Object { + def stringOf(vc: SomeValueClass): String = js.native + } + + trait InteroperabilityTestNoUnboxResultInStatement extends js.Object { + def test(): String = js.native + } + + trait InteroperabilityTestAsInstanceOfResult extends js.Object { + def testChar(): Char = js.native + def testInt(): Int = js.native + def testShort(): Short = js.native + def testDouble(): Double = js.native + def testString(): String = js.native + def testValueClass(): SomeValueClass = js.native + def testNormalClass(): List[Int] = js.native + def testAny(): Any = js.native + } +} + +/* + * Helper classes, traits and objects defined here since they cannot be nested. + */ + +@JSName("InteroperabilityTestInherit.Pattern") +class InteroperabilityTestPattern protected () extends js.Object { + def this(pattern: String) = this() + val field: Int = js.native + def method(): String = js.native + def getConstructorParam(): String = js.native +} + +trait InteroperabilityTestTopLevel extends js.Object { + val value: String = js.native + def valueAsInt(): Int = js.native +} + +@JSName("InteroperabilityTestTopLevelObject") +object InteroperabilityTestTopLevel extends js.Object { + def apply(value: String): InteroperabilityTestTopLevel = js.native +} + +trait InteroperabilityTestVariadicMethod extends js.Object { + def foo(args: Any*): js.Array[Any] = js.native +} + +class InteroperabilityTestVariadicCtor(inargs: Any*) extends js.Object { + val args: js.Array[Any] = js.native +} + +object InteroperabilityTestGlobalScope extends js.GlobalScope { + var interoperabilityTestGlobalScopeValue: String = js.native + def interoperabilityTestGlobalScopeValueAsInt(): Int = js.native +} + +class SomeValueClass(val i: Int) extends AnyVal { + override def toString(): String = s"SomeValueClass($i)" +} + +class InteroperabilityTestCtor(x: Int = 5, y: Int = ???) extends js.Object { + def values: js.Array[Int] = js.native +} + +class InteroparabilityCtorInlineValue(val x: Int, var y: Int) extends js.Object diff --git a/test-suite/src/test/scala/scala/scalajs/testsuite/compiler/LongTest.scala b/test-suite/src/test/scala/scala/scalajs/testsuite/compiler/LongTest.scala new file mode 100644 index 0000000..01d6f6e --- /dev/null +++ b/test-suite/src/test/scala/scala/scalajs/testsuite/compiler/LongTest.scala @@ -0,0 +1,159 @@ +/* __ *\ +** ________ ___ / / ___ __ ____ Scala.js Test Suite ** +** / __/ __// _ | / / / _ | __ / // __/ (c) 2013, LAMP/EPFL ** +** __\ \/ /__/ __ |/ /__/ __ |/_// /_\ \ http://scala-js.org/ ** +** /____/\___/_/ |_/____/_/ | |__/ /____/ ** +** |/____/ ** +\* */ +package scala.scalajs.testsuite.compiler + +import scala.scalajs.js + +import org.scalajs.jasminetest.JasmineTest + +/** + * tests the compiler re-patching of native longs to + * scala.scalajs.runtime.Long + * see scala.scalajs.testsuite.jsinterop.RuntimeLongTest + * for a test of the implementation itself + */ +object LongTest extends JasmineTest { + + describe("JavaScript 64-bit long compatibility") { + it("should correctly handle literals") { + expect(5L + 100L == 105L).toBeTruthy + expect(2147483649L + 2L == 2147483651L).toBeTruthy + expect(-2147483648L * 4 == -8589934592L).toBeTruthy + expect(4503599627370510L * (-4) == -18014398509482040L).toBeTruthy + } + + it("should correctly dispatch unary ops on Longs") { + val x = 10L + expect(-x == -10L).toBeTruthy + val y = 5L + expect(-y == -5L).toBeTruthy + expect(+y == 5L).toBeTruthy + expect(~y == -6L).toBeTruthy + } + + it("should correctly dispatch binary ops on Longs") { + expect(5L * 5F == 25F).toBeTruthy + expect(5L % 4F == 1F).toBeTruthy + expect(5F * 4L == 20F).toBeTruthy + } + + it("should support shifts with Longs - #622") { + def l(x: Long): Long = x + def i(x: Int): Int = x + + expect(l(-7L) >>> 100L == 268435455L).toBeTruthy + expect(l(-7L) >> 100L == -1L).toBeTruthy + expect(l(-7L) >> 100 == -1L).toBeTruthy + expect(l(-7L) >>> 100 == 268435455).toBeTruthy + expect(l(-7L) << 100L == -481036337152L).toBeTruthy + expect(l(-7L) << 100 == -481036337152L).toBeTruthy + expect(l(7L) << 100L == 481036337152L).toBeTruthy + expect(l(8L) << 100L == 549755813888L).toBeTruthy + expect(l(-7L) >>> 4 == 1152921504606846975L).toBeTruthy + + expect(i(7) << 100).toEqual(112) + expect(i(-7) >> 100).toEqual(-1) + expect(i(-7) >>> 100).toEqual(268435455) + expect(i(-65) >> 100).toEqual(-5) + expect(i(-65) >> 4).toEqual(-5) + } + + it("primitives should convert to Long") { + // Byte + expect(112.toByte.toLong == 112L).toBeTruthy + // Short + expect((-10).toShort.toLong == -10L).toBeTruthy + // Char + expect('A'.toLong == 65L).toBeTruthy + // Int + expect(5.toLong == 5L).toBeTruthy + // Long + expect(10L.toLong == 10L).toBeTruthy + // Float + expect(100000.6f.toLong == 100000L).toBeTruthy + // Double + expect(100000.6.toLong == 100000L).toBeTruthy + } + + it("should support hashCode()") { + expect(0L .hashCode()).toEqual(0) + expect(55L .hashCode()).toEqual(55) + expect((-12L) .hashCode()).toEqual(11) + expect(10006548L .hashCode()).toEqual(10006548) + expect((-1098748L).hashCode()).toEqual(1098747) + + expect(613354684553L .hashCode()).toEqual(-825638905) + expect(9863155567412L .hashCode()).toEqual(1910653900) + expect(3632147899696541255L.hashCode()).toEqual(1735398658) + expect(7632147899696541255L.hashCode()).toEqual(-1689438124) + } + + it("should support ##") { + expect(0L .##).toEqual(0) + expect(55L .##).toEqual(55) + expect((-12L) .##).toEqual(-12) + expect(10006548L .##).toEqual(10006548) + expect((-1098748L).##).toEqual(-1098748) + + expect(9863155567412L .##).toEqual(1910653900) + expect(3632147899696541255L.##).toEqual(1735398658) + + // These two (correctly) give different results on 2.10 and 2.11 + //expect(613354684553L .##).toEqual(-825638905) // xx06 on 2.10 + //expect(7632147899696541255L.##).toEqual(-1689438124) // xx25 on 2.10 + } + + it("should correctly concat to string") { + val x = 20L + expect("asdf" + 5L + x + "hello").toEqual("asdf520hello") + expect(x + "hello").toEqual("20hello") + } + + it("string should convert to Long") { + expect("45678901234567890".toLong == 45678901234567890L).toBeTruthy + } + + it("should convert from and to js.prim.Number") { + val x = 5: js.prim.Number + expect((5L: js.prim.Number) == x).toBeTruthy + expect(x.toLong == 5L).toBeTruthy + } + + it("should correctly implement is/asInstanceOf Longs") { + val dyn: Any = 5L + val stat: Long = 5L + + expect(stat.asInstanceOf[Long]).toEqual(5L) + // models current scala behavior. See SI-1448 + expect(stat.asInstanceOf[Int]).toEqual(5) + + expect(stat.isInstanceOf[Long]).toBeTruthy + expect(stat.isInstanceOf[Int]).toBeFalsy + + expect(dyn.asInstanceOf[Long]).toEqual(5L) + + expect(dyn.isInstanceOf[Long]).toBeTruthy + expect(dyn.isInstanceOf[Int]).toBeFalsy + } + + when("compliant-asinstanceof"). + it("should correctly implement asInstanceOf Longs (negative)") { + val dyn: Any = 5L + + expect(() => dyn.asInstanceOf[Int]).toThrow + } + + it("should correctly compare to other numeric types") { + expect(5L == 5).toBeTruthy + expect(5 == 5L).toBeTruthy + expect(4 == 5l).toBeFalsy + expect('A' == 65L).toBeTruthy + } + } + +} diff --git a/test-suite/src/test/scala/scala/scalajs/testsuite/compiler/OptimizerTest.scala b/test-suite/src/test/scala/scala/scalajs/testsuite/compiler/OptimizerTest.scala new file mode 100644 index 0000000..986c25a --- /dev/null +++ b/test-suite/src/test/scala/scala/scalajs/testsuite/compiler/OptimizerTest.scala @@ -0,0 +1,43 @@ +/* __ *\ +** ________ ___ / / ___ __ ____ Scala.js Test Suite ** +** / __/ __// _ | / / / _ | __ / // __/ (c) 2013, LAMP/EPFL ** +** __\ \/ /__/ __ |/ /__/ __ |/_// /_\ \ http://scala-js.org/ ** +** /____/\___/_/ |_/____/_/ | |__/ /____/ ** +** |/____/ ** +\* */ +package scala.scalajs.testsuite.compiler + +import org.scalajs.jasminetest.JasmineTest + +object OptimizerTest extends JasmineTest { + + describe("Inlineable classes") { + + it("must update fields of `this` in the computation of other fields - #1153") { + val foo = new InlineClassDependentFields(5) + expect(foo.x).toEqual(5) + expect(foo.b).toBeTruthy + expect(foo.y).toEqual(11) + } + + it("must not break code that assigns `this` to a field") { + val foo = new InlineClassThisAlias(5) + expect(foo.z).toEqual(5) + } + + } + + @inline + class InlineClassDependentFields(val x: Int) { + val b = x > 3 + val y = if (b) x + 6 else x-2 + } + + @inline + class InlineClassThisAlias(val x: Int) { + val t = this + val y = x + val z = t.y + } + +} diff --git a/test-suite/src/test/scala/scala/scalajs/testsuite/compiler/ReflectionTest.scala b/test-suite/src/test/scala/scala/scalajs/testsuite/compiler/ReflectionTest.scala new file mode 100644 index 0000000..3e1d7a2 --- /dev/null +++ b/test-suite/src/test/scala/scala/scalajs/testsuite/compiler/ReflectionTest.scala @@ -0,0 +1,69 @@ +/* __ *\ +** ________ ___ / / ___ __ ____ Scala.js Test Suite ** +** / __/ __// _ | / / / _ | __ / // __/ (c) 2013, LAMP/EPFL ** +** __\ \/ /__/ __ |/ /__/ __ |/_// /_\ \ http://scala-js.org/ ** +** /____/\___/_/ |_/____/_/ | |__/ /____/ ** +** |/____/ ** +\* */ +package scala.scalajs.testsuite.compiler + +import scala.language.implicitConversions + +import scala.scalajs.js + +import org.scalajs.jasminetest.JasmineTest + +/** Tests the little reflection we support */ +object ReflectionTest extends JasmineTest { + + describe("Scala.js Reflection (through java.lang.Class)") { + it("should append $ to class name of objects") { + expect(TestObject.getClass.getName).toEqual( + "scala.scalajs.testsuite.compiler.ReflectionTest$TestObject$") + } + + it("should support isInstance") { + class A + class B extends A + val b = new B + expect(classOf[A].isInstance(b)).toBeTruthy + expect(classOf[A].isInstance("hello")).toBeFalsy + } + + it("getClass() for normal types") { + class Foo { + def bar() = super.getClass() + } + val foo = new Foo + expect(foo.getClass() eq classOf[Foo]).toBeTruthy + expect(foo.bar() eq classOf[Foo]).toBeTruthy + } + + it("getClass() for anti-boxed primitive types") { + implicit def classAsAny(c: java.lang.Class[_]): js.Any = + c.asInstanceOf[js.Any] + expect((false: Any).getClass).toBe(classOf[java.lang.Boolean]) + expect(('a': Any).getClass).toBe(classOf[java.lang.Character]) + expect((1.toByte: Any).getClass).toBe(classOf[java.lang.Byte]) + expect((1.toShort: Any).getClass).toBe(classOf[java.lang.Byte]) + expect((1: Any).getClass).toBe(classOf[java.lang.Byte]) + expect((1L: Any).getClass).toBe(classOf[java.lang.Long]) + expect((1.5f: Any).getClass).toBe(classOf[java.lang.Float]) + expect((1.5: Any).getClass).toBe(classOf[java.lang.Float]) + expect(((): Any).getClass).toBe(classOf[scala.runtime.BoxedUnit]) + } + + it("Class.isAssignableFrom should mimic runtime type tests behavior - #879") { + expect(classOf[Short].isAssignableFrom(classOf[Byte])).toBeTruthy + expect(classOf[Byte].isAssignableFrom(classOf[Byte])).toBeTruthy + expect(classOf[Byte].isAssignableFrom(classOf[Short])).toBeFalsy + expect(classOf[Int].isAssignableFrom(classOf[Byte])).toBeTruthy + expect(classOf[Double].isAssignableFrom(classOf[Int])).toBeTruthy + expect(classOf[Int].isAssignableFrom(classOf[Double])).toBeFalsy + expect(classOf[Long].isAssignableFrom(classOf[Int])).toBeFalsy + } + } + + object TestObject + +} diff --git a/test-suite/src/test/scala/scala/scalajs/testsuite/compiler/ReflectiveCallTest.scala b/test-suite/src/test/scala/scala/scalajs/testsuite/compiler/ReflectiveCallTest.scala new file mode 100644 index 0000000..6020a5f --- /dev/null +++ b/test-suite/src/test/scala/scala/scalajs/testsuite/compiler/ReflectiveCallTest.scala @@ -0,0 +1,330 @@ +/* __ *\ +** ________ ___ / / ___ __ ____ Scala.js Test Suite ** +** / __/ __// _ | / / / _ | __ / // __/ (c) 2013, LAMP/EPFL ** +** __\ \/ /__/ __ |/ /__/ __ |/_// /_\ \ http://scala-js.org/ ** +** /____/\___/_/ |_/____/_/ | |__/ /____/ ** +** |/____/ ** +\* */ +package scala.scalajs.testsuite.compiler + +import scala.scalajs.js +import org.scalajs.jasminetest.JasmineTest + +import language.reflectiveCalls + +import java.lang.{Float => JFloat, Double => JDouble} + +object ReflectiveCallTest extends JasmineTest { + + describe("Reflective Calls") { + it("should allow subtyping in return types") { + class A { def x = 1 } + class B extends A { override def x = 2 } + + object Generator { + def generate(): B = new B + } + + def f(x: { def generate(): A }) = x.generate + + expect(f(Generator).x).toEqual(2) + } + + it("should allow this.type in return types") { + type valueType = { def value: this.type } + def f(x: valueType) = x.value + + class StringValue(x: String) { + def value: this.type = this + override def toString = s"StringValue($x)" + } + + expect(f(new StringValue("foo")).toString).toEqual("StringValue(foo)") + } + + it("should allow generic return types") { + case class Tata(name: String) + + object Rec { + def e(x: Tata) = new Tata("iei") + } + + def m[T](r: Object { def e(x: Tata): T}) = + r.e(new Tata("foo")) + + expect(m[Tata](Rec).toString).toEqual("Tata(iei)") + } + + it("should work with unary methods on primitive types") { + def fInt(x: Any { def unary_- :Int }) = -x + expect(fInt(1.toByte)).toEqual(-1) + expect(fInt(1.toShort)).toEqual(-1) + expect(fInt(1.toChar)).toEqual(-1) + expect(fInt(1)).toEqual(-1) + + def fLong(x: Any { def unary_- :Long }) = -x + expect(fLong(1L)).toEqual(-1L) + + def fFloat(x: Any { def unary_- :Float}) = -x + expect(fFloat(1.5f)).toEqual(-1.5f) + + def fDouble(x: Any { def unary_- :Double }) = -x + expect(fDouble(1.5)).toEqual(-1.5) + + def fBoolean(x: Any { def unary_! :Boolean }) = !x + expect(fBoolean(false)).toBeTruthy + expect(fBoolean(true)).toBeFalsy + } + + it("should work with binary operators on primitive types") { + def fLong(x: Any { def +(x: Long): Long }) = x + 5L + expect(fLong(5.toByte)).toEqual(10L) + expect(fLong(10.toShort)).toEqual(15L) + expect(fLong(10.toChar)).toEqual(15L) + expect(fLong(-1)).toEqual(4L) + expect(fLong(17L)).toEqual(22L) + + def fInt(x: Any { def /(x: Int): Int }) = x / 7 + expect(fInt(65.toByte)).toEqual(9) + expect(fInt(15.toShort)).toEqual(2) + expect(fInt(25.toChar)).toEqual(3) + expect(fInt(-40)).toEqual(-5) + + def fShort(x: Any { def +(x: Short): Int }) = x + 6.toShort + expect(fShort(65.toByte)).toEqual(71) + expect(fShort(15.toShort)).toEqual(21) + expect(fShort(25.toChar)).toEqual(31) + expect(fShort(-40)).toEqual(-34) + + def fFloat(x: Any { def %(x: Float): Float}) = x % 3.4f + expect(fFloat(5.5f)).toEqual(2.1f) + + def fDouble(x: Any { def /(x: Double): Double }) = x / 1.4 + expect(fDouble(-1.5)).toEqual(-1.0714285714285714) + + def fBoolean(x: Any { def &&(x: Boolean): Boolean }) = x && true + expect(fBoolean(false)).toBeFalsy + expect(fBoolean(true)).toBeTruthy + } + + it("should work with equality operators on primitive types") { + def fNum(obj: Any { def ==(x: Int): Boolean }) = obj == 5 + expect(fNum(5.toByte)).toBeTruthy + expect(fNum(6.toByte)).toBeFalsy + expect(fNum(5.toShort)).toBeTruthy + expect(fNum(7.toShort)).toBeFalsy + expect(fNum(5.toChar)).toBeTruthy + expect(fNum('r')).toBeFalsy + expect(fNum(5)).toBeTruthy + expect(fNum(-4)).toBeFalsy + expect(fNum(5L)).toBeTruthy + expect(fNum(400L)).toBeFalsy + expect(fNum(5.0f)).toBeTruthy + expect(fNum(5.6f)).toBeFalsy + expect(fNum(5.0)).toBeTruthy + expect(fNum(7.9)).toBeFalsy + def fBool(obj: Any { def ==(x: Boolean): Boolean }) = obj == false + expect(fBool(true)).toBeFalsy + expect(fBool(false)).toBeTruthy + + def fNumN(obj: Any { def !=(x: Int): Boolean }) = obj != 5 + expect(fNumN(5.toByte)).toBeFalsy + expect(fNumN(6.toByte)).toBeTruthy + expect(fNumN(5.toShort)).toBeFalsy + expect(fNumN(7.toShort)).toBeTruthy + expect(fNumN(5.toChar)).toBeFalsy + expect(fNumN('r')).toBeTruthy + expect(fNumN(5)).toBeFalsy + expect(fNumN(-4)).toBeTruthy + expect(fNumN(5L)).toBeFalsy + expect(fNumN(400L)).toBeTruthy + expect(fNumN(5.0f)).toBeFalsy + expect(fNumN(5.6f)).toBeTruthy + expect(fNumN(5.0)).toBeFalsy + expect(fNumN(7.9)).toBeTruthy + def fBoolN(obj: Any { def !=(x: Boolean): Boolean }) = obj != false + expect(fBoolN(true)).toBeTruthy + expect(fBoolN(false)).toBeFalsy + + } + + it("should work with Arrays") { + type UPD = { def update(i: Int, x: String): Unit } + type APL = { def apply(i: Int): String } + type LEN = { def length: Int } + type CLONE = Any { def clone(): Object } + def upd(obj: UPD, i: Int, x: String) = obj.update(i,x) + def apl(obj: APL, i: Int) = obj.apply(i) + def len(obj: LEN) = obj.length + def clone(obj: CLONE) = obj.clone + + val x = Array("asdf","foo","bar") + val y = clone(x).asInstanceOf[Array[String]] + + expect(len(x)).toEqual(3) + expect(apl(x,0)).toEqual("asdf") + upd(x,1,"2foo") + expect(x(1)).toEqual("2foo") + expect(y(1)).toEqual("foo") + } + + it("should work with Arrays of primitive values") { + type UPD = { def update(i: Int, x: Int): Unit } + type APL = { def apply(i: Int): Int} + type LEN = { def length: Int } + type CLONE = Any { def clone(): Object } + def upd(obj: UPD, i: Int, x: Int) = obj.update(i,x) + def apl(obj: APL, i: Int) = obj.apply(i) + def len(obj: LEN) = obj.length + def clone(obj: CLONE) = obj.clone + + val x = Array(5,2,8) + val y = clone(x).asInstanceOf[Array[Int]] + + expect(len(x)).toEqual(3) + expect(apl(x,0)).toEqual(5) + upd(x,1,1000) + expect(x(1)).toEqual(1000) + expect(y(1)).toEqual(2) + } + + it("should work with Strings") { + def get(obj: { def codePointAt(str: Int): Int }) = + obj.codePointAt(1) + expect(get("Hi")).toEqual('i'.toInt) + + def sub(x: { def substring(x: Int): AnyRef }) = x.substring(5) + expect(sub("asdfasdfasdf") == "sdfasdf").toBeTruthy + + type LEN_A = { def length: Any } + def lenA(x: LEN_A) = x.length + expect(lenA("asdf") == 4).toBeTruthy + } + + it("should properly generate forwarders for inherited methods") { + trait A { + def foo: Int + } + + abstract class B extends A + + class C extends B { + def foo = 1 + } + + def call(x: { def foo: Int }) = x.foo + + expect(call(new C)).toEqual(1) + } + + it("should work on java.lang.Object.{ notify, notifyAll } - #303") { + type ObjNotifyLike = Any { + def notify(): Unit + def notifyAll(): Unit + } + def objNotifyTest(obj: ObjNotifyLike) = { + obj.notify() + obj.notifyAll() + 1 + } + + class A + + expect(objNotifyTest(new A())).toEqual(1) + } + + it("should work on java.lang.Object.clone - #303") { + type ObjCloneLike = Any { def clone(): AnyRef } + def objCloneTest(obj: ObjCloneLike) = obj.clone() + + class B(val x: Int) extends Cloneable { + override def clone() = super.clone + } + + val b = new B(1) + val bClone = objCloneTest(b).asInstanceOf[B] + + expect(b eq bClone).toBeFalsy + expect(bClone.x).toEqual(1) + } + + it("should work on scala.AnyRef.{ eq, ne } - #303") { + type ObjEqLike = Any { + def eq(that: AnyRef): Boolean + def ne(that: AnyRef): Boolean + } + def objEqTest(obj: ObjEqLike, that: AnyRef) = obj eq that + def objNeTest(obj: ObjEqLike, that: AnyRef) = obj ne that + + class A + + val a1 = new A + val a2 = new A + + expect(objEqTest(a1,a2)).toBeFalsy + expect(objEqTest(a1,a1)).toBeTruthy + + expect(objNeTest(a1,a2)).toBeTruthy + expect(objNeTest(a1,a1)).toBeFalsy + } + + it("should work on java.lang.{Float,Double}.{isNaN,isInfinite}") { + type FloatingNumberLike = Any { + def isNaN(): Boolean + def isInfinite(): Boolean + } + def test(x: FloatingNumberLike, isNaN: Boolean, + isInfinite: Boolean) = { + expect(x.isNaN()).toEqual(isNaN) + expect(x.isInfinite()).toEqual(isInfinite) + } + + test(new JFloat(Float.NaN), true, false) + test(new JFloat(Float.PositiveInfinity), false, true) + test(new JFloat(Float.NegativeInfinity), false, true) + test(new JFloat(54.67), false, false) + + test(new JDouble(Double.NaN), true, false) + test(new JDouble(Double.PositiveInfinity), false, true) + test(new JDouble(Double.NegativeInfinity), false, true) + test(new JDouble(54.67), false, false) + } + + it("should work with default arguments - #390") { + def pimpIt(a: Int) = new { + def foo(b: Int, c: Int = 1): Int = a + b + c + } + + expect(pimpIt(1).foo(2)).toEqual(4) + expect(pimpIt(2).foo(2,4)).toEqual(8) + } + + it("should unbox all types of arguments - #899") { + class Foo { + def makeInt: Int = 5 + def testInt(x: Int): Unit = expect(x).toEqual(5) + + def makeRef: Option[String] = Some("hi") + def testRef(x: Option[String]): Unit = expect(x == Some("hi")).toBeTruthy + } + + /* Note: we should also test with value classes, except that Scala itself + * does not support value classes as parameters or result type of + * methods in structural types. + */ + + def test(foo: { + def makeInt: Int + def testInt(x: Int): Unit + def makeRef: Option[String] + def testRef(x: Option[String]): Unit + }): Unit = { + foo.testInt(foo.makeInt) + foo.testRef(foo.makeRef) + } + + test(new Foo) + } + + } +} diff --git a/test-suite/src/test/scala/scala/scalajs/testsuite/compiler/RegressionTest.scala b/test-suite/src/test/scala/scala/scalajs/testsuite/compiler/RegressionTest.scala new file mode 100644 index 0000000..19cceb2 --- /dev/null +++ b/test-suite/src/test/scala/scala/scalajs/testsuite/compiler/RegressionTest.scala @@ -0,0 +1,287 @@ +/* __ *\ +** ________ ___ / / ___ __ ____ Scala.js Test Suite ** +** / __/ __// _ | / / / _ | __ / // __/ (c) 2013, LAMP/EPFL ** +** __\ \/ /__/ __ |/ /__/ __ |/_// /_\ \ http://scala-js.org/ ** +** /____/\___/_/ |_/____/_/ | |__/ /____/ ** +** |/____/ ** +\* */ +package scala.scalajs.testsuite.compiler + +import scala.annotation.tailrec + +import scala.scalajs.js +import org.scalajs.jasminetest.JasmineTest + +object RegressionTest extends JasmineTest { + + class Bug218Foo[T](val x: T) extends AnyVal + + describe("Scala.js compiler regression tests") { + + it("Wrong division conversion (7 / 2.0) - #18") { + val div = 7 / 2.0 + expect(div).toEqual(3.5) + expect(div.getClass.getName).toEqual("double") + + val mod = 7 % 2.0 + expect(mod).toEqual(1.0) + expect(mod.getClass.getName).toEqual("double") + } + + it("js.prim.String + js.prim.String is ambiguous - #20") { + val a: js.prim.String = "a" + val b: js.prim.String = "b" + val c: js.prim.String = a + b + expect(c).toEqual("ab") + } + + it("Abort with some pattern match guards - #22") { + object PatternMatchGuards { + def go(f: Int => Int) = f(1) + def main(): Unit = { + go { + case x if false => x + } + } + } + // Nothing to check + } + + it("Bad encoding for characters spanning 2 UTF-16 chars - #23") { + val str = "A∀\uD835\uDCAB" + var s: String = "" + for (c <- str) { + val code: Int = c + s = s + code + " " + } + expect(s).toEqual("65 8704 55349 56491 ") + } + + it("String concatenation with null - #26") { + val x: Object = null + expect(x + "check").toEqual("nullcheck") + } + + class Bug66A(s: String, e: Object) { + def this(e: Object) = this("", e) + def this(s: String) = this(s, "") + } + class Bug66B(s: String, e: Object) extends Bug66A(s) + + it("should emit static calls when forwarding to another constructor - #66") { + new Bug66B("", "") + } + + it("should not swallow Unit expressions when converting to js.prim.Undefined - #83") { + var effectHappened = false + def doEffect(): Unit = effectHappened = true + def f(): js.prim.Undefined = doEffect() + f() + expect(effectHappened).toBeTruthy + } + + it("should correctly call subSequence on non-string CharSequences - #55") { + val arr: CharSequence = Array('a','b','c','d') + val ss = arr.subSequence(2,3) + expect(ss.length()).toEqual(1) + expect(ss.charAt(0)).toEqual('c') + } + + it("should correctly concat primitive values to strings - #113") { + expect(4 + "foo").toEqual("4foo") + expect('a' + "foo").toEqual("afoo") + } + + it("should resolve overloads on scala.Function.apply when converting to js.Function - #125") { + class Fct extends Function1[Int,Any] { + def apply(n: Int) = n + } + + val scalaFunction = new Fct + val jsFunction: js.Any = scalaFunction + val thisFunction: js.ThisFunction = scalaFunction + } + + it("should correctly dispatch calls on private functions - #165") { + class A { + private def x = 1 + def value = x + } + class B extends A { + private def x = 2 + } + expect(new B().value).toEqual(1) + } + + it("should correctly mangle JavaScript reserved identifiers - #153") { + // Class name + class break { + // class variable + var continue = 1 + // method name + def switch = { + // local name + val default = 2 + default + } + } + trait Foo { + // static member (through mixin) + def function = 3 + } + + val x = new break with Foo + expect(x.continue).toEqual(1) + expect(x.switch).toEqual(2) + expect(x.function).toEqual(3) + } + + it("should correctly mangle identifiers starting with a digit - #153") { + // Class name + class `0` { + // class variable + var `1` = 1 + // method name + def `2` = { + // local name + val `22` = 2 + `22` + } + } + trait Foo { + // static member (through mixin) + def `3` = 3 + } + + val x = new `0` with Foo + expect(x.`1`).toEqual(1) + expect(x.`2`).toEqual(2) + expect(x.`3`).toEqual(3) + } + + it("should reserve `eval` and `arguments` - #743") { + val eval = 5 + expect(eval).toEqual(5) + val arguments = "hello" + expect(arguments).toEqual("hello") + } + + it("should support class literals for existential value types - #218") { + expect(scala.reflect.classTag[Bug218Foo[_]].toString).toEqual( + "scala.scalajs.testsuite.compiler.RegressionTest$Bug218Foo") + } + + it("should support Buffer - #268") { + val a = scala.collection.mutable.Buffer.empty[Int] + a.insert(0, 0) + a.remove(0) + for (i <- 0 to 10) { + a.insert(a.length / 2, i) + } + expect(a.mkString(", ")).toEqual("1, 3, 5, 7, 9, 10, 8, 6, 4, 2, 0") + } + + it("should not call equals when comparing with a literal null - #362") { + class A { override def equals(x: Any) = !(this == null) } + + val x = new A + val y = new A + + // If the null comparisons actually call equals, the following two will + // cause infinite recursion + expect(x == y).toBeTruthy + expect(y == x).toBeTruthy + } + + it("should unbox null to the zero of types - #674") { + class Box[A] { + var value: A = _ + } + def zero[A]: A = new Box[A].value + + /* Note: the same shape of test for Unit does not work, but it seems to + * be a problem in scalac because it does not work on the JVM either. + */ + + val bool = zero[Boolean] + expect((bool: Any).isInstanceOf[Boolean]).toBeTruthy + expect(bool == false).toBeTruthy + + val char = zero[Char] + expect((char: Any).isInstanceOf[Char]).toBeTruthy + expect(char == '\u0000').toBeTruthy + + val byte = zero[Byte] + expect((byte: Any).isInstanceOf[Byte]).toBeTruthy + expect(byte == 0.toByte).toBeTruthy + + val short = zero[Short] + expect((short: Any).isInstanceOf[Short]).toBeTruthy + expect(short == 0.toShort).toBeTruthy + + val int = zero[Int] + expect((int: Any).isInstanceOf[Int]).toBeTruthy + expect(int == 0).toBeTruthy + + val long = zero[Long] + expect((long: Any).isInstanceOf[Long]).toBeTruthy + expect(long == 0L).toBeTruthy + + val float = zero[Float] + expect((float: Any).isInstanceOf[Float]).toBeTruthy + expect(float == 0.0f).toBeTruthy + + val double = zero[Double] + expect((double: Any).isInstanceOf[Double]).toBeTruthy + expect(double == 0.0).toBeTruthy + + val ref = zero[AnyRef] + expect(ref == null).toBeTruthy + } + + it("Param defs in tailrec methods should be considered mutable - #825") { + @tailrec + def foo(x: Int, y: Int): Unit = { + if (x < y) foo(y, x) + else { + expect(x).toEqual(4) + expect(y).toEqual(2) + } + } + foo(2, 4) + } + + it("null.synchronized should throw - #874") { + expect(() => null.synchronized(5)).toThrow + } + + it("x.synchronized should preserve side-effects of x") { + var c = 0 + def x = { c += 1; this } + expect(x.synchronized(5)).toEqual(5) + expect(c).toEqual(1) + } + + it("IR checker should allow Apply/Select on NullType and NothingType - #1123") { + def giveMeANull(): Null = null + expect(() => (giveMeANull(): StringBuilder).append(5)).toThrow + expect(() => (giveMeANull(): scala.runtime.IntRef).elem).toThrow + + def giveMeANothing(): Nothing = sys.error("boom") + expect(() => (giveMeANothing(): StringBuilder).append(5)).toThrow + expect(() => (giveMeANothing(): scala.runtime.IntRef).elem).toThrow + } + + it("should not put bad flags on caseaccessor export forwarders - #1191") { + // This test used to choke patmat + + @scala.scalajs.js.annotation.JSExportAll + case class T(one: Int, two: Int) + + val T(a, b) = T(1, 2) + + expect(a).toEqual(1) + expect(b).toEqual(2) + } + } +} diff --git a/test-suite/src/test/scala/scala/scalajs/testsuite/compiler/RuntimeTypesTest.scala b/test-suite/src/test/scala/scala/scalajs/testsuite/compiler/RuntimeTypesTest.scala new file mode 100644 index 0000000..b1a32c4 --- /dev/null +++ b/test-suite/src/test/scala/scala/scalajs/testsuite/compiler/RuntimeTypesTest.scala @@ -0,0 +1,77 @@ +/* __ *\ +** ________ ___ / / ___ __ ____ Scala.js Test Suite ** +** / __/ __// _ | / / / _ | __ / // __/ (c) 2013, LAMP/EPFL ** +** __\ \/ /__/ __ |/ /__/ __ |/_// /_\ \ http://scala-js.org/ ** +** /____/\___/_/ |_/____/_/ | |__/ /____/ ** +** |/____/ ** +\* */ +package scala.scalajs.testsuite.compiler + +import scala.scalajs.js +import org.scalajs.jasminetest.JasmineTest + +import scala.util.{ Try, Failure } + +object RuntimeTypesTest extends JasmineTest { + + describe("scala.Nothing") { + + when("compliant-asinstanceof"). + it("casts to scala.Nothing should fail") { + val msg = Try("a".asInstanceOf[Nothing]) match { + case Failure(thr: ClassCastException) => thr.getMessage + case _ => "not failed" + } + expect(msg).toEqual("a is not an instance of scala.runtime.Nothing$") + } + + it("Array[Nothing] should be allowed to exists and be castable") { + val arr = Array[Nothing]() + arr.asInstanceOf[Array[Nothing]] + } + + it("Array[Array[Nothing]], too") { + val arr = Array[Array[Nothing]]() + arr.asInstanceOf[Array[Array[Nothing]]] + // This apparently works too... Dunno why + arr.asInstanceOf[Array[Nothing]] + } + + } + + describe("scala.Null") { + + when("compliant-asinstanceof"). + it("casts to scala.Null should fail for everything else but null") { + val msg = Try("a".asInstanceOf[Null]) match { + case Failure(thr: ClassCastException) => thr.getMessage + case _ => "not failed" + } + expect(msg).toEqual("a is not an instance of scala.runtime.Null$") + } + + it("classTag of scala.Null should contain proper Class[_] - #297") { + val tag = scala.reflect.classTag[Null] + expect(tag.runtimeClass != null).toBeTruthy + expect(tag.runtimeClass.getName).toEqual("scala.runtime.Null$") + } + + it("casts to scala.Null should succeed on null") { + null.asInstanceOf[Null] + } + + it("Array[Null] should be allowed to exist and be castable") { + val arr = Array.fill[Null](5)(null) + arr.asInstanceOf[Array[Null]] + } + + it("Array[Array[Null]] too") { + val arr = Array.fill[Null](5,5)(null) + arr.asInstanceOf[Array[Array[Null]]] + // This apparently works too... Dunno why + arr.asInstanceOf[Array[Null]] + } + + } + +} diff --git a/test-suite/src/test/scala/scala/scalajs/testsuite/compiler/ShortTest.scala b/test-suite/src/test/scala/scala/scalajs/testsuite/compiler/ShortTest.scala new file mode 100644 index 0000000..10746ba --- /dev/null +++ b/test-suite/src/test/scala/scala/scalajs/testsuite/compiler/ShortTest.scala @@ -0,0 +1,38 @@ +/* __ *\ +** ________ ___ / / ___ __ ____ Scala.js Test Suite ** +** / __/ __// _ | / / / _ | __ / // __/ (c) 2013, LAMP/EPFL ** +** __\ \/ /__/ __ |/ /__/ __ |/_// /_\ \ http://scala-js.org/ ** +** /____/\___/_/ |_/____/_/ | |__/ /____/ ** +** |/____/ ** +\* */ +package scala.scalajs.testsuite.compiler + +import org.scalajs.jasminetest.JasmineTest +import scala.scalajs.js + +object ShortTest extends JasmineTest { + + describe("Short primitives") { + + it("should always be in their range") { + def test(x: Int, y: Short): Unit = + expect(x.toShort).toEqual(y) + + test(0, 0) + test(-500, -500) + test(-90000, -24464) + test(123456789, -13035) + test(-40000, 25536) + test(65536, 0) + test(32768, -32768) + + def testC(x: Char, y: Short): Unit = + expect(x.toShort).toEqual(y) + + testC(-1.toChar, -1) + testC(200.toChar, 200) + testC(60000.toChar, -5536) + } + + } +} diff --git a/test-suite/src/test/scala/scala/scalajs/testsuite/compiler/UnitTest.scala b/test-suite/src/test/scala/scala/scalajs/testsuite/compiler/UnitTest.scala new file mode 100644 index 0000000..8e2be64 --- /dev/null +++ b/test-suite/src/test/scala/scala/scalajs/testsuite/compiler/UnitTest.scala @@ -0,0 +1,47 @@ +/* __ *\ +** ________ ___ / / ___ __ ____ Scala.js Test Suite ** +** / __/ __// _ | / / / _ | __ / // __/ (c) 2013, LAMP/EPFL ** +** __\ \/ /__/ __ |/ /__/ __ |/_// /_\ \ http://scala-js.org/ ** +** /____/\___/_/ |_/____/_/ | |__/ /____/ ** +** |/____/ ** +\* */ +package scala.scalajs.testsuite.compiler + +import org.scalajs.jasminetest.JasmineTest +import scala.scalajs.js + +object UnitTest extends JasmineTest { + + describe("Unit primitive") { + + it("should have toString()") { + expect(().toString()).toEqual("undefined") + expect(((): Any).toString()).toEqual("undefined") + } + + it("should have hashCode()") { + expect(().hashCode()).toEqual(0) + expect(((): Any).hashCode()).toEqual(0) + expect(().##).toEqual(0) + } + + it("should equal itself") { + expect(().equals(())).toBeTruthy + expect(((): Any).equals((): Any)).toBeTruthy + } + + it("should not equal other values") { + def testAgainst(v: Any): Unit = { + expect(().equals(v)).toBeFalsy + expect(((): Any).equals(v)).toBeFalsy + } + + testAgainst(0) + testAgainst(1) + testAgainst(null) + testAgainst(false) + testAgainst("") + } + + } +} |