diff options
Diffstat (limited to 'test-suite/src/test')
83 files changed, 14537 insertions, 0 deletions
diff --git a/test-suite/src/test/require-sam/scala/scalajs/testsuite/jsinterop/ArraySAMTest.scala b/test-suite/src/test/require-sam/scala/scalajs/testsuite/jsinterop/ArraySAMTest.scala new file mode 100644 index 0000000..534d203 --- /dev/null +++ b/test-suite/src/test/require-sam/scala/scalajs/testsuite/jsinterop/ArraySAMTest.scala @@ -0,0 +1,32 @@ +/* __ *\ +** ________ ___ / / ___ __ ____ 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 ArraySAMTest extends JasmineTest { + + import js.JSArrayOps._ + + describe("scala.scalajs.js.Array with SAM support") { + + it("should provide jsMap") { + expect(js.Array("Sc", "ala", ".", "js").jsMap(_.length)).toEqual( + js.Array(2, 3, 1, 2)) + } + + it("should provide jsFilter") { + expect(js.Array(56, 30, -20, 33, 54, 86).jsFilter(_ % 3 != 0)).toEqual( + js.Array(56, -20, 86)) + } + + } + +} diff --git a/test-suite/src/test/resources/SourceMapTestTemplate.scala b/test-suite/src/test/resources/SourceMapTestTemplate.scala new file mode 100644 index 0000000..2b135ef --- /dev/null +++ b/test-suite/src/test/resources/SourceMapTestTemplate.scala @@ -0,0 +1,655 @@ +package scala.scalajs.testsuite.compiler + +import org.scalajs.jasminetest.{JasmineTest, JasmineTestFramework} + +/** The test counter */ +private[testsuite] object TC { + var testNum: Int = _ + + def is(x: Int): Boolean = testNum == x +} + +/** Exception to test source maps. Not a ControlThrowable, because it has + * NoStackTrace which would defeat its purpose + */ +case class TestException(lineNo: Int) extends Exception + +/** + * Template to generate source-map tests, verifying that the line numbers + * reported in the source-mapped stacktraces match up with the line number + * that the error originated from. + * + * /two-star/s in this file are replaced with a code-snippet to throw + * an exception if `testNum` is set to the /two-star/'s index. The + * exception is then caught and its stacktrace checked to see + * that it reports the line number expected (stored in the error + * message). /three-star/s in are replaced with a dangling else (to + * allow throwing in expression position). + * `0/*<testCount>*/` is replaced by the number of /n-star/s in the + * file. + */ +object SourceMapTest extends JasmineTest { + + val testCount: Int = 0/*<testCount>*/ + + if (JasmineTestFramework.hasTag("nodejs")) { + scalajs.js.Dynamic.global.require("source-map-support").install() + } + + when("source-maps"). + describe("Source Maps") { + + for (i <- 0 until testCount) { + it(s"work (test $i)") { + TC.testNum = i + + try { + run() + sys.error("No exception thrown") + } catch { + case e @ TestException(lineNo) => + val trace0 = e.getStackTrace.toList + val trace1 = trace0.dropWhile( + _.getFileName.endsWith("/scala/scalajs/runtime/StackTrace.scala")) + val trace2 = trace1.dropWhile( + _.getFileName.endsWith("/java/lang/Throwables.scala")) + + val exSte :: throwSte :: _ = trace2 + + expect(exSte.getFileName).toContain("/SourceMapTest.scala") + // line where `case class TestException is written` above + expect(exSte.getLineNumber).toBe(15) + + expect(throwSte.getFileName).toContain("/SourceMapTest.scala") + expect(throwSte.getLineNumber).toBe(lineNo) + } + } + } + } + + def get(json: JsValue, index: Int) = { + /**/ + /**/json.asInstanceOf[JsArray].value(index).value + } + + def get(json: JsValue, index: Int, fieldName: String) = { + /**/ + /**//***/json.asInstanceOf[JsArray].value(index).asInstanceOf[JsObject].value(fieldName).value + } + def run() = { + /**/ + /**/val ugly = + """ + |[ + | "JSON Test Pattern pass1", + | {"object with 1 member":["array with 1 element"]}, + | {}, + | [], + | -42, + | true, + | false, + | null, + | { + | "integer": 1234567890, + | "real": -9876.543210, + | "e": 0.123456789e-12, + | "E": 1.234567890E+34, + | "": 23456789012E66, + | "zero": 0, + | "one": 1, + | "space": " ", + | "quote": "\"", + | "backslash": "\\", + | "controls": "\b\f\n\r\t", + | "slash": "/ & \/", + | "alpha": "abcdefghijklmnopqrstuvwyz", + | "ALPHA": "ABCDEFGHIJKLMNOPQRSTUVWYZ", + | "digit": "0123456789", + | "0123456789": "digit", + | "special": "`1~!@#$%^&*()_+-={':[,]}|;.</>?", + | "hex": "\u0123\u4567\u89AB\uCDEF\uabcd\uef4A", + | "true": true, + | "false": false, + | "null": null, + | "array":[ ], + | "object":{ }, + | "address": "50 St. James Street", + | "url": "http://www.JSON.org/", + | "comment": "// /* <!-- --", + | "# -- --> */": " ", + | " s p a c e d " :[1,2 , 3 + | + |, + | + |4 , 5 , 6 ,7 ],"compact":[1,2,3,4,5,6,7], + | "jsontext": "{\"object with 1 member\":[\"array with 1 element\"]}", + | "quotes": "" \u005Cu0022 %22 0x22 034 "", + | "\/\\\"\uCAFE\uBABE\uAB98\uFCDE\ubcda\uef4A\b\f\n\r\t`1~!@#$%^&*()_+-=[]{}|;:',./<>?" + |: "A key can be any string" + | }, + | 0.5 ,98.6 + |, + |99.44 + |, + | + |1066, + |1e1, + |0.1e1, + |1e-1, + |1e00,2e+00,2e-00 + |,"rosebud"] + """.stripMargin/**/ + /**/val json = new Json()/**/ + /**/val parsed = json.read(ugly)/**/ + /**/ + /**/val unparsed = json.write(parsed)/**/ + /**/val reparsed = json.read(unparsed)/**/ + + for (json <- Seq(parsed, reparsed)){/**/ + assert(get(json, 0) == "JSON Test Pattern pass1") + /**/ + assert(get(json, 5) == true) + assert(get(json, 6) == false) + assert(get(json, 8, "real") == "-9876.543210")/**/ + /**/assert(get(json, 8, "comment") == "// /* <!-- --") + assert(get(json, 8, "jsontext") == "{\"object with 1 member\":[\"array with 1 element\"]}") + assert(get(json, 19) == "rosebud")/**/ + } + /**/ + } +} + + + +sealed trait JsValue { + def value: Any +} + +case class JsString(value: java.lang.String) extends JsValue + +case class JsObject(value: Map[String, JsValue]) extends JsValue + +case class JsArray(value: Seq[JsValue]) extends JsValue + +case class JsNumber(value: java.lang.String) extends JsValue + +sealed trait JsBoolean extends JsValue { + def value: Boolean +} + +case object JsFalse extends JsBoolean { + def value = {/**/false} +} + +case object JsTrue extends JsBoolean { + def value = {/**/true} +} + +case object JsNull extends JsValue { + def value = {null} +} + +trait Writer{ + /**/ + def writeToBuffer(v: JsValue, sb: StringBuffer): Unit = v match { + case JsString(s) => + /**/sb.append('"')/**/ + /**/var i = 0/**/ + while(i < s.length){/**/ + /**/s.charAt(i) match { + case '\\' => /**/sb.append("\\\\")/**/ + case '"' => sb.append("\\\"") + case '/' => /**/sb.append("\\/")/**/ + case '\b' => sb.append("\\b") + case '\t' => sb.append("\\t") + case '\n' => /**/sb.append("\\n")/**/ + case '\f' => sb.append("\\f") + case '\r' => sb.append("\\r") + case c => + if (c < ' '){ + val t = "000" + Integer.toHexString(c) + sb.append("\\u" + t.takeRight(4)) + }else{ + sb.append(c.toString) + } + } + i += 1 + } + /**/ + sb.append('"') + /**/ + case JsObject(kvs) => + /**/ + sb.append("{") + /**/ + var first = true + kvs.foreach(kv => { + /**/ + val (k, v) = kv + if (first) + first = false + else + sb.append(", ") + + /**/ + writeToBuffer(JsString(k), sb) + sb.append(": ") + /**/ + writeToBuffer(v, sb) + }) + sb.append("}") + + case JsArray(vs) => /**/ + sb.append("[") + if (vs.length > 0) writeToBuffer(vs(0), sb) + var i = 1 + while(i < vs.length){ + sb.append(", ") + writeToBuffer(vs(i), sb) + i += 1 + } + sb.append("]") + case JsNumber(d) => sb.append(d) + case JsFalse => sb.append("false") + case JsTrue => sb.append("true") + case JsNull => sb.append("null") + } + /**/ +} +class Writer2 extends Writer{ + /**/ + def write(v: JsValue): String = { + /**/ + val sb = new StringBuffer() + writeToBuffer(v, sb) + sb.toString + } + /**/ +} +class Json extends Writer2{ + + /** + * Self-contained JSON parser adapted from + * + * https://github.com/nestorpersist/json + */ + def read(s: String): JsValue = { + + // *** Character Kinds + /**/ + type CharKind = Int + val Letter = 0 + val Digit = 1 + val Minus = 2 + val Quote = 3 + val Colon = 4 + val Comma = 5 + val Lbra = 6 + val Rbra = 7 + val Larr = 8 + val Rarr = 9 + val Blank = 10 + val Other = 11 + val Eof = 12 + val Slash = 13 + + // *** Token Kinds + + type TokenKind = Int + val ID = 0 + val STRING = 1 + val NUMBER = 2 + val BIGNUMBER = 3 + val FLOATNUMBER = 4 + val COLON = 5 + val COMMA = 6 + val LOBJ = 7 + val ROBJ = 8 + val LARR = 9 + val RARR = 10 + val BLANK = 11 + val EOF = 12 + /**/ + // *** Character => CharKind Map *** + + val charKind = (0 to 255).toArray.map { + case c if 'a'.toInt <= c && c <= 'z'.toInt => Letter + case c if 'A'.toInt <= c && c <= 'Z'.toInt => Letter + case c if '0'.toInt <= c && c <= '9'.toInt => Digit + case '-' => /**/Minus + case ',' => /**/Comma + case '"' => /**/Quote + case ':' => /**/Colon + case '{' => /**/Lbra + case '}' => Rbra + case '[' => Larr + case ']' => Rarr + case ' ' => Blank + case '\t' => Blank + case '\n' => Blank + case '\r' => Blank + case '/' => Slash + case _ => Other + } + + // *** Character Escapes + /**/ + val escapeMap = Map[Int, String]( + '\\'.toInt -> "\\", + '/'.toInt -> "/", + '\"'.toInt -> "\"", + 'b'.toInt -> "\b", + 'f'.toInt -> "\f", + 'n'.toInt -> "\n", + 'r'.toInt -> "\r", + 't'.toInt -> "\t" + ) + // *** Import Shared Data *** + + // *** INPUT STRING *** + + // array faster than accessing string directly using charAt + //final val s1 = s.toCharArray() + val size = s.size + + // *** CHARACTERS *** + + var pos = 0 + + var ch: Int = 0 + var chKind: CharKind = 0 + var chLinePos: Int = 0 + var chCharPos: Int = 0 + + def chNext() = {/**/ + if (pos < size) {/**/ + //ch = s1(pos).toInt + /**/ch = s.charAt(pos)/**/ + /**/chKind = /***/if (ch < 255) {/**/ + /**//***/charKind(ch) + } else {/**/ + /**//***/Other + }/**/ + pos += 1 + if (ch == '\n'.toInt) { + chLinePos += 1 + chCharPos = 1 + } else {/**/ + chCharPos += 1/**/ + } + } else { + ch = -1 + pos = size + 1 + chKind = Eof + } + }/**/ + /**/ + /**/ + /**/def chError(msg: String): Nothing = { + throw new Json.Exception(msg, s, chLinePos, chCharPos) + } + + def chMark = pos - 1 + + def chSubstr(first: Int, delta: Int = 0) = { + s.substring(first, pos - 1 - delta) + } + + // *** LEXER *** + + var tokenKind = BLANK + var tokenValue = "" + var linePos = 1 + var charPos = 1 + + def getDigits() = { + while (chKind == Digit) chNext() + } + + def handleDigit() { + val first = chMark + getDigits() + val k1 = if (ch == '.'.toInt) { + chNext() + getDigits() + BIGNUMBER + } else { + NUMBER + } + val k2 = if (ch == 'E'.toInt || ch == 'e'.toInt) { + chNext() + if (ch == '+'.toInt) { + chNext() + } else if (ch == '-'.toInt) { + chNext() + } + getDigits() + FLOATNUMBER + } else { + k1 + } + /**/tokenKind = k2/**/ + /**/tokenValue = chSubstr(first)/**/ + /**/}/**/ + /**/ + def handleRaw() { + chNext() + val first = chMark + var state = 0 + do { + if (chKind == Eof) chError("EOF encountered in raw string") + state = (ch, state) match { + case ('}', _) => 1 + case ('"', 1) => 2 + case ('"', 2) => 3 + case ('"', 3) => 0 + case _ => 0 + } + + chNext() + } while (state != 3) + tokenKind = STRING + tokenValue = chSubstr(first, 3) + } + + def handle(i: Int) = { + chNext() + tokenKind = i + tokenValue = "" + } + + def tokenNext() { + do { + linePos = chLinePos + charPos = chCharPos + val kind: Int = chKind + kind match { + case Letter => + val first = chMark + while (chKind == Letter || chKind == Digit) { + chNext() + } + tokenKind = ID + tokenValue = chSubstr(first) + + case Digit => handleDigit() + case Minus => + chNext() + handleDigit() + tokenValue = "-" + tokenValue + + case Quote => + val sb = new StringBuilder(50) + chNext() + var first = chMark + while (ch != '"'.toInt && ch >= 32) { + if (ch == '\\'.toInt) { + sb.append(chSubstr(first)) + chNext() + escapeMap.get(ch) match { + case Some(s) => + sb.append(s) + chNext() + + case None => + if (ch != 'u'.toInt) chError("Illegal escape") + chNext() + var code = 0 + for (i <- 1 to 4) { + val ch1 = ch.toChar.toString + val i = "0123456789abcdef".indexOf(ch1.toLowerCase) + if (i == -1) chError("Illegal hex character") + code = code * 16 + i + chNext() + } + sb.append(code.toChar.toString) + } + first = chMark + } else { + chNext() + } + } + if (ch != '"') chError("Unexpected string character: " + ch.toChar) + + sb.append(chSubstr(first)) + + tokenKind = STRING + + tokenValue = sb.toString() + chNext() + if (tokenValue.length() == 0 && ch == '{') { + handleRaw() + } + + case Colon => handle(COLON)/**/ + case Comma => handle(COMMA)/**/ + case Lbra => handle(LOBJ)/**/ + case Rbra => handle(ROBJ)/**/ + case Larr => handle(LARR)/**/ + case Rarr => handle(RARR)/**/ + case Blank => + do chNext() while (chKind == Blank) + tokenKind = BLANK + tokenValue = "" + + case Other => chError("Unexpected character: " + ch.toChar + " " + ch) + case Eof => + chNext() + tokenKind = EOF + tokenValue = "" + + case Slash => + if (chKind != Slash) chError("Expecting Slash") + do chNext() while (ch != '\n' && chKind != Eof) + tokenKind = BLANK + tokenValue = "" + + } + } while (tokenKind == BLANK) + } + /**/ + def tokenError(msg: String): Nothing = { + throw new Json.Exception(msg, s, linePos, charPos) + } + /**/ + // *** PARSER *** + + def handleEof() = tokenError("Unexpected eof") + def handleUnexpected(i: String) = tokenError(s"Unexpected input: [$i]") + + def handleArray(): JsArray = { + tokenNext() + var result = List.empty[JsValue] + while (tokenKind != RARR) {/**/ + result = getJson() :: result + /**/tokenKind match{ + case COMMA => /**/tokenNext() + case RARR => // do nothing + case _ => tokenError("Expecting , or ]") + } + } + tokenNext() + JsArray(result.reverse) + } + + def handleObject(): JsObject = { + tokenNext() + var result = List.empty[(String, JsValue)] + /**/ + while (tokenKind != ROBJ) { + if (tokenKind != STRING && tokenKind != ID) tokenError("Expecting string or name") + val name = tokenValue + tokenNext() + if (tokenKind != COLON) tokenError("Expecting :") + tokenNext() + result = (name -> getJson()) :: result + tokenKind match{ + case COMMA => tokenNext() + case ROBJ => // do nothing + case _ => tokenError("Expecting , or }") + } + } + tokenNext() + JsObject(result.toMap) + } + def handleNumber(name: String, f: String => Unit) = { + try { + f(tokenValue) + } catch { + case _: Throwable => tokenError("Bad " + name) + } + val old = tokenValue + tokenNext() + + JsNumber(old) + } + def getJson(): JsValue = { + val kind: Int = tokenKind + val result: JsValue = kind match { + case ID => + val result: JsValue = tokenValue match { + case "true" => JsTrue + case "false" => JsFalse + case "null" => JsNull + case _ => tokenError("Not true, false, or null") + } + + tokenNext() + result + + case STRING => + val result = tokenValue + tokenNext() + JsString(result) + + case NUMBER => handleNumber("NUMBER", _.toLong) + case BIGNUMBER => handleNumber("BIGNUMBER", _.toDouble) + case FLOATNUMBER => handleNumber("FLOATNUMBER", _.toDouble) + case COLON => handleUnexpected(":") + case COMMA => handleUnexpected(",") + case LOBJ => handleObject() + case ROBJ => handleUnexpected("}") + case LARR => handleArray() + case RARR => handleUnexpected("]") + case EOF => handleEof() + } + result + } + def parse(): JsValue = { + chNext() + tokenNext() + val result = getJson + if (tokenKind != EOF) tokenError("Excess input") + result + } + parse() + } +} + +object Json { + class Exception(val msg: String, + val input: String, + val line: Int, + val char: Int) + extends scala.Exception(s"JsonParse Error: $msg line $line [$char] in $input") +} 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("") + } + + } +} diff --git a/test-suite/src/test/scala/scala/scalajs/testsuite/javalib/ArraysTest.scala b/test-suite/src/test/scala/scala/scalajs/testsuite/javalib/ArraysTest.scala new file mode 100644 index 0000000..d0d97f1 --- /dev/null +++ b/test-suite/src/test/scala/scala/scalajs/testsuite/javalib/ArraysTest.scala @@ -0,0 +1,749 @@ +/* __ *\ +** ________ ___ / / ___ __ ____ Scala.js Test Suite ** +** / __/ __// _ | / / / _ | __ / // __/ (c) 2013, LAMP/EPFL ** +** __\ \/ /__/ __ |/ /__/ __ |/_// /_\ \ http://scala-js.org/ ** +** /____/\___/_/ |_/____/_/ | |__/ /____/ ** +** |/____/ ** +\* */ +package scala.scalajs.testsuite.javalib + +import language.implicitConversions + +import scala.scalajs.js +import scala.scalajs.js.JSConverters._ + +import org.scalajs.jasminetest.JasmineTest + +import java.util.{ Arrays, Comparator } + +import scala.reflect.ClassTag + +object ArraysTest extends ArraysTest + +/** This is also used in the typedarray package to test scala.Arrays backed + * by TypedArrays + */ +trait ArraysTest extends JasmineTest { + + // Just in here, we allow ourselves to do this + implicit def array2jsArray[T](arr: Array[T]): js.Array[T] = arr.toJSArray + + /** Overridden by typedarray tests */ + def Array[T : ClassTag](v: T*): scala.Array[T] = scala.Array(v: _*) + + /** Overridden by typedarray tests */ + def testBody(suite: => Unit) = describe("java.util.Arrays")(suite) + + val stringComparator = new Comparator[String]() { + def compare(s1: String, s2: String) = s1.compareTo(s2) + } + + val intComparator = new Comparator[Int]() { + def compare(i1: Int, i2: Int) = i1 - i2 + } + + testBody { + + it("should respond to `sort` for Int") { + val scalaInts = Array(5, 3, 6, 1, 2, 4) + val ints = new Array[Object](scalaInts.length) + for (i <- 0 until scalaInts.length) + ints(i) = scalaInts(i).asInstanceOf[Object] + val sorted = Array(1, 2, 3, 4, 5, 6) + + Arrays.sort(ints, intComparator.asInstanceOf[Comparator[Object]]) + expect(ints).toEqual(Array(1, 2, 3, 4, 5, 6)) + } + + it("should respond to `sort` for String") { + val scalajs: Array[Object] = Array("S", "c", "a", "l", "a", ".", "j", "s") + val sorted = Array(".", "S", "a", "a", "c", "j", "l", "s") + + Arrays.sort(scalajs, stringComparator.asInstanceOf[Comparator[Object]]) + expect(scalajs).toEqual(sorted) + } + + it("should respond to `fill` for Boolean") { + val booleans = new Array[Boolean](6) + Arrays.fill(booleans, false) + expect(booleans).toEqual(Array(false, false, false, false, false, false)) + + Arrays.fill(booleans, true) + expect(booleans).toEqual(Array(true, true, true, true, true, true)) + } + + it("should respond to `fill` with start and end index for Boolean") { + val booleans = new Array[Boolean](6) + Arrays.fill(booleans, 1, 4, true) + expect(booleans).toEqual(Array(false, true, true, true, false, false)) + } + + it("should respond to `fill` for Byte") { + val bytes = new Array[Byte](6) + Arrays.fill(bytes, 42.toByte) + expect(bytes).toEqual(Array[Byte](42, 42, 42, 42, 42, 42)) + + Arrays.fill(bytes, -1.toByte) + expect(bytes).toEqual(Array[Byte](-1, -1, -1, -1, -1, -1)) + } + + it("should respond to `fill` with start and end index for Byte") { + val bytes = new Array[Byte](6) + Arrays.fill(bytes, 1, 4, 42.toByte) + expect(bytes).toEqual(Array[Byte](0, 42, 42, 42, 0, 0)) + + Arrays.fill(bytes, 2, 5, -1.toByte) + expect(bytes).toEqual(Array[Byte](0, 42, -1, -1, -1, 0)) + } + + it("should respond to `fill` for Short") { + val shorts = new Array[Short](6) + Arrays.fill(shorts, 42.toShort) + expect(shorts).toEqual(Array[Short](42, 42, 42, 42, 42, 42)) + + Arrays.fill(shorts, -1.toShort) + expect(shorts).toEqual(Array[Short](-1, -1, -1, -1, -1, -1)) + } + + it("should respond to `fill` with start and end index for Short") { + val shorts = new Array[Short](6) + Arrays.fill(shorts, 1, 4, 42.toShort) + expect(shorts).toEqual(Array[Short](0, 42, 42, 42, 0, 0)) + + Arrays.fill(shorts, 2, 5, -1.toShort) + expect(shorts).toEqual(Array[Short](0, 42, -1, -1, -1, 0)) + } + + it("should respond to `fill` for Int") { + val ints = new Array[Int](6) + Arrays.fill(ints, 42) + expect(ints).toEqual(Array(42, 42, 42, 42, 42, 42)) + + Arrays.fill(ints, -1) + expect(ints).toEqual(Array(-1, -1, -1, -1, -1, -1)) + } + + it("should respond to `fill` with start and end index for Int") { + val ints = new Array[Int](6) + Arrays.fill(ints, 1, 4, 42) + expect(ints).toEqual(Array(0, 42, 42, 42, 0, 0)) + + Arrays.fill(ints, 2, 5, -1) + expect(ints).toEqual(Array(0, 42, -1, -1, -1, 0)) + } + + it("should respond to `fill` for Long") { + val longs = new Array[Long](6) + Arrays.fill(longs, 42L) + expect(longs).toEqual(Array(42L, 42L, 42L, 42L, 42L, 42L)) + + Arrays.fill(longs, -1L) + expect(longs).toEqual(Array(-1L, -1L, -1L, -1L, -1L, -1L)) + } + + it("should respond to `fill` with start and end index for Long") { + val longs = new Array[Long](6) + Arrays.fill(longs, 1, 4, 42L) + expect(longs).toEqual(Array(0L, 42L, 42L, 42L, 0L, 0L)) + + Arrays.fill(longs, 2, 5, -1L) + expect(longs).toEqual(Array(0L, 42L, -1L, -1L, -1L, 0L)) + } + + it("should respond to `fill` for Float") { + val floats = new Array[Float](6) + Arrays.fill(floats, 42.0f) + expect(floats).toEqual(Array(42.0f, 42.0f, 42.0f, 42.0f, 42.0f, 42.0f)) + + Arrays.fill(floats, -1.0f) + expect(floats).toEqual(Array(-1.0f, -1.0f, -1.0f, -1.0f, -1.0f, -1.0f)) + } + + it("should respond to `fill` with start and end index for Float") { + val floats = new Array[Float](6) + Arrays.fill(floats, 1, 4, 42.0f) + expect(floats).toEqual(Array(0.0f, 42.0f, 42.0f, 42.0f, 0.0f, 0.0f)) + + Arrays.fill(floats, 2, 5, -1.0f) + expect(floats).toEqual(Array(0.0f, 42.0f, -1.0f, -1.0f, -1.0f, 0.0f)) + } + + it("should respond to `fill` for Double") { + val doubles = new Array[Double](6) + Arrays.fill(doubles, 42.0) + expect(doubles).toEqual(Array(42.0, 42.0, 42.0, 42.0, 42.0, 42.0)) + + Arrays.fill(doubles, -1.0f) + expect(doubles).toEqual(Array(-1.0, -1.0, -1.0, -1.0, -1.0, -1.0)) + } + + it("should respond to `fill` with start and end index for Double") { + val doubles = new Array[Double](6) + Arrays.fill(doubles, 1, 4, 42.0) + expect(doubles).toEqual(Array(0.0, 42.0, 42.0, 42.0, 0.0, 0.0)) + + Arrays.fill(doubles, 2, 5, -1.0) + expect(doubles).toEqual(Array(0.0, 42.0, -1.0, -1.0, -1.0, 0.0)) + } + + it("should respond to `fill` for AnyRef") { + val array = new Array[AnyRef](6) + Arrays.fill(array, "a") + expect(array).toEqual(Array[AnyRef]("a", "a", "a", "a", "a", "a")) + + Arrays.fill(array, "b") + expect(array).toEqual(Array[AnyRef]("b", "b", "b", "b", "b", "b")) + } + + it("should respond to `fill` with start and end index for AnyRef") { + val bytes = new Array[AnyRef](6) + Arrays.fill(bytes, 1, 4, "a") + expect(bytes).toEqual(Array[AnyRef](null, "a", "a", "a", null, null)) + + Arrays.fill(bytes, 2, 5, "b") + expect(bytes).toEqual(Array[AnyRef](null, "a", "b", "b", "b", null)) + } + + it("should respond to `binarySearch` with start index, end index and key for Long") { + val longs: Array[Long] = Array(1, 2, 3, 5, 6, 7) + var ret = Arrays.binarySearch(longs, 0, 6, 5) + expect(ret).toEqual(3) + + ret = Arrays.binarySearch(longs, 0, 6, 0) + expect(ret).toEqual(-1) + + ret = Arrays.binarySearch(longs, 0, 6, 4) + expect(ret).toEqual(-4) + + ret = Arrays.binarySearch(longs, 0, 6, 8) + expect(ret).toEqual(-7) + } + + it("should respond to `binarySearch` with key for Long") { + val longs: Array[Long] = Array(1, 2, 3, 5, 6, 7) + var ret = Arrays.binarySearch(longs, 5) + expect(ret).toEqual(3) + + ret = Arrays.binarySearch(longs, 0) + expect(ret).toEqual(-1) + + ret = Arrays.binarySearch(longs, 4) + expect(ret).toEqual(-4) + + ret = Arrays.binarySearch(longs, 8) + expect(ret).toEqual(-7) + } + + it("should respond to `binarySearch` with start index, end index and key for Int") { + val ints: Array[Int] = Array(1, 2, 3, 5, 6, 7) + var ret = Arrays.binarySearch(ints, 0, 6, 5) + expect(ret).toEqual(3) + + ret = Arrays.binarySearch(ints, 0, 6, 0) + expect(ret).toEqual(-1) + + ret = Arrays.binarySearch(ints, 0, 6, 4) + expect(ret).toEqual(-4) + + ret = Arrays.binarySearch(ints, 0, 6, 8) + expect(ret).toEqual(-7) + } + + it("should respond to `binarySearch` with key for Int") { + val ints: Array[Int] = Array(1, 2, 3, 5, 6, 7) + var ret = Arrays.binarySearch(ints, 5) + expect(ret).toEqual(3) + + ret = Arrays.binarySearch(ints, 0) + expect(ret).toEqual(-1) + + ret = Arrays.binarySearch(ints, 4) + expect(ret).toEqual(-4) + + ret = Arrays.binarySearch(ints, 8) + expect(ret).toEqual(-7) + } + + it("should respond to `binarySearch` with start index, end index and key for Short") { + val shorts: Array[Short] = Array(1, 2, 3, 5, 6, 7) + var ret = Arrays.binarySearch(shorts, 0, 6, 5.toShort) + expect(ret).toEqual(3) + + ret = Arrays.binarySearch(shorts, 0, 6, 0.toShort) + expect(ret).toEqual(-1) + + ret = Arrays.binarySearch(shorts, 0, 6, 4.toShort) + expect(ret).toEqual(-4) + + ret = Arrays.binarySearch(shorts, 0, 6, 8.toShort) + expect(ret).toEqual(-7) + } + + it("should respond to `binarySearch` with key for Short") { + val shorts: Array[Short] = Array(1, 2, 3, 5, 6, 7) + var ret = Arrays.binarySearch(shorts, 5.toShort) + expect(ret).toEqual(3) + + ret = Arrays.binarySearch(shorts, 0.toShort) + expect(ret).toEqual(-1) + + ret = Arrays.binarySearch(shorts, 4.toShort) + expect(ret).toEqual(-4) + + ret = Arrays.binarySearch(shorts, 8.toShort) + expect(ret).toEqual(-7) + } + + it("should respond to `binarySearch` with start index, end index and key for Char") { + val chars: Array[Char] = Array('b', 'c', 'd', 'f', 'g', 'h') + var ret = Arrays.binarySearch(chars, 0, 6, 'f') + expect(ret).toEqual(3) + + ret = Arrays.binarySearch(chars, 0, 6, 'a') + expect(ret).toEqual(-1) + + ret = Arrays.binarySearch(chars, 0, 6, 'e') + expect(ret).toEqual(-4) + + ret = Arrays.binarySearch(chars, 0, 6, 'i') + expect(ret).toEqual(-7) + } + + it("should respond to `binarySearch` with key for Char") { + val chars: Array[Char] = Array('b', 'c', 'd', 'f', 'g', 'h') + var ret = Arrays.binarySearch(chars, 'f') + expect(ret).toEqual(3) + + ret = Arrays.binarySearch(chars, 'a') + expect(ret).toEqual(-1) + + ret = Arrays.binarySearch(chars, 'e') + expect(ret).toEqual(-4) + + ret = Arrays.binarySearch(chars, 'i') + expect(ret).toEqual(-7) + } + + it("should respond to `binarySearch` with start index, end index and key for Double") { + val doubles: Array[Double] = Array(0.1, 0.2, 0.3, 0.5, 0.6, 0.7) + var ret = Arrays.binarySearch(doubles, 0, 6, 0.5) + expect(ret).toEqual(3) + + ret = Arrays.binarySearch(doubles, 0, 6, 0.0) + expect(ret).toEqual(-1) + + ret = Arrays.binarySearch(doubles, 0, 6, 0.4) + expect(ret).toEqual(-4) + + ret = Arrays.binarySearch(doubles, 0, 6, 0.8) + expect(ret).toEqual(-7) + } + + it("should respond to `binarySearch` with key for Double") { + val doubles: Array[Double] = Array(0.1, 0.2, 0.3, 0.5, 0.6, 0.7) + var ret = Arrays.binarySearch(doubles, 0.5) + expect(ret).toEqual(3) + + ret = Arrays.binarySearch(doubles, 0.0) + expect(ret).toEqual(-1) + + ret = Arrays.binarySearch(doubles, 0.4) + expect(ret).toEqual(-4) + + ret = Arrays.binarySearch(doubles, 0.8) + expect(ret).toEqual(-7) + } + + it("should respond to `binarySearch` with start index, end index and key for Float") { + val floats: Array[Float] = Array(0.1f, 0.2f, 0.3f, 0.5f, 0.6f, 0.7f) + var ret = Arrays.binarySearch(floats, 0, 6, 0.5f) + expect(ret).toEqual(3) + + ret = Arrays.binarySearch(floats, 0, 6, 0.0f) + expect(ret).toEqual(-1) + + ret = Arrays.binarySearch(floats, 0, 6, 0.4f) + expect(ret).toEqual(-4) + + ret = Arrays.binarySearch(floats, 0, 6, 0.8f) + expect(ret).toEqual(-7) + } + + it("should respond to `binarySearch` with key for Float") { + val floats: Array[Float] = Array(0.1f, 0.2f, 0.3f, 0.5f, 0.6f, 0.7f) + var ret = Arrays.binarySearch(floats, 0.5f) + expect(ret).toEqual(3) + + ret = Arrays.binarySearch(floats, 0.0f) + expect(ret).toEqual(-1) + + ret = Arrays.binarySearch(floats, 0.4f) + expect(ret).toEqual(-4) + + ret = Arrays.binarySearch(floats, 0.8f) + expect(ret).toEqual(-7) + } + + it("should respond to `binarySearch` with start index, end index and key for AnyRef") { + val strings: Array[AnyRef] = Array("aa", "abc", "cc", "zz", "zzzs", "zzzt") + var ret = Arrays.binarySearch(strings, 0, 6, "zz") + expect(ret).toEqual(3) + + ret = Arrays.binarySearch(strings, 0, 6, "a") + expect(ret).toEqual(-1) + + ret = Arrays.binarySearch(strings, 0, 6, "cd") + expect(ret).toEqual(-4) + + ret = Arrays.binarySearch(strings, 0, 6, "zzzz") + expect(ret).toEqual(-7) + } + + it("should respond to `binarySearch` with key for AnyRef") { + val strings: Array[AnyRef] = Array("aa", "abc", "cc", "zz", "zzzs", "zzzt") + var ret = Arrays.binarySearch(strings, "zz") + expect(ret).toEqual(3) + + ret = Arrays.binarySearch(strings, "a") + expect(ret).toEqual(-1) + + ret = Arrays.binarySearch(strings, "cd") + expect(ret).toEqual(-4) + + ret = Arrays.binarySearch(strings, "zzzz") + expect(ret).toEqual(-7) + } + + it("should check ranges of input to `binarySearch`") { + def expectException(block: => Unit)(expected: PartialFunction[Throwable, Unit]): Unit = { + val catchAll: PartialFunction[Throwable, Unit] = { + case e: Throwable => expect(e.getClass.getName).toBe("not thrown") + } + + try { + block + expect("exception").toBe("thrown") + } catch expected orElse catchAll + } + + val array = Array(0, 1, 3, 4) + + expectException({ Arrays.binarySearch(array, 3, 2, 2) }) { + case exception: IllegalArgumentException => + expect(exception.getMessage).toBe("fromIndex(3) > toIndex(2)") + } + + // start/end comparison is made before index ranges checks + expectException({ Arrays.binarySearch(array, 7, 5, 2) }) { + case exception: IllegalArgumentException => + expect(exception.getMessage).toBe("fromIndex(7) > toIndex(5)") + } + + expectException({ Arrays.binarySearch(array, -1, 4, 2) }) { + case exception: ArrayIndexOutOfBoundsException => + expect(exception.getMessage).toBe("Array index out of range: -1") + } + + expectException({ Arrays.binarySearch(array, 0, 5, 2) }) { + case exception: ArrayIndexOutOfBoundsException => + expect(exception.getMessage).toBe("Array index out of range: 5") + } + } + + it("should respond to `copyOf` with key for Int") { + val ints: Array[Int] = Array(1, 2, 3) + val intscopy = Arrays.copyOf(ints, 5) + expect(intscopy).toEqual(Array(1, 2, 3, 0, 0)) + } + + it("should respond to `copyOf` with key for Long") { + val longs: Array[Long] = Array(1, 2, 3) + val longscopy = Arrays.copyOf(longs, 5) + expect(longscopy).toEqual(Array[Long](1, 2, 3, 0, 0)) + } + + it("should respond to `copyOf` with key for Short") { + val shorts: Array[Short] = Array(1, 2, 3) + val shortscopy = Arrays.copyOf(shorts, 5) + expect(shortscopy).toEqual(Array[Short](1, 2, 3, 0, 0)) + } + + it("should respond to `copyOf` with key for Byte") { + val bytes: Array[Byte] = Array(42, 43, 44) + val floatscopy = Arrays.copyOf(bytes, 5) + expect(floatscopy).toEqual(Array[Byte](42, 43, 44, 0, 0)) + } + + it("should respond to `copyOf` with key for Char") { + val chars: Array[Char] = Array('a', 'b', '0') + val charscopy = Arrays.copyOf(chars, 5) + expect(charscopy(4)).toEqual(0.toChar) + } + + it("should respond to `copyOf` with key for Double") { + val doubles: Array[Double] = Array(0.1, 0.2, 0.3) + val doublescopy = Arrays.copyOf(doubles, 5) + expect(doublescopy).toEqual(Array[Double](0.1, 0.2, 0.3, 0, 0)) + } + + it("should respond to `copyOf` with key for Float") { + val floats: Array[Float] = Array(0.1f, 0.2f, 0.3f) + val floatscopy = Arrays.copyOf(floats, 5) + expect(floatscopy).toEqual(Array[Float](0.1f, 0.2f, 0.3f, 0f, 0f)) + } + + it("should respond to `copyOf` with key for Boolean") { + val bools: Array[Boolean] = Array(false, true, false) + val boolscopy = Arrays.copyOf(bools, 5) + expect(boolscopy).toEqual(Array[Boolean](false, true, false, false, false)) + } + + it("should respond to `copyOf` with key for AnyRef") { + val anyrefs: Array[AnyRef] = Array("a", "b", "c") + val anyrefscopy = Arrays.copyOf(anyrefs, 5) + expect(anyrefscopy.getClass() == classOf[Array[AnyRef]]).toBeTruthy + expect(anyrefscopy).toEqual(Array[AnyRef]("a", "b", "c", null, null)) + + val sequences: Array[CharSequence] = Array("a", "b", "c") + val sequencescopy = Arrays.copyOf(sequences, 2) + expect(sequencescopy.getClass() == classOf[Array[CharSequence]]) + expect(sequencescopy).toEqual(Array[CharSequence]("a", "b")) + } + + it("should respond to `copyOfRange` for AnyRef") { + val anyrefs: Array[AnyRef] = Array("a", "b", "c", "d", "e") + val anyrefscopy = Arrays.copyOfRange(anyrefs, 2, 4) + expect(anyrefscopy.getClass() == classOf[Array[AnyRef]]).toBeTruthy + expect(anyrefscopy).toEqual(Array[AnyRef]("c", "d")) + + val sequences: Array[CharSequence] = Array("a", "b", "c", "d", "e") + val sequencescopy = Arrays.copyOfRange(sequences, 1, 5) + expect(sequencescopy.getClass() == classOf[Array[CharSequence]]) + expect(sequencescopy).toEqual(Array[CharSequence]("b", "c", "d", "e")) + } + + it("should respond to `hashCode` for Boolean") { + expect(Arrays.hashCode(null: Array[Boolean])).toEqual(0) + expect(Arrays.hashCode(Array[Boolean]())).toEqual(1) + expect(Arrays.hashCode(Array[Boolean](false))).toEqual(1268) + expect(Arrays.hashCode(Array[Boolean](true, false))).toEqual(40359) + } + + it("should respond to `hashCode` for Chars") { + expect(Arrays.hashCode(null: Array[Char])).toEqual(0) + expect(Arrays.hashCode(Array[Char]())).toEqual(1) + expect(Arrays.hashCode(Array[Char]('a'))).toEqual(128) + expect(Arrays.hashCode(Array[Char]('c', '&'))).toEqual(4068) + expect(Arrays.hashCode(Array[Char]('-', '5', 'q'))).toEqual(74792) + expect(Arrays.hashCode(Array[Char]('.', ' ', '\u4323', 'v', '~'))).toEqual(88584920) + } + + it("should respond to `hashCode` for Bytes") { + expect(Arrays.hashCode(null: Array[Byte])).toEqual(0) + expect(Arrays.hashCode(Array[Byte]())).toEqual(1) + expect(Arrays.hashCode(Array[Byte](1))).toEqual(32) + expect(Arrays.hashCode(Array[Byte](7, -125))).toEqual(1053) + expect(Arrays.hashCode(Array[Byte](3, 0, 45))).toEqual(32719) + expect(Arrays.hashCode(Array[Byte](0, 45, 100, 1, 1))).toEqual(30065878) + } + + it("should respond to `hashCode` for Shorts") { + expect(Arrays.hashCode(null: Array[Short])).toEqual(0) + expect(Arrays.hashCode(Array[Short]())).toEqual(1) + expect(Arrays.hashCode(Array[Short](1))).toEqual(32) + expect(Arrays.hashCode(Array[Short](7, -125))).toEqual(1053) + expect(Arrays.hashCode(Array[Short](3, 0, 4534))).toEqual(37208) + expect(Arrays.hashCode(Array[Short](0, 45, 100, 1, 1))).toEqual(30065878) + } + + it("should respond to `hashCode` for Ints") { + expect(Arrays.hashCode(null: Array[Int])).toEqual(0) + expect(Arrays.hashCode(Array[Int]())).toEqual(1) + expect(Arrays.hashCode(Array[Int](1))).toEqual(32) + expect(Arrays.hashCode(Array[Int](7, -125))).toEqual(1053) + expect(Arrays.hashCode(Array[Int](3, 0, 4534))).toEqual(37208) + expect(Arrays.hashCode(Array[Int](0, 45, 100, 1, 1, Int.MaxValue))).toEqual(-1215441431) + } + + it("should respond to `hashCode` for Longs") { + expect(Arrays.hashCode(null: Array[Long])).toEqual(0) + expect(Arrays.hashCode(Array[Long]())).toEqual(1) + expect(Arrays.hashCode(Array[Long](1L))).toEqual(32) + expect(Arrays.hashCode(Array[Long](7L, -125L))).toEqual(1302) + expect(Arrays.hashCode(Array[Long](3L, 0L, 4534L))).toEqual(37208) + expect(Arrays.hashCode(Array[Long](0L, 45L, 100L, 1L, 1L, Int.MaxValue))).toEqual(-1215441431) + expect(Arrays.hashCode(Array[Long](0L, 34573566354545L, 100L, 1L, 1L, Int.MaxValue))).toEqual(-1952288964) + } + + it("should respond to `hashCode` for Floats") { + expect(Arrays.hashCode(null: Array[Float])).toEqual(0) + expect(Arrays.hashCode(Array[Float]())).toEqual(1) + expect(Arrays.hashCode(Array[Float](1f))).toEqual(32) + expect(Arrays.hashCode(Array[Float](7.2f, -125.2f))).toEqual(-2082726591) + expect(Arrays.hashCode(Array[Float](302.1f, 0.0f, 4534f))).toEqual(-1891539602) + expect(Arrays.hashCode(Array[Float](0.0f, 45f, -100f, 1.1f, -1f, 3567f))).toEqual(-1591440133) + } + + it("should respond to `hashCode` for Doubles") { + expect(Arrays.hashCode(null: Array[Double])).toEqual(0) + expect(Arrays.hashCode(Array[Double]())).toEqual(1) + expect(Arrays.hashCode(Array[Double](1.1))).toEqual(-1503133662) + expect(Arrays.hashCode(Array[Double](7.3, -125.23))).toEqual(-2075734168) + expect(Arrays.hashCode(Array[Double](3.9, 0.2, 4534.9))).toEqual(-557562564) + expect(Arrays.hashCode(Array[Double](0.1, 45.1, -100.0, 1.1, 1.7))).toEqual(-1750344582) + expect(Arrays.hashCode(Array[Double](0.0, 34573566354545.9, 100.2, 1.1, 1.2, Int.MaxValue))).toEqual(-1764602991) + } + + it("should respond to `hashCode` for AnyRef") { + expect(Arrays.hashCode(null: Array[AnyRef])).toEqual(0) + expect(Arrays.hashCode(Array[AnyRef]())).toEqual(1) + expect(Arrays.hashCode(Array[AnyRef](null, null))).toEqual(961) + expect(Arrays.hashCode(Array[AnyRef]("a", "b", null))).toEqual(126046) + expect(Arrays.hashCode(Array[AnyRef](null, "a", "b", null, "fooooo"))).toEqual(-1237252983) + } + + it("should respond to `equals` for Booleans") { + val a1 = Array(true, false) + + expect(Arrays.equals(a1, a1)).toBeTruthy + expect(Arrays.equals(a1, Array(true, false))).toBeTruthy + + expect(Arrays.equals(a1, Array(true))).toBeFalsy + expect(Arrays.equals(a1, Array(false))).toBeFalsy + expect(Arrays.equals(a1, Array[Boolean]())).toBeFalsy + expect(Arrays.equals(a1, Array(false, true))).toBeFalsy + expect(Arrays.equals(a1, Array(false, true, false))).toBeFalsy + } + + it("should respond to `equals` for Bytes") { + val a1 = Array[Byte](1, -7, 10) + + expect(Arrays.equals(null: Array[Byte], null: Array[Byte])).toBeTruthy + expect(Arrays.equals(a1, a1)).toBeTruthy + expect(Arrays.equals(a1, Array[Byte](1, -7, 10))).toBeTruthy + + expect(Arrays.equals(a1, null)).toBeFalsy + expect(Arrays.equals(a1, Array[Byte](3))).toBeFalsy + expect(Arrays.equals(a1, Array[Byte](1))).toBeFalsy + expect(Arrays.equals(a1, Array[Byte]())).toBeFalsy + expect(Arrays.equals(a1, Array[Byte](1, -7, 11))).toBeFalsy + expect(Arrays.equals(a1, Array[Byte](1, -7, 11, 20))).toBeFalsy + } + + it("should respond to `equals` for Chars") { + val a1 = Array[Char]('a', '0', '-') + + expect(Arrays.equals(null: Array[Char], null: Array[Char])).toBeTruthy + expect(Arrays.equals(a1, a1)).toBeTruthy + expect(Arrays.equals(a1, Array[Char]('a', '0', '-'))).toBeTruthy + + expect(Arrays.equals(a1, null)).toBeFalsy + expect(Arrays.equals(a1, Array[Char]('z'))).toBeFalsy + expect(Arrays.equals(a1, Array[Char]('a'))).toBeFalsy + expect(Arrays.equals(a1, Array[Char]())).toBeFalsy + expect(Arrays.equals(a1, Array[Char]('a', '0', '+'))).toBeFalsy + expect(Arrays.equals(a1, Array[Char]('a', '0', '-', 'z'))).toBeFalsy + } + + it("should respond to `equals` for Shorts") { + val a1 = Array[Short](1, -7, 10) + + expect(Arrays.equals(null: Array[Short], null: Array[Short])).toBeTruthy + expect(Arrays.equals(a1, a1)).toBeTruthy + expect(Arrays.equals(a1, Array[Short](1, -7, 10))).toBeTruthy + + expect(Arrays.equals(a1, null)).toBeFalsy + expect(Arrays.equals(a1, Array[Short](3))).toBeFalsy + expect(Arrays.equals(a1, Array[Short](1))).toBeFalsy + expect(Arrays.equals(a1, Array[Short]())).toBeFalsy + expect(Arrays.equals(a1, Array[Short](1, -7, 11))).toBeFalsy + expect(Arrays.equals(a1, Array[Short](1, -7, 11, 20))).toBeFalsy + } + + it("should respond to `equals` for Ints") { + val a1 = Array[Int](1, -7, 10) + + expect(Arrays.equals(null: Array[Int], null: Array[Int])).toBeTruthy + expect(Arrays.equals(a1, a1)).toBeTruthy + expect(Arrays.equals(a1, Array[Int](1, -7, 10))).toBeTruthy + + expect(Arrays.equals(a1, null)).toBeFalsy + expect(Arrays.equals(a1, Array[Int](3))).toBeFalsy + expect(Arrays.equals(a1, Array[Int](1))).toBeFalsy + expect(Arrays.equals(a1, Array[Int]())).toBeFalsy + expect(Arrays.equals(a1, Array[Int](1, -7, 11))).toBeFalsy + expect(Arrays.equals(a1, Array[Int](1, -7, 11, 20))).toBeFalsy + } + + it("should respond to `equals` for Longs") { + val a1 = Array[Long](1L, -7L, 10L) + + expect(Arrays.equals(null: Array[Long], null: Array[Long])).toBeTruthy + expect(Arrays.equals(a1, a1)).toBeTruthy + expect(Arrays.equals(a1, Array[Long](1L, -7L, 10L))).toBeTruthy + + expect(Arrays.equals(a1, null)).toBeFalsy + expect(Arrays.equals(a1, Array[Long](3L))).toBeFalsy + expect(Arrays.equals(a1, Array[Long](1L))).toBeFalsy + expect(Arrays.equals(a1, Array[Long]())).toBeFalsy + expect(Arrays.equals(a1, Array[Long](1L, -7L, 11L))).toBeFalsy + expect(Arrays.equals(a1, Array[Long](1L, -7L, 11L, 20L))).toBeFalsy + } + + it("should respond to `equals` for Floats") { + val a1 = Array[Float](1.1f, -7.4f, 10.0f) + + expect(Arrays.equals(null: Array[Float], null: Array[Float])).toBeTruthy + expect(Arrays.equals(a1, a1)).toBeTruthy + expect(Arrays.equals(a1, Array[Float](1.1f, -7.4f, 10.0f))).toBeTruthy + + expect(Arrays.equals(a1, null)).toBeFalsy + expect(Arrays.equals(a1, Array[Float](3.0f))).toBeFalsy + expect(Arrays.equals(a1, Array[Float](1.1f))).toBeFalsy + expect(Arrays.equals(a1, Array[Float]())).toBeFalsy + expect(Arrays.equals(a1, Array[Float](1.1f, -7.4f, 11.0f))).toBeFalsy + expect(Arrays.equals(a1, Array[Float](1.1f, -7.4f, 10.0f, 20.0f))).toBeFalsy + } + + it("should respond to `equals` for Doubles") { + val a1 = Array[Double](1.1, -7.4, 10.0) + + expect(Arrays.equals(null: Array[Double], null: Array[Double])).toBeTruthy + expect(Arrays.equals(a1, a1)).toBeTruthy + expect(Arrays.equals(a1, Array[Double](1.1, -7.4, 10.0))).toBeTruthy + + expect(Arrays.equals(a1, null)).toBeFalsy + expect(Arrays.equals(a1, Array[Double](3.0))).toBeFalsy + expect(Arrays.equals(a1, Array[Double](1.1))).toBeFalsy + expect(Arrays.equals(a1, Array[Double]())).toBeFalsy + expect(Arrays.equals(a1, Array[Double](1.1, -7.4, 11.0))).toBeFalsy + expect(Arrays.equals(a1, Array[Double](1.1, -7.4, 10.0, 20.0))).toBeFalsy + } + + it("should respond to `equals` for AnyRefs") { + class A(private val x: Int) { + override def equals(that: Any) = that match { + case that: A => this.x == that.x + case _ => false + } + } + + def A(x: Int) = new A(x) + + val a1 = Array[AnyRef](A(1), A(-7), A(10)) + + expect(Arrays.equals(null: Array[AnyRef], null: Array[AnyRef])).toBeTruthy + expect(Arrays.equals(a1, a1)).toBeTruthy + expect(Arrays.equals(a1, Array[AnyRef](A(1), A(-7), A(10)))).toBeTruthy + + expect(Arrays.equals(a1, null)).toBeFalsy + expect(Arrays.equals(a1, Array[AnyRef](A(3)))).toBeFalsy + expect(Arrays.equals(a1, Array[AnyRef](A(1)))).toBeFalsy + expect(Arrays.equals(a1, Array[AnyRef]())).toBeFalsy + expect(Arrays.equals(a1, Array[AnyRef](A(1), null, A(11)))).toBeFalsy + expect(Arrays.equals(a1, Array[AnyRef](A(1), A(-7), A(11), A(20)))).toBeFalsy + } + + } + +} diff --git a/test-suite/src/test/scala/scala/scalajs/testsuite/javalib/AtomicTest.scala b/test-suite/src/test/scala/scala/scalajs/testsuite/javalib/AtomicTest.scala new file mode 100644 index 0000000..c4f065a --- /dev/null +++ b/test-suite/src/test/scala/scala/scalajs/testsuite/javalib/AtomicTest.scala @@ -0,0 +1,119 @@ +/* __ *\ +** ________ ___ / / ___ __ ____ Scala.js Test Suite ** +** / __/ __// _ | / / / _ | __ / // __/ (c) 2013, LAMP/EPFL ** +** __\ \/ /__/ __ |/ /__/ __ |/_// /_\ \ http://scala-js.org/ ** +** /____/\___/_/ |_/____/_/ | |__/ /____/ ** +** |/____/ ** +\* */ +package scala.scalajs.testsuite.javalib + +import scala.language.implicitConversions + +import scala.scalajs.js + +import org.scalajs.jasminetest.JasmineTest + +object AtomicTest extends JasmineTest { + + describe("java.util.concurrent.AtomicLong") { + + it("Should have all the normal operations") { + val atomic = new java.util.concurrent.atomic.AtomicLong(10) + expect(atomic.get()).toEqual(10) + atomic.set(20) + expect(atomic.get()).toEqual(20) + expect(atomic.getAndIncrement()).toEqual(20) + expect(atomic.get()).toEqual(21) + expect(atomic.getAndDecrement()).toEqual(21) + expect(atomic.get()).toEqual(20) + expect(atomic.getAndSet(0)).toEqual(20) + expect(atomic.get()).toEqual(0) + expect(atomic.incrementAndGet()).toEqual(1) + expect(atomic.get()).toEqual(1) + expect(atomic.decrementAndGet()).toEqual(0) + expect(atomic.get()).toEqual(0) + expect(atomic.addAndGet(10)).toEqual(10) + expect(atomic.get()).toEqual(10) + expect(atomic.intValue).toEqual(10) + expect(atomic.longValue).toEqual(10L) + expect(atomic.floatValue).toEqual(10.0f) + expect(atomic.doubleValue).toEqual(10) + expect(atomic.compareAndSet(1, 20)).toEqual(false) + expect(atomic.get()).toEqual(10) + expect(atomic.compareAndSet(10, 20)).toEqual(true) + expect(atomic.get()).toEqual(20) + } + } + describe("java.util.concurrent.AtomicInteger") { + it("Should have all the normal operations") { + val atomic = new java.util.concurrent.atomic.AtomicInteger(10) + expect(atomic.get()).toEqual(10) + atomic.set(20) + expect(atomic.get()).toEqual(20) + expect(atomic.getAndIncrement()).toEqual(20) + expect(atomic.get()).toEqual(21) + expect(atomic.getAndDecrement()).toEqual(21) + expect(atomic.get()).toEqual(20) + expect(atomic.getAndSet(0)).toEqual(20) + expect(atomic.get()).toEqual(0) + expect(atomic.incrementAndGet()).toEqual(1) + expect(atomic.get()).toEqual(1) + expect(atomic.decrementAndGet()).toEqual(0) + expect(atomic.get()).toEqual(0) + expect(atomic.addAndGet(10)).toEqual(10) + expect(atomic.get()).toEqual(10) + expect(atomic.intValue).toEqual(10) + expect(atomic.longValue).toEqual(10L) + expect(atomic.floatValue).toEqual(10.0f) + expect(atomic.doubleValue).toEqual(10) + expect(atomic.compareAndSet(1, 20)).toEqual(false) + expect(atomic.get()).toEqual(10) + expect(atomic.compareAndSet(10, 20)).toEqual(true) + expect(atomic.get()).toEqual(20) + } + } + describe("java.util.concurrent.AtomicBoolean") { + it("Should have all the normal operations") { + val atomic = new java.util.concurrent.atomic.AtomicBoolean(true) + expect(atomic.get()).toEqual(true) + atomic.set(false) + expect(atomic.get()).toEqual(false) + expect(atomic.compareAndSet(true, true)).toEqual(false) + expect(atomic.get()).toEqual(false) + expect(atomic.compareAndSet(false, true)).toEqual(true) + expect(atomic.get()).toEqual(true) + expect(atomic.getAndSet(false)).toEqual(true) + expect(atomic.get()).toEqual(false) + } + } + describe("java.util.concurrent.AtomicReference") { + it("Should have all the normal operations") { + val thing1 = Foo(5) + val thing1bis = Foo(5) // equals(), but not the same reference + val thing2 = Foo(10) + + implicit def foo2js(foo: Foo): js.Any = foo.asInstanceOf[js.Any] + + // sanity + expect(thing1 == thing1bis).toBeTruthy + expect(thing1 == thing2).toBeFalsy + expect(thing1).toBe(thing1) + expect(thing1).not.toBe(thing1bis) + + // actual test + val atomic = new java.util.concurrent.atomic.AtomicReference(thing1) + expect(atomic.get()).toBe(thing1) + atomic.set(thing2) + expect(atomic.get()).toBe(thing2) + expect(atomic.compareAndSet(thing1, thing1)).toEqual(false) + expect(atomic.get()).toBe(thing2) + expect(atomic.compareAndSet(thing2, thing1)).toEqual(true) + expect(atomic.get()).toBe(thing1) + expect(atomic.compareAndSet(thing1bis, thing2)).toEqual(false) + expect(atomic.getAndSet(thing2)).toBe(thing1) + expect(atomic.get()).toBe(thing2) + } + } + + case class Foo(i: Int) +} diff --git a/test-suite/src/test/scala/scala/scalajs/testsuite/javalib/BooleanTest.scala b/test-suite/src/test/scala/scala/scalajs/testsuite/javalib/BooleanTest.scala new file mode 100644 index 0000000..87c65e9 --- /dev/null +++ b/test-suite/src/test/scala/scala/scalajs/testsuite/javalib/BooleanTest.scala @@ -0,0 +1,62 @@ +/* __ *\ +** ________ ___ / / ___ __ ____ Scala.js Test Suite ** +** / __/ __// _ | / / / _ | __ / // __/ (c) 2013, LAMP/EPFL ** +** __\ \/ /__/ __ |/ /__/ __ |/_// /_\ \ http://scala-js.org/ ** +** /____/\___/_/ |_/____/_/ | |__/ /____/ ** +** |/____/ ** +\* */ +package scala.scalajs.testsuite.javalib + +import java.lang.{Boolean => JBoolean} + +import org.scalajs.jasminetest.JasmineTest + +/** + * tests the implementation of the java standard library Boolean + */ +object BooleanTest extends JasmineTest { + + describe("java.lang.Boolean") { + + it("should provide `booleanValue`") { + expect(JBoolean.TRUE.booleanValue()).toBe(true) + expect(JBoolean.FALSE.booleanValue()).toBe(false) + expect(() => (null: JBoolean).booleanValue()).toThrow + } + + it("should provide `compareTo`") { + def compare(x: Boolean, y: Boolean): Int = + new JBoolean(x).compareTo(new JBoolean(y)) + + expect(compare(false, false)).toEqual(0) + expect(compare(false, true)).toBeLessThan(0) + expect(compare(true, false)).toBeGreaterThan(0) + expect(compare(true, true)).toEqual(0) + } + + it("should be a Comparable") { + def compare(x: Any, y: Any): Int = + x.asInstanceOf[Comparable[Any]].compareTo(y) + + expect(compare(false, false)).toEqual(0) + expect(compare(false, true)).toBeLessThan(0) + expect(compare(true, false)).toBeGreaterThan(0) + expect(compare(true, true)).toEqual(0) + } + + it("should parse strings") { + def test(s: String, v: Boolean): Unit = { + expect(JBoolean.parseBoolean(s)).toEqual(v) + expect(JBoolean.valueOf(s).booleanValue()).toEqual(v) + expect(new JBoolean(s).booleanValue()).toEqual(v) + } + + test("false", false) + test("true", true) + test("TrUe", true) + test(null, false) + test("truee", false) + } + + } +} diff --git a/test-suite/src/test/scala/scala/scalajs/testsuite/javalib/ByteTest.scala b/test-suite/src/test/scala/scala/scalajs/testsuite/javalib/ByteTest.scala new file mode 100644 index 0000000..b033c59 --- /dev/null +++ b/test-suite/src/test/scala/scala/scalajs/testsuite/javalib/ByteTest.scala @@ -0,0 +1,64 @@ +/* __ *\ +** ________ ___ / / ___ __ ____ Scala.js Test Suite ** +** / __/ __// _ | / / / _ | __ / // __/ (c) 2013, LAMP/EPFL ** +** __\ \/ /__/ __ |/ /__/ __ |/_// /_\ \ http://scala-js.org/ ** +** /____/\___/_/ |_/____/_/ | |__/ /____/ ** +** |/____/ ** +\* */ +package scala.scalajs.testsuite.javalib + +import java.lang.{Byte => JByte} + +import org.scalajs.jasminetest.JasmineTest + +/** + * tests the implementation of the java standard library Byte + */ +object ByteTest extends JasmineTest { + + describe("java.lang.Byte") { + + it("should provide `compareTo`") { + def compare(x: Byte, y: Byte): Int = + new JByte(x).compareTo(new JByte(y)) + + expect(compare(0.toByte, 5.toByte)).toBeLessThan(0) + expect(compare(10.toByte, 9.toByte)).toBeGreaterThan(0) + expect(compare(-2.toByte, -1.toByte)).toBeLessThan(0) + expect(compare(3.toByte, 3.toByte)).toEqual(0) + } + + it("should be a Comparable") { + def compare(x: Any, y: Any): Int = + x.asInstanceOf[Comparable[Any]].compareTo(y) + + expect(compare(0.toByte, 5.toByte)).toBeLessThan(0) + expect(compare(10.toByte, 9.toByte)).toBeGreaterThan(0) + expect(compare(-2.toByte, -1.toByte)).toBeLessThan(0) + expect(compare(3.toByte, 3.toByte)).toEqual(0) + } + + it("should parse strings") { + def test(s: String, v: Byte): Unit = { + expect(JByte.parseByte(s)).toEqual(v) + expect(JByte.valueOf(s).byteValue()).toEqual(v) + expect(new JByte(s).byteValue()).toEqual(v) + } + + test("0", 0) + test("5", 5) + test("127", 127) + test("-100", -100) + } + + it("should reject invalid strings when parsing") { + def test(s: String): Unit = + expect(() => JByte.parseByte(s)).toThrow + + test("abc") + test("") + test("200") // out of range + } + + } +} diff --git a/test-suite/src/test/scala/scala/scalajs/testsuite/javalib/CharacterTest.scala b/test-suite/src/test/scala/scala/scalajs/testsuite/javalib/CharacterTest.scala new file mode 100644 index 0000000..f206221 --- /dev/null +++ b/test-suite/src/test/scala/scala/scalajs/testsuite/javalib/CharacterTest.scala @@ -0,0 +1,672 @@ +/* __ *\ +** ________ ___ / / ___ __ ____ Scala.js Test Suite ** +** / __/ __// _ | / / / _ | __ / // __/ (c) 2013, LAMP/EPFL ** +** __\ \/ /__/ __ |/ /__/ __ |/_// /_\ \ http://scala-js.org/ ** +** /____/\___/_/ |_/____/_/ | |__/ /____/ ** +** |/____/ ** +\* */ +package scala.scalajs.testsuite.javalib + +import org.scalajs.jasminetest.JasmineTest +import scala.scalajs.js + +object CharacterTest extends JasmineTest { + + describe("java.lang.Character") { + + it("should provide `isISOControl`") { + val isoControlChars = (('\u0000' to '\u001F') ++ ('\u007F' to '\u009F')).map(_.toInt).toSet + isoControlChars foreach { c => + expect(Character.isISOControl(c)).toEqual(true) + } + + val randomInts = List.fill(100)(scala.util.Random.nextInt) + ((-1000 to 1000) ++ randomInts).filterNot(isoControlChars) foreach { c => + expect(Character.isISOControl(c)).toEqual(false) + } + } + + it("should provide `digit`") { + expect(Character.digit('a', 16)).toEqual(10) + expect(Character.digit('}', 5)).toEqual(-1) + expect(Character.digit('1', 50)).toEqual(-1) + expect(Character.digit('1', 36)).toEqual(1) + expect(Character.digit('Z', 36)).toEqual(35) + expect(Character.digit('\uFF22', 20)).toEqual(11) + } + + it("should provide isDigit") { + expect(Character.isDigit('a')).toBeFalsy + expect(Character.isDigit('0')).toBeTruthy + expect(Character.isDigit('5')).toBeTruthy + expect(Character.isDigit('9')).toBeTruthy + expect(Character.isDigit('z')).toBeFalsy + expect(Character.isDigit(' ')).toBeFalsy + } + + it("should provide `compareTo`") { + def compare(x: Char, y: Char): Int = + new Character(x).compareTo(new Character(y)) + + expect(compare('0', '5')).toBeLessThan(0) + expect(compare('o', 'g')).toBeGreaterThan(0) + expect(compare('A', 'a')).toBeLessThan(0) + expect(compare('b', 'b')).toEqual(0) + } + + it("should be a Comparable") { + def compare(x: Any, y: Any): Int = + x.asInstanceOf[Comparable[Any]].compareTo(y) + + expect(compare('0', '5')).toBeLessThan(0) + expect(compare('o', 'g')).toBeGreaterThan(0) + expect(compare('A', 'a')).toBeLessThan(0) + expect(compare('b', 'b')).toEqual(0) + } + + it("should provide isIdentifierIgnorable") { + for (c <- '\u0000' to '\u0008') + expect(Character.isIdentifierIgnorable(c)).toBeTruthy + + for (c <- '\u000E' to '\u001B') + expect(Character.isIdentifierIgnorable(c)).toBeTruthy + + for (c <- '\u007F' to '\u009F') + expect(Character.isIdentifierIgnorable(c)).toBeTruthy + + // Exhaustive list of Cf category. Unicode 7.0.0 + expect(Character.isIdentifierIgnorable('\u00AD')).toBeTruthy + expect(Character.isIdentifierIgnorable('\u0600')).toBeTruthy + expect(Character.isIdentifierIgnorable('\u0601')).toBeTruthy + expect(Character.isIdentifierIgnorable('\u0602')).toBeTruthy + expect(Character.isIdentifierIgnorable('\u0603')).toBeTruthy + expect(Character.isIdentifierIgnorable('\u0604')).toBeTruthy + expect(Character.isIdentifierIgnorable('\u0605')).toBeTruthy + expect(Character.isIdentifierIgnorable('\u061C')).toBeTruthy + expect(Character.isIdentifierIgnorable('\u06DD')).toBeTruthy + expect(Character.isIdentifierIgnorable('\u070F')).toBeTruthy + expect(Character.isIdentifierIgnorable('\u180E')).toBeTruthy + expect(Character.isIdentifierIgnorable('\u200B')).toBeTruthy + expect(Character.isIdentifierIgnorable('\u200C')).toBeTruthy + expect(Character.isIdentifierIgnorable('\u200D')).toBeTruthy + expect(Character.isIdentifierIgnorable('\u200E')).toBeTruthy + expect(Character.isIdentifierIgnorable('\u200F')).toBeTruthy + expect(Character.isIdentifierIgnorable('\u202A')).toBeTruthy + expect(Character.isIdentifierIgnorable('\u202B')).toBeTruthy + expect(Character.isIdentifierIgnorable('\u202C')).toBeTruthy + expect(Character.isIdentifierIgnorable('\u202D')).toBeTruthy + expect(Character.isIdentifierIgnorable('\u202E')).toBeTruthy + expect(Character.isIdentifierIgnorable('\u2060')).toBeTruthy + expect(Character.isIdentifierIgnorable('\u2061')).toBeTruthy + expect(Character.isIdentifierIgnorable('\u2062')).toBeTruthy + expect(Character.isIdentifierIgnorable('\u2063')).toBeTruthy + expect(Character.isIdentifierIgnorable('\u2064')).toBeTruthy + expect(Character.isIdentifierIgnorable('\u2066')).toBeTruthy + expect(Character.isIdentifierIgnorable('\u2067')).toBeTruthy + expect(Character.isIdentifierIgnorable('\u2068')).toBeTruthy + expect(Character.isIdentifierIgnorable('\u2069')).toBeTruthy + expect(Character.isIdentifierIgnorable('\u206A')).toBeTruthy + expect(Character.isIdentifierIgnorable('\u206B')).toBeTruthy + expect(Character.isIdentifierIgnorable('\u206C')).toBeTruthy + expect(Character.isIdentifierIgnorable('\u206D')).toBeTruthy + expect(Character.isIdentifierIgnorable('\u206E')).toBeTruthy + expect(Character.isIdentifierIgnorable('\u206F')).toBeTruthy + expect(Character.isIdentifierIgnorable('\uFEFF')).toBeTruthy + expect(Character.isIdentifierIgnorable('\uFFF9')).toBeTruthy + expect(Character.isIdentifierIgnorable('\uFFFA')).toBeTruthy + expect(Character.isIdentifierIgnorable('\uFFFB')).toBeTruthy + + // BUG in JDK? 17B4 should be "Mn", Java says "Cf" + //expect(Character.isIdentifierIgnorable('\u17b4')).toBeTruthy + + // 100 randomly generated negatives + expect(Character.isIdentifierIgnorable('\u745a')).toBeFalsy + expect(Character.isIdentifierIgnorable('\ub445')).toBeFalsy + expect(Character.isIdentifierIgnorable('\ub23a')).toBeFalsy + expect(Character.isIdentifierIgnorable('\ub029')).toBeFalsy + expect(Character.isIdentifierIgnorable('\ufb5c')).toBeFalsy + expect(Character.isIdentifierIgnorable('\u1b67')).toBeFalsy + expect(Character.isIdentifierIgnorable('\u943b')).toBeFalsy + expect(Character.isIdentifierIgnorable('\ue766')).toBeFalsy + expect(Character.isIdentifierIgnorable('\uad12')).toBeFalsy + expect(Character.isIdentifierIgnorable('\ub80b')).toBeFalsy + expect(Character.isIdentifierIgnorable('\u7341')).toBeFalsy + expect(Character.isIdentifierIgnorable('\ubc73')).toBeFalsy + expect(Character.isIdentifierIgnorable('\uabb9')).toBeFalsy + expect(Character.isIdentifierIgnorable('\ub34b')).toBeFalsy + expect(Character.isIdentifierIgnorable('\u1063')).toBeFalsy + expect(Character.isIdentifierIgnorable('\u272f')).toBeFalsy + expect(Character.isIdentifierIgnorable('\u3801')).toBeFalsy + expect(Character.isIdentifierIgnorable('\u53a6')).toBeFalsy + expect(Character.isIdentifierIgnorable('\u2ec2')).toBeFalsy + expect(Character.isIdentifierIgnorable('\u540c')).toBeFalsy + expect(Character.isIdentifierIgnorable('\uc85f')).toBeFalsy + expect(Character.isIdentifierIgnorable('\ud2c8')).toBeFalsy + expect(Character.isIdentifierIgnorable('\u551b')).toBeFalsy + expect(Character.isIdentifierIgnorable('\uc0a1')).toBeFalsy + expect(Character.isIdentifierIgnorable('\ud25a')).toBeFalsy + expect(Character.isIdentifierIgnorable('\u2b98')).toBeFalsy + expect(Character.isIdentifierIgnorable('\u398b')).toBeFalsy + expect(Character.isIdentifierIgnorable('\ubc77')).toBeFalsy + expect(Character.isIdentifierIgnorable('\u54cc')).toBeFalsy + expect(Character.isIdentifierIgnorable('\uc9a0')).toBeFalsy + expect(Character.isIdentifierIgnorable('\ud10f')).toBeFalsy + expect(Character.isIdentifierIgnorable('\uf7e1')).toBeFalsy + expect(Character.isIdentifierIgnorable('\u0f29')).toBeFalsy + expect(Character.isIdentifierIgnorable('\uafcd')).toBeFalsy + expect(Character.isIdentifierIgnorable('\uf187')).toBeFalsy + expect(Character.isIdentifierIgnorable('\u6287')).toBeFalsy + expect(Character.isIdentifierIgnorable('\uacb6')).toBeFalsy + expect(Character.isIdentifierIgnorable('\uff99')).toBeFalsy + expect(Character.isIdentifierIgnorable('\ub59e')).toBeFalsy + expect(Character.isIdentifierIgnorable('\uf630')).toBeFalsy + expect(Character.isIdentifierIgnorable('\ufaec')).toBeFalsy + expect(Character.isIdentifierIgnorable('\ua7d7')).toBeFalsy + expect(Character.isIdentifierIgnorable('\u3eab')).toBeFalsy + expect(Character.isIdentifierIgnorable('\u54a5')).toBeFalsy + expect(Character.isIdentifierIgnorable('\u393a')).toBeFalsy + expect(Character.isIdentifierIgnorable('\uc621')).toBeFalsy + expect(Character.isIdentifierIgnorable('\u766c')).toBeFalsy + expect(Character.isIdentifierIgnorable('\ud64c')).toBeFalsy + expect(Character.isIdentifierIgnorable('\u8beb')).toBeFalsy + expect(Character.isIdentifierIgnorable('\u44e2')).toBeFalsy + expect(Character.isIdentifierIgnorable('\ub6f6')).toBeFalsy + expect(Character.isIdentifierIgnorable('\u58b6')).toBeFalsy + expect(Character.isIdentifierIgnorable('\u3bad')).toBeFalsy + expect(Character.isIdentifierIgnorable('\u3c28')).toBeFalsy + expect(Character.isIdentifierIgnorable('\ufbfd')).toBeFalsy + expect(Character.isIdentifierIgnorable('\u585f')).toBeFalsy + expect(Character.isIdentifierIgnorable('\u7227')).toBeFalsy + expect(Character.isIdentifierIgnorable('\ucea7')).toBeFalsy + expect(Character.isIdentifierIgnorable('\u2c82')).toBeFalsy + expect(Character.isIdentifierIgnorable('\u686d')).toBeFalsy + expect(Character.isIdentifierIgnorable('\u120d')).toBeFalsy + expect(Character.isIdentifierIgnorable('\uf3db')).toBeFalsy + expect(Character.isIdentifierIgnorable('\u320a')).toBeFalsy + expect(Character.isIdentifierIgnorable('\ud96e')).toBeFalsy + expect(Character.isIdentifierIgnorable('\u85eb')).toBeFalsy + expect(Character.isIdentifierIgnorable('\u9648')).toBeFalsy + expect(Character.isIdentifierIgnorable('\u08a4')).toBeFalsy + expect(Character.isIdentifierIgnorable('\u9db7')).toBeFalsy + expect(Character.isIdentifierIgnorable('\u82c7')).toBeFalsy + expect(Character.isIdentifierIgnorable('\ufe12')).toBeFalsy + expect(Character.isIdentifierIgnorable('\u0eaf')).toBeFalsy + expect(Character.isIdentifierIgnorable('\u96dc')).toBeFalsy + expect(Character.isIdentifierIgnorable('\u3a2a')).toBeFalsy + expect(Character.isIdentifierIgnorable('\uc72e')).toBeFalsy + expect(Character.isIdentifierIgnorable('\u3745')).toBeFalsy + expect(Character.isIdentifierIgnorable('\ubcf9')).toBeFalsy + expect(Character.isIdentifierIgnorable('\u5f66')).toBeFalsy + expect(Character.isIdentifierIgnorable('\u9be1')).toBeFalsy + expect(Character.isIdentifierIgnorable('\ud81d')).toBeFalsy + expect(Character.isIdentifierIgnorable('\u3ca3')).toBeFalsy + expect(Character.isIdentifierIgnorable('\u3e82')).toBeFalsy + expect(Character.isIdentifierIgnorable('\u7ce4')).toBeFalsy + expect(Character.isIdentifierIgnorable('\u33ca')).toBeFalsy + expect(Character.isIdentifierIgnorable('\ue725')).toBeFalsy + expect(Character.isIdentifierIgnorable('\uef49')).toBeFalsy + expect(Character.isIdentifierIgnorable('\ue2cf')).toBeFalsy + expect(Character.isIdentifierIgnorable('\udcf0')).toBeFalsy + expect(Character.isIdentifierIgnorable('\u5f2e')).toBeFalsy + expect(Character.isIdentifierIgnorable('\u2a63')).toBeFalsy + expect(Character.isIdentifierIgnorable('\ud2d2')).toBeFalsy + expect(Character.isIdentifierIgnorable('\u8023')).toBeFalsy + expect(Character.isIdentifierIgnorable('\ua957')).toBeFalsy + expect(Character.isIdentifierIgnorable('\u10ba')).toBeFalsy + expect(Character.isIdentifierIgnorable('\uf85f')).toBeFalsy + expect(Character.isIdentifierIgnorable('\uc40d')).toBeFalsy + expect(Character.isIdentifierIgnorable('\u2509')).toBeFalsy + expect(Character.isIdentifierIgnorable('\u0d8e')).toBeFalsy + expect(Character.isIdentifierIgnorable('\u9db8')).toBeFalsy + expect(Character.isIdentifierIgnorable('\u824d')).toBeFalsy + expect(Character.isIdentifierIgnorable('\u5670')).toBeFalsy + expect(Character.isIdentifierIgnorable('\u6005')).toBeFalsy + expect(Character.isIdentifierIgnorable('\ub8de')).toBeFalsy + expect(Character.isIdentifierIgnorable('\uff5c')).toBeFalsy + expect(Character.isIdentifierIgnorable('\ub36d')).toBeFalsy + expect(Character.isIdentifierIgnorable('\u0cf2')).toBeFalsy + expect(Character.isIdentifierIgnorable('\u82f6')).toBeFalsy + expect(Character.isIdentifierIgnorable('\u9206')).toBeFalsy + expect(Character.isIdentifierIgnorable('\u95e1')).toBeFalsy + expect(Character.isIdentifierIgnorable('\u990f')).toBeFalsy + expect(Character.isIdentifierIgnorable('\u9fc7')).toBeFalsy + expect(Character.isIdentifierIgnorable('\udffb')).toBeFalsy + expect(Character.isIdentifierIgnorable('\u0ecb')).toBeFalsy + expect(Character.isIdentifierIgnorable('\u7563')).toBeFalsy + expect(Character.isIdentifierIgnorable('\uf0ff')).toBeFalsy + expect(Character.isIdentifierIgnorable('\u6b2e')).toBeFalsy + expect(Character.isIdentifierIgnorable('\u894c')).toBeFalsy + expect(Character.isIdentifierIgnorable('\u8f06')).toBeFalsy + expect(Character.isIdentifierIgnorable('\uffa9')).toBeFalsy + expect(Character.isIdentifierIgnorable('\u37b0')).toBeFalsy + expect(Character.isIdentifierIgnorable('\u3e04')).toBeFalsy + + } + + it("should provide isUnicodeIdentifierStart") { + // 100 randomly generated positives and 100 randomly generated negatives + + expect(Character.isUnicodeIdentifierStart('\ud6d5')).toBeTruthy + expect(Character.isUnicodeIdentifierStart('\u3f9c')).toBeTruthy + expect(Character.isUnicodeIdentifierStart('\u3a40')).toBeTruthy + expect(Character.isUnicodeIdentifierStart('\u53af')).toBeTruthy + expect(Character.isUnicodeIdentifierStart('\u1636')).toBeTruthy + expect(Character.isUnicodeIdentifierStart('\u4884')).toBeTruthy + expect(Character.isUnicodeIdentifierStart('\ucba4')).toBeTruthy + expect(Character.isUnicodeIdentifierStart('\u1ee4')).toBeTruthy + expect(Character.isUnicodeIdentifierStart('\u6dec')).toBeTruthy + expect(Character.isUnicodeIdentifierStart('\u10d4')).toBeTruthy + expect(Character.isUnicodeIdentifierStart('\u631f')).toBeTruthy + expect(Character.isUnicodeIdentifierStart('\u3661')).toBeTruthy + expect(Character.isUnicodeIdentifierStart('\u55f8')).toBeTruthy + expect(Character.isUnicodeIdentifierStart('\ub4ef')).toBeTruthy + expect(Character.isUnicodeIdentifierStart('\ud509')).toBeTruthy + expect(Character.isUnicodeIdentifierStart('\u65b5')).toBeTruthy + expect(Character.isUnicodeIdentifierStart('\u316b')).toBeTruthy + expect(Character.isUnicodeIdentifierStart('\ub270')).toBeTruthy + expect(Character.isUnicodeIdentifierStart('\u7f0f')).toBeTruthy + expect(Character.isUnicodeIdentifierStart('\uff84')).toBeTruthy + expect(Character.isUnicodeIdentifierStart('\u11cc')).toBeTruthy + expect(Character.isUnicodeIdentifierStart('\u0294')).toBeTruthy + expect(Character.isUnicodeIdentifierStart('\u51b1')).toBeTruthy + expect(Character.isUnicodeIdentifierStart('\u9ae2')).toBeTruthy + expect(Character.isUnicodeIdentifierStart('\u304a')).toBeTruthy + expect(Character.isUnicodeIdentifierStart('\ud5c7')).toBeTruthy + expect(Character.isUnicodeIdentifierStart('\u3b4b')).toBeTruthy + expect(Character.isUnicodeIdentifierStart('\u5e42')).toBeTruthy + expect(Character.isUnicodeIdentifierStart('\u51fc')).toBeTruthy + expect(Character.isUnicodeIdentifierStart('\uc148')).toBeTruthy + expect(Character.isUnicodeIdentifierStart('\uc1ae')).toBeTruthy + expect(Character.isUnicodeIdentifierStart('\u7372')).toBeTruthy + expect(Character.isUnicodeIdentifierStart('\uc116')).toBeTruthy + expect(Character.isUnicodeIdentifierStart('\u5d29')).toBeTruthy + expect(Character.isUnicodeIdentifierStart('\u8753')).toBeTruthy + expect(Character.isUnicodeIdentifierStart('\u50f8')).toBeTruthy + expect(Character.isUnicodeIdentifierStart('\u3f9d')).toBeTruthy + expect(Character.isUnicodeIdentifierStart('\u1f44')).toBeTruthy + expect(Character.isUnicodeIdentifierStart('\ucd43')).toBeTruthy + expect(Character.isUnicodeIdentifierStart('\u9126')).toBeTruthy + expect(Character.isUnicodeIdentifierStart('\u8d2e')).toBeTruthy + expect(Character.isUnicodeIdentifierStart('\u4f5c')).toBeTruthy + expect(Character.isUnicodeIdentifierStart('\u66d7')).toBeTruthy + expect(Character.isUnicodeIdentifierStart('\ua30b')).toBeTruthy + expect(Character.isUnicodeIdentifierStart('\u140b')).toBeTruthy + expect(Character.isUnicodeIdentifierStart('\ub264')).toBeTruthy + expect(Character.isUnicodeIdentifierStart('\u7b35')).toBeTruthy + expect(Character.isUnicodeIdentifierStart('\u15e4')).toBeTruthy + expect(Character.isUnicodeIdentifierStart('\ubb37')).toBeTruthy + expect(Character.isUnicodeIdentifierStart('\u34e3')).toBeTruthy + expect(Character.isUnicodeIdentifierStart('\uac3e')).toBeTruthy + expect(Character.isUnicodeIdentifierStart('\ubd0e')).toBeTruthy + expect(Character.isUnicodeIdentifierStart('\ub641')).toBeTruthy + expect(Character.isUnicodeIdentifierStart('\u1580')).toBeTruthy + expect(Character.isUnicodeIdentifierStart('\u30c1')).toBeTruthy + expect(Character.isUnicodeIdentifierStart('\ub0c8')).toBeTruthy + expect(Character.isUnicodeIdentifierStart('\u8681')).toBeTruthy + expect(Character.isUnicodeIdentifierStart('\u7f14')).toBeTruthy + expect(Character.isUnicodeIdentifierStart('\u4142')).toBeTruthy + expect(Character.isUnicodeIdentifierStart('\u56c1')).toBeTruthy + expect(Character.isUnicodeIdentifierStart('\u0444')).toBeTruthy + expect(Character.isUnicodeIdentifierStart('\u9964')).toBeTruthy + expect(Character.isUnicodeIdentifierStart('\ub5c0')).toBeTruthy + expect(Character.isUnicodeIdentifierStart('\u43d8')).toBeTruthy + expect(Character.isUnicodeIdentifierStart('\u479e')).toBeTruthy + expect(Character.isUnicodeIdentifierStart('\u0853')).toBeTruthy + expect(Character.isUnicodeIdentifierStart('\ube08')).toBeTruthy + expect(Character.isUnicodeIdentifierStart('\u9346')).toBeTruthy + expect(Character.isUnicodeIdentifierStart('\uf9c1')).toBeTruthy + expect(Character.isUnicodeIdentifierStart('\u0e8a')).toBeTruthy + expect(Character.isUnicodeIdentifierStart('\u212c')).toBeTruthy + expect(Character.isUnicodeIdentifierStart('\u810c')).toBeTruthy + expect(Character.isUnicodeIdentifierStart('\u8089')).toBeTruthy + expect(Character.isUnicodeIdentifierStart('\u1331')).toBeTruthy + expect(Character.isUnicodeIdentifierStart('\ua5f7')).toBeTruthy + expect(Character.isUnicodeIdentifierStart('\u5e5e')).toBeTruthy + expect(Character.isUnicodeIdentifierStart('\u613b')).toBeTruthy + expect(Character.isUnicodeIdentifierStart('\u34a7')).toBeTruthy + expect(Character.isUnicodeIdentifierStart('\ud15b')).toBeTruthy + expect(Character.isUnicodeIdentifierStart('\uc1fc')).toBeTruthy + expect(Character.isUnicodeIdentifierStart('\u92f1')).toBeTruthy + expect(Character.isUnicodeIdentifierStart('\u3ae6')).toBeTruthy + expect(Character.isUnicodeIdentifierStart('\ufceb')).toBeTruthy + expect(Character.isUnicodeIdentifierStart('\u7584')).toBeTruthy + expect(Character.isUnicodeIdentifierStart('\ufe98')).toBeTruthy + expect(Character.isUnicodeIdentifierStart('\ubb23')).toBeTruthy + expect(Character.isUnicodeIdentifierStart('\u7961')).toBeTruthy + expect(Character.isUnicodeIdentifierStart('\u4445')).toBeTruthy + expect(Character.isUnicodeIdentifierStart('\u4d5f')).toBeTruthy + expect(Character.isUnicodeIdentifierStart('\u61cb')).toBeTruthy + expect(Character.isUnicodeIdentifierStart('\u5176')).toBeTruthy + expect(Character.isUnicodeIdentifierStart('\ub987')).toBeTruthy + expect(Character.isUnicodeIdentifierStart('\u906a')).toBeTruthy + expect(Character.isUnicodeIdentifierStart('\u4317')).toBeTruthy + expect(Character.isUnicodeIdentifierStart('\u93ad')).toBeTruthy + expect(Character.isUnicodeIdentifierStart('\u825a')).toBeTruthy + expect(Character.isUnicodeIdentifierStart('\u7ff8')).toBeTruthy + expect(Character.isUnicodeIdentifierStart('\u533a')).toBeTruthy + expect(Character.isUnicodeIdentifierStart('\u5617')).toBeTruthy + expect(Character.isUnicodeIdentifierStart('\ufcc6')).toBeTruthy + expect(Character.isUnicodeIdentifierStart('\ue398')).toBeFalsy + expect(Character.isUnicodeIdentifierStart('\ueab6')).toBeFalsy + expect(Character.isUnicodeIdentifierStart('\ue7bc')).toBeFalsy + expect(Character.isUnicodeIdentifierStart('\uf8ab')).toBeFalsy + expect(Character.isUnicodeIdentifierStart('\ue27f')).toBeFalsy + expect(Character.isUnicodeIdentifierStart('\uebea')).toBeFalsy + expect(Character.isUnicodeIdentifierStart('\ueedc')).toBeFalsy + expect(Character.isUnicodeIdentifierStart('\uf091')).toBeFalsy + expect(Character.isUnicodeIdentifierStart('\u2785')).toBeFalsy + expect(Character.isUnicodeIdentifierStart('\u287b')).toBeFalsy + expect(Character.isUnicodeIdentifierStart('\uf042')).toBeFalsy + expect(Character.isUnicodeIdentifierStart('\u20f9')).toBeFalsy + expect(Character.isUnicodeIdentifierStart('\u23d6')).toBeFalsy + expect(Character.isUnicodeIdentifierStart('\udc5b')).toBeFalsy + expect(Character.isUnicodeIdentifierStart('\ued16')).toBeFalsy + expect(Character.isUnicodeIdentifierStart('\u1b6b')).toBeFalsy + expect(Character.isUnicodeIdentifierStart('\ue7ba')).toBeFalsy + expect(Character.isUnicodeIdentifierStart('\uf7fa')).toBeFalsy + expect(Character.isUnicodeIdentifierStart('\u2125')).toBeFalsy + expect(Character.isUnicodeIdentifierStart('\uea97')).toBeFalsy + expect(Character.isUnicodeIdentifierStart('\ue624')).toBeFalsy + expect(Character.isUnicodeIdentifierStart('\ufbb8')).toBeFalsy + expect(Character.isUnicodeIdentifierStart('\u2730')).toBeFalsy + expect(Character.isUnicodeIdentifierStart('\udb89')).toBeFalsy + expect(Character.isUnicodeIdentifierStart('\ue30d')).toBeFalsy + expect(Character.isUnicodeIdentifierStart('\u2e24')).toBeFalsy + expect(Character.isUnicodeIdentifierStart('\uf03e')).toBeFalsy + expect(Character.isUnicodeIdentifierStart('\uda27')).toBeFalsy + expect(Character.isUnicodeIdentifierStart('\u28fc')).toBeFalsy + expect(Character.isUnicodeIdentifierStart('\u9ffe')).toBeFalsy + expect(Character.isUnicodeIdentifierStart('\ude19')).toBeFalsy + expect(Character.isUnicodeIdentifierStart('\u0b70')).toBeFalsy + expect(Character.isUnicodeIdentifierStart('\uddfc')).toBeFalsy + expect(Character.isUnicodeIdentifierStart('\ued53')).toBeFalsy + expect(Character.isUnicodeIdentifierStart('\ue8cb')).toBeFalsy + expect(Character.isUnicodeIdentifierStart('\udccc')).toBeFalsy + expect(Character.isUnicodeIdentifierStart('\u00a3')).toBeFalsy + expect(Character.isUnicodeIdentifierStart('\u0bed')).toBeFalsy + expect(Character.isUnicodeIdentifierStart('\u0c68')).toBeFalsy + expect(Character.isUnicodeIdentifierStart('\uf47b')).toBeFalsy + expect(Character.isUnicodeIdentifierStart('\u0f96')).toBeFalsy + expect(Character.isUnicodeIdentifierStart('\ue9c3')).toBeFalsy + expect(Character.isUnicodeIdentifierStart('\uf784')).toBeFalsy + expect(Character.isUnicodeIdentifierStart('\uef4b')).toBeFalsy + expect(Character.isUnicodeIdentifierStart('\udee1')).toBeFalsy + expect(Character.isUnicodeIdentifierStart('\u2f61')).toBeFalsy + expect(Character.isUnicodeIdentifierStart('\uf622')).toBeFalsy + expect(Character.isUnicodeIdentifierStart('\u19f9')).toBeFalsy + expect(Character.isUnicodeIdentifierStart('\ud86a')).toBeFalsy + expect(Character.isUnicodeIdentifierStart('\ued83')).toBeFalsy + expect(Character.isUnicodeIdentifierStart('\uf7e4')).toBeFalsy + expect(Character.isUnicodeIdentifierStart('\uecce')).toBeFalsy + + // BUG in JDK? A699 should be "Ll", Java says "Cn" + // expect(Character.isUnicodeIdentifierStart('\ua699')).toBeFalsy + + expect(Character.isUnicodeIdentifierStart('\uaa5f')).toBeFalsy + expect(Character.isUnicodeIdentifierStart('\udf24')).toBeFalsy + expect(Character.isUnicodeIdentifierStart('\u2e0e')).toBeFalsy + expect(Character.isUnicodeIdentifierStart('\uf322')).toBeFalsy + expect(Character.isUnicodeIdentifierStart('\ue137')).toBeFalsy + expect(Character.isUnicodeIdentifierStart('\ued19')).toBeFalsy + expect(Character.isUnicodeIdentifierStart('\u21ab')).toBeFalsy + expect(Character.isUnicodeIdentifierStart('\ue972')).toBeFalsy + expect(Character.isUnicodeIdentifierStart('\udbf2')).toBeFalsy + expect(Character.isUnicodeIdentifierStart('\uf54c')).toBeFalsy + expect(Character.isUnicodeIdentifierStart('\u4dd3')).toBeFalsy + expect(Character.isUnicodeIdentifierStart('\u2769')).toBeFalsy + expect(Character.isUnicodeIdentifierStart('\ue363')).toBeFalsy + + // BUG in JDK? 1BBB should be "Lo", Java says "Cn" + // expect(Character.isUnicodeIdentifierStart('\u1bbb')).toBeFalsy + + expect(Character.isUnicodeIdentifierStart('\ueae7')).toBeFalsy + expect(Character.isUnicodeIdentifierStart('\u2bf3')).toBeFalsy + expect(Character.isUnicodeIdentifierStart('\ue704')).toBeFalsy + expect(Character.isUnicodeIdentifierStart('\u1c7f')).toBeFalsy + expect(Character.isUnicodeIdentifierStart('\uf52b')).toBeFalsy + expect(Character.isUnicodeIdentifierStart('\ue9e3')).toBeFalsy + expect(Character.isUnicodeIdentifierStart('\u259b')).toBeFalsy + expect(Character.isUnicodeIdentifierStart('\uf250')).toBeFalsy + expect(Character.isUnicodeIdentifierStart('\uf42f')).toBeFalsy + expect(Character.isUnicodeIdentifierStart('\ue244')).toBeFalsy + expect(Character.isUnicodeIdentifierStart('\u20d9')).toBeFalsy + expect(Character.isUnicodeIdentifierStart('\ua881')).toBeFalsy + expect(Character.isUnicodeIdentifierStart('\u0ee6')).toBeFalsy + expect(Character.isUnicodeIdentifierStart('\u2203')).toBeFalsy + expect(Character.isUnicodeIdentifierStart('\u0fc7')).toBeFalsy + expect(Character.isUnicodeIdentifierStart('\u07fc')).toBeFalsy + expect(Character.isUnicodeIdentifierStart('\udb86')).toBeFalsy + expect(Character.isUnicodeIdentifierStart('\u2a70')).toBeFalsy + expect(Character.isUnicodeIdentifierStart('\u2bb7')).toBeFalsy + expect(Character.isUnicodeIdentifierStart('\uecf0')).toBeFalsy + expect(Character.isUnicodeIdentifierStart('\ude48')).toBeFalsy + expect(Character.isUnicodeIdentifierStart('\u0a3b')).toBeFalsy + expect(Character.isUnicodeIdentifierStart('\u20b8')).toBeFalsy + expect(Character.isUnicodeIdentifierStart('\uf898')).toBeFalsy + expect(Character.isUnicodeIdentifierStart('\u23e6')).toBeFalsy + expect(Character.isUnicodeIdentifierStart('\ud8ba')).toBeFalsy + expect(Character.isUnicodeIdentifierStart('\uda1e')).toBeFalsy + expect(Character.isUnicodeIdentifierStart('\udc12')).toBeFalsy + expect(Character.isUnicodeIdentifierStart('\u2a06')).toBeFalsy + expect(Character.isUnicodeIdentifierStart('\u0888')).toBeFalsy + expect(Character.isUnicodeIdentifierStart('\ud9ec')).toBeFalsy + expect(Character.isUnicodeIdentifierStart('\uf81f')).toBeFalsy + expect(Character.isUnicodeIdentifierStart('\uf817')).toBeFalsy + } + + it("should provide isUnicodeIdentifierPart") { + // 100 randomly generated positives and 100 randomly generated negatives + + expect(Character.isUnicodeIdentifierPart('\u48d3')).toBeTruthy + expect(Character.isUnicodeIdentifierPart('\u0905')).toBeTruthy + expect(Character.isUnicodeIdentifierPart('\u8f51')).toBeTruthy + expect(Character.isUnicodeIdentifierPart('\u9bcb')).toBeTruthy + expect(Character.isUnicodeIdentifierPart('\ud358')).toBeTruthy + expect(Character.isUnicodeIdentifierPart('\u1538')).toBeTruthy + expect(Character.isUnicodeIdentifierPart('\uffcf')).toBeTruthy + expect(Character.isUnicodeIdentifierPart('\u83ec')).toBeTruthy + expect(Character.isUnicodeIdentifierPart('\u3a89')).toBeTruthy + expect(Character.isUnicodeIdentifierPart('\ub63a')).toBeTruthy + expect(Character.isUnicodeIdentifierPart('\ufe24')).toBeTruthy + expect(Character.isUnicodeIdentifierPart('\u2d62')).toBeTruthy + expect(Character.isUnicodeIdentifierPart('\u15ca')).toBeTruthy + expect(Character.isUnicodeIdentifierPart('\u4fa4')).toBeTruthy + expect(Character.isUnicodeIdentifierPart('\u47d1')).toBeTruthy + expect(Character.isUnicodeIdentifierPart('\u831c')).toBeTruthy + expect(Character.isUnicodeIdentifierPart('\u84e6')).toBeTruthy + expect(Character.isUnicodeIdentifierPart('\u7783')).toBeTruthy + expect(Character.isUnicodeIdentifierPart('\ua03c')).toBeTruthy + expect(Character.isUnicodeIdentifierPart('\u6ecf')).toBeTruthy + expect(Character.isUnicodeIdentifierPart('\u147f')).toBeTruthy + expect(Character.isUnicodeIdentifierPart('\u67a9')).toBeTruthy + expect(Character.isUnicodeIdentifierPart('\u8b6c')).toBeTruthy + expect(Character.isUnicodeIdentifierPart('\u3410')).toBeTruthy + expect(Character.isUnicodeIdentifierPart('\u2cc0')).toBeTruthy + expect(Character.isUnicodeIdentifierPart('\ua332')).toBeTruthy + expect(Character.isUnicodeIdentifierPart('\u9733')).toBeTruthy + expect(Character.isUnicodeIdentifierPart('\u5df3')).toBeTruthy + expect(Character.isUnicodeIdentifierPart('\u3fd7')).toBeTruthy + expect(Character.isUnicodeIdentifierPart('\u6611')).toBeTruthy + expect(Character.isUnicodeIdentifierPart('\u55b4')).toBeTruthy + expect(Character.isUnicodeIdentifierPart('\u8bc8')).toBeTruthy + expect(Character.isUnicodeIdentifierPart('\u6f74')).toBeTruthy + expect(Character.isUnicodeIdentifierPart('\u6c97')).toBeTruthy + expect(Character.isUnicodeIdentifierPart('\u6a86')).toBeTruthy + expect(Character.isUnicodeIdentifierPart('\u6000')).toBeTruthy + expect(Character.isUnicodeIdentifierPart('\u614f')).toBeTruthy + expect(Character.isUnicodeIdentifierPart('\u206e')).toBeTruthy + expect(Character.isUnicodeIdentifierPart('\ua801')).toBeTruthy + expect(Character.isUnicodeIdentifierPart('\u9edf')).toBeTruthy + expect(Character.isUnicodeIdentifierPart('\ub42c')).toBeTruthy + expect(Character.isUnicodeIdentifierPart('\u7fcd')).toBeTruthy + expect(Character.isUnicodeIdentifierPart('\u8a60')).toBeTruthy + expect(Character.isUnicodeIdentifierPart('\u182f')).toBeTruthy + expect(Character.isUnicodeIdentifierPart('\u5d0a')).toBeTruthy + expect(Character.isUnicodeIdentifierPart('\uaf9c')).toBeTruthy + expect(Character.isUnicodeIdentifierPart('\u9d4b')).toBeTruthy + expect(Character.isUnicodeIdentifierPart('\u5088')).toBeTruthy + expect(Character.isUnicodeIdentifierPart('\uc1a6')).toBeTruthy + expect(Character.isUnicodeIdentifierPart('\ubbe4')).toBeTruthy + expect(Character.isUnicodeIdentifierPart('\uad25')).toBeTruthy + expect(Character.isUnicodeIdentifierPart('\u4653')).toBeTruthy + expect(Character.isUnicodeIdentifierPart('\u8add')).toBeTruthy + expect(Character.isUnicodeIdentifierPart('\u3d1c')).toBeTruthy + expect(Character.isUnicodeIdentifierPart('\u80a8')).toBeTruthy + expect(Character.isUnicodeIdentifierPart('\u810e')).toBeTruthy + expect(Character.isUnicodeIdentifierPart('\uc1d2')).toBeTruthy + expect(Character.isUnicodeIdentifierPart('\ub984')).toBeTruthy + expect(Character.isUnicodeIdentifierPart('\u9d13')).toBeTruthy + expect(Character.isUnicodeIdentifierPart('\u37c2')).toBeTruthy + expect(Character.isUnicodeIdentifierPart('\u13cd')).toBeTruthy + expect(Character.isUnicodeIdentifierPart('\u53f9')).toBeTruthy + expect(Character.isUnicodeIdentifierPart('\u98b7')).toBeTruthy + expect(Character.isUnicodeIdentifierPart('\u57f3')).toBeTruthy + expect(Character.isUnicodeIdentifierPart('\ub554')).toBeTruthy + expect(Character.isUnicodeIdentifierPart('\u0176')).toBeTruthy + expect(Character.isUnicodeIdentifierPart('\ua318')).toBeTruthy + expect(Character.isUnicodeIdentifierPart('\u9704')).toBeTruthy + expect(Character.isUnicodeIdentifierPart('\u8d52')).toBeTruthy + expect(Character.isUnicodeIdentifierPart('\u940a')).toBeTruthy + expect(Character.isUnicodeIdentifierPart('\u0fa5')).toBeTruthy + expect(Character.isUnicodeIdentifierPart('\u38d1')).toBeTruthy + expect(Character.isUnicodeIdentifierPart('\u3b33')).toBeTruthy + expect(Character.isUnicodeIdentifierPart('\u93bb')).toBeTruthy + expect(Character.isUnicodeIdentifierPart('\u03bd')).toBeTruthy + expect(Character.isUnicodeIdentifierPart('\u4c88')).toBeTruthy + expect(Character.isUnicodeIdentifierPart('\ud67d')).toBeTruthy + expect(Character.isUnicodeIdentifierPart('\ubcbf')).toBeTruthy + expect(Character.isUnicodeIdentifierPart('\u3867')).toBeTruthy + expect(Character.isUnicodeIdentifierPart('\u4368')).toBeTruthy + expect(Character.isUnicodeIdentifierPart('\u8f2d')).toBeTruthy + expect(Character.isUnicodeIdentifierPart('\u049a')).toBeTruthy + expect(Character.isUnicodeIdentifierPart('\u4c01')).toBeTruthy + expect(Character.isUnicodeIdentifierPart('\u5589')).toBeTruthy + expect(Character.isUnicodeIdentifierPart('\u5e71')).toBeTruthy + expect(Character.isUnicodeIdentifierPart('\ua1fd')).toBeTruthy + expect(Character.isUnicodeIdentifierPart('\u3a4a')).toBeTruthy + expect(Character.isUnicodeIdentifierPart('\uc111')).toBeTruthy + expect(Character.isUnicodeIdentifierPart('\ub465')).toBeTruthy + expect(Character.isUnicodeIdentifierPart('\u95af')).toBeTruthy + expect(Character.isUnicodeIdentifierPart('\ubf2c')).toBeTruthy + expect(Character.isUnicodeIdentifierPart('\u8488')).toBeTruthy + expect(Character.isUnicodeIdentifierPart('\u4317')).toBeTruthy + expect(Character.isUnicodeIdentifierPart('\u6b77')).toBeTruthy + expect(Character.isUnicodeIdentifierPart('\u8995')).toBeTruthy + expect(Character.isUnicodeIdentifierPart('\u7467')).toBeTruthy + expect(Character.isUnicodeIdentifierPart('\u16b7')).toBeTruthy + expect(Character.isUnicodeIdentifierPart('\u3ca0')).toBeTruthy + expect(Character.isUnicodeIdentifierPart('\u5332')).toBeTruthy + expect(Character.isUnicodeIdentifierPart('\u8654')).toBeTruthy + expect(Character.isUnicodeIdentifierPart('\ua8c8')).toBeFalsy + expect(Character.isUnicodeIdentifierPart('\ue3ca')).toBeFalsy + expect(Character.isUnicodeIdentifierPart('\uebee')).toBeFalsy + expect(Character.isUnicodeIdentifierPart('\u270e')).toBeFalsy + expect(Character.isUnicodeIdentifierPart('\uf0ac')).toBeFalsy + expect(Character.isUnicodeIdentifierPart('\ue9ec')).toBeFalsy + expect(Character.isUnicodeIdentifierPart('\u296a')).toBeFalsy + expect(Character.isUnicodeIdentifierPart('\u33fd')).toBeFalsy + expect(Character.isUnicodeIdentifierPart('\ue5f4')).toBeFalsy + expect(Character.isUnicodeIdentifierPart('\ueb01')).toBeFalsy + expect(Character.isUnicodeIdentifierPart('\uf38b')).toBeFalsy + expect(Character.isUnicodeIdentifierPart('\u2e6f')).toBeFalsy + expect(Character.isUnicodeIdentifierPart('\uea69')).toBeFalsy + expect(Character.isUnicodeIdentifierPart('\uf155')).toBeFalsy + expect(Character.isUnicodeIdentifierPart('\u0f0e')).toBeFalsy + expect(Character.isUnicodeIdentifierPart('\ueb80')).toBeFalsy + expect(Character.isUnicodeIdentifierPart('\ud959')).toBeFalsy + expect(Character.isUnicodeIdentifierPart('\ue25e')).toBeFalsy + expect(Character.isUnicodeIdentifierPart('\uf566')).toBeFalsy + expect(Character.isUnicodeIdentifierPart('\ue4a3')).toBeFalsy + expect(Character.isUnicodeIdentifierPart('\uec44')).toBeFalsy + expect(Character.isUnicodeIdentifierPart('\u3297')).toBeFalsy + expect(Character.isUnicodeIdentifierPart('\u3214')).toBeFalsy + expect(Character.isUnicodeIdentifierPart('\u1bfd')).toBeFalsy + expect(Character.isUnicodeIdentifierPart('\u4dd0')).toBeFalsy + expect(Character.isUnicodeIdentifierPart('\uea99')).toBeFalsy + expect(Character.isUnicodeIdentifierPart('\u309b')).toBeFalsy + expect(Character.isUnicodeIdentifierPart('\uf592')).toBeFalsy + expect(Character.isUnicodeIdentifierPart('\uf4dd')).toBeFalsy + expect(Character.isUnicodeIdentifierPart('\udfaf')).toBeFalsy + expect(Character.isUnicodeIdentifierPart('\udd38')).toBeFalsy + expect(Character.isUnicodeIdentifierPart('\uf820')).toBeFalsy + expect(Character.isUnicodeIdentifierPart('\uaacd')).toBeFalsy + expect(Character.isUnicodeIdentifierPart('\uff5b')).toBeFalsy + expect(Character.isUnicodeIdentifierPart('\ude36')).toBeFalsy + expect(Character.isUnicodeIdentifierPart('\ue33b')).toBeFalsy + expect(Character.isUnicodeIdentifierPart('\udbce')).toBeFalsy + expect(Character.isUnicodeIdentifierPart('\ue1f6')).toBeFalsy + expect(Character.isUnicodeIdentifierPart('\uf78a')).toBeFalsy + expect(Character.isUnicodeIdentifierPart('\ueb44')).toBeFalsy + expect(Character.isUnicodeIdentifierPart('\uebd4')).toBeFalsy + expect(Character.isUnicodeIdentifierPart('\u1df7')).toBeFalsy + expect(Character.isUnicodeIdentifierPart('\u2f10')).toBeFalsy + expect(Character.isUnicodeIdentifierPart('\u1cbf')).toBeFalsy + expect(Character.isUnicodeIdentifierPart('\u2362')).toBeFalsy + expect(Character.isUnicodeIdentifierPart('\uebeb')).toBeFalsy + expect(Character.isUnicodeIdentifierPart('\u2ede')).toBeFalsy + expect(Character.isUnicodeIdentifierPart('\u221d')).toBeFalsy + expect(Character.isUnicodeIdentifierPart('\u2021')).toBeFalsy + expect(Character.isUnicodeIdentifierPart('\udf41')).toBeFalsy + expect(Character.isUnicodeIdentifierPart('\u05f5')).toBeFalsy + expect(Character.isUnicodeIdentifierPart('\u24ab')).toBeFalsy + expect(Character.isUnicodeIdentifierPart('\uee15')).toBeFalsy + expect(Character.isUnicodeIdentifierPart('\uf175')).toBeFalsy + expect(Character.isUnicodeIdentifierPart('\uf35c')).toBeFalsy + expect(Character.isUnicodeIdentifierPart('\udc7b')).toBeFalsy + expect(Character.isUnicodeIdentifierPart('\ud883')).toBeFalsy + expect(Character.isUnicodeIdentifierPart('\uf341')).toBeFalsy + expect(Character.isUnicodeIdentifierPart('\ueec6')).toBeFalsy + expect(Character.isUnicodeIdentifierPart('\u2f57')).toBeFalsy + expect(Character.isUnicodeIdentifierPart('\uff64')).toBeFalsy + expect(Character.isUnicodeIdentifierPart('\ue6a4')).toBeFalsy + expect(Character.isUnicodeIdentifierPart('\uec34')).toBeFalsy + expect(Character.isUnicodeIdentifierPart('\u22a5')).toBeFalsy + expect(Character.isUnicodeIdentifierPart('\uf5ac')).toBeFalsy + expect(Character.isUnicodeIdentifierPart('\u3360')).toBeFalsy + expect(Character.isUnicodeIdentifierPart('\u28b0')).toBeFalsy + expect(Character.isUnicodeIdentifierPart('\uf678')).toBeFalsy + expect(Character.isUnicodeIdentifierPart('\ue0e4')).toBeFalsy + expect(Character.isUnicodeIdentifierPart('\u233f')).toBeFalsy + expect(Character.isUnicodeIdentifierPart('\u0afa')).toBeFalsy + expect(Character.isUnicodeIdentifierPart('\u2013')).toBeFalsy + expect(Character.isUnicodeIdentifierPart('\ud7af')).toBeFalsy + expect(Character.isUnicodeIdentifierPart('\ud98e')).toBeFalsy + expect(Character.isUnicodeIdentifierPart('\ud8a5')).toBeFalsy + + // BUG in JDK? A79E should be "Lu", Java says "Cn" + // expect(Character.isUnicodeIdentifierPart('\ua79e')).toBeFalsy + + expect(Character.isUnicodeIdentifierPart('\u1806')).toBeFalsy + expect(Character.isUnicodeIdentifierPart('\ue07a')).toBeFalsy + expect(Character.isUnicodeIdentifierPart('\u2748')).toBeFalsy + expect(Character.isUnicodeIdentifierPart('\uabad')).toBeFalsy + expect(Character.isUnicodeIdentifierPart('\uec5c')).toBeFalsy + expect(Character.isUnicodeIdentifierPart('\ue832')).toBeFalsy + + // BUG in JDK? 08A9 should be "Lo", Java says "Cn" + // expect(Character.isUnicodeIdentifierPart('\u08a9')).toBeFalsy + + expect(Character.isUnicodeIdentifierPart('\ue4bd')).toBeFalsy + expect(Character.isUnicodeIdentifierPart('\u208a')).toBeFalsy + expect(Character.isUnicodeIdentifierPart('\uf840')).toBeFalsy + expect(Character.isUnicodeIdentifierPart('\uf570')).toBeFalsy + expect(Character.isUnicodeIdentifierPart('\uef1e')).toBeFalsy + expect(Character.isUnicodeIdentifierPart('\u2bd4')).toBeFalsy + expect(Character.isUnicodeIdentifierPart('\ue385')).toBeFalsy + expect(Character.isUnicodeIdentifierPart('\udc18')).toBeFalsy + expect(Character.isUnicodeIdentifierPart('\u0af0')).toBeFalsy + expect(Character.isUnicodeIdentifierPart('\u244a')).toBeFalsy + expect(Character.isUnicodeIdentifierPart('\uf01e')).toBeFalsy + expect(Character.isUnicodeIdentifierPart('\uf114')).toBeFalsy + expect(Character.isUnicodeIdentifierPart('\ue9c4')).toBeFalsy + + // BUG in JDK? AAF4 should be "Lm", Java says "Cn" + // expect(Character.isUnicodeIdentifierPart('\uaaf4')).toBeFalsy + + expect(Character.isUnicodeIdentifierPart('\uf7b9')).toBeFalsy + expect(Character.isUnicodeIdentifierPart('\udd2f')).toBeFalsy + expect(Character.isUnicodeIdentifierPart('\u2d2c')).toBeFalsy + } + + } +} diff --git a/test-suite/src/test/scala/scala/scalajs/testsuite/javalib/ClassTest.scala b/test-suite/src/test/scala/scala/scalajs/testsuite/javalib/ClassTest.scala new file mode 100644 index 0000000..424edd6 --- /dev/null +++ b/test-suite/src/test/scala/scala/scalajs/testsuite/javalib/ClassTest.scala @@ -0,0 +1,30 @@ +/* __ *\ +** ________ ___ / / ___ __ ____ Scala.js Test Suite ** +** / __/ __// _ | / / / _ | __ / // __/ (c) 2013, LAMP/EPFL ** +** __\ \/ /__/ __ |/ /__/ __ |/_// /_\ \ http://scala-js.org/ ** +** /____/\___/_/ |_/____/_/ | |__/ /____/ ** +** |/____/ ** +\* */ +package scala.scalajs.testsuite.javalib + +import org.scalajs.jasminetest.JasmineTest +import scala.scalajs.js + +object ClassTest extends JasmineTest { + + describe("java.lang.Class") { + + it("should provide getSimpleName()") { + expect(classOf[java.lang.Integer].getSimpleName()).toEqual("Integer") + expect(classOf[java.lang.Class[_]].getSimpleName()).toEqual("Class") + expect(classOf[scala.collection.Map[_, _]].getSimpleName()).toEqual("Map") + expect(classOf[ClassTestClass#InnerClass].getSimpleName()).toEqual("InnerClass") + } + + } + +} + +class ClassTestClass { + class InnerClass +} diff --git a/test-suite/src/test/scala/scala/scalajs/testsuite/javalib/DateTest.scala b/test-suite/src/test/scala/scala/scalajs/testsuite/javalib/DateTest.scala new file mode 100644 index 0000000..f62f926 --- /dev/null +++ b/test-suite/src/test/scala/scala/scalajs/testsuite/javalib/DateTest.scala @@ -0,0 +1,87 @@ +/* __ *\ +** ________ ___ / / ___ __ ____ Scala.js Test Suite ** +** / __/ __// _ | / / / _ | __ / // __/ (c) 2013, LAMP/EPFL ** +** __\ \/ /__/ __ |/ /__/ __ |/_// /_\ \ http://scala-js.org/ ** +** /____/\___/_/ |_/____/_/ | |__/ /____/ ** +** |/____/ ** +\* */ +package scala.scalajs.testsuite.javalib + +import java.util.Date + +import org.scalajs.jasminetest.JasmineTest + +/** + * tests the implementation of the java standard library Date + */ +object DateTest extends JasmineTest { + + describe("java.lang.Date") { + + it("should provide `compareTo`") { + def compare(x: Date, y: Date): Int = { + x.compareTo(y) + } + + expect(compare(new Date(97, 11, 5, 0, 0), new Date(98, 11, 5, 0, 0))).toBeLessThan(0) + expect(compare(new Date(98, 11, 5, 0, 0), new Date(97, 11, 5, 0, 0))).toBeGreaterThan(0) + expect(compare(new Date(97, 11, 5, 0, 0), new Date(97, 11, 5))).toEqual(0) + expect(compare(new Date(97, 11, 5, 0, 0), new Date(97, 11, 5, 0, 1))).toBeLessThan(0) + expect(compare(new Date(97, 11, 5), new Date(97, 11, 5, 0, 0))).toEqual(0) + } + + it("should be a Comparable") { + def compare(x: Any, y: Any): Int = + x.asInstanceOf[Comparable[Any]].compareTo(y) + + expect(compare(new Date(97, 11, 5, 0, 0), new Date(98, 11, 5, 0, 0))).toBeLessThan(0) + expect(compare(new Date(98, 11, 5, 0, 0), new Date(97, 11, 5, 0, 0))).toBeGreaterThan(0) + expect(compare(new Date(97, 11, 5, 0, 0), new Date(97, 11, 5))).toEqual(0) + expect(compare(new Date(97, 11, 5, 0, 0), new Date(97, 11, 5, 0, 1))).toBeLessThan(0) + expect(compare(new Date(97, 11, 5), new Date(97, 11, 5, 0, 0))).toEqual(0) + } + + it("should parse strings") { + def test(s: String, v: Date): Unit = + expect(new Date(s).compareTo(v)).toEqual(0) + + test("Nov 5 1997 5:23:27 GMT", new Date(Date.UTC(97, 10, 5, 5, 23, 27))) + test("Nov 1 1997 GMT", new Date(Date.UTC(97,10,1, 0, 0, 0))) + test("Jan 1 1970 18:11:01 GMT", new Date(Date.UTC(70,0,1,18,11,1))) + } + + it("should provide after") { + expect(new Date(97, 11, 5, 0, 0).after(new Date(98, 11, 5, 0, 0))).toBe(false) + expect(new Date(99, 11, 5, 0, 0).after(new Date(98, 11, 5, 0, 0))).toBe(true) + expect(new Date(99, 11, 5, 0, 0).after(new Date(99, 11, 5, 0, 0))).toBe(false) + } + + it("should provide before") { + expect(new Date(97, 11, 5, 0, 0).before(new Date(98, 11, 5, 0, 0))).toBe(true) + expect(new Date(99, 11, 5, 0, 0).before(new Date(98, 11, 5, 0, 0))).toBe(false) + expect(new Date(99, 11, 5, 0, 0).before(new Date(99, 11, 5, 0, 0))).toBe(false) + } + + it("should provide clone") { + def testClone(date: Date) = { + val cloned = date.clone() + date == cloned + } + + expect(testClone(new Date(97, 11, 5, 0, 0))).toBe(true) + expect(testClone(new Date(92, 14, 6, 2, 1))).toBe(true) + expect(testClone(new Date(4, 1, 2, 3, 0, 0))).toBe(true) + } + + it("should respond to getYear") { + def testYear(year: Int) = { + val date = new Date() + date.setYear(year) + expect(date.getYear).toEqual(year) + } + testYear(1940) + testYear(1920) + testYear(2030) + } + } +} diff --git a/test-suite/src/test/scala/scala/scalajs/testsuite/javalib/DoubleTest.scala b/test-suite/src/test/scala/scala/scalajs/testsuite/javalib/DoubleTest.scala new file mode 100644 index 0000000..59c6e10 --- /dev/null +++ b/test-suite/src/test/scala/scala/scalajs/testsuite/javalib/DoubleTest.scala @@ -0,0 +1,217 @@ +/* __ *\ +** ________ ___ / / ___ __ ____ Scala.js Test Suite ** +** / __/ __// _ | / / / _ | __ / // __/ (c) 2013, LAMP/EPFL ** +** __\ \/ /__/ __ |/ /__/ __ |/_// /_\ \ http://scala-js.org/ ** +** /____/\___/_/ |_/____/_/ | |__/ /____/ ** +** |/____/ ** +\* */ +package scala.scalajs.testsuite.javalib + +import org.scalajs.jasminetest.JasmineTest +import scala.scalajs.js + +import java.lang.{Double => JDouble} + +import scala.util.Try + +object DoubleTest extends JasmineTest { + + describe("java.lang.Double") { + + it("should provide proper `equals`") { + expect(Double.box(0.0) == Double.box(-0.0)).toBeTruthy + expect(Double.box(Double.NaN) == Double.box(Double.NaN)).toBeTruthy + } + + it("hashCode") { + def hashCodeNotInlined(x: Any): Int = { + var y = x // do not inline + y.hashCode + } + + def test(x: Double, expected: Int): Unit = { + expect(x.hashCode).toEqual(expected) + expect(hashCodeNotInlined(x)).toEqual(expected) + } + + test(0.0, 0) + test(-0.0, 0) + test(1234.0, 1234) + test(1.5, 1073217536) + test(Math.PI, 340593891) + test(-54.0, -54) + + test(Double.MinPositiveValue, 1) + test(Double.MinValue, 1048576) + test(Double.MaxValue, -2146435072) + + test(Double.NaN, 2146959360) + test(Double.PositiveInfinity, 2146435072) + test(Double.NegativeInfinity, -1048576) + } + + it("should provide `toString` with integer values when an integer") { + expect(0.0.toString).toEqual("0") + expect(-0.0.toString).toEqual("0") + expect(Double.NaN.toString).toEqual("NaN") + expect(Double.PositiveInfinity.toString).toEqual("Infinity") + expect(Double.NegativeInfinity.toString).toEqual("-Infinity") + expect(5.0.toString).toEqual("5") + expect(-5.0.toString).toEqual("-5") + expect(1.2.toString).toEqual("1.2") + } + + it("should parse strings") { + expect("0.0".toDouble).toEqual(0.0f) + expect("NaN".toDouble.isNaN).toBeTruthy + expect(Try("asdf".toDouble).isFailure).toBeTruthy + + def test(s: String, v: Double): Unit = { + expect(JDouble.parseDouble(s)).toBeCloseTo(v) + expect(JDouble.valueOf(s).doubleValue()).toBeCloseTo(v) + expect(new JDouble(s).doubleValue()).toBeCloseTo(v) + } + + test("0", 0.0) + test("5.3", 5.3) + test("127e2", 12700.0) + test("127E-2", 1.27) + test("1E+1", 10) + test("-123.4", -123.4) + test("65432.1", 65432.10) + test("-87654.321", -87654.321) + test("+.3f", 0.3) + } + + it("should reject invalid strings when parsing") { + def test(s: String): Unit = + expect(() => JDouble.parseDouble(s)).toThrow + + test("4.3.5") + test("4e3.5") + test("hello world") + test("--4") + test("4E-3.2") + } + + it("should provide `compareTo`") { + def compare(x: Double, y: Double): Int = + new JDouble(x).compareTo(new JDouble(y)) + + expect(compare(0.0, 5.5)).toBeLessThan(0) + expect(compare(10.5, 10.2)).toBeGreaterThan(0) + expect(compare(-2.1, -1.0)).toBeLessThan(0) + expect(compare(3.14, 3.14)).toEqual(0) + + // From compareTo's point of view, NaN is equal to NaN + expect(compare(Double.NaN, Double.NaN)).toEqual(0) + } + + it("should be a Comparable") { + def compare(x: Any, y: Any): Int = + x.asInstanceOf[Comparable[Any]].compareTo(y) + + expect(compare(0.0, 5.5)).toBeLessThan(0) + expect(compare(10.5, 10.2)).toBeGreaterThan(0) + expect(compare(-2.1, -1.0)).toBeLessThan(0) + expect(compare(3.14, 3.14)).toEqual(0) + + // From compareTo's point of view, NaN is equal to NaN + expect(compare(Double.NaN, Double.NaN)).toEqual(0) + } + + it("should provide isInfinite - #515") { + expect(Double.PositiveInfinity.isInfinite).toBeTruthy + expect(Double.NegativeInfinity.isInfinite).toBeTruthy + expect((1.0/0).isInfinite).toBeTruthy + expect((-1.0/0).isInfinite).toBeTruthy + expect((0.0).isInfinite).toBeFalsy + } + + it("isNaN") { + def f(v: Double): Boolean = { + var v2 = v // do not inline + v2.isNaN + } + + expect(f(Double.NaN)).toBeTruthy + + expect(f(Double.PositiveInfinity)).toBeFalsy + expect(f(Double.NegativeInfinity)).toBeFalsy + expect(f(1.0 / 0)).toBeFalsy + expect(f(-1.0 / 0)).toBeFalsy + expect(f(0.0)).toBeFalsy + expect(f(3.0)).toBeFalsy + expect(f(-1.5)).toBeFalsy + } + + it("longBitsToDouble") { + def isZero(v: Double, neg: Boolean): Boolean = { + (v == 0.0) && (1 / v == ( + if (neg) Double.NegativeInfinity + else Double.PositiveInfinity)) + } + + import JDouble.{longBitsToDouble => f} + + // Specials + expect(f(0x7ff0000000000000L)).toEqual(Double.PositiveInfinity) + expect(f(0xfff0000000000000L)).toEqual(Double.NegativeInfinity) + expect(isZero(f(0x0000000000000000L), false)).toBeTruthy + expect(isZero(f(0x8000000000000000L), true)).toBeTruthy + expect(f(0x7ff8000000000000L).isNaN).toBeTruthy // canonical NaN + + // Non-canonical NaNs + expect(f(0x7ff0000000000001L).isNaN).toBeTruthy // smallest positive NaN + expect(f(0x7ff15ab515d3cca1L).isNaN).toBeTruthy // an arbitrary positive NaN + expect(f(0x7fffffffffffffffL).isNaN).toBeTruthy // largest positive NaN + expect(f(0xfff0000000000001L).isNaN).toBeTruthy // smallest negative NaN + expect(f(0xfff15ab515d3cca1L).isNaN).toBeTruthy // an arbitrary negative NaN + expect(f(0xffffffffffffffffL).isNaN).toBeTruthy // largest negative NaN + + // Normal forms + expect(f(0x0010000000000000L)).toEqual(2.2250738585072014e-308) // smallest pos normal form + expect(f(0x7fefffffffffffffL)).toEqual(1.7976931348623157e308) // largest pos normal form + expect(f(0x4d124568bc6584caL)).toEqual(1.8790766677624813e63) // an arbitrary pos normal form + expect(f(0x8010000000000000L)).toEqual(-2.2250738585072014e-308) // smallest neg normal form + expect(f(0xffefffffffffffffL)).toEqual(-1.7976931348623157e308) // largest neg normal form + expect(f(0xcd124568bc6584caL)).toEqual(-1.8790766677624813e63) // an arbitrary neg normal form + + // Subnormal forms + expect(f(0x0000000000000001L)).toEqual(Double.MinPositiveValue) // smallest pos subnormal form + expect(f(0x000fffffffffffffL)).toEqual(2.225073858507201e-308) // largest pos subnormal form + expect(f(0x000c5d44ae45cb60L)).toEqual(1.719471609939382e-308) // an arbitrary pos subnormal form + expect(f(0x8000000000000001L)).toEqual(-Double.MinPositiveValue) // smallest neg subnormal form + expect(f(0x800fffffffffffffL)).toEqual(-2.225073858507201e-308) // largest neg subnormal form + expect(f(0x800c5d44ae45cb60L)).toEqual(-1.719471609939382e-308) // an arbitrary neg subnormal form + } + + it("doubleToLongBits") { + import JDouble.{doubleToLongBits => f} + + // Specials + expect(f(Double.PositiveInfinity) == 0x7ff0000000000000L).toBeTruthy + expect(f(Double.NegativeInfinity) == 0xfff0000000000000L) + expect(f(0.0) == 0x0000000000000000L).toBeTruthy + expect(f(-0.0) == 0x8000000000000000L).toBeTruthy + expect(f(Double.NaN) == 0x7ff8000000000000L).toBeTruthy // canonical NaN + + // Normal forms + expect(f(2.2250738585072014e-308) == 0x0010000000000000L).toBeTruthy // smallest pos normal form + expect(f(1.7976931348623157e308) == 0x7fefffffffffffffL).toBeTruthy // largest pos normal form + expect(f(1.8790766677624813e63) == 0x4d124568bc6584caL).toBeTruthy // an arbitrary pos normal form + expect(f(-2.2250738585072014e-308) == 0x8010000000000000L).toBeTruthy // smallest neg normal form + expect(f(-1.7976931348623157e308) == 0xffefffffffffffffL).toBeTruthy // largest neg normal form + expect(f(-1.8790766677624813e63) == 0xcd124568bc6584caL).toBeTruthy // an arbitrary neg normal form + + // Subnormal forms + expect(f(Double.MinPositiveValue) == 0x0000000000000001L).toBeTruthy // smallest pos subnormal form + expect(f(2.225073858507201e-308) == 0x000fffffffffffffL).toBeTruthy // largest pos subnormal form + expect(f(1.719471609939382e-308) == 0x000c5d44ae45cb60L).toBeTruthy // an arbitrary pos subnormal form + expect(f(-Double.MinPositiveValue) == 0x8000000000000001L).toBeTruthy // smallest neg subnormal form + expect(f(-2.225073858507201e-308) == 0x800fffffffffffffL).toBeTruthy // largest neg subnormal form + expect(f(-1.719471609939382e-308) == 0x800c5d44ae45cb60L).toBeTruthy // an arbitrary neg subnormal form + } + + } +} diff --git a/test-suite/src/test/scala/scala/scalajs/testsuite/javalib/FloatTest.scala b/test-suite/src/test/scala/scala/scalajs/testsuite/javalib/FloatTest.scala new file mode 100644 index 0000000..e45a34a --- /dev/null +++ b/test-suite/src/test/scala/scala/scalajs/testsuite/javalib/FloatTest.scala @@ -0,0 +1,221 @@ +/* __ *\ +** ________ ___ / / ___ __ ____ Scala.js Test Suite ** +** / __/ __// _ | / / / _ | __ / // __/ (c) 2013, LAMP/EPFL ** +** __\ \/ /__/ __ |/ /__/ __ |/_// /_\ \ http://scala-js.org/ ** +** /____/\___/_/ |_/____/_/ | |__/ /____/ ** +** |/____/ ** +\* */ +package scala.scalajs.testsuite.javalib + +import org.scalajs.jasminetest.JasmineTest +import scala.scalajs.js + +import java.lang.{Float => JFloat} + +import scala.util.Try + +object FloatTest extends JasmineTest { + + describe("java.lang.Float") { + + it("should provide proper `equals`") { + expect(Float.box(0.0f) == Float.box(-0.0f)).toBeTruthy + expect(Float.box(Float.NaN) == Float.box(Float.NaN)).toBeTruthy + } + + it("hashCode") { + def hashCodeNotInlined(x: Any): Int = { + var y = x // do not inline + y.hashCode + } + + def test(x: Float, expected: Int): Unit = { + expect(x.hashCode).toEqual(expected) + expect(hashCodeNotInlined(x)).toEqual(expected) + } + + test(0.0f, 0) + test(-0.0f, 0) + test(1234.0f, 1234) + test(1.5f, 1073217536) + test(-54f, -54) + + test(Float.MinPositiveValue, 916455424) + test(Float.MinValue, 670040063) + test(Float.MaxValue, -1477443585) + + test(Float.NaN, 2146959360) + test(Float.PositiveInfinity, 2146435072) + test(Float.NegativeInfinity, -1048576) + } + + it("should provide `toString` with integer values when an integer") { + expect(0.0f.toString).toEqual("0") + expect(-0.0f.toString).toEqual("0") + expect(Float.NaN.toString).toEqual("NaN") + expect(Float.PositiveInfinity.toString).toEqual("Infinity") + expect(Float.NegativeInfinity.toString).toEqual("-Infinity") + expect(5.0f.toString).toEqual("5") + expect(-5.0f.toString).toEqual("-5") + + // We need to explicitly cut the string here, since floats are + // represented by doubles (but the literal is emitted as + // float). Therefore there may be some imprecision. This is + // documented as semantic difference. + expect(1.2f.toString.substring(0,3)).toEqual("1.2") + } + + it("should parse strings") { + expect("0.0".toFloat).toEqual(0.0f) + expect("NaN".toFloat.isNaN).toBeTruthy + expect(Try("asdf".toFloat).isFailure).toBeTruthy + + def test(s: String, v: Float): Unit = { + expect(JFloat.parseFloat(s)).toBeCloseTo(v) + expect(JFloat.valueOf(s).floatValue()).toBeCloseTo(v) + expect(new JFloat(s).floatValue()).toBeCloseTo(v) + } + + test("0", 0.0f) + test("5.3", 5.3f) + test("127e2", 12700.0f) + test("127E-2", 1.27f) + test("1E+1", 10f) + test("-123.4", -123.4f) + test("65432.1", 65432.10f) + test("-87654.321", -87654.321f) + test("+.3f", 0.3f) + } + + it("should reject invalid strings when parsing") { + def test(s: String): Unit = + expect(() => JFloat.parseFloat(s)).toThrow + + test("4.3.5") + test("4e3.5") + test("hello world") + test("--4") + test("4E-3.2") + } + + it("should provide `compareTo`") { + def compare(x: Float, y: Float): Int = + new JFloat(x).compareTo(new JFloat(y)) + + expect(compare(0.0f, 5.5f)).toBeLessThan(0) + expect(compare(10.5f, 10.2f)).toBeGreaterThan(0) + expect(compare(-2.1f, -1.0f)).toBeLessThan(0) + expect(compare(3.14f, 3.14f)).toEqual(0) + + // From compareTo's point of view, NaN is equal to NaN + expect(compare(Float.NaN, Float.NaN)).toEqual(0) + } + + it("should be a Comparable") { + def compare(x: Any, y: Any): Int = + x.asInstanceOf[Comparable[Any]].compareTo(y) + + expect(compare(0.0f, 5.5f)).toBeLessThan(0) + expect(compare(10.5f, 10.2f)).toBeGreaterThan(0) + expect(compare(-2.1f, -1.0f)).toBeLessThan(0) + expect(compare(3.14f, 3.14f)).toEqual(0) + + // From compareTo's point of view, NaN is equal to NaN + expect(compare(Float.NaN, Float.NaN)).toEqual(0) + } + + it("should provide isInfinite - #515") { + expect(Float.PositiveInfinity.isInfinite).toBeTruthy + expect(Float.NegativeInfinity.isInfinite).toBeTruthy + expect((1f/0).isInfinite).toBeTruthy + expect((-1f/0).isInfinite).toBeTruthy + expect(0f.isInfinite).toBeFalsy + } + + it("isNaN") { + def f(v: Float): Boolean = { + var v2 = v // do not inline + v2.isNaN + } + + expect(f(Float.NaN)).toBeTruthy + + expect(f(Float.PositiveInfinity)).toBeFalsy + expect(f(Float.NegativeInfinity)).toBeFalsy + expect(f(1f / 0)).toBeFalsy + expect(f(-1f / 0)).toBeFalsy + expect(f(0f)).toBeFalsy + expect(f(3f)).toBeFalsy + expect(f(-1.5f)).toBeFalsy + } + + it("intBitsToFloat") { + def isZero(v: Float, neg: Boolean): Boolean = { + (v == 0.0f) && (1 / v == ( + if (neg) Float.NegativeInfinity + else Float.PositiveInfinity)) + } + + import JFloat.{intBitsToFloat => f} + + // Specials + expect(f(0x7f800000)).toEqual(Float.PositiveInfinity) + expect(f(0xff800000)).toEqual(Float.NegativeInfinity) + expect(isZero(f(0x00000000), false)).toBeTruthy + expect(isZero(f(0x80000000), true)).toBeTruthy + expect(f(0x7fc00000).isNaN).toBeTruthy // canonical NaN + + // Non-canonical NaNs + expect(f(0x7f800001).isNaN).toBeTruthy // smallest positive NaN + expect(f(0x7f915ab5).isNaN).toBeTruthy // an arbitrary positive NaN + expect(f(0x7fffffff).isNaN).toBeTruthy // largest positive NaN + expect(f(0xff800001).isNaN).toBeTruthy // smallest negative NaN + expect(f(0xff915ab5).isNaN).toBeTruthy // an arbitrary negative NaN + expect(f(0xffffffff).isNaN).toBeTruthy // largest negative NaN + + // Normal forms + expect(f(0x00800000)).toEqual(1.17549435e-38f) // smallest pos normal form + expect(f(0x7f7fffff)).toEqual(3.4028234e38f) // largest pos normal form + expect(f(0x4d124568)).toEqual(1.53376384e8f) // an arbitrary pos normal form + expect(f(0x80800000)).toEqual(-1.17549435e-38f) // smallest neg normal form + expect(f(0xff7fffff)).toEqual(-3.4028234e38f) // largest neg normal form + expect(f(0xcd124568)).toEqual(-1.53376384e8f) // an arbitrary neg normal form + + // Subnormal forms + expect(f(0x00000001)).toEqual(Float.MinPositiveValue) // smallest pos subnormal form + expect(f(0x007fffff)).toEqual(1.1754942e-38f) // largest pos subnormal form + expect(f(0x007c5d44)).toEqual(1.1421059e-38f) // an arbitrary pos subnormal form + expect(f(0x80000001)).toEqual(-Float.MinPositiveValue) // smallest neg subnormal form + expect(f(0x807fffff)).toEqual(-1.1754942e-38f) // largest neg subnormal form + expect(f(0x807c5d44)).toEqual(-1.1421059e-38f) // an arbitrary neg subnormal form + } + + it("floatToIntBits") { + import JFloat.{floatToIntBits => f} + + // Specials + expect(f(Float.PositiveInfinity)).toEqual(0x7f800000) + expect(f(Float.NegativeInfinity)).toEqual(0xff800000) + expect(f(0.0f)).toEqual(0x00000000) + expect(f(-0.0f)).toEqual(0x80000000) + expect(f(Float.NaN)).toEqual(0x7fc00000) // canonical NaN + + // Normal forms + expect(f(1.17549435e-38f)).toEqual(0x00800000) // smallest pos normal form + expect(f(3.4028234e38f)).toEqual(0x7f7fffff) // largest pos normal form + expect(f(1.53376384e8f)).toEqual(0x4d124568) // an arbitrary pos normal form + expect(f(-1.17549435e-38f)).toEqual(0x80800000) // smallest neg normal form + expect(f(-3.4028234e38f)).toEqual(0xff7fffff) // largest neg normal form + expect(f(-1.53376384e8f)).toEqual(0xcd124568) // an arbitrary neg normal form + + // Subnormal forms + expect(f(Float.MinPositiveValue)).toEqual(0x00000001) // smallest pos subnormal form + expect(f(1.1754942e-38f)).toEqual(0x007fffff) // largest pos subnormal form + expect(f(1.1421059e-38f)).toEqual(0x007c5d44) // an arbitrary pos subnormal form + expect(f(-Float.MinPositiveValue)).toEqual(0x80000001) // smallest neg subnormal form + expect(f(-1.1754942e-38f)).toEqual(0x807fffff) // largest neg subnormal form + expect(f(-1.1421059e-38f)).toEqual(0x807c5d44) // an arbitrary neg subnormal form + } + + } +} diff --git a/test-suite/src/test/scala/scala/scalajs/testsuite/javalib/FormatterTest.scala b/test-suite/src/test/scala/scala/scalajs/testsuite/javalib/FormatterTest.scala new file mode 100644 index 0000000..e7a705c --- /dev/null +++ b/test-suite/src/test/scala/scala/scalajs/testsuite/javalib/FormatterTest.scala @@ -0,0 +1,241 @@ +/* __ *\ +** ________ ___ / / ___ __ ____ Scala.js Test Suite ** +** / __/ __// _ | / / / _ | __ / // __/ (c) 2013, LAMP/EPFL ** +** __\ \/ /__/ __ |/ /__/ __ |/_// /_\ \ http://scala-js.org/ ** +** /____/\___/_/ |_/____/_/ | |__/ /____/ ** +** |/____/ ** +\* */ +package scala.scalajs.testsuite.javalib + +import scala.scalajs.js +import org.scalajs.jasminetest.JasmineTest + +import java.util.{ Formatter, Formattable, FormattableFlags } + +import java.lang.{ + Double => JDouble, + Float => JFloat, + Integer => JInteger, + Long => JLong, + Byte => JByte, + Short => JShort, + Boolean => JBoolean, + String => JString +} + + +object FormatterTest extends JasmineTest { + + class HelperClass + class FormattableClass extends Formattable { + var frm: Formatter = _ + var flags: Int = _ + var width: Int = _ + var precision: Int = _ + var calls = 0 + def formatTo(frm: Formatter, flags: Int, width: Int, precision: Int) = { + this.calls += 1 + this.flags = flags + this.width = width + this.precision = precision + frm.out().append("foobar") + } + + def expectCalled(times: Int, flags: Int, width: Int, precision: Int) = { + expect(this.calls).toEqual(times) + expect(this.flags).toEqual(flags) + expect(this.width).toEqual(width) + expect(this.precision).toEqual(precision) + } + + } + + def expectF(format: String, args: AnyRef*) = { + val fmt = new Formatter() + val res = fmt.format(format, args:_*).toString() + fmt.close() + expect(res) + } + + def expectFC(format: String, flags: Int, width: Int, precision: Int) = { + val fc = new FormattableClass + val exp = expectF(format, fc) + fc.expectCalled(1, flags, width, precision) + exp + } + + def expectThrow(format: String, args: AnyRef*) = { + val fmt = new Formatter() + expect(() => fmt.format(format, args:_*)).toThrow + } + + describe("java.util.Formatter") { + + // Explicitly define these as `var`'s to avoid any compile-time constant folding + var IntMax: Int = Int.MaxValue + var IntMin: Int = Int.MinValue + var ByteMax: Byte = Byte.MaxValue + var ByteMin: Byte = Byte.MinValue + var ShortMax: Short = Short.MaxValue + var ShortMin: Short = Short.MinValue + + it("should provide 'b' conversion") { + expectF("%b", null).toEqual("false") + expectF("%b", true: JBoolean).toEqual(JString.valueOf(true)) + expectF("%b", false: JBoolean).toEqual(JString.valueOf(false)) + expectF("%b", new HelperClass).toEqual("true") + } + + it("should provide 'h' conversion") { + val x = new HelperClass + expectF("%h", x).toEqual(Integer.toHexString(x.hashCode())) + expectF("%H", x).toEqual(Integer.toHexString(x.hashCode()).toUpperCase()) + expectF("%h", null).toEqual("null") + } + + it("should provide 's' conversion") { + expectFC("%s", 0, -1, -1).toEqual("foobar") + expectFC("%-s", FormattableFlags.LEFT_JUSTIFY, -1, -1).toEqual("foobar") + expectFC("%-10s", FormattableFlags.LEFT_JUSTIFY, 10, -1).toEqual("foobar") + expectFC("%#-10.2s", FormattableFlags.LEFT_JUSTIFY | + FormattableFlags.ALTERNATE, 10, 2).toEqual("foobar") + expectFC("%#10.2S", FormattableFlags.UPPERCASE | + FormattableFlags.ALTERNATE, 10, 2).toEqual("foobar") + expectF("%10s", "hello").toEqual(" hello") + expectF("%-10s", "hello").toEqual("hello ") + expectThrow("%#s", "hello") + } + + it("should provide 'c' conversion") { + expectF("%-5c", new Character('!')).toEqual("! ") + } + + it("should provide 'd' conversion") { + expectF("%d", new Integer(5)).toEqual("5") + expectF("%05d", new Integer(5)).toEqual("00005") + expectF("%5d", new Integer(-10)).toEqual(" -10") + expectF("%05d", new Integer(-10)).toEqual("-0010") + } + + it("should provide 'o' conversion") { + expectF("%o", new JInteger(8)).toEqual("10") + expectF("%05o", new JInteger(16)).toEqual("00020") + expectF("%5o", new JInteger(-10)).toEqual("37777777766") + expectF("%05o", new JInteger(-10)).toEqual("37777777766") + expectF("%o", new JByte(8.toByte)).toEqual("10") + expectF("%05o", new JByte(16.toByte)).toEqual("00020") + expectF("%14o", new JByte(-10.toByte)).toEqual(" 37777777766") + expectF("%05o", new JByte(-10.toByte)).toEqual("37777777766") + expectF("%o", new JShort(8.toShort)).toEqual("10") + expectF("%05o", new JShort(16.toShort)).toEqual("00020") + expectF("%5o", new JShort(-10.toShort)).toEqual("37777777766") + expectF("%015o",new JShort(-10.toShort)).toEqual("000037777777766") + expectF("%05o", new JLong(-5L)).toEqual("1777777777777777777773") + } + + it("should provide 'x' conversion") { + expectF("%0#5x", new JInteger(5)).toEqual("0x005") + expectF("%#5x", new JInteger(5)).toEqual(" 0x5") + expectF("%#5X", new JInteger(5)).toEqual(" 0X5") + expectF("%x", new JInteger(-3)).toEqual("fffffffd") + expectF("%x", new JByte(-4.toByte)).toEqual("fffffffc") + expectF("%0#5x", new JByte(5.toByte)).toEqual("0x005") + expectF("%#5x", new JByte(5.toByte)).toEqual(" 0x5") + expectF("%#5X", new JByte(5.toByte)).toEqual(" 0X5") + expectF("%x", new JByte(-3.toByte)).toEqual("fffffffd") + expectF("%0#5x", new JShort(5.toShort)).toEqual("0x005") + expectF("%#5x", new JShort(5.toShort)).toEqual(" 0x5") + expectF("%#5X", new JShort(5.toShort)).toEqual(" 0X5") + expectF("%x", new JShort(-3.toShort)).toEqual("fffffffd") + expectF("%x", new JLong(-5L)).toEqual("fffffffffffffffb") + expectF("%X", new JLong(26L)).toEqual("1A") + } + + it("should provide 'e' conversion") { + expectF("%e", new JDouble(1000)).toEqual("1.000000e+03") + expectF("%.0e", new JDouble(1.2e100)).toEqual("1e+100") + // We use 1.51e100 in this test, since we seem to have a floating + // imprecision at exactly 1.5e100 that yields to a rounding error + // towards (1e+100 instead of 2e+100) + expectF("%.0e", new JDouble(1.51e100)).toEqual("2e+100") + expectF("%10.2e", new JDouble(1.2e100)).toEqual(" 1.20e+100") + expectF("%012.4e", new JFloat(1.2e-21f)).toEqual("001.2000e-21") + expectF("%012.4E", new JFloat(1.2e-21f)).toEqual("001.2000E-21") + expectF("%(015.4e", new JFloat(-1.2e-21f)).toEqual("(0001.2000e-21)") + + // Tests with infinity and NaN + expectF("%e", new JDouble(Double.PositiveInfinity)).toEqual("Infinity") + expectF("%e", new JDouble(Double.NegativeInfinity)).toEqual("-Infinity") + expectF("%010e", new JDouble(Double.PositiveInfinity)).toEqual(" Infinity") + expectF("%-10e", new JDouble(Double.PositiveInfinity)).toEqual("Infinity ") + expectF("%(e", new JDouble(Double.NegativeInfinity)).toEqual("(Infinity)") + expectF("%010e", new JDouble(Double.NaN)).toEqual(" NaN") + } + + it("should provide 'g' conversion") { + expectF("%g", new JDouble(.5e-4)).toEqual("5.00000e-05") + expectF("%g", new JDouble(3e-4)).toEqual("0.000300000") + expectF("%.3g", new JDouble(3e-4)).toEqual("0.000300") + expectF("%.2g", new JDouble(1e-3)).toEqual("0.0010") + expectF("%g", new JDouble(3e5)).toEqual("300000") + expectF("%.3g", new JDouble(3e5)).toEqual("3.00e+05") + expectF("%04g", new JDouble(Double.NaN)).toEqual(" NaN") + } + + it("should provide 'f' conversion") { + expectF("%f", new JDouble(3.3)).toEqual("3.300000") + expectF("%0(9.4f", new JDouble(-4.6)).toEqual("(04.6000)") + expectF("%f", new JFloat(3e10f)).toEqual("30000001024.000000") + expectF("%f", new JDouble(3e10)).toEqual("30000000000.000000") + expectF("%04f", new JDouble(Double.NaN)).toEqual(" NaN") + } + + it("should support '%%'") { + expectF("%d%%%d", new JInteger(1), new JInteger(2)).toEqual("1%2") + } + + it("should support '%n'") { + expectF("%d%n%d", new JInteger(1), new JInteger(2)).toEqual("1\n2") + } + + it("should survive `null` and `undefined`") { + expectF("%s", null).toEqual("null") + expectF("%s", js.undefined).toEqual("undefined") + } + + it("should allow 'f' string interpolation to survive `null` and `undefined`") { + expect(f"${null}%s").toEqual("null") + expect(f"${js.undefined}%s").toEqual("undefined") + } + + it("should allow positional arguments") { + expectF("%2$d %1$d", new JInteger(1), new JInteger(2)).toEqual("2 1") + expectF("%2$d %2$d %d", new JInteger(1), new JInteger(2)).toEqual("2 2 1") + expectF("%2$d %<d %d", new JInteger(1), new JInteger(2)).toEqual("2 2 1") + } + + it("should fail when called after close") { + val f = new Formatter() + f.close() + expect(() => f.toString()).toThrow + } + + it("should fail with bad format specifier") { + expectThrow("hello world%") + expectThrow("%%%") + expectThrow("%q") + expectThrow("%1") + expectThrow("%_f") + } + + it("should fail with not enough arguments") { + expectThrow("%f") + expectThrow("%d%d%d", new JInteger(1), new JInteger(1)) + expectThrow("%10$d", new JInteger(1)) + } + + } + + +} + diff --git a/test-suite/src/test/scala/scala/scalajs/testsuite/javalib/IntegerTest.scala b/test-suite/src/test/scala/scala/scalajs/testsuite/javalib/IntegerTest.scala new file mode 100644 index 0000000..5a01de4 --- /dev/null +++ b/test-suite/src/test/scala/scala/scalajs/testsuite/javalib/IntegerTest.scala @@ -0,0 +1,161 @@ +/* __ *\ +** ________ ___ / / ___ __ ____ Scala.js Test Suite ** +** / __/ __// _ | / / / _ | __ / // __/ (c) 2013, LAMP/EPFL ** +** __\ \/ /__/ __ |/ /__/ __ |/_// /_\ \ http://scala-js.org/ ** +** /____/\___/_/ |_/____/_/ | |__/ /____/ ** +** |/____/ ** +\* */ +package scala.scalajs.testsuite.javalib + +import org.scalajs.jasminetest.JasmineTest +import scala.scalajs.js + +object IntegerTest extends JasmineTest { + + describe("java.lang.Integer") { + + // Explicitly define these as `var`'s to avoid any compile-time constant folding + var MaxValue: Int = Int.MaxValue + var MinValue: Int = Int.MinValue + + it("should provide `reverseBytes` used by scala.Enumeration") { + expect(Integer.reverseBytes(0xdeadbeef)).toEqual(0xefbeadde) + } + + it("should provide `rotateLeft`") { + expect(Integer.rotateLeft(0x689cd401, 0)).toEqual(0x689cd401) + expect(Integer.rotateLeft(0x689cd401, 1)).toEqual(0xd139a802) + expect(Integer.rotateLeft(0x689cd401, 8)).toEqual(0x9cd40168) + expect(Integer.rotateLeft(0x689cd401, 13)).toEqual(0x9a802d13) + expect(Integer.rotateLeft(0x689cd401, 32)).toEqual(0x689cd401) + expect(Integer.rotateLeft(0x689cd401, 33)).toEqual(0xd139a802) + expect(Integer.rotateLeft(0x689cd401, 43)).toEqual(0xe6a00b44) + expect(Integer.rotateLeft(0x689cd401, -1)).toEqual(0xb44e6a00) + expect(Integer.rotateLeft(0x689cd401, -28)).toEqual(0x89cd4016) + expect(Integer.rotateLeft(0x689cd401, -39)).toEqual(0x2d139a8) + } + + it("should provide `rotateRight`") { + expect(Integer.rotateRight(0x689cd401, 0)).toEqual(0x689cd401) + expect(Integer.rotateRight(0x689cd401, 1)).toEqual(0xb44e6a00) + expect(Integer.rotateRight(0x689cd401, 8)).toEqual(0x1689cd4) + expect(Integer.rotateRight(0x689cd401, 13)).toEqual(0xa00b44e6) + expect(Integer.rotateRight(0x689cd401, 32)).toEqual(0x689cd401) + expect(Integer.rotateRight(0x689cd401, 33)).toEqual(0xb44e6a00) + expect(Integer.rotateRight(0x689cd401, 43)).toEqual(0x802d139a) + expect(Integer.rotateRight(0x689cd401, -1)).toEqual(0xd139a802) + expect(Integer.rotateRight(0x689cd401, -28)).toEqual(0x1689cd40) + expect(Integer.rotateRight(0x689cd401, -39)).toEqual(0x4e6a00b4) + } + + it("should provide `bitCount` used by Map") { + abstract sealed class Status + case object Used extends Status + case object Current extends Status + case object OneMove extends Status + case object MultipleMoves extends Status + case object Other extends Status + + val map = Map(Used -> 0, Other -> 0, Current -> 0, MultipleMoves -> 1, OneMove -> 2) + + expect(map.size).toEqual(5) + expect(map(MultipleMoves)).toEqual(1) + } + + it("should provide `numberOfTrailingZeros`") { + expect(Integer.numberOfTrailingZeros(0xa3c49000)).toEqual(12) + expect(Integer.numberOfTrailingZeros(0x43f49020)).toEqual(5) + expect(Integer.numberOfTrailingZeros(0x43c08000)).toEqual(15) + expect(Integer.numberOfTrailingZeros(0)).toEqual(32) + } + + it("should provide `toBinaryString` for values in range") { + expect(Integer.toBinaryString(-1)).toEqual("11111111111111111111111111111111") + expect(Integer.toBinaryString(-10001)).toEqual("11111111111111111101100011101111") + expect(Integer.toBinaryString(MinValue)).toEqual("10000000000000000000000000000000") + expect(Integer.toBinaryString(MaxValue)).toEqual("1111111111111111111111111111111") + } + + it("should provide `toHexString` for values in range") { + expect(Integer.toHexString(-1)).toEqual("ffffffff") + expect(Integer.toHexString(-10001)).toEqual("ffffd8ef") + expect(Integer.toHexString(MinValue)).toEqual("80000000") + expect(Integer.toHexString(-2147000002)).toEqual("8007613e") + expect(Integer.toHexString(MaxValue)).toEqual("7fffffff") + } + + it("should provide `toOctalString` for values in range") { + expect(Integer.toOctalString(-1)).toEqual("37777777777") + expect(Integer.toOctalString(-10001)).toEqual("37777754357") + expect(Integer.toOctalString(MinValue)).toEqual("20000000000") + expect(Integer.toOctalString(MaxValue)).toEqual("17777777777") + } + + it("should provide `compareTo`") { + def compare(x: Int, y: Int): Int = + new Integer(x).compareTo(new Integer(y)) + + expect(compare(0, 5)).toBeLessThan(0) + expect(compare(10, 9)).toBeGreaterThan(0) + expect(compare(-2, -1)).toBeLessThan(0) + expect(compare(3, 3)).toEqual(0) + } + + it("should be a Comparable") { + def compare(x: Any, y: Any): Int = + x.asInstanceOf[Comparable[Any]].compareTo(y) + + expect(compare(0, 5)).toBeLessThan(0) + expect(compare(10, 9)).toBeGreaterThan(0) + expect(compare(-2, -1)).toBeLessThan(0) + expect(compare(3, 3)).toEqual(0) + } + + it("should parse strings") { + def test(s: String, v: Int, radix: Int = 10): Unit = { + expect(Integer.parseInt(s, radix)).toEqual(v) + expect(Integer.valueOf(s, radix).intValue()).toEqual(v) + if (radix == 10) + expect(new Integer(s).intValue()).toEqual(v) + } + + test("0", 0) + test("5", 5) + test("127", 127) + test("-100", -100) + test("30000", 30000) + test("-90000", -90000) + test("Kona", 411787, 27) + test("+42", 42) + test("-0", 0) + test("-FF", -255, 16) + } + + it("should reject invalid strings when parsing") { + def test(s: String, radix: Int = 10): Unit = + expect(() => Integer.parseInt(s, radix)).toThrow + + test("abc") + test("5a") + test("2147483648") + test("99", 8) + test("-") + test("") + } + + it("should parse strings in base 16") { + def test(s: String, v: Int): Unit = { + expect(Integer.parseInt(s, 16)).toEqual(v) + expect(Integer.valueOf(s, 16).intValue()).toEqual(v) + } + + test("0", 0x0) + test("5", 0x5) + test("ff", 0xff) + test("-24", -0x24) + test("30000", 0x30000) + test("-90000", -0x90000) + } + + } +} diff --git a/test-suite/src/test/scala/scala/scalajs/testsuite/javalib/LongTest.scala b/test-suite/src/test/scala/scala/scalajs/testsuite/javalib/LongTest.scala new file mode 100644 index 0000000..86783c3 --- /dev/null +++ b/test-suite/src/test/scala/scala/scalajs/testsuite/javalib/LongTest.scala @@ -0,0 +1,178 @@ +/* __ *\ +** ________ ___ / / ___ __ ____ Scala.js Test Suite ** +** / __/ __// _ | / / / _ | __ / // __/ (c) 2013, LAMP/EPFL ** +** __\ \/ /__/ __ |/ /__/ __ |/_// /_\ \ http://scala-js.org/ ** +** /____/\___/_/ |_/____/_/ | |__/ /____/ ** +** |/____/ ** +\* */ +package scala.scalajs.testsuite.javalib + +import java.lang.{Long => JLong} + +import org.scalajs.jasminetest.JasmineTest + +/** + * tests the implementation of the java standard library Long + * requires jsinterop/LongTest to work to make sense + */ +object LongTest extends JasmineTest { + + describe("java.lang.Long") { + it("should provide `reverseBytes`") { + expect(JLong.reverseBytes(0xf5ab689cd401ff14L) == 0x14ff01d49c68abf5L).toBeTruthy + } + + it("should provide `rotateLeft`") { + expect(JLong.rotateLeft(0xf5ab689cd401ff14L, 0) == 0xf5ab689cd401ff14L).toBeTruthy + expect(JLong.rotateLeft(0xf5ab689cd401ff14L, 1) == 0xeb56d139a803fe29L).toBeTruthy + expect(JLong.rotateLeft(0xf5ab689cd401ff14L, 8) == 0xab689cd401ff14f5L).toBeTruthy + expect(JLong.rotateLeft(0xf5ab689cd401ff14L, 13) == 0x6d139a803fe29eb5L).toBeTruthy + expect(JLong.rotateLeft(0xf5ab689cd401ff14L, 64) == 0xf5ab689cd401ff14L).toBeTruthy + expect(JLong.rotateLeft(0xf5ab689cd401ff14L, 65) == 0xeb56d139a803fe29L).toBeTruthy + expect(JLong.rotateLeft(0xf5ab689cd401ff14L, 80) == 0x689cd401ff14f5abL).toBeTruthy + expect(JLong.rotateLeft(0xf5ab689cd401ff14L, -1) == 0x7ad5b44e6a00ff8aL).toBeTruthy + expect(JLong.rotateLeft(0xf5ab689cd401ff14L, -56) == 0xab689cd401ff14f5L).toBeTruthy + expect(JLong.rotateLeft(0xf5ab689cd401ff14L, -70) == 0x53d6ada2735007fcL).toBeTruthy + } + + it("should provide `rotateRight`") { + expect(JLong.rotateRight(0xf5ab689cd401ff14L, 0) == 0xf5ab689cd401ff14L).toBeTruthy + expect(JLong.rotateRight(0xf5ab689cd401ff14L, 1) == 0x7ad5b44e6a00ff8aL).toBeTruthy + expect(JLong.rotateRight(0xf5ab689cd401ff14L, 8) == 0x14f5ab689cd401ffL).toBeTruthy + expect(JLong.rotateRight(0xf5ab689cd401ff14L, 13) == 0xf8a7ad5b44e6a00fL).toBeTruthy + expect(JLong.rotateRight(0xf5ab689cd401ff14L, 64) == 0xf5ab689cd401ff14L).toBeTruthy + expect(JLong.rotateRight(0xf5ab689cd401ff14L, 65) == 0x7ad5b44e6a00ff8aL).toBeTruthy + expect(JLong.rotateRight(0xf5ab689cd401ff14L, 80) == 0xff14f5ab689cd401L).toBeTruthy + expect(JLong.rotateRight(0xf5ab689cd401ff14L, -1) == 0xeb56d139a803fe29L).toBeTruthy + expect(JLong.rotateRight(0xf5ab689cd401ff14L, -56) == 0x14f5ab689cd401ffL).toBeTruthy + expect(JLong.rotateRight(0xf5ab689cd401ff14L, -70) == 0x6ada2735007fc53dL).toBeTruthy + } + + it("should implement bitCount") { + expect(JLong.bitCount(0L)).toEqual(0) + expect(JLong.bitCount(35763829229342837L)).toEqual(26) + expect(JLong.bitCount(-350003829229342837L)).toEqual(32) + } + + it("should provide `compareTo`") { + def compare(x: Long, y: Long): Int = + new JLong(x).compareTo(new JLong(y)) + + expect(compare(0L, 5L)).toBeLessThan(0) + expect(compare(10L, 9L)).toBeGreaterThan(0) + expect(compare(-2L, -1L)).toBeLessThan(0) + expect(compare(3L, 3L)).toEqual(0) + } + + it("should be a Comparable") { + def compare(x: Any, y: Any): Int = + x.asInstanceOf[Comparable[Any]].compareTo(y) + + expect(compare(0L, 5L)).toBeLessThan(0) + expect(compare(10L, 9L)).toBeGreaterThan(0) + expect(compare(-2L, -1L)).toBeLessThan(0) + expect(compare(3L, 3L)).toEqual(0) + } + + it("should parse strings") { + def test(s: String, v: Long): Unit = { + expect(JLong.parseLong(s)).toEqual(v) + expect(JLong.valueOf(s).longValue()).toEqual(v) + expect(new JLong(s).longValue()).toEqual(v) + } + + test("0", 0L) + test("5", 5L) + test("127", 127L) + test("-100", -100L) + test("30000", 30000L) + test("-90000", -90000L) + test("4", 4L) + test("-4", -4L) + test("4000000000", 4000000000L) + test("-18014398509482040", -18014398509482040L) + } + + it("should reject invalid strings when parsing") { + def test(s: String): Unit = + expect(() => JLong.parseLong(s)).toThrow + + test("abc") + test("asdf") + test("") + } + + it("should parse strings in base 16") { + def test(s: String, v: Long): Unit = { + expect(JLong.parseLong(s, 16)).toEqual(v) + expect(JLong.valueOf(s, 16).longValue()).toEqual(v) + } + + test("0", 0x0L) + test("5", 0x5L) + test("ff", 0xffL) + test("-24", -0x24L) + test("30000", 0x30000L) + test("-90000", -0x90000L) + } + + it("should implement toString") { + expect(Int.MaxValue.toLong.toString).toEqual("2147483647") + expect((-50L).toString).toEqual("-50") + expect((-1000000000L).toString).toEqual("-1000000000") + expect((Int.MaxValue.toLong+1L).toString).toEqual("2147483648") + expect(Int.MinValue.toLong.toString).toEqual("-2147483648") + } + + it("should implement toBinaryString") { + expect(JLong.toBinaryString( 0L)).toEqual("0") + expect(JLong.toBinaryString( -1L)).toEqual("1111111111111111111111111111111111111111111111111111111111111111") + expect(JLong.toBinaryString( 456324454L)).toEqual("11011001100101111010101100110") + expect(JLong.toBinaryString( -456324454L)).toEqual("1111111111111111111111111111111111100100110011010000101010011010") + expect(JLong.toBinaryString( 98765432158845L)).toEqual("10110011101001110011110011111111111101001111101") + expect(JLong.toBinaryString(-49575304457780L)).toEqual("1111111111111111110100101110100101011001100101101001000111001100") + expect(JLong.toBinaryString(Long.MinValue )).toEqual("1000000000000000000000000000000000000000000000000000000000000000") + expect(JLong.toBinaryString(Long.MaxValue )).toEqual("111111111111111111111111111111111111111111111111111111111111111") + } + + it("should implement toHexString") { + expect(JLong.toHexString( 0L)).toEqual("0") + expect(JLong.toHexString( -1L)).toEqual("ffffffffffffffff") + expect(JLong.toHexString( 456324454L)).toEqual("1b32f566") + expect(JLong.toHexString( -456324454L)).toEqual("ffffffffe4cd0a9a") + expect(JLong.toHexString( 98765432158845L)).toEqual("59d39e7ffa7d") + expect(JLong.toHexString(-49575304457780L)).toEqual("ffffd2e9599691cc") + expect(JLong.toHexString(Long.MinValue )).toEqual("8000000000000000") + expect(JLong.toHexString(Long.MaxValue )).toEqual("7fffffffffffffff") + } + + it("should implement toOctalString") { + expect(JLong.toOctalString( 0L)).toEqual("0") + expect(JLong.toOctalString( -1L)).toEqual("1777777777777777777777") + expect(JLong.toOctalString( 456324454L)).toEqual("3314572546") + expect(JLong.toOctalString( -456324454L)).toEqual("1777777777774463205232") + expect(JLong.toOctalString( 98765432158845L)).toEqual("2635163637775175") + expect(JLong.toOctalString(-49575304457780L)).toEqual("1777776456453145510714") + expect(JLong.toOctalString(Long.MinValue )).toEqual("1000000000000000000000") + expect(JLong.toOctalString(Long.MaxValue )).toEqual("777777777777777777777") + } + + it("should correctly compute trailing zeros") { + expect(JLong.numberOfTrailingZeros(0xff10000000000000L)).toEqual(52) + expect(JLong.numberOfTrailingZeros(0xff20000000000000L)).toEqual(53) + expect(JLong.numberOfTrailingZeros(0xff40000000000000L)).toEqual(54) + expect(JLong.numberOfTrailingZeros(0xff80000000000000L)).toEqual(55) + + expect(JLong.numberOfTrailingZeros(0x0000010000000000L)).toEqual(40) + expect(JLong.numberOfTrailingZeros(0x0000020000000000L)).toEqual(41) + expect(JLong.numberOfTrailingZeros(0x0000040000000000L)).toEqual(42) + expect(JLong.numberOfTrailingZeros(0x0000080000000000L)).toEqual(43) + + expect(JLong.numberOfTrailingZeros(0x0000000000010000L)).toEqual(16) + expect(JLong.numberOfTrailingZeros(0x0000000000020000L)).toEqual(17) + expect(JLong.numberOfTrailingZeros(0x0000000000040000L)).toEqual(18) + expect(JLong.numberOfTrailingZeros(0x0000000000080000L)).toEqual(19) + } + + } +} diff --git a/test-suite/src/test/scala/scala/scalajs/testsuite/javalib/MathTest.scala b/test-suite/src/test/scala/scala/scalajs/testsuite/javalib/MathTest.scala new file mode 100644 index 0000000..a3c887a --- /dev/null +++ b/test-suite/src/test/scala/scala/scalajs/testsuite/javalib/MathTest.scala @@ -0,0 +1,142 @@ +/* __ *\ +** ________ ___ / / ___ __ ____ Scala.js Test Suite ** +** / __/ __// _ | / / / _ | __ / // __/ (c) 2013, LAMP/EPFL ** +** __\ \/ /__/ __ |/ /__/ __ |/_// /_\ \ http://scala-js.org/ ** +** /____/\___/_/ |_/____/_/ | |__/ /____/ ** +** |/____/ ** +\* */ +package scala.scalajs.testsuite.javalib + +import scala.scalajs.js +import org.scalajs.jasminetest.JasmineTest +import java.lang.Math + +object MathTest extends JasmineTest { + + describe("java.lang.Math") { + + it("should respond to `cbrt`") { + expect(1 / Math.cbrt(-0.0) < 0).toBeTruthy + expect(Math.cbrt(27.0)).toEqual(3.0) + expect(Math.cbrt(1000000.0)).toEqual(100.0) + expect(Math.cbrt(1000000000.0)).toEqual(1000.0) + expect(Math.cbrt(-1.0E24)).toEqual(-100000000.0) + expect(Math.cbrt(-65890311319.0E24)).toEqual(-4039.0E8) + } + + it("should respond to `log1p`") { + expect(Math.log1p(-2.0).isNaN).toBeTruthy + expect(Math.log1p(js.Number.NaN.toDouble).isNaN).toBeTruthy + expect(Math.log1p(0.0)).toEqual(0.0) + } + + it("should respond to `log10`") { + expect(Math.log10(-230.0).isNaN).toBeTruthy + expect(Math.log10(js.Number.NaN.toDouble).isNaN).toBeTruthy + } + + it("should respond to `signum` for Double") { + expect(Math.signum(234394.2198273)).toEqual(1.0) + expect(Math.signum(-124937498.58)).toEqual(-1.0) + + expect(Math.signum(+0.0)).toEqual(0.0) + expect(1 / Math.signum(+0.0) > 0).toBeTruthy + + expect(Math.signum(-0.0)).toEqual(-0.0) + expect(1 / Math.signum(-0.0) < 0).toBeTruthy + + expect(Math.signum(js.Number.NaN.toDouble).isNaN).toBeTruthy + } + + it("should respond to `signum` for Float") { + expect(Math.signum(234394.2198273f)).toEqual(1.0f) + expect(Math.signum(-124937498.58f)).toEqual(-1.0f) + + expect(Math.signum(+0.0f)).toEqual(0.0f) + expect(1 / Math.signum(+0.0f) > 0).toBeTruthy + + expect(Math.signum(-0.0f)).toEqual(-0.0f) + expect(1 / Math.signum(-0.0f) < 0).toBeTruthy + + expect(Math.signum(js.Number.NaN.toFloat).isNaN).toBeTruthy + } + + it("should respond to `nextUp` for Double") { + expect(Math.nextUp(Double.PositiveInfinity)).toEqual(Double.PositiveInfinity) + expect(Math.nextUp(Double.NegativeInfinity)).toEqual(-Double.MaxValue) + expect(Math.nextUp(Double.MaxValue)).toEqual(Double.PositiveInfinity) + expect(Math.nextUp(-Double.MaxValue)).toEqual(-1.7976931348623155e+308) + expect(Math.nextUp(-Double.MinValue)).toEqual(Double.PositiveInfinity) + expect(Math.nextUp(0.0)).toEqual(Double.MinValue) + expect(Math.nextUp(-0.0)).toEqual(Double.MinValue) + expect(Math.nextUp(9007199254740991.0)).toEqual(9007199254740992.0) + expect(Math.nextUp(9007199254740992.0)).toEqual(9007199254740994.0) + expect(Math.nextUp(1.0)).toEqual(1 + 2.2204460492503130808472633361816E-16) + } + + it("should respond to `nextAfter` for Double") { + expect(Math.nextAfter(1.0, js.Number.NaN.toDouble).isNaN).toBeTruthy + expect(Math.nextAfter(js.Number.NaN.toDouble, 1.0).isNaN).toBeTruthy + expect(Math.nextAfter(0.0, 0.0)).toEqual(0.0) + expect(Math.nextAfter(0.0, -0.0)).toEqual(-0.0) + expect(Math.nextAfter(-0.0, 0.0)).toEqual(0.0) + expect(Math.nextAfter(-0.0, -0.0)).toEqual(-0.0) + expect(Math.nextAfter(Double.MinValue, Double.NegativeInfinity)).toEqual(Double.NegativeInfinity) + expect(Math.nextAfter(-Double.MinValue, Double.PositiveInfinity)).toEqual(Double.PositiveInfinity) + expect(Math.nextAfter(Double.PositiveInfinity, Double.NegativeInfinity)).toEqual(Double.MaxValue) + expect(Math.nextAfter(Double.NegativeInfinity, Double.PositiveInfinity)).toEqual(-Double.MaxValue) + expect(Math.nextAfter(Double.MaxValue, Double.PositiveInfinity)).toEqual(Double.PositiveInfinity) + expect(Math.nextAfter(-Double.MaxValue, Double.NegativeInfinity)).toEqual(Double.NegativeInfinity) + expect(Math.nextAfter(1.0, 1.0)).toEqual(1.0) + } + + it("should respond to `ulp` for Double") { + expect(Math.ulp(3.4)).toEqual(4.440892098500626E-16) + expect(Math.ulp(3.423E109)).toEqual(4.1718496795330275E93) + expect(Math.ulp(0.0)).toEqual(Double.MinValue) + } + + it("should respond to `hypot`") { + expect(Math.hypot(0.0, 0.0)).toBeCloseTo(0.0) + expect(Math.hypot(3.0, 4.0)).toBeCloseTo(5.0) + expect(Math.hypot(3.0, js.Number.NaN.toDouble).isNaN).toBeTruthy + expect(Math.hypot(Double.NegativeInfinity, 4.0)).toEqual(Double.PositiveInfinity) + } + + it("should respond to `expm1`") { + expect(1 / Math.expm1(-0.0) < 0).toBeTruthy + expect(Math.expm1(-0.0)).toBeCloseTo(0.0) + expect(Math.expm1(3.0)).toBeCloseTo(19.085536923187668) + expect(Math.expm1(15.0)).toBeCloseTo(3269016.3724721107) + expect(Math.expm1(1.8E10)).toEqual(Double.PositiveInfinity) + expect(Math.expm1(Double.PositiveInfinity)).toEqual(Double.PositiveInfinity) + expect(Math.expm1(Double.NegativeInfinity)).toBeCloseTo(-1.0) + expect(Math.expm1(4.9E-324)).toBeCloseTo(4.9E-324) + } + + it("should respond to `sinh`") { + expect(Math.sinh(-1234.56)).toEqual(Double.NegativeInfinity) + expect(Math.sinh(1234.56)).toEqual(Double.PositiveInfinity) + expect(Math.sinh(0.0)).toBeCloseTo(0.0) + expect(Math.sinh(Double.PositiveInfinity)).toEqual(Double.PositiveInfinity) + } + + it("should respond to `cosh`") { + expect(Math.cosh(-1234.56)).toEqual(Double.PositiveInfinity) + expect(Math.cosh(1234.56)).toEqual(Double.PositiveInfinity) + expect(Math.cosh(-0.0)).toBeCloseTo(1.0) + expect(Math.cosh(Double.PositiveInfinity)).toEqual(Double.PositiveInfinity) + } + + it("should respond to `tanh`") { + expect(Math.tanh(-1234.56)).toBeCloseTo(-1.0) + expect(Math.tanh(-120.56)).toBeCloseTo(-1.0) + expect(Math.tanh(1234.56)).toBeCloseTo(1.0) + expect(Math.tanh(0.0)).toBeCloseTo(0.0) + expect(Math.tanh(Double.PositiveInfinity)).toBeCloseTo(1.0) + expect(Math.tanh(Double.NegativeInfinity)).toBeCloseTo(-1.0) + } + + } + +} diff --git a/test-suite/src/test/scala/scala/scalajs/testsuite/javalib/MockByteArrayOutputStream.scala b/test-suite/src/test/scala/scala/scalajs/testsuite/javalib/MockByteArrayOutputStream.scala new file mode 100644 index 0000000..3356a85 --- /dev/null +++ b/test-suite/src/test/scala/scala/scalajs/testsuite/javalib/MockByteArrayOutputStream.scala @@ -0,0 +1,47 @@ +package scala.scalajs.testsuite.javalib + +import java.io._ + +/** A ByteArrayOutputStream that exposes various hooks for testing purposes. */ +class MockByteArrayOutputStream extends ByteArrayOutputStream { + private var _flushed: Boolean = true + private var _closed: Boolean = false + + var throwing: Boolean = false + + def flushed: Boolean = _flushed + def closed: Boolean = _closed + + private def maybeThrow(): Unit = { + if (throwing) + throw new IOException("MockByteArrayOutputStream throws") + } + + private def writeOp[A](op: => A): A = { + maybeThrow() + _flushed = false + op + } + + override def flush(): Unit = { + maybeThrow() + super.flush() + _flushed = true + } + + override def close(): Unit = { + maybeThrow() + super.close() + _closed = true + } + + override def write(c: Int): Unit = + writeOp(super.write(c)) + + override def write(b: Array[Byte]): Unit = + writeOp(super.write(b)) + + override def write(b: Array[Byte], off: Int, len: Int): Unit = + writeOp(super.write(b, off, len)) + +} diff --git a/test-suite/src/test/scala/scala/scalajs/testsuite/javalib/ObjectTest.scala b/test-suite/src/test/scala/scala/scalajs/testsuite/javalib/ObjectTest.scala new file mode 100644 index 0000000..3584454 --- /dev/null +++ b/test-suite/src/test/scala/scala/scalajs/testsuite/javalib/ObjectTest.scala @@ -0,0 +1,72 @@ +/* __ *\ +** ________ ___ / / ___ __ ____ Scala.js Test Suite ** +** / __/ __// _ | / / / _ | __ / // __/ (c) 2013, LAMP/EPFL ** +** __\ \/ /__/ __ |/ /__/ __ |/_// /_\ \ http://scala-js.org/ ** +** /____/\___/_/ |_/____/_/ | |__/ /____/ ** +** |/____/ ** +\* */ +package scala.scalajs.testsuite.javalib + +import org.scalajs.jasminetest.JasmineTest + +import scala.scalajs.js + +object ObjectTest extends JasmineTest { + + describe("java.lang.Object") { + + it("should provide `equals`") { + case class xy(x: Int, y: Int) + + val l = List(xy(1, 2), xy(2, 1)) + val xy12 = xy(1, 2) + + expect(l.contains(xy12)).toBeTruthy + expect(l.exists(_ == xy12)).toBeTruthy // the workaround + } + + it("everything but null should be an Object") { + expect((() : Any).isInstanceOf[Object]).toBeTruthy + expect((true : Any).isInstanceOf[Object]).toBeTruthy + expect(('a' : Any).isInstanceOf[Object]).toBeTruthy + expect((1.toByte : Any).isInstanceOf[Object]).toBeTruthy + expect((658.toShort : Any).isInstanceOf[Object]).toBeTruthy + expect((60000 : Any).isInstanceOf[Object]).toBeTruthy + expect((12345678910112L: Any).isInstanceOf[Object]).toBeTruthy + expect((6.5f : Any).isInstanceOf[Object]).toBeTruthy + expect((12.4 : Any).isInstanceOf[Object]).toBeTruthy + expect((new Object : Any).isInstanceOf[Object]).toBeTruthy + expect(("hello" : Any).isInstanceOf[Object]).toBeTruthy + expect((List(1) : Any).isInstanceOf[Object]).toBeTruthy + expect((Array(1) : Any).isInstanceOf[Object]).toBeTruthy + expect((Array(Nil) : Any).isInstanceOf[Object]).toBeTruthy + expect((new js.Object : Any).isInstanceOf[Object]).toBeTruthy + expect((js.Array(5) : Any).isInstanceOf[Object]).toBeTruthy + } + + it("null should not be an Object") { + expect((null: Any).isInstanceOf[Object]).toBeFalsy + } + + it("everything should cast to Object successfully, including null") { + expect(() => (() : Any).asInstanceOf[Object]).not.toThrow + expect(() => (true : Any).asInstanceOf[Object]).not.toThrow + expect(() => ('a' : Any).asInstanceOf[Object]).not.toThrow + expect(() => (1.toByte : Any).asInstanceOf[Object]).not.toThrow + expect(() => (658.toShort : Any).asInstanceOf[Object]).not.toThrow + expect(() => (60000 : Any).asInstanceOf[Object]).not.toThrow + expect(() => (12345678910112L: Any).asInstanceOf[Object]).not.toThrow + expect(() => (6.5f : Any).asInstanceOf[Object]).not.toThrow + expect(() => (12.4 : Any).asInstanceOf[Object]).not.toThrow + expect(() => (new Object : Any).asInstanceOf[Object]).not.toThrow + expect(() => ("hello" : Any).asInstanceOf[Object]).not.toThrow + expect(() => (List(1) : Any).asInstanceOf[Object]).not.toThrow + expect(() => (Array(1) : Any).asInstanceOf[Object]).not.toThrow + expect(() => (Array(Nil) : Any).asInstanceOf[Object]).not.toThrow + expect(() => (new js.Object : Any).asInstanceOf[Object]).not.toThrow + expect(() => (js.Array(5) : Any).asInstanceOf[Object]).not.toThrow + expect(() => (null : Any).asInstanceOf[Object]).not.toThrow + } + + } +} diff --git a/test-suite/src/test/scala/scala/scalajs/testsuite/javalib/OutputStreamWriterTest.scala b/test-suite/src/test/scala/scala/scalajs/testsuite/javalib/OutputStreamWriterTest.scala new file mode 100644 index 0000000..7987a4c --- /dev/null +++ b/test-suite/src/test/scala/scala/scalajs/testsuite/javalib/OutputStreamWriterTest.scala @@ -0,0 +1,134 @@ +/* __ *\ +** ________ ___ / / ___ __ ____ Scala.js Test Suite ** +** / __/ __// _ | / / / _ | __ / // __/ (c) 2013, LAMP/EPFL ** +** __\ \/ /__/ __ |/ /__/ __ |/_// /_\ \ http://scala-js.org/ ** +** /____/\___/_/ |_/____/_/ | |__/ /____/ ** +** |/____/ ** +\* */ +package scala.scalajs.testsuite.javalib + +import java.io._ + +import scala.scalajs.js +import js.JSConverters._ +import org.scalajs.jasminetest.JasmineTest + +object OutputStreamWriterTest extends JasmineTest { + private def newOSWriter(): (OutputStreamWriter, MockByteArrayOutputStream) = { + val bos = new MockByteArrayOutputStream + val osw = new OutputStreamWriter(bos) + (osw, bos) + } + + describe("java.io.OutputStreamWriter") { + it("flush") { + val (osw, bos) = newOSWriter() + bos.write(1) + osw.write("ABC") + expect(bos.flushed).toBeFalsy + osw.flush() + expect(bos.flushed).toBeTruthy + } + + it("close") { + val (osw, bos) = newOSWriter() + bos.write(1) + osw.write("ABC") + expect(bos.flushed).toBeFalsy + + osw.close() + expect(bos.flushed).toBeTruthy + expect(bos.closed).toBeTruthy + + // can double-close without error + osw.close() + + // when closed, other operations cause error + expect(() => osw.write('A')).toThrow + expect(() => osw.write("never printed")).toThrow + expect(() => osw.write(Array('a', 'b'))).toThrow + expect(() => osw.append("hello", 1, 3)).toThrow + expect(() => osw.flush()).toThrow + + // at the end of it all, bos is still what it was when it was closed + expect(bos.toByteArray().toJSArray).toEqual(js.Array(1, 65, 66, 67)) + } + + def testW(body: OutputStreamWriter => Unit, + expected: js.Array[Int], alreadyFlushed: Boolean = false): Unit = { + val (osw, bos) = newOSWriter() + body(osw) + if (!alreadyFlushed) { + expect(bos.size).toEqual(0) // write() methods should buffer + osw.flush() + } + expect(bos.flushed).toBeTruthy + expect(bos.toByteArray.toJSArray).toEqual(expected.map(_.toByte)) + } + + it("write(), ASCII repertoire") { + // Pure ASCII + testW(_.write('\n'), js.Array('\n')) + testW(_.write("hello\n"), js.Array('h', 'e', 'l', 'l', 'o', '\n')) + testW(_.write("hello\nworld", 3, 4), js.Array('l', 'o', '\n', 'w')) + testW(_.write(Array('A', '\n')), js.Array('A', '\n')) + testW(_.write(Array('A', 'B', '\n', 'C'), 1, 2), js.Array('B', '\n')) + } + + it("write(), Unicode repertoire without surrogates") { + testW(_.write('é'), js.Array(0xc3, 0xa9)) + testW(_.write("こんにちは"), js.Array( + 0xe3, 0x81, 0x93, 0xe3, 0x82, 0x93, 0xe3, 0x81, 0xab, 0xe3, 0x81, 0xa1, 0xe3, 0x81, 0xaf)) + testW(_.write("Καλημέρα", 3, 4), js.Array( + 0xce, 0xb7, 0xce, 0xbc, 0xce, 0xad, 0xcf, 0x81)) + } + + it("write(), surrogate pairs") { + testW(_.write("\ud83d\udca9"), js.Array(0xf0, 0x9f, 0x92, 0xa9)) + testW(_.write("ab\ud83d\udca9cd", 1, 3), js.Array('b', 0xf0, 0x9f, 0x92, 0xa9)) + } + + it("write(), surrogate pairs spread across multiple writes") { + testW({ osw => osw.write('\ud83d'); osw.write('\udca9') }, + js.Array(0xf0, 0x9f, 0x92, 0xa9)) + + testW({ osw => osw.write('\ud83d'); osw.flush(); osw.write('\udca9') }, + js.Array(0xf0, 0x9f, 0x92, 0xa9)) + + testW({ osw => osw.write("ab\ud83d"); osw.write('\udca9') }, + js.Array('a', 'b', 0xf0, 0x9f, 0x92, 0xa9)) + + testW({ osw => osw.write("ab\ud83d"); osw.write("\udca9cd") }, + js.Array('a', 'b', 0xf0, 0x9f, 0x92, 0xa9, 'c', 'd')) + + testW({ osw => osw.write("ab\ud83dzz", 1, 2); osw.write("ww\udca9cd", 2, 2) }, + js.Array('b', 0xf0, 0x9f, 0x92, 0xa9, 'c')) + } + + it("write(), malformed surrogates") { + testW(_.write("\ud83da"), js.Array('?', 'a')) + testW(_.write("\udca9"), js.Array('?')) + } + + it("write(), malformed surrogates spread across multiple writes") { + testW({ osw => osw.write('\ud83d'); osw.write('a') }, + js.Array('?', 'a')) + + testW({ osw => osw.write("ab\ud83d"); osw.write("\ud83d") }, + js.Array('a', 'b', '?')) + + testW({ osw => osw.write("ab\ud83d"); osw.write("\ud83dc") }, + js.Array('a', 'b', '?', '?', 'c')) + } + + it("write(), malformed surrogates at end of input") { + testW({ osw => osw.write('\ud83d'); osw.close() }, + js.Array('?'), alreadyFlushed = true) + + testW({ osw => osw.write("ab\ud83d"); osw.close() }, + js.Array('a', 'b', '?'), alreadyFlushed = true) + } + + } + +} diff --git a/test-suite/src/test/scala/scala/scalajs/testsuite/javalib/PrintStreamTest.scala b/test-suite/src/test/scala/scala/scalajs/testsuite/javalib/PrintStreamTest.scala new file mode 100644 index 0000000..01c872b --- /dev/null +++ b/test-suite/src/test/scala/scala/scalajs/testsuite/javalib/PrintStreamTest.scala @@ -0,0 +1,296 @@ +/* __ *\ +** ________ ___ / / ___ __ ____ Scala.js Test Suite ** +** / __/ __// _ | / / / _ | __ / // __/ (c) 2013, LAMP/EPFL ** +** __\ \/ /__/ __ |/ /__/ __ |/_// /_\ \ http://scala-js.org/ ** +** /____/\___/_/ |_/____/_/ | |__/ /____/ ** +** |/____/ ** +\* */ +package scala.scalajs.testsuite.javalib + +import java.io._ + +import scala.scalajs.js +import js.JSConverters._ +import org.scalajs.jasminetest.JasmineTest + +object PrintStreamTest extends JasmineTest { + private def newPrintStream( + autoFlush: Boolean = false): (MockPrintStream, MockByteArrayOutputStream) = { + val bos = new MockByteArrayOutputStream + val ps = new MockPrintStream(bos, autoFlush) + (ps, bos) + } + + describe("java.io.PrintStream") { + it("flush") { + val (ps, bos) = newPrintStream() + ps.print("hello") + expect(bos.flushed).toBeFalsy + ps.flush() + expect(bos.flushed).toBeTruthy + } + + it("close") { + val (ps, bos) = newPrintStream() + ps.write(Array[Byte](1)) + expect(bos.flushed).toBeFalsy + + ps.close() + expect(bos.flushed).toBeTruthy + expect(bos.closed).toBeTruthy + expect(ps.checkError()).toBeFalsy + + // can double-close without error + ps.close() + expect(ps.checkError()).toBeFalsy + ps.clearError() + + // when closed, other operations cause error + def expectCausesError(body: => Unit): Unit = { + body + expect(ps.checkError()).toBeTruthy + ps.clearError() + } + expectCausesError(ps.print("never printed")) + expectCausesError(ps.write(Array[Byte]('a', 'b'))) + expectCausesError(ps.append("hello", 1, 3)) + expectCausesError(ps.flush()) + + // at the end of it all, bos is still what it was when it was closed + expect(bos.toByteArray.toJSArray).toEqual(js.Array(1)) + } + + it("write, pass the bytes through") { + def test(body: PrintStream => Unit, expected: js.Array[Int], + testFlushed: Boolean = false): Unit = { + val (ps, bos) = newPrintStream(autoFlush = true) + body(ps) + if (testFlushed) + expect(bos.flushed).toBeTruthy + expect(ps.checkError()).toBeFalsy + expect(bos.toByteArray.toJSArray).toEqual(expected.map(_.toByte)) + } + + test(_.write('a'), js.Array('a')) + test(_.write('\n'), js.Array('\n'), testFlushed = true) + test(_.write(Array[Byte]('A', '\n')), + js.Array('A', '\n'), testFlushed = true) + test(_.write(Array[Byte]('A', 'B', '\n', 'C'), 1, 2), + js.Array('B', '\n'), testFlushed = true) + + test(_.write('é'.toByte), js.Array('é')) + test(_.write(Array[Byte]('é'.toByte, 'à'.toByte)), js.Array('é', 'à')) + } + + it("print") { + def test(body: PrintStream => Unit, expected: String, + testFlushed: Boolean = false): Unit = { + val (ps, bos) = newPrintStream(autoFlush = true) + body(ps) + if (testFlushed) + expect(bos.flushed).toBeTruthy + expect(ps.checkError()).toBeFalsy + expect(bos.toString()).toBe(expected) + } + + test(_.print(true), "true") + test(_.print('Z'), "Z") + test(_.print('\n'), "\n", testFlushed = true) + test(_.print(5), "5") + test(_.print(1234567891011L), "1234567891011") + test(_.print(1.5f), "1.5") + test(_.print(Math.PI), "3.141592653589793") + test(_.print(Array('A', '\n')), "A\n", testFlushed = true) + test(_.print("hello\n"), "hello\n", testFlushed = true) + test(_.print(null: String), "null") + test(_.print((1, 2)), "(1,2)") + test(_.print(null: AnyRef), "null") + } + + it("print encodes in UTF-8") { + def test(body: PrintStream => Unit, expected: js.Array[Int]): Unit = { + val (ps, bos) = newPrintStream(autoFlush = false) + body(ps) + expect(ps.checkError()).toBeFalsy + expect(bos.toByteArray.toJSArray).toEqual(expected.map(_.toByte)) + } + + test(_.print('é'), js.Array(0xc3, 0xa9)) + test(_.print("こんにちは"), js.Array( + 0xe3, 0x81, 0x93, 0xe3, 0x82, 0x93, 0xe3, 0x81, 0xab, 0xe3, 0x81, 0xa1, 0xe3, 0x81, 0xaf)) + test(_.print("ημέρ"), js.Array( + 0xce, 0xb7, 0xce, 0xbc, 0xce, 0xad, 0xcf, 0x81)) + + test(_.print("\ud83d\udca9"), js.Array(0xf0, 0x9f, 0x92, 0xa9)) + test(_.print("b\ud83d\udca9c"), js.Array('b', 0xf0, 0x9f, 0x92, 0xa9, 'c')) + + test({ osw => osw.print("ab\ud83d"); osw.print('\udca9') }, + js.Array('a', 'b', 0xf0, 0x9f, 0x92, 0xa9)) + + test({ osw => osw.print("ab\ud83d"); osw.print("\udca9cd") }, + js.Array('a', 'b', 0xf0, 0x9f, 0x92, 0xa9, 'c', 'd')) + + // Start of malformed sequences + + test(_.print("\ud83da"), js.Array('?', 'a')) + test(_.print("\udca9"), js.Array('?')) + + test({ osw => osw.print('\ud83d'); osw.print('a') }, + js.Array('?', 'a')) + + test({ osw => osw.print("ab\ud83d"); osw.print("\ud83d") }, + js.Array('a', 'b', '?')) + + test({ osw => osw.print("ab\ud83d"); osw.print("\ud83dc") }, + js.Array('a', 'b', '?', '?', 'c')) + + test({ osw => osw.print('\ud83d'); osw.close() }, + js.Array('?')) + + test({ osw => osw.print("ab\ud83d"); osw.close() }, + js.Array('a', 'b', '?')) + } + + for (autoFlush <- Seq(true, false)) { + val title = + if (autoFlush) "println forwards and flushes when autoFlush is true" + else "println forwards, does not flush when autoFlush is false" + it(title) { + def test(body: PrintStream => Unit, expected: String): Unit = { + val (ps, bos) = newPrintStream(autoFlush = autoFlush) + body(ps) + if (autoFlush) expect(bos.flushed).toBeTruthy + else expect(bos.flushed).toBeFalsy + expect(ps.checkError()).toBeFalsy + expect(bos.toString()).toBe(expected) + } + + test(_.println(), "\n") + test(_.println(true), "true\n") + test(_.println('Z'), "Z\n") + test(_.println('\n'), "\n\n") + test(_.println(5), "5\n") + test(_.println(1234567891011L), "1234567891011\n") + test(_.println(1.5f), "1.5\n") + test(_.println(Math.PI), "3.141592653589793\n") + test(_.println(Array('A', '\n')), "A\n\n") + test(_.println("hello\n"), "hello\n\n") + test(_.println(null: String), "null\n") + test(_.println((1, 2)), "(1,2)\n") + test(_.println(null: AnyRef), "null\n") + } + } + + for (autoFlush <- Seq(true, false)) { + val title = + if (autoFlush) "printf/format, which flushes when autoFlush is true" + else "printf/format, does not flush when autoFlush is false" + it(title) { + def test(body: PrintStream => Unit, expected: String): Unit = { + val (ps, bos) = newPrintStream(autoFlush = autoFlush) + body(ps) + if (autoFlush) expect(bos.flushed).toBeTruthy + else expect(bos.flushed).toBeFalsy + expect(ps.checkError()).toBeFalsy + expect(bos.toString()).toBe(expected) + } + + test(_.printf("%04d", Int.box(5)), "0005") + test(_.format("%.5f", Double.box(Math.PI)), "3.14159") + } + } + + it("append") { + def test(body: PrintStream => Unit, expected: String, + testFlushed: Boolean = false): Unit = { + val (ps, bos) = newPrintStream(autoFlush = true) + body(ps) + if (testFlushed) + expect(bos.flushed).toBeTruthy + expect(ps.checkError()).toBeFalsy + expect(bos.toString()).toBe(expected) + } + + test(_.append("hello\n"), "hello\n", testFlushed = true) + test(_.append(null: CharSequence), "null") + test(_.append("hello\nworld", 3, 6), "lo\n", testFlushed = true) + test(_.append(null: CharSequence, 1, 2), "u") + test(_.append('A'), "A") + test(_.append('\n'), "\n", testFlushed = true) + } + + it("traps all IOException and updates checkError") { + def test(body: PrintStream => Unit): Unit = { + val (ps, bos) = newPrintStream() + bos.throwing = true + body(ps) + expect(ps.checkError()).toBeTruthy + } + + test(_.flush()) + test(_.close()) + + test(_.write('Z')) + test(_.write(Array[Byte]('A', 'B'))) + test(_.write(Array[Byte]('A', 'B'), 1, 1)) + + test(_.print(true)) + test(_.print('Z')) + test(_.print('\n')) + test(_.print(5)) + test(_.print(1234567891011L)) + test(_.print(1.5f)) + test(_.print(Math.PI)) + test(_.print(Array('A', '\n'))) + test(_.print("hello\n")) + test(_.print(null: String)) + test(_.print((1, 2))) + test(_.print(null: AnyRef)) + + test(_.println()) + test(_.println(true)) + test(_.println('Z')) + test(_.println('\n')) + test(_.println(5)) + test(_.println(1234567891011L)) + test(_.println(1.5f)) + test(_.println(Math.PI)) + test(_.println(Array('A', '\n'))) + test(_.println("hello\n")) + test(_.println(null: String)) + test(_.println((1, 2))) + test(_.println(null: AnyRef)) + + test(_.append("hello\n")) + test(_.append(null: CharSequence)) + test(_.append("hello\nworld", 3, 6)) + test(_.append(null: CharSequence, 1, 2)) + test(_.append('A')) + test(_.append('\n')) + } + + it("write short-circuits pending high surrogates in print") { + val (ps, bos) = newPrintStream() + ps.print('A') + expect(bos.toByteArray.toJSArray).toEqual(js.Array[Byte]('A')) + ps.print('\ud83d') + expect(bos.toByteArray.toJSArray).toEqual(js.Array[Byte]('A')) + ps.flush() + expect(bos.toByteArray.toJSArray).toEqual(js.Array[Byte]('A')) + ps.write('Z') + expect(bos.toByteArray.toJSArray).toEqual(js.Array[Byte]('A', 'Z')) + ps.print('\udca9') + expect(bos.toByteArray.toJSArray).toEqual(js.Array[Byte]( + 'A', 'Z', -16, -97, -110, -87)) + } + } + + /** A PrintStream that exposes various hooks for testing purposes. */ + private class MockPrintStream(out: OutputStream, + autoFlush: Boolean) extends PrintStream(out, autoFlush) { + def this(out: OutputStream) = this(out, false) + + override def clearError(): Unit = super.clearError() + } + +} diff --git a/test-suite/src/test/scala/scala/scalajs/testsuite/javalib/PrintWriterTest.scala b/test-suite/src/test/scala/scala/scalajs/testsuite/javalib/PrintWriterTest.scala new file mode 100644 index 0000000..b2b3309 --- /dev/null +++ b/test-suite/src/test/scala/scala/scalajs/testsuite/javalib/PrintWriterTest.scala @@ -0,0 +1,287 @@ +/* __ *\ +** ________ ___ / / ___ __ ____ Scala.js Test Suite ** +** / __/ __// _ | / / / _ | __ / // __/ (c) 2013, LAMP/EPFL ** +** __\ \/ /__/ __ |/ /__/ __ |/_// /_\ \ http://scala-js.org/ ** +** /____/\___/_/ |_/____/_/ | |__/ /____/ ** +** |/____/ ** +\* */ +package scala.scalajs.testsuite.javalib + +import scala.language.implicitConversions + +import java.io._ + +import scala.scalajs.js +import org.scalajs.jasminetest.JasmineTest + +object PrintWriterTest extends JasmineTest { + private def newPrintWriter( + autoFlush: Boolean = false): (MockPrintWriter, MockStringWriter) = { + val sw = new MockStringWriter + val pw = new MockPrintWriter(sw, autoFlush) + (pw, sw) + } + + describe("java.io.PrintWriter") { + it("flush") { + val (pw, sw) = newPrintWriter() + pw.print("hello") + expect(sw.flushed).toBeFalsy + pw.flush() + expect(sw.flushed).toBeTruthy + } + + it("close") { + val (pw, sw) = newPrintWriter() + pw.write("begin") + expect(sw.flushed).toBeFalsy + + pw.close() + expect(sw.flushed).toBeTruthy + expect(sw.closed).toBeTruthy + expect(pw.checkError()).toBeFalsy + + // can double-close without error + pw.close() + expect(pw.checkError()).toBeFalsy + pw.clearError() + + // when closed, other operations cause error + def expectCausesError(body: => Unit): Unit = { + body + expect(pw.checkError()).toBeTruthy + pw.clearError() + } + expectCausesError(pw.print("never printed")) + expectCausesError(pw.write(Array('a', 'b'))) + expectCausesError(pw.append("hello", 1, 3)) + expectCausesError(pw.flush()) + + // at the end of it all, sw is still what it was when it was closed + expect(sw.toString()).toBe("begin") + } + + it("write, does not flush even with \\n") { + def test(body: PrintWriter => Unit, expected: String): Unit = { + val (pw, sw) = newPrintWriter(autoFlush = true) + body(pw) + expect(sw.flushed).toBeFalsy + expect(pw.checkError()).toBeFalsy + expect(sw.toString()).toBe(expected) + } + + test(_.write('\n'), "\n") + test(_.write("hello\n"), "hello\n") + test(_.write("hello\nworld", 3, 3), "lo\n") + test(_.write(Array('A', '\n')), "A\n") + test(_.write(Array('A', 'B', '\n', 'C'), 1, 2), "B\n") + } + + it("print, does not flush even with \\n") { + def test(body: PrintWriter => Unit, expected: String): Unit = { + val (pw, sw) = newPrintWriter(autoFlush = true) + body(pw) + expect(sw.flushed).toBeFalsy + expect(pw.checkError()).toBeFalsy + expect(sw.toString()).toBe(expected) + } + + test(_.print(true), "true") + test(_.print('Z'), "Z") + test(_.print('\n'), "\n") + test(_.print(5), "5") + test(_.print(1234567891011L), "1234567891011") + test(_.print(1.5f), "1.5") + test(_.print(Math.PI), "3.141592653589793") + test(_.print(Array('A', '\n')), "A\n") + test(_.print("hello\n"), "hello\n") + test(_.print(null: String), "null") + test(_.print((1, 2)), "(1,2)") + test(_.print(null: AnyRef), "null") + } + + for (autoFlush <- Seq(true, false)) { + val title = + if (autoFlush) "println forwards and flushes when autoFlush is true" + else "println forwards, does not flush when autoFlush is false" + it(title) { + def test(body: PrintWriter => Unit, expected: String): Unit = { + val (pw, sw) = newPrintWriter(autoFlush = autoFlush) + body(pw) + if (autoFlush) expect(sw.flushed).toBeTruthy + else expect(sw.flushed).toBeFalsy + expect(pw.checkError()).toBeFalsy + expect(sw.toString()).toBe(expected) + } + + test(_.println(), "\n") + test(_.println(true), "true\n") + test(_.println('Z'), "Z\n") + test(_.println('\n'), "\n\n") + test(_.println(5), "5\n") + test(_.println(1234567891011L), "1234567891011\n") + test(_.println(1.5f), "1.5\n") + test(_.println(Math.PI), "3.141592653589793\n") + test(_.println(Array('A', '\n')), "A\n\n") + test(_.println("hello\n"), "hello\n\n") + test(_.println(null: String), "null\n") + test(_.println((1, 2)), "(1,2)\n") + test(_.println(null: AnyRef), "null\n") + } + } + + for (autoFlush <- Seq(true, false)) { + val title = + if (autoFlush) "printf/format, which flushes when autoFlush is true" + else "printf/format, does not flush when autoFlush is false" + it(title) { + def test(body: PrintWriter => Unit, expected: String): Unit = { + val (pw, sw) = newPrintWriter(autoFlush = autoFlush) + body(pw) + if (autoFlush) expect(sw.flushed).toBeTruthy + else expect(sw.flushed).toBeFalsy + expect(pw.checkError()).toBeFalsy + expect(sw.toString()).toBe(expected) + } + + test(_.printf("%04d", Int.box(5)), "0005") + test(_.format("%.5f", Double.box(Math.PI)), "3.14159") + } + } + + it("append, does not flush even with \\n") { + def test(body: PrintWriter => Unit, expected: String): Unit = { + val (pw, sw) = newPrintWriter(autoFlush = true) + body(pw) + expect(sw.flushed).toBeFalsy + expect(pw.checkError()).toBeFalsy + expect(sw.toString()).toBe(expected) + } + + test(_.append("hello\n"), "hello\n") + test(_.append(null: CharSequence), "null") + test(_.append("hello\nworld", 3, 6), "lo\n") + test(_.append(null: CharSequence, 1, 2), "u") + test(_.append('A'), "A") + test(_.append('\n'), "\n") + } + + it("traps all IOException and updates checkError") { + def test(body: PrintWriter => Unit): Unit = { + val (pw, sw) = newPrintWriter() + sw.throwing = true + body(pw) + expect(pw.checkError()).toBeTruthy + } + + test(_.flush()) + test(_.close()) + + test(_.write('Z')) + test(_.write("booh")) + test(_.write("booh", 1, 1)) + test(_.write(Array('A', 'B'))) + test(_.write(Array('A', 'B'), 1, 1)) + + test(_.print(true)) + test(_.print('Z')) + test(_.print('\n')) + test(_.print(5)) + test(_.print(1234567891011L)) + test(_.print(1.5f)) + test(_.print(Math.PI)) + test(_.print(Array('A', '\n'))) + test(_.print("hello\n")) + test(_.print(null: String)) + test(_.print((1, 2))) + test(_.print(null: AnyRef)) + + test(_.println()) + test(_.println(true)) + test(_.println('Z')) + test(_.println('\n')) + test(_.println(5)) + test(_.println(1234567891011L)) + test(_.println(1.5f)) + test(_.println(Math.PI)) + test(_.println(Array('A', '\n'))) + test(_.println("hello\n")) + test(_.println(null: String)) + test(_.println((1, 2))) + test(_.println(null: AnyRef)) + + test(_.append("hello\n")) + test(_.append(null: CharSequence)) + test(_.append("hello\nworld", 3, 6)) + test(_.append(null: CharSequence, 1, 2)) + test(_.append('A')) + test(_.append('\n')) + } + } + + /** A PrintWriter that exposes various hooks for testing purposes. */ + private class MockPrintWriter(out: Writer, + autoFlush: Boolean) extends PrintWriter(out, autoFlush) { + def this(out: Writer) = this(out, false) + + override def clearError(): Unit = super.clearError() + } + + /** A StringWriter that exposes various hooks for testing purposes. */ + private class MockStringWriter extends StringWriter { + private var _flushed: Boolean = true + private var _closed: Boolean = false + + var throwing: Boolean = false + + def flushed: Boolean = _flushed + def closed: Boolean = _closed + + private def maybeThrow(): Unit = { + if (throwing) + throw new IOException("MockStringWriter throws") + } + + private def writeOp[A](op: => A): A = { + maybeThrow() + _flushed = false + op + } + + override def flush(): Unit = { + maybeThrow() + super.flush() + _flushed = true + } + + override def close(): Unit = { + maybeThrow() + super.close() + _closed = true + } + + override def append(c: Char): StringWriter = + writeOp(super.append(c)) + + override def append(csq: CharSequence): StringWriter = + writeOp(super.append(csq)) + + override def append(csq: CharSequence, start: Int, end: Int): StringWriter = + writeOp(super.append(csq, start, end)) + + override def write(c: Int): Unit = + writeOp(super.write(c)) + + override def write(cbuf: Array[Char]): Unit = + writeOp(super.write(cbuf)) + + override def write(cbuf: Array[Char], off: Int, len: Int): Unit = + writeOp(super.write(cbuf, off, len)) + + override def write(str: String): Unit = + writeOp(super.write(str)) + + override def write(str: String, off: Int, len: Int): Unit = + writeOp(super.write(str, off, len)) + } +} diff --git a/test-suite/src/test/scala/scala/scalajs/testsuite/javalib/RandomTest.scala b/test-suite/src/test/scala/scala/scalajs/testsuite/javalib/RandomTest.scala new file mode 100644 index 0000000..1794d4a --- /dev/null +++ b/test-suite/src/test/scala/scala/scalajs/testsuite/javalib/RandomTest.scala @@ -0,0 +1,225 @@ +/* __ *\ +** ________ ___ / / ___ __ ____ Scala.js Test Suite ** +** / __/ __// _ | / / / _ | __ / // __/ (c) 2013, LAMP/EPFL ** +** __\ \/ /__/ __ |/ /__/ __ |/_// /_\ \ http://scala-js.org/ ** +** /____/\___/_/ |_/____/_/ | |__/ /____/ ** +** |/____/ ** +\* */ +package scala.scalajs.testsuite.javalib + +import org.scalajs.jasminetest.JasmineTest + +import java.util.Random + +import scala.scalajs.js +import scala.scalajs.js.JSConverters._ + +object RandomTest extends JasmineTest { + + describe("java.util.Random") { + + it("should produce bits according to spec with seed=10") { + val random = new HackRandom(10) + + expect(random.next(10)).toBe(747) + expect(random.next(1)).toBe(0) + expect(random.next(6)).toBe(16) + expect(random.next(20)).toBe(432970) + expect(random.next(32)).toBe(254270492) + } + + it("should produce bits according to spec with seed=-5") { + val random = new HackRandom(-5) + + expect(random.next(10)).toBe(275) + expect(random.next(1)).toBe(0) + expect(random.next(6)).toBe(21) + expect(random.next(20)).toBe(360349) + expect(random.next(32)).toBe(1635930704) + } + + it("should produce bits according to spec with seed=MaxLong") { + val random = new HackRandom(Long.MaxValue) + + expect(random.next(10)).toBe(275) + expect(random.next(1)).toBe(0) + expect(random.next(6)).toBe(0) + expect(random.next(20)).toBe(574655) + expect(random.next(32)).toBe(-1451336087) + } + + it("should produce bits according to spec with seed=MinInt") { + val random = new HackRandom(Int.MinValue) + + expect(random.next(10)).toBe(388) + expect(random.next(1)).toBe(0) + expect(random.next(6)).toBe(25) + expect(random.next(20)).toBe(352095) + expect(random.next(32)).toBe(-2140124682) + } + + it("should allow resetting the seed") { + val random = new HackRandom(11) + expect(random.next(10)).toBe(747) + expect(random.next(1)).toBe(1) + expect(random.next(6)).toBe(27) + + random.setSeed(11) + expect(random.next(10)).toBe(747) + expect(random.next(1)).toBe(1) + expect(random.next(6)).toBe(27) + } + + it("should reset nextNextGaussian when setting the seed") { + val random = new Random(-1) + expect(random.nextGaussian()).toBe(1.7853314409882288) + random.setSeed(-1) + expect(random.nextGaussian()).toBe(1.7853314409882288) + } + + it("should correctly implement nextDouble") { + val random = new Random(-45) + expect(random.nextDouble()).toBe(0.27288421395636253) + expect(random.nextDouble()).toBe(0.5523165360074201) + expect(random.nextDouble()).toBe(0.5689979434708298) + expect(random.nextDouble()).toBe(0.9961166166874871) + expect(random.nextDouble()).toBe(0.5368984665202684) + expect(random.nextDouble()).toBe(0.19849067496547423) + expect(random.nextDouble()).toBe(0.6021019223595357) + expect(random.nextDouble()).toBe(0.06132131151816378) + expect(random.nextDouble()).toBe(0.7303867762743866) + expect(random.nextDouble()).toBe(0.7426529384056163) + } + + it("should correctly implement nextBoolean") { + val random = new Random(4782934) + expect(random.nextBoolean()).toBe(false) + expect(random.nextBoolean()).toBe(true) + expect(random.nextBoolean()).toBe(true) + expect(random.nextBoolean()).toBe(false) + expect(random.nextBoolean()).toBe(false) + expect(random.nextBoolean()).toBe(false) + expect(random.nextBoolean()).toBe(true) + expect(random.nextBoolean()).toBe(false) + } + + it("should correctly implement nextInt") { + val random = new Random(-84638) + expect(random.nextInt()).toBe(-1217585344) + expect(random.nextInt()).toBe(1665699216) + expect(random.nextInt()).toBe(382013296) + expect(random.nextInt()).toBe(1604432482) + expect(random.nextInt()).toBe(-1689010196) + expect(random.nextInt()).toBe(1743354032) + expect(random.nextInt()).toBe(454046816) + expect(random.nextInt()).toBe(922172344) + expect(random.nextInt()).toBe(-1890515287) + expect(random.nextInt()).toBe(1397525728) + } + + it("should correctly implement nextInt(n)") { + val random = new Random(7) + expect(random.nextInt(76543)).toBe(32736) + expect(() => random.nextInt(0)).toThrow + expect(random.nextInt(45)).toBe(29) + expect(random.nextInt(945)).toBe(60) + expect(random.nextInt(35694839)).toBe(20678044) + expect(random.nextInt(35699)).toBe(23932) + expect(random.nextInt(3699)).toBe(2278) + expect(random.nextInt(10)).toBe(8) + } + + it("should correctly implement nextInt(n) for powers of 2") { + val random = new Random(-56938) + + expect(random.nextInt(32)).toBe(8) + expect(random.nextInt(8)).toBe(3) + expect(random.nextInt(128)).toBe(3) + expect(random.nextInt(4096)).toBe(1950) + expect(random.nextInt(8192)).toBe(3706) + expect(random.nextInt(8192)).toBe(4308) + expect(random.nextInt(8192)).toBe(3235) + expect(random.nextInt(8192)).toBe(7077) + expect(random.nextInt(8192)).toBe(2392) + expect(random.nextInt(32)).toBe(31) + } + + it("should correctly implement nextLong") { + val random = new Random(205620432625028L) + expect(random.nextLong()).toBe(3710537363280377478L) + expect(random.nextLong()).toBe(4121778334981170700L) + expect(random.nextLong()).toBe(289540773990891960L) + expect(random.nextLong()).toBe(307008980197674441L) + expect(random.nextLong()).toBe(7527069864796025013L) + expect(random.nextLong()).toBe(-4563192874520002144L) + expect(random.nextLong()).toBe(7619507045427546529L) + expect(random.nextLong()).toBe(-7888117030898487184L) + expect(random.nextLong()).toBe(-3499168703537933266L) + expect(random.nextLong()).toBe(-1998975913933474L) + } + + it("should correctly implement nextFloat") { + val random = new Random(-3920005825473L) + expect(random.nextFloat()).toBeCloseTo(0.059591234, 7) + expect(random.nextFloat()).toBeCloseTo(0.7007871, 7) + expect(random.nextFloat()).toBeCloseTo(0.39173192, 7) + expect(random.nextFloat()).toBeCloseTo(0.0647918, 7) + expect(random.nextFloat()).toBeCloseTo(0.9029677, 7) + expect(random.nextFloat()).toBeCloseTo(0.18226051, 7) + expect(random.nextFloat()).toBeCloseTo(0.94444054, 7) + expect(random.nextFloat()).toBeCloseTo(0.008844078, 7) + expect(random.nextFloat()).toBeCloseTo(0.08891684, 7) + expect(random.nextFloat()).toBeCloseTo(0.06482434, 7) + } + + it("should correctly implement nextBytes") { + val random = new Random(7399572013373333L) + + def test(exps: Int*) = { + val exp = js.Array(exps.map(_.toByte): _*) + val buf = new Array[Byte](exp.length) + random.nextBytes(buf) + expect(buf.toJSArray).toEqual(exp) + } + + test(62, 89, 68, -91, 10, 0, 85) + test(-89, -76, 88, 121, -25, 47, 58, -8, 78, 20, -77, 84, -3, + -33, 58, -9, 11, 57, -118, 40, -74, -86, 78, 123, 58) + test(-77, 112, -116) + test() + test(-84, -96, 108) + test(57, -106, 42, -100, -47, -84, 67, -48, 45) + } + + it("should correctly implement nextGaussian") { + val random = new Random(2446004) + expect(random.nextGaussian()).toBe(-0.5043346938630431) + expect(random.nextGaussian()).toBe(-0.3250983270156675) + expect(random.nextGaussian()).toBe(-0.23799457294994966) + expect(random.nextGaussian()).toBe(0.4164610631507695) + expect(random.nextGaussian()).toBe(0.22086348814760687) + expect(random.nextGaussian()).toBe(-0.706833209972521) + expect(random.nextGaussian()).toBe(0.6730758289772553) + expect(random.nextGaussian()).toBe(0.2797393696191283) + expect(random.nextGaussian()).toBe(-0.2979099632667685) + expect(random.nextGaussian()).toBe(0.37443415981434314) + expect(random.nextGaussian()).toBe(0.9584801742918951) + expect(random.nextGaussian()).toBe(1.1762179112229345) + expect(random.nextGaussian()).toBe(0.8736960092848826) + expect(random.nextGaussian()).toBe(0.12301554931271008) + expect(random.nextGaussian()).toBe(-0.6052081187207353) + expect(random.nextGaussian()).toBe(-0.2015925608755316) + expect(random.nextGaussian()).toBe(-1.0071216119742104) + expect(random.nextGaussian()).toBe(0.6734222041441913) + expect(random.nextGaussian()).toBe(0.3990565555091522) + expect(random.nextGaussian()).toBe(2.0051627385915154) + } + + } + + /** Helper class to access next */ + class HackRandom(seed: Long) extends Random(seed) { + override def next(bits: Int): Int = super.next(bits) + } + +} diff --git a/test-suite/src/test/scala/scala/scalajs/testsuite/javalib/ReadersTest.scala b/test-suite/src/test/scala/scala/scalajs/testsuite/javalib/ReadersTest.scala new file mode 100644 index 0000000..f970141 --- /dev/null +++ b/test-suite/src/test/scala/scala/scalajs/testsuite/javalib/ReadersTest.scala @@ -0,0 +1,244 @@ +/* __ *\ +** ________ ___ / / ___ __ ____ Scala.js Test Suite ** +** / __/ __// _ | / / / _ | __ / // __/ (c) 2013, LAMP/EPFL ** +** __\ \/ /__/ __ |/ /__/ __ |/_// /_\ \ http://scala-js.org/ ** +** /____/\___/_/ |_/____/_/ | |__/ /____/ ** +** |/____/ ** +\* */ +package scala.scalajs.testsuite.javalib + +import scala.annotation.tailrec + +import java.io._ + +import scala.scalajs.js +import scala.scalajs.js.JSConverters._ + +import org.scalajs.jasminetest.JasmineTest + +/** Tests for our implementation of java.io._ reader classes */ +object ReadersTest extends JasmineTest { + + describe("java.io.StringReader") { + val str = "asdf" + def newReader = new StringReader(str) + + it("should provide read()") { + val r = newReader + + for (c <- str) { + expect(r.read().toChar).toEqual(c) + } + + expect(r.read()).toEqual(-1) + } + + it("should provide read(buf: Array[Char], off: Int, len: Int)") { + val r = newReader + val buf = new Array[Char](10) + + expect(r.read(buf, 2, 8)).toBe(4) + expect(buf.map(_.toInt).toJSArray).toEqual( + js.Array[Int](0,0,'a','s','d','f',0,0,0,0)) + } + + it("should provide read(java.nio.CharBuffer)") { + val r = newReader + val buf0 = java.nio.CharBuffer.allocate(25) + buf0.position(3) + val buf = buf0.slice() + buf.position(4) + buf.limit(14) + + expect(r.read(buf)).toBe(4) + expect(buf.position()).toBe(8) + buf.flip() + expect(buf.toString().map(_.toInt).toJSArray).toEqual( + js.Array[Int](0, 0, 0, 0, 'a', 's', 'd', 'f')) + } + + it("should provide ready") { + val r = newReader + + for (c <- str) { + expect(r.ready()).toBeTruthy + expect(r.read().toChar).toEqual(c) + } + + expect(r.ready()).toBeFalsy + expect(r.read()).toEqual(-1) + } + + it("should provide mark/reset") { + val r = newReader + r.mark(str.length) + + for (c <- str) { + expect(r.read().toChar).toEqual(c) + } + expect(r.read()).toEqual(-1) + + r.reset() + + for (c <- str) { + expect(r.read().toChar).toEqual(c) + } + expect(r.read()).toEqual(-1) + } + + it("should provide skip") { + val r = newReader + + expect(r.read()).toEqual('a') + expect(r.skip(2L).toInt).toBe(2) + + expect(r.read()).toEqual('f') + expect(r.read()).toEqual(-1) + } + + it("should provide close") { + val r = newReader + + r.close() + expect(() => r.read()).toThrow + } + + it("should support marking") { + expect(newReader.markSupported).toBeTruthy + } + } + + describe("java.io.BufferedReader") { + val str = "line1\nline2\r\n\nline4\rline5" + def newReader = new BufferedReader(new StringReader(str), 3) + + it("should provide read()") { + val r = newReader + + for (c <- str) { + expect(r.read().toChar).toEqual(c) + } + expect(r.read()).toEqual(-1) + } + + it("should provide read(cbuf)") { + var read = 0 + val r = newReader + val buf = new Array[Char](15) + + // twice to force filling internal buffer + for (_ <- 0 to 1) { + val len = r.read(buf) + expect(len).toBeGreaterThan(0) + + for (i <- 0 until len) + expect(buf(i)).toEqual(str.charAt(i+read)) + + read += len + } + } + + it("should provide read(cbuf, off, len)") { + var read = 0 + val r = newReader + val buf = new Array[Char](15) + + // twice to force filling internal buffer + for (_ <- 0 to 1) { + val len = r.read(buf, 1, 10) + expect(len).toBeGreaterThan(0) + expect(len).toBeLessThan(11) + + for (i <- 0 until len) + expect(buf(i+1)).toEqual(str.charAt(i+read)) + + read += len + } + } + + it("should provide mark/reset") { + val r = newReader + expect(r.read()).toEqual('l') + + // force moving and resizing buffer + r.mark(10) + + for (i <- 0 until 10) { + expect(r.read()).toEqual(str.charAt(i+1)) + } + + r.reset() + + for (i <- 1 until str.length) { + expect(r.read()).toEqual(str.charAt(i)) + } + } + + it("should provide readLine") { + val r = newReader + + expect(r.readLine()).toEqual("line1") + expect(r.readLine()).toEqual("line2") + expect(r.readLine()).toEqual("") + expect(r.readLine()).toEqual("line4") + expect(r.readLine()).toEqual("line5") + expect(r.readLine()).toEqual(null) + } + + it("should readLine on an empty stream") { + val r = new BufferedReader(new StringReader("")) + + expect(r.readLine()).toEqual(null) + } + + it("should readline with empty lines only") { + val r = new BufferedReader(new StringReader("\n\r\n\r\r\n"), 1) + + for (_ <- 1 to 4) + expect(r.readLine()).toEqual("") + + expect(r.readLine()).toEqual(null) + } + + it("should support marking") { + expect(newReader.markSupported).toBeTruthy + } + } + + describe("java.io.InputStreamReader") { + + it("should read UTF8") { + + val buf = Array[Byte](72, 101, 108, 108, 111, 32, 87, 111, 114, 108, 100, + 46, -29, -127, -109, -29, -126, -109, -29, -127, -85, -29, -127, -95, + -29, -127, -81, -26, -105, -91, -26, -100, -84, -24, -86, -98, -29, + -126, -110, -24, -86, -83, -29, -126, -127, -29, -127, -66, -29, -127, + -103, -29, -127, -117, -29, -128, -126) + + val r = new InputStreamReader(new ByteArrayInputStream(buf)) + + def expectRead(str: String) = { + val buf = new Array[Char](str.length) + @tailrec + def readAll(readSoFar: Int): Int = { + if (readSoFar == buf.length) readSoFar + else { + val newlyRead = r.read(buf, readSoFar, buf.length - readSoFar) + if (newlyRead == -1) readSoFar + else readAll(readSoFar + newlyRead) + } + } + expect(readAll(0)).toBe(str.length) + expect(new String(buf)).toEqual(str) + } + + expectRead("Hello World.") + expectRead("こんにちは") + expectRead("日本語を読めますか。") + expect(r.read()).toBe(-1) + + } + + } + +} diff --git a/test-suite/src/test/scala/scala/scalajs/testsuite/javalib/ReferenceTest.scala b/test-suite/src/test/scala/scala/scalajs/testsuite/javalib/ReferenceTest.scala new file mode 100644 index 0000000..cf0fd0c --- /dev/null +++ b/test-suite/src/test/scala/scala/scalajs/testsuite/javalib/ReferenceTest.scala @@ -0,0 +1,28 @@ +/* __ *\ +** ________ ___ / / ___ __ ____ Scala.js Test Suite ** +** / __/ __// _ | / / / _ | __ / // __/ (c) 2013, LAMP/EPFL ** +** __\ \/ /__/ __ |/ /__/ __ |/_// /_\ \ http://scala-js.org/ ** +** /____/\___/_/ |_/____/_/ | |__/ /____/ ** +** |/____/ ** +\* */ +package scala.scalajs.testsuite.javalib + +import org.scalajs.jasminetest.JasmineTest + +object ReferenceTest extends JasmineTest { + + describe("java.land.ref.Reference") { + + it("Should have all the normal operations") { + val s = "string" + val ref = new java.lang.ref.WeakReference(s) + expect(ref.get).toEqual(s) + expect(ref.enqueue).toEqual(false) + expect(ref.isEnqueued).toEqual(false) + ref.clear + // can't use `expect` because it tries to be clever and .toString things, + // which makes it blow up when you pass in null + assert(ref.get == null) + } + } +} diff --git a/test-suite/src/test/scala/scala/scalajs/testsuite/javalib/RegexTest.scala b/test-suite/src/test/scala/scala/scalajs/testsuite/javalib/RegexTest.scala new file mode 100644 index 0000000..a27584a --- /dev/null +++ b/test-suite/src/test/scala/scala/scalajs/testsuite/javalib/RegexTest.scala @@ -0,0 +1,397 @@ +/* __ *\ +** ________ ___ / / ___ __ ____ Scala.js Test Suite ** +** / __/ __// _ | / / / _ | __ / // __/ (c) 2013, LAMP/EPFL ** +** __\ \/ /__/ __ |/ /__/ __ |/_// /_\ \ http://scala-js.org/ ** +** /____/\___/_/ |_/____/_/ | |__/ /____/ ** +** |/____/ ** +\* */ +package scala.scalajs.testsuite.javalib + +import scala.scalajs.js +import scala.scalajs.js.JSConverters._ + +import org.scalajs.jasminetest.JasmineTest + +import java.util.regex.Pattern + +object RegexTest extends JasmineTest { + + describe("java.util.regex.Pattern") { + + it("should respond to `matches`") { + expect(Pattern.matches("[Scal]*\\.js", "Scala.js")).toBeTruthy + expect(Pattern.matches(".[cal]*\\.j.", "Scala.js")).toBeTruthy + expect(Pattern.matches(".*\\.js", "Scala.js")).toBeTruthy + expect(Pattern.matches("S[a-z]*", "Scala.js")).toBeFalsy + } + + it("should respond to `matches` with flags") { + matches("scala.js", "Scala.js") + matches("SCALA.JS", "Scala.js") + matches("waz*up", "WAZZZZZZZZZZZUP") + + def matches(regex: String, input: String): Unit = { + val result = Pattern.compile(regex, Pattern.CASE_INSENSITIVE).matcher(input) + expect(result.matches()).toBeTruthy + } + } + + it("should respond to `split`") { + val result = Pattern.compile("[aj]").split("Scala.js") + val expected = js.Array("Sc", "l", ".", "s") + expect(result.length).toEqual(4) + expect(result.toJSArray).toEqual(expected) + + // Tests from JavaDoc + split("boo:and:foo", ":", Array("boo", "and", "foo")) + split("boo:and:foo", "o", Array("b", "", ":and:f")) + + // Splitting the empty string must return 1 element - #987 + split("", "a", Array("")) + split("", "\\*", Array("")) + split("", "\n", Array("")) + split("", "", Array("")) + + // Should remove leading empty match under some conditions - #1171 + // These tests are "measured" on the JVM since the spec is unclear + split("abc", "(?=a)", Array("abc")) + split("abc", "(?=b)", Array("a", "bc")) + split("abc", "(?=a)|b", Array("", "a", "c")) + split("abc", "", Array("", "a", "b", "c")) + split("abc", "(?=a)|(?=b)", Array("", "a", "bc")) + split("abc", "(?=a)|(?=a)", Array("abc")) + split("abc", "(?=a|b)", Array("", "a", "bc")) + split("abc", "(?=a|d)", Array("abc")) + split("abc", "^d*", Array("abc")) + split("abc", "d*", Array("", "a", "b", "c")) + split("a", "", Array("", "a")) + split("a", "^d*", Array("a")) + split("a", "d*", Array("", "a")) + split("a", "(?=a)", Array("a")) + split("ab", "a", Array("", "b")) + + def split(input: String, regex: String, expected: Array[String]): Unit = { + val result = Pattern.compile(regex).split(input) + expect(result.toJSArray).toEqual(expected.toJSArray) + } + } + + it("should respond to `split` with limit") { + // Tests from JavaDoc + splitWithLimit("boo:and:foo", ":", 2, Array("boo", "and:foo")) + splitWithLimit("boo:and:foo", ":", 5, Array("boo", "and", "foo")) + splitWithLimit("boo:and:foo", ":", -2, Array("boo", "and", "foo")) + splitWithLimit("boo:and:foo", "o", 5, Array("b", "", ":and:f", "", "")) + splitWithLimit("boo:and:foo", "o", -2, Array("b", "", ":and:f", "", "")) + splitWithLimit("boo:and:foo", "o", 0, Array("b", "", ":and:f")) + + // Splitting the empty string must return 1 element - #987 + splitWithLimit("", "a", 0, Array("")) + splitWithLimit("", "\\*", 5, Array("")) + splitWithLimit("", "\n", -2, Array("")) + splitWithLimit("", "", 1, Array("")) + + // Should remove leading empty match under some conditions - #1171 + splitWithLimit("abc", "", 2, Array("", "abc")) + splitWithLimit("abc", "(?=a)", 2, Array("abc")) + splitWithLimit("ab", "a", 1, Array("ab")) + + def splitWithLimit(input: String, regex: String, limit: Int, expected: Array[String]): Unit = { + val result = Pattern.compile(regex).split(input, limit) + expect(result.toJSArray).toEqual(expected.toJSArray) + } + } + + it("should respond to `flags`") { + val pattern0 = Pattern.compile("a") + val pattern1 = Pattern.compile("a", 0) + val flags2 = Pattern.CASE_INSENSITIVE | Pattern.DOTALL + val pattern2 = Pattern.compile("a", flags2) + + expect(pattern0.flags).toEqual(0) + expect(pattern1.flags).toEqual(0) + expect(pattern2.flags).toEqual(flags2) + } + + it("should respond to `pattern` and `toString`") { + def checkPatternAndToString(regex: String): Unit = { + val pattern0 = Pattern.compile(regex) + expect(pattern0.pattern).toEqual(regex) + expect(pattern0.toString).toEqual(regex) + + val pattern1 = Pattern.compile(regex, Pattern.CASE_INSENSITIVE) + expect(pattern1.pattern).toEqual(regex) + expect(pattern1.toString).toEqual(regex) + } + + checkPatternAndToString("a*b+c") + checkPatternAndToString("\\S[(a1]a.js") + } + + it("should respond to `quote`") { + val splitWithQuote = Pattern.compile(Pattern.quote("$1&$2")).split("Scala$1&$2.js") + val splitNoQuote = Pattern.compile("$1&$2").split("Scala$1&$2.js") + expect(splitWithQuote.mkString).toEqual("Scala.js") + expect(splitNoQuote.mkString).toEqual("Scala$1&$2.js") + } + + } + + describe("java.util.regex.Matcher") { + + it("should respond to `find`") { + val matcher = Pattern.compile("a").matcher("Scala.js") + + expect(matcher.find()).toBeTruthy + expect(matcher.find()).toBeTruthy + expect(matcher.find()).toBeFalsy + expect(matcher.find(4)).toBeTruthy + expect(matcher.find()).toBeFalsy + } + + it("should respond to `start`, `end`, `group`, and `toMatchResult`") { + val matcher = Pattern.compile("\\s(([A-Za-z]{5}(hum)?).js)\\s").matcher("Write Scala.js everyday!") + + def checkGroup0(start: Int, end: Int, group: String) = + checkGroup(start, 5, end, 15, group, " Scala.js ") + + def checkGroup1(start: Int, end: Int, group: String) = + checkGroup(start, 6, end, 14, group, "Scala.js") + + def checkGroup2(start: Int, end: Int, group: String) = + checkGroup(start, 6, end, 11, group, "Scala") + + def checkGroup3(start: Int, end: Int, group: String) = + checkGroup(start, -1, end, -1, group, null) + + def checkGroup(start: Int, startExpected: Int, end: Int, endExpected: Int, + group: String, groupExpected: String): Unit = { + expect(start).toEqual(startExpected) + expect(end).toEqual(endExpected) + expect(group).toEqual(groupExpected) + } + + expect(matcher.find()).toBeTruthy + expect(matcher.groupCount).toEqual(3) + checkGroup0(matcher.start, matcher.end, matcher.group) + checkGroup0(matcher.start(0), matcher.end(0), matcher.group(0)) + checkGroup1(matcher.start(1), matcher.end(1), matcher.group(1)) + checkGroup2(matcher.start(2), matcher.end(2), matcher.group(2)) + checkGroup3(matcher.start(3), matcher.end(3), matcher.group(3)) + + val matchResult = matcher.toMatchResult + expect(matchResult.groupCount).toEqual(3) + checkGroup0(matchResult.start, matchResult.end, matchResult.group) + checkGroup0(matchResult.start(0), matchResult.end(0), matchResult.group(0)) + checkGroup1(matchResult.start(1), matchResult.end(1), matchResult.group(1)) + checkGroup2(matchResult.start(2), matchResult.end(2), matchResult.group(2)) + checkGroup3(matchResult.start(3), matchResult.end(3), matchResult.group(3)) + } + + it("should respond to `matches`") { + val matcher0 = Pattern.compile("S[a-z]+").matcher("Scala") + val matcher1 = Pattern.compile("S[a-z]+").matcher("Scala.js") + + expect(matcher0.matches()).toBeTruthy + expect(matcher1.matches()).toBeFalsy + } + + it("should respond to `reset`") { + val matcher = Pattern.compile("S[a-z]+").matcher("Scalable") + + expect(matcher.find()).toBeTruthy + expect(matcher.find()).toBeFalsy + matcher.reset() + expect(matcher.find()).toBeTruthy + } + + it("should respond to `reset(String)`") { + val matcher = Pattern.compile("S[a-z]+").matcher("Scalable") + + expect(matcher.matches()).toBeTruthy + matcher.reset("Scala.js") + expect(matcher.matches()).toBeFalsy + } + + it("should respond to `usePattern`") { + val patternNoDots = Pattern.compile("S[a-z]+") + val patternWithDots = Pattern.compile("S[a-z.]+") + + val matcher0 = patternNoDots.matcher("Scala.js") + expect(matcher0.matches()).toBeFalsy + matcher0.usePattern(patternWithDots) + expect(matcher0.matches()).toBeTruthy + + val matcher1 = patternWithDots.matcher("Scala.js") + expect(matcher1.matches()).toBeTruthy + matcher1.usePattern(patternNoDots) + expect(matcher1.matches()).toBeFalsy + } + + it("should respond to `lookingAt`") { + val matcher0 = Pattern.compile("S[a-z]+").matcher("Scala") + val matcher1 = Pattern.compile("S[a-z]+").matcher("Scala.js") + val matcher2 = Pattern.compile("[a-z]+").matcher("Scala.js") + + expect(matcher0.lookingAt()).toBeTruthy + expect(matcher1.lookingAt()).toBeTruthy + expect(matcher2.lookingAt()).toBeFalsy + + val matcher3 = Pattern.compile("S[a-z]+").matcher("Scala.js") + expect(matcher3.find()).toBeTruthy + expect(matcher3.lookingAt()).toBeTruthy + } + + it("should respond to `hitEnd`") { + val matcher0 = Pattern.compile("S[a-z]*").matcher("Scala.js") + expect(matcher0.find()).toBeTruthy + expect(matcher0.hitEnd).toBeFalsy + expect(matcher0.find()).toBeFalsy + expect(matcher0.hitEnd).toBeTruthy + + val matcher1 = Pattern.compile("[A-Za-z]+").matcher("Scala.js") + expect(matcher1.find()).toBeTruthy + expect(matcher1.hitEnd).toBeFalsy + expect(matcher1.group).toBe("Scala") + expect(matcher1.find()).toBeTruthy + expect(matcher1.hitEnd).toBeTruthy + expect(matcher1.group).toBe("js") + expect(matcher1.lookingAt()).toBeTruthy + expect(matcher1.group).toBe("Scala") + expect(matcher1.hitEnd).toBeFalsy + } + + it("should respond to `region`") { + val matcher0 = Pattern.compile("S[a-z]+").matcher("A Scalable Solution") + + val region0to3 = matcher0.region(0, 3) + expect(region0to3.regionStart).toBe(0) + expect(region0to3.regionEnd).toBe(3) + expect(region0to3.find()).toBeFalsy + + val region0to15 = matcher0.region(0, 15) + expect(region0to15.regionStart).toBe(0) + expect(region0to15.regionEnd).toBe(15) + expect(region0to15.find()).toBeTruthy + expect(region0to15.group).toEqual("Scalable") + + val region2to7 = region0to15.region(2, 7) + expect(region2to7.regionStart).toBe(2) + expect(region2to7.regionEnd).toBe(7) + expect(region2to7.find()).toBeTruthy + expect(region2to7.group).toEqual("Scala") + + val region5toEnd = matcher0.region(5, matcher0.regionEnd) + expect(region5toEnd.regionStart).toBe(5) + expect(region5toEnd.regionEnd).toBe(19) + expect(region5toEnd.find()).toBeTruthy + expect(region5toEnd.group).toEqual("Solution") + + val matcher1 = Pattern.compile("0[xX][A-Fa-f0-9]{3}$").matcher("In CSS, 0xc4fe is not a color") + + val region5to13 = matcher1.region(5, 13) + expect(region5to13.regionStart).toBe(5) + expect(region5to13.regionEnd).toBe(13) + expect(region5to13.find()).toBeTruthy + expect(region5to13.group).toEqual("0xc4f") + + val region5to20 = matcher1.region(5, 20) + expect(region5to20.regionStart).toBe(5) + expect(region5to20.regionEnd).toBe(20) + expect(region5to20.find()).toBeFalsy + } + + it("should respond to `appendReplacement` and `appendTail`") { + // From the JavaDoc + val matcher = Pattern.compile("cat").matcher("one cat two cats in the yard") + val sb = new StringBuffer + + while (matcher.find()) { + matcher.appendReplacement(sb, "dog") + } + matcher.appendTail(sb) + + expect(sb.toString).toBe("one dog two dogs in the yard") + } + + it("should respond to `replaceAll`") { + // From the JavaDoc + val matcher = Pattern.compile("a*b").matcher("aabfooaabfooabfoob") + expect(matcher.replaceAll("-")).toBe("-foo-foo-foo-") + } + + it("should respond to `replaceFirst`") { + // From the JavaDoc + val matcher = Pattern.compile("dog").matcher("zzzdogzzzdogzzz") + expect(matcher.replaceFirst("cat")).toBe("zzzcatzzzdogzzz") + } + + it("should throw exception if match accessors are called before `find`") { + def checkInvalidAccess(block: => Unit): Unit = { + val exception: Throwable = try { + block + throw new Error("No exception thrown") + } catch { + case e: Throwable => e + } + + expect(exception.getClass.getName).toBe("java.lang.IllegalStateException") + expect(exception.getMessage).toBe("No match available") + } + + val matcher = Pattern.compile("(Sc([a-z]*))").matcher("Scala.js") + + checkInvalidAccess { matcher.start } + checkInvalidAccess { matcher.end } + checkInvalidAccess { matcher.group } + checkInvalidAccess { matcher.group(42) } + + val matchResult = matcher.toMatchResult + + checkInvalidAccess { matchResult.start } + checkInvalidAccess { matchResult.end } + checkInvalidAccess { matchResult.group } + checkInvalidAccess { matchResult.group(42) } + } + + it("should correctly handle zero-length matches") { + val pat = Pattern.compile("a*?") + val mat = pat.matcher("aaaaa") + for (i <- 0 to 5) { + expect(mat.find()).toBeTruthy + expect(mat.start).toEqual(i) + expect(mat.end).toEqual(i) + } + + // Make sure we don't suddenly re-match + for (i <- 0 to 5) { + expect(mat.find()).toBeFalsy + } + } + + it("should support in-pattern flags - #997") { + val p0 = Pattern.compile("(?i)abc") + + expect(p0.flags() & Pattern.CASE_INSENSITIVE).not.toBe(0) + + val m0 = p0.matcher("abcABC") + + expect(m0.find()).toBeTruthy + expect(m0.group()).toEqual("abc") + expect(m0.find()).toBeTruthy + expect(m0.group()).toEqual("ABC") + expect(m0.find()).toBeFalsy + + val p1 = Pattern.compile("(?-i)abc", Pattern.CASE_INSENSITIVE) + + expect(p1.flags() & Pattern.CASE_INSENSITIVE).toBe(0) + + val m1 = p1.matcher("abcABC") + + expect(m1.find()).toBeTruthy + expect(m1.group()).toEqual("abc") + expect(m1.find()).toBeFalsy + } + + } +} diff --git a/test-suite/src/test/scala/scala/scalajs/testsuite/javalib/ShortTest.scala b/test-suite/src/test/scala/scala/scalajs/testsuite/javalib/ShortTest.scala new file mode 100644 index 0000000..e59f2e9 --- /dev/null +++ b/test-suite/src/test/scala/scala/scalajs/testsuite/javalib/ShortTest.scala @@ -0,0 +1,66 @@ +/* __ *\ +** ________ ___ / / ___ __ ____ Scala.js Test Suite ** +** / __/ __// _ | / / / _ | __ / // __/ (c) 2013, LAMP/EPFL ** +** __\ \/ /__/ __ |/ /__/ __ |/_// /_\ \ http://scala-js.org/ ** +** /____/\___/_/ |_/____/_/ | |__/ /____/ ** +** |/____/ ** +\* */ +package scala.scalajs.testsuite.javalib + +import java.lang.{Short => JShort} + +import org.scalajs.jasminetest.JasmineTest + +/** + * tests the implementation of the java standard library Short + */ +object ShortTest extends JasmineTest { + + describe("java.lang.Short") { + + it("should provide `compareTo`") { + def compare(x: Short, y: Short): Int = + new JShort(x).compareTo(new JShort(y)) + + expect(compare(0.toShort, 5.toShort)).toBeLessThan(0) + expect(compare(10.toShort, 9.toShort)).toBeGreaterThan(0) + expect(compare(-2.toShort, -1.toShort)).toBeLessThan(0) + expect(compare(3.toShort, 3.toShort)).toEqual(0) + } + + it("should be a Comparable") { + def compare(x: Any, y: Any): Int = + x.asInstanceOf[Comparable[Any]].compareTo(y) + + expect(compare(0.toShort, 5.toShort)).toBeLessThan(0) + expect(compare(10.toShort, 9.toShort)).toBeGreaterThan(0) + expect(compare(-2.toShort, -1.toShort)).toBeLessThan(0) + expect(compare(3.toShort, 3.toShort)).toEqual(0) + } + + it("should parse strings") { + def test(s: String, v: Short): Unit = { + expect(JShort.parseShort(s)).toEqual(v) + expect(JShort.valueOf(s).shortValue()).toEqual(v) + expect(new JShort(s).shortValue()).toEqual(v) + } + + test("0", 0) + test("5", 5) + test("127", 127) + test("-100", -100) + test("30000", 30000) + } + + it("should reject invalid strings when parsing") { + def test(s: String): Unit = + expect(() => JShort.parseShort(s)).toThrow + + test("abc") + test("") + test("60000") // out of range + test("-90000") // out of range + } + + } +} diff --git a/test-suite/src/test/scala/scala/scalajs/testsuite/javalib/StackTraceElementTest.scala b/test-suite/src/test/scala/scala/scalajs/testsuite/javalib/StackTraceElementTest.scala new file mode 100644 index 0000000..b02a889 --- /dev/null +++ b/test-suite/src/test/scala/scala/scalajs/testsuite/javalib/StackTraceElementTest.scala @@ -0,0 +1,29 @@ +/* __ *\ +** ________ ___ / / ___ __ ____ Scala.js Test Suite ** +** / __/ __// _ | / / / _ | __ / // __/ (c) 2013, LAMP/EPFL ** +** __\ \/ /__/ __ |/ /__/ __ |/_// /_\ \ http://scala-js.org/ ** +** /____/\___/_/ |_/____/_/ | |__/ /____/ ** +** |/____/ ** +\* */ +package scala.scalajs.testsuite.javalib + +import scala.scalajs.js + +import org.scalajs.jasminetest.JasmineTest + +object StackTraceElementTest extends JasmineTest { + + describe("java.lang.StackTraceElement") { + it("should use the magic columnNumber field in its toString") { + val st = new StackTraceElement("MyClass", "myMethod", "myFile.scala", 1) + st.asInstanceOf[js.Dynamic].columnNumber = 5 + expect(st.toString).toEqual("MyClass.myMethod(myFile.scala:1:5)") + } + + it("should leave toString unmodified without magic columnNumber") { + val st = new StackTraceElement("MyClass", "myMethod", "myFile.scala", 1) + expect(st.toString).toEqual("MyClass.myMethod(myFile.scala:1)") + } + } + +} diff --git a/test-suite/src/test/scala/scala/scalajs/testsuite/javalib/StreamsTest.scala b/test-suite/src/test/scala/scala/scalajs/testsuite/javalib/StreamsTest.scala new file mode 100644 index 0000000..6975614 --- /dev/null +++ b/test-suite/src/test/scala/scala/scalajs/testsuite/javalib/StreamsTest.scala @@ -0,0 +1,308 @@ +/* __ *\ +** ________ ___ / / ___ __ ____ Scala.js Test Suite ** +** / __/ __// _ | / / / _ | __ / // __/ (c) 2013, LAMP/EPFL ** +** __\ \/ /__/ __ |/ /__/ __ |/_// /_\ \ http://scala-js.org/ ** +** /____/\___/_/ |_/____/_/ | |__/ /____/ ** +** |/____/ ** +\* */ +package scala.scalajs.testsuite.javalib + +import java.io._ + +import scala.language.implicitConversions + +import scala.scalajs.js + +import org.scalajs.jasminetest.JasmineTest + +/** Tests for our implementation of java.io._ stream classes */ +object StreamsTest extends JasmineTest with CommonStreamsTests { + + // Need to define this again, otherwise conversion on function + // triggers for Seqs + override implicit def traversable2array[T]( + a: TraversableOnce[T]): js.Array[T] = super.traversable2array(a) + + describe("java.io.InputStream") { + + class DummyInputStream(val length: Int) extends InputStream { + private var i: Int = 0 + def read(): Int = if (i < length) { i += 1; i } else -1 + } + + it("should provide a default implementation of `read` to an array") { + val stream = new DummyInputStream(200) + + val buf = new Array[Byte](50) + + // Should read first 50 bytes (next: 51) + expect(stream.read(buf)).toBe(50) + expect(buf).toEqual((1 to 50)) + + // Should read another 20 (next: 71) + expect(stream.read(buf, 10, 20)).toBe(20) + expect(buf).toEqual((1 to 10) ++ (51 to 70) ++ (31 to 50)) + + // Test some Exception conditions + expect(() => stream.read(null, 0, 10)).toThrow + expect(() => stream.read(buf, -1, 10)).toThrow + expect(() => stream.read(buf, 0, -1)).toThrow + expect(() => stream.read(buf, 10, 100)).toThrow + // Buffer should be unmodified + expect(buf).toEqual((1 to 10) ++ (51 to 70) ++ (31 to 50)) + + // Should read nothing (next: 71) + expect(stream.read(buf, 10, 0)).toBe(0) + expect(buf).toEqual((1 to 10) ++ (51 to 70) ++ (31 to 50)) + + // Skip 40 bytes (next: 111) + expect(stream.skip(40)).toBe(40) + + // Read 50 bytes, should wrap (next: 161) + expect(stream.read(buf)).toBe(50) + expect(buf).toEqual((111 to 127) ++ (-128 to -96)) + + // Read 45 bytes, should read 40 (next: EOF) + expect(stream.read(buf, 5, 45)).toBe(40) + expect(buf).toEqual((111 to 115) ++ (-95 to -56) ++ (-100 to -96)) + + // Read 50 bytes, should read nothing + expect(stream.read(buf)).toBe(-1) + expect(stream.read(buf, 0, 0)).toBe(0) + expect(buf).toEqual((111 to 115) ++ (-95 to -56) ++ (-100 to -96)) + } + + it("should provide a default implementation of `skip`") { + val stream = new DummyInputStream(10) + + expect(stream.skip(5)).toBe(5) + expect(stream.read()).toBe(6) + expect(stream.skip(1)).toBe(1) + expect(stream.read()).toBe(8) + expect(stream.skip(-5)).toBe(0) + expect(stream.read()).toBe(9) + expect(stream.skip(0)).toBe(0) + expect(stream.read()).toBe(10) + expect(stream.skip(10)).toBe(0) + } + + } + + describe("java.io.ByteArrayInputStream") { + byteArrayInputStreamLikeTests(seq => + new ByteArrayInputStream(seq.map(_.toByte).toArray)) + } + + describe("java.io.ByteArrayOutputStream") { + + it("should support simple write(x: Int)") { + val out = new ByteArrayOutputStream() + + for (i <- 0 to 9) + out.write(i) + + expect(out.toByteArray).toEqual(js.Array(0, 1, 2, 3, 4, 5, 6, 7, 8, 9)) + } + + it("should support simple write(x: Array[Byte])") { + val out = new ByteArrayOutputStream() + val arr = Array[Byte](0, 1, 2, 3, 4, 5) + + out.write(arr, 1, 4) + out.write(arr) + + expect(out.toByteArray).toEqual(js.Array(1, 2, 3, 4, 0, 1, 2, 3, 4, 5)) + } + + it("should support write(x: Array[Byte]) with buffer resize") { + val out = new ByteArrayOutputStream(16) + val arr = Array[Byte](0, 1, 2, 3, 4, 5, 6, 7, 8, 9) + + out.write(arr) + out.write(arr) + + expect(out.toByteArray).toEqual(arr ++ arr) + } + + it("should support toString (with UTF8)") { + val buf = Array[Byte](72, 101, 108, 108, 111, 32, 87, 111, 114, 108, 100, + 46, -29, -127, -109, -29, -126, -109, -29, -127, -85, -29, -127, -95, + -29, -127, -81, -26, -105, -91, -26, -100, -84, -24, -86, -98, -29, + -126, -110, -24, -86, -83, -29, -126, -127, -29, -127, -66, -29, -127, + -103, -29, -127, -117, -29, -128, -126) + + val out = new ByteArrayOutputStream() + out.write(buf) + + expect(out.toString).toEqual("Hello World.こんにちは日本語を読めますか。") + } + + it("should support reset()") { + val out = new ByteArrayOutputStream() + for (i <- 0 to 9) out.write(i) + out.reset() + for (i <- 0 to 9) out.write(i) + + expect(out.toByteArray).toEqual(js.Array(0, 1, 2, 3, 4, 5, 6, 7, 8, 9)) + } + + } + +} + +/** tests also used by typedarray.ArrayBufferInputStreamTests */ +trait CommonStreamsTests extends JasmineTest { + + implicit def traversable2array[T](a: TraversableOnce[T]): js.Array[T] = { + import js.JSConverters._ + a.toJSArray + } + + implicit def array2array[T](a: Array[T]): js.Array[T] = { + import js.JSConverters._ + a.toJSArray + } + + def byteArrayInputStreamLikeTests(mkStream: Seq[Int] => InputStream): Unit = { + val length = 50 + def newStream = mkStream(1 to length) + + it("should provide `read()`") { + val stream = newStream + + for (i <- 1 to length) + expect(stream.read()).toBe(i) + + for (_ <- 1 to 5) + expect(stream.read()).toBe(-1) + } + + it("should provide `read(buf)`") { + val stream = newStream + val buf = new Array[Byte](10) + + expect(stream.read(buf)).toBe(10) + expect(buf).toEqual(1 to 10) + + expect(stream.skip(35)).toBe(35) + + expect(stream.read(buf)).toBe(5) + expect(buf).toEqual((46 to 50) ++ (6 to 10)) + + expect(stream.read(buf)).toBe(-1) + expect(stream.read()).toBe(-1) + } + + it("should provide full-argument `read`") { + val stream = newStream + val buf = new Array[Byte](20) + + expect(stream.read(buf, 10, 5)).toBe(5) + expect(buf).toEqual(Seq.fill(10)(0) ++ (1 to 5) ++ Seq.fill(5)(0)) + + expect(stream.read(buf, 0, 20)).toBe(20) + expect(buf).toEqual(6 to 25) + + expect(stream.read(buf, 10, 0)).toBe(0) + expect(buf).toEqual(6 to 25) + + expect(() => stream.read(buf, -1, 0)).toThrow + expect(() => stream.read(buf, 0, -1)).toThrow + expect(() => stream.read(buf, 100, 0)).toThrow + expect(() => stream.read(buf, 10, 100)).toThrow + expect(buf).toEqual(6 to 25) + + expect(stream.skip(20)).toBe(20) + + expect(stream.read(buf, 0, 10)).toBe(5) + expect(buf).toEqual((46 to 50) ++ (11 to 25)) + + expect(stream.read(buf, 0, 10)).toBe(-1) + expect(stream.read(buf, 0, 0)).toBe(0) + expect(buf).toEqual((46 to 50) ++ (11 to 25)) + + } + + it("should provide `available`") { + val stream = newStream + + def mySkip(n: Int) = for (_ <- 1 to n) expect(stream.read()).not.toBe(-1) + def check(n: Int) = expect(stream.available).toBe(n) + + check(50) + mySkip(5) + check(45) + expect(stream.skip(10)).toBe(10) + check(35) + mySkip(30) + check(5) + expect(stream.skip(20)).toBe(5) + check(0) + } + + it("should provide `skip`") { + val stream = newStream + + expect(stream.skip(7)).toBe(7) + + for (i <- 8 to 32) + expect(stream.read()).toBe(i) + + expect(stream.skip(0)).toBe(0) + expect(stream.read()).toBe(33) + expect(stream.skip(-4)).toBe(0) + expect(stream.read()).toBe(34) + + expect(stream.skip(30)).toBe(16) + expect(stream.skip(30)).toBe(0) + } + + it("should return true from `markSupported`") { + expect(newStream.markSupported).toBe(true) + } + + it("should provide no-op `close`") { + val stream = newStream + + for (i <- 1 to length) { + stream.close() + expect(stream.read()).toBe(i) + } + } + + it("should provide `mark`/`reset`") { + val stream = newStream + + def read(range: Range) = for (i <- range) expect(stream.read()).toBe(i) + + read(1 to 10) + stream.reset() // mark must be 0 at creation + read(1 to 5) + stream.mark(length) + read(6 to 22) + stream.reset() + read(6 to 20) + stream.reset() + read(6 to 25) + stream.reset() + expect(stream.skip(40)).toBe(40) + stream.mark(length) + read(46 to 50) + stream.reset() + read(46 to 50) + stream.mark(length) + expect(stream.read()).toBe(-1) + stream.reset() + expect(stream.read()).toBe(-1) + } + + it("should return positive integers when calling read") { + val stream = mkStream(Seq(-1, -2, -3)) + expect(stream.read()).toBe(255) + expect(stream.read()).toBe(254) + expect(stream.read()).toBe(253) + expect(stream.read()).toBe(-1) + } + } + +} diff --git a/test-suite/src/test/scala/scala/scalajs/testsuite/javalib/StringBufferTest.scala b/test-suite/src/test/scala/scala/scalajs/testsuite/javalib/StringBufferTest.scala new file mode 100644 index 0000000..a034ce6 --- /dev/null +++ b/test-suite/src/test/scala/scala/scalajs/testsuite/javalib/StringBufferTest.scala @@ -0,0 +1,219 @@ +/* __ *\ +** ________ ___ / / ___ __ ____ Scala.js Test Suite ** +** / __/ __// _ | / / / _ | __ / // __/ (c) 2013, LAMP/EPFL ** +** __\ \/ /__/ __ |/ /__/ __ |/_// /_\ \ http://scala-js.org/ ** +** /____/\___/_/ |_/____/_/ | |__/ /____/ ** +** |/____/ ** +\* */ +package scala.scalajs.testsuite.javalib + +import scala.reflect.{classTag, ClassTag} +import scala.scalajs.js +import org.scalajs.jasminetest.JasmineTest + +object StringBufferTest extends JasmineTest { + + def shouldThrow[T : ClassTag](fn: => Unit) = + try { + fn + expect("exception").toBe("thrown") + } catch { + case e: T => + case x: Throwable => expect(x.toString).toBe(classTag[T].runtimeClass.getSimpleName) + } + + describe("java.lang.StringBuffer") { + + def newBuf = new java.lang.StringBuffer + def initBuf(str: String) = new java.lang.StringBuffer(str) + + it("should respond to `append`") { + expect(newBuf.append("asdf").toString).toEqual("asdf") + expect(newBuf.append(null: AnyRef).toString).toEqual("null") + expect(newBuf.append(null: String).toString).toEqual("null") + expect(newBuf.append(null: CharSequence,0,2).toString).toEqual("nu") + expect(newBuf.append(js.undefined).toString).toEqual("undefined") + expect(newBuf.append(true).toString).toEqual("true") + expect(newBuf.append('a').toString).toEqual("a") + expect(newBuf.append(Array('a','b','c','d')).toString).toEqual("abcd") + expect(newBuf.append(Array('a','b','c','d'), 1, 2).toString).toEqual("bc") + expect(newBuf.append(4.toByte).toString).toEqual("4") + expect(newBuf.append(304.toShort).toString).toEqual("304") + expect(newBuf.append(100000).toString).toEqual("100000") + expect(newBuf.append(2.5f).toString).toEqual("2.5") + expect(newBuf.append(3.5).toString).toEqual("3.5") + } + + it("should respond to `insert`") { + expect(newBuf.insert(0, "asdf").toString).toEqual("asdf") + expect(newBuf.insert(0, null: AnyRef).toString).toEqual("null") + expect(newBuf.insert(0, null: String).toString).toEqual("null") + expect(newBuf.insert(0, null: CharSequence,0,2).toString).toEqual("nu") + expect(newBuf.insert(0, js.undefined).toString).toEqual("undefined") + expect(newBuf.insert(0, true).toString).toEqual("true") + expect(newBuf.insert(0, 'a').toString).toEqual("a") + expect(newBuf.insert(0, Array('a','b','c','d')).toString).toEqual("abcd") + expect(newBuf.insert(0, Array('a','b','c','d'), 1, 2).toString).toEqual("bc") + expect(newBuf.insert(0, 4.toByte).toString).toEqual("4") + expect(newBuf.insert(0, 304.toShort).toString).toEqual("304") + expect(newBuf.insert(0, 100000).toString).toEqual("100000") + expect(newBuf.insert(0, 2.5f).toString).toEqual("2.5") + expect(newBuf.insert(0, 3.5).toString).toEqual("3.5") + + expect(initBuf("adef").insert(1, "bc")).toEqual("abcdef") + expect(initBuf("abcd").insert(4, "ef")).toEqual("abcdef") + expect(initBuf("adef").insert(1, Array('b','c'))).toEqual("abcdef") + expect(initBuf("adef").insert(1, initBuf("bc"))).toEqual("abcdef") + expect(initBuf("abef").insert(2, Array('a','b','c','d','e'), 2, 2)).toEqual("abcdef") + expect(initBuf("abef").insert(2, initBuf("abcde"), 2, 4)).toEqual("abcdef") + + shouldThrow[StringIndexOutOfBoundsException](initBuf("abcd").insert(5, "whatever")) + shouldThrow[StringIndexOutOfBoundsException](initBuf("abcd").insert(-1, "whatever")) + } + + it("should respond to `deleteCharAt`") { + expect(initBuf("0123").deleteCharAt(1).toString).toEqual("023") + expect(initBuf("0123").deleteCharAt(0).toString).toEqual("123") + expect(initBuf("0123").deleteCharAt(3).toString).toEqual("012") + shouldThrow[StringIndexOutOfBoundsException](initBuf("0123").deleteCharAt(-1)) + shouldThrow[StringIndexOutOfBoundsException](initBuf("0123").deleteCharAt(4)) + } + + it("should respond to `replace`") { + expect(initBuf("0123").replace(1,3,"bc").toString).toEqual("0bc3") + expect(initBuf("0123").replace(0,4,"abcd").toString).toEqual("abcd") + expect(initBuf("0123").replace(0,10,"abcd").toString).toEqual("abcd") + expect(initBuf("0123").replace(3,10,"defg").toString).toEqual("012defg") + expect(initBuf("0123").replace(0,1,"xxxx").toString).toEqual("xxxx123") + expect(initBuf("0123").replace(1,1,"xxxx").toString).toEqual("0xxxx123") + + shouldThrow[StringIndexOutOfBoundsException](initBuf("0123").replace(-1,3,"x")) + shouldThrow[StringIndexOutOfBoundsException](initBuf("0123").replace(4,5,"x")) + } + + it("should respond to `setCharAt`") { + val buf = newBuf + buf.append("foobar") + + buf.setCharAt(2, 'x') + expect(buf.toString).toEqual("foxbar") + + buf.setCharAt(5, 'h') + expect(buf.toString).toEqual("foxbah") + + expect(() => buf.setCharAt(-1, 'h')).toThrow + expect(() => buf.setCharAt(6, 'h')).toThrow + } + + it("should properly setLength") { + val buf = newBuf + buf.append("foobar") + + expect(() => buf.setLength(-3)).toThrow + + expect({ buf.setLength(3); buf.toString }).toEqual("foo") + expect({ buf.setLength(6); buf.toString }).toEqual("foo\u0000\u0000\u0000") + } + + } + + describe("java.lang.StringBuilder") { + + def newBuilder = new java.lang.StringBuilder + def initBuilder(str: String) = new java.lang.StringBuilder(str) + + it("should respond to `append`") { + expect(newBuilder.append("asdf").toString).toEqual("asdf") + expect(newBuilder.append(null: AnyRef).toString).toEqual("null") + expect(newBuilder.append(null: String).toString).toEqual("null") + expect(newBuilder.append(null: CharSequence,0,2).toString).toEqual("nu") + expect(newBuilder.append(js.undefined).toString).toEqual("undefined") + expect(newBuilder.append(true).toString).toEqual("true") + expect(newBuilder.append('a').toString).toEqual("a") + expect(newBuilder.append(Array('a','b','c','d')).toString).toEqual("abcd") + expect(newBuilder.append(Array('a','b','c','d'), 1, 2).toString).toEqual("bc") + expect(newBuilder.append(4.toByte).toString).toEqual("4") + expect(newBuilder.append(304.toShort).toString).toEqual("304") + expect(newBuilder.append(100000).toString).toEqual("100000") + expect(newBuilder.append(2.5f).toString).toEqual("2.5") + expect(newBuilder.append(3.5).toString).toEqual("3.5") + } + + it("should respond to `insert`") { + expect(newBuilder.insert(0, "asdf").toString).toEqual("asdf") + expect(newBuilder.insert(0, null: AnyRef).toString).toEqual("null") + expect(newBuilder.insert(0, null: String).toString).toEqual("null") + expect(newBuilder.insert(0, null: CharSequence,0,2).toString).toEqual("nu") + expect(newBuilder.insert(0, js.undefined).toString).toEqual("undefined") + expect(newBuilder.insert(0, true).toString).toEqual("true") + expect(newBuilder.insert(0, 'a').toString).toEqual("a") + expect(newBuilder.insert(0, Array('a','b','c','d')).toString).toEqual("abcd") + expect(newBuilder.insert(0, Array('a','b','c','d'), 1, 2).toString).toEqual("bc") + expect(newBuilder.insert(0, 4.toByte).toString).toEqual("4") + expect(newBuilder.insert(0, 304.toShort).toString).toEqual("304") + expect(newBuilder.insert(0, 100000).toString).toEqual("100000") + expect(newBuilder.insert(0, 2.5f).toString).toEqual("2.5") + expect(newBuilder.insert(0, 3.5).toString).toEqual("3.5") + + expect(initBuilder("adef").insert(1, "bc")).toEqual("abcdef") + expect(initBuilder("abcd").insert(4, "ef")).toEqual("abcdef") + expect(initBuilder("adef").insert(1, Array('b','c'))).toEqual("abcdef") + expect(initBuilder("adef").insert(1, initBuilder("bc"))).toEqual("abcdef") + expect(initBuilder("abef").insert(2, Array('a','b','c','d','e'), 2, 2)).toEqual("abcdef") + expect(initBuilder("abef").insert(2, initBuilder("abcde"), 2, 4)).toEqual("abcdef") + + shouldThrow[StringIndexOutOfBoundsException](initBuilder("abcd").insert(5, "whatever")) + shouldThrow[StringIndexOutOfBoundsException](initBuilder("abcd").insert(-1, "whatever")) + } + + it("should allow string interpolation to survive `null` and `undefined`") { + expect(s"${null}").toEqual("null") + expect(s"${js.undefined}").toEqual("undefined") + } + + it("should respond to `deleteCharAt`") { + expect(initBuilder("0123").deleteCharAt(1).toString).toEqual("023") + expect(initBuilder("0123").deleteCharAt(0).toString).toEqual("123") + expect(initBuilder("0123").deleteCharAt(3).toString).toEqual("012") + shouldThrow[StringIndexOutOfBoundsException](initBuilder("0123").deleteCharAt(-1)) + shouldThrow[StringIndexOutOfBoundsException](initBuilder("0123").deleteCharAt(4)) + } + + it("should respond to `replace`") { + expect(initBuilder("0123").replace(1,3,"bc").toString).toEqual("0bc3") + expect(initBuilder("0123").replace(0,4,"abcd").toString).toEqual("abcd") + expect(initBuilder("0123").replace(0,10,"abcd").toString).toEqual("abcd") + expect(initBuilder("0123").replace(3,10,"defg").toString).toEqual("012defg") + expect(initBuilder("0123").replace(0,1,"xxxx").toString).toEqual("xxxx123") + expect(initBuilder("0123").replace(1,1,"xxxx").toString).toEqual("0xxxx123") + + shouldThrow[StringIndexOutOfBoundsException](initBuilder("0123").replace(-1,3,"x")) + shouldThrow[StringIndexOutOfBoundsException](initBuilder("0123").replace(4,5,"x")) + } + + it("should respond to `setCharAt`") { + val b = newBuilder + b.append("foobar") + + b.setCharAt(2, 'x') + expect(b.toString).toEqual("foxbar") + + b.setCharAt(5, 'h') + expect(b.toString).toEqual("foxbah") + + expect(() => b.setCharAt(-1, 'h')).toThrow + expect(() => b.setCharAt(6, 'h')).toThrow + } + + it("should properly setLength") { + val b = newBuilder + b.append("foobar") + + expect(() => b.setLength(-3)).toThrow + + expect({ b.setLength(3); b.toString }).toEqual("foo") + expect({ b.setLength(6); b.toString }).toEqual("foo\u0000\u0000\u0000") + } + + } +} diff --git a/test-suite/src/test/scala/scala/scalajs/testsuite/javalib/StringTest.scala b/test-suite/src/test/scala/scala/scalajs/testsuite/javalib/StringTest.scala new file mode 100644 index 0000000..a49e521 --- /dev/null +++ b/test-suite/src/test/scala/scala/scalajs/testsuite/javalib/StringTest.scala @@ -0,0 +1,237 @@ +/* __ *\ +** ________ ___ / / ___ __ ____ Scala.js Test Suite ** +** / __/ __// _ | / / / _ | __ / // __/ (c) 2013, LAMP/EPFL ** +** __\ \/ /__/ __ |/ /__/ __ |/_// /_\ \ http://scala-js.org/ ** +** /____/\___/_/ |_/____/_/ | |__/ /____/ ** +** |/____/ ** +\* */ +package scala.scalajs.testsuite.javalib + +import scala.scalajs.js +import scala.scalajs.js.JSConverters._ + +import org.scalajs.jasminetest.JasmineTest + +object StringTest extends JasmineTest { + + describe("java.lang.String") { + + it("should respond to `length`") { + expect("Scala.js".length).toEqual(8) + expect("".length).toEqual(0) + } + + it("should respond to `intern`") { + val s = "Scala.js" + expect(s.intern).toEqual(s) + } + + it("should respond to `equals`") { + expect("Scala.js".equals("Scala.js")).toBeTruthy + expect("Scala.js".equals("Java")).toBeFalsy + } + + it("should respond to `equalsIgnoreCase`") { + expect("Scala.JS".equalsIgnoreCase("Scala.js")).toBeTruthy + expect("åløb".equalsIgnoreCase("ÅLØb")).toBeTruthy + expect("Scala.js".equalsIgnoreCase("Java")).toBeFalsy + expect("Scala.js".equalsIgnoreCase(null)).toBeFalsy + } + + it("should respond to `compareTo`") { + expect("Scala.js".compareTo("Scala")).toBeGreaterThan(0) + expect("Scala.js".compareTo("Scala.js")).toBe(0) + expect("Scala.js".compareTo("banana")).toBeLessThan(0) + } + + it("should respond to `compareToIgnoreCase`") { + expect("Scala.JS".compareToIgnoreCase("Scala.js")).toBe(0) + expect("Scala.JS".compareToIgnoreCase("scala")).toBeGreaterThan(0) + expect("åløb".compareToIgnoreCase("ÅLØB")).toBe(0) + expect("Java".compareToIgnoreCase("Scala")).toBeLessThan(0) + } + + it("should respond to `isEmpty`") { + expect("Scala.js".isEmpty).toBeFalsy + expect("".isEmpty).toBeTruthy + } + + it("should respond to `contains`") { + expect("Scala.js".contains("Scala")).toBeTruthy + expect("Scala.js".contains("Scala.js")).toBeTruthy + expect("ananas".contains("na")).toBeTruthy + expect("Scala.js".contains("scala")).toBeFalsy + } + + it("should respond to `startWith`") { + expect("Scala.js".startsWith("Scala")).toBeTruthy + expect("Scala.js".startsWith("Scala.js")).toBeTruthy + expect("Scala.js".startsWith("scala")).toBeFalsy + expect("ananas".startsWith("an")).toBeTruthy + } + + it("should respond to `endsWith`") { + expect("Scala.js".endsWith("js")).toBeTruthy + expect("Scala.js".endsWith("Scala.js")).toBeTruthy + expect("Scala.js".endsWith("JS")).toBeFalsy + expect("banana".endsWith("na")).toBeTruthy + } + + it("should respond to `indexOf(String)`") { + expect("Scala.js".indexOf("js")).toBe(6) + expect("Scala.js".indexOf("Scala.js")).toBe(0) + expect("ananas".indexOf("na")).toBe(1) + expect("Scala.js".indexOf("Java")).toBe(-1) + } + + it("should respond to `indexOf(int)`") { + expect("abc\uD834\uDF06def\uD834\uDF06def".indexOf(0x61)).toEqual(0) + expect("abc\uD834\uDF06def\uD834\uDF06def".indexOf(0x1D306)).toEqual(3) + expect("abc\uD834\uDF06def\uD834\uDF06def".indexOf(0xD834)).toEqual(3) + expect("abc\uD834\uDF06def\uD834\uDF06def".indexOf(0xDF06)).toEqual(4) + expect("abc\uD834\uDF06def\uD834\uDF06def".indexOf(0x64)).toEqual(5) + } + + it("should respond to `lastIndexOf(String)`") { + expect("Scala.js".lastIndexOf("Scala.js")).toBe(0) + expect("ananas".lastIndexOf("na")).toBe(3) + expect("Scala.js".lastIndexOf("Java")).toBe(-1) + } + + it("should respond to `lastIndexOf(int)`") { + expect("abc\uD834\uDF06def\uD834\uDF06def".lastIndexOf(0x61)).toEqual(0) + expect("abc\uD834\uDF06def\uD834\uDF06def".lastIndexOf(0x1D306)).toEqual(8) + expect("abc\uD834\uDF06def\uD834\uDF06def".lastIndexOf(0xD834)).toEqual(8) + expect("abc\uD834\uDF06def\uD834\uDF06def".lastIndexOf(0xDF06)).toEqual(9) + expect("abc\uD834\uDF06def\uD834\uDF06def".lastIndexOf(0x64)).toEqual(10) + } + + it("should respond to `toUpperCase`") { + expect("Scala.js".toUpperCase()).toBe("SCALA.JS") + } + + it("should respond to `toLowerCase`") { + expect("Scala.js".toLowerCase()).toBe("scala.js") + } + + it("should respond to `charAt`") { + expect("Scala.js".charAt(5)).toBe('.') + expect("Scala.js".charAt(6)).not.toBe('.') + } + + when("compliant-asinstanceofs"). + it("charAt() should throw with out-of-bound indices") { + // Type Strings both as CharSequence and String. One will invoke the + // helper, the other directly the method on RuntimeString. + expect(() => ("Scala.js": CharSequence).charAt(-3)).toThrow + expect(() => ("Scala.js": CharSequence).charAt(20)).toThrow + expect(() => "Scala.js".charAt(-3)).toThrow + expect(() => "Scala.js".charAt(20)).toThrow + } + + it("should respond to `codePointAt`") { + // String that starts with a BMP symbol + expect("abc\uD834\uDF06def".codePointAt(0)).toEqual(0x61) + expect("abc\uD834\uDF06def".codePointAt(3)).toEqual(0x1D306) + expect("abc\uD834\uDF06def".codePointAt(4)).toEqual(0xDF06) + expect("abc\uD834\uDF06def".codePointAt(5)).toEqual(0x64) + + // String that starts with an astral symbol + expect("\uD834\uDF06def".codePointAt(0)).toEqual(0x1D306) + expect("\uD834\uDF06def".codePointAt(1)).toEqual(0xDF06) + + // Lone high surrogates + expect("\uD834abc".codePointAt(0)).toEqual(0xD834) + + // Lone low surrogates + expect("\uDF06abc".codePointAt(0)).toEqual(0xDF06) + } + + it("should respond to `subSequence`") { + expect("Scala.js".subSequence(0, 5)).toBe("Scala") + expect("Scala.js".subSequence(6, 8)).toBe("js") + expect("Scala.js".subSequence(3, 5)).toBe("la") + expect("Scala.js".subSequence(3, 3)).toBe("") + } + + it("should respond to `replace`") { + expect("Scala.js".replace(".js", "")).toBe("Scala") + expect("Scala.js".replace("JS", "")).toBe("Scala.js") + expect("aa".replace('a', 'b')).toBe("bb") // #25 + } + + it("should respond to `matches`") { + expect("Scala.js".matches(".*js")).toBeTruthy + expect("Scala.js".matches(".*JS")).toBeFalsy + } + + it("should respond to `split`") { + expect("Scala.js".split("a").toJSArray).toEqual(js.Array("Sc", "l", ".js")) + expect("asdf".split("").toJSArray).toEqual(js.Array("","a","s","d","f")) + expect("asdf".split("", -1).toJSArray).toEqual(js.Array("","a","s","d","f", "")) + } + + it("should respond to `split` with char as argument") { + expect("Scala.js".split('.').toJSArray).toEqual(js.Array("Scala","js")) + for (i <- 0 to 32) { + val c = i.toChar + expect(s"blah${c}blah${c}blah${c}blah".split(c).toJSArray).toEqual( + js.Array("blah", "blah", "blah", "blah")) + } + } + + it("should respond to `toCharArray`") { + expect("Scala.js".toCharArray()(5)).toEqual('.') + } + + it("should respond to `hashCode`") { + expect("a`jkxzcbfaslkjfbkj,289oinkasdf".hashCode()).toEqual(-1395193631) + expect("-34".hashCode()).toEqual(44878) + expect("".hashCode()).toEqual(0) + } + + it("should respond to `getChars`") { + val trg = new Array[Char](10) + "asdf_foo".getChars(2, 6, trg, 3) + val exp = Array(0,0,0,'d','f','_','f',0,0,0) + + for ((i,e) <- trg zip exp) { + expect(i).toEqual(e) + } + } + + + it("should respond to `concat`") { + expect("asdf".concat("fdsa")).toEqual("asdffdsa") + } + + it("should respond to constructors") { + val charArray = + Array('a', 'b', 'c', 'd', '\uD834', '\uDF06', 'e', 'f', 'g', 'h', 'i') + val codePointArray = + Array(65, 0x1D306, 67, 68, 0xD834, 69, 72, 0xDF06) + + expect(new String()).toEqual("") + expect(new String(charArray)).toEqual("abcd\uD834\uDF06efghi") + expect(new String(charArray, 3, 5)).toEqual("d\uD834\uDF06ef") + expect(new String(codePointArray, 1, 5)).toEqual("\uD834\uDF06CD\uD834E") + expect(new String("foo")).toEqual("foo") + expect(new String(new StringBuffer("buffer-foo"))).toEqual("buffer-foo") + expect(new String(new java.lang.StringBuilder("builder-foo")) + ).toEqual("builder-foo") + } + + it("should provide `format`") { + expect(String.format("%d", new Integer(5))).toEqual("5") + expect(String.format("%05d", new Integer(5))).toEqual("00005") + expect(String.format("%0#5x", new Integer(5))).toEqual("0x005") + expect(String.format("%#5x", new Integer(5))).toEqual(" 0x5") + expect(String.format("%#5X", new Integer(5))).toEqual(" 0X5") + expect(String.format("%5d", new Integer(-10))).toEqual(" -10") + expect(String.format("%05d", new Integer(-10))).toEqual("-0010") + expect(String.format("%x", new Integer(-3))).toEqual("fffffffd") + expect(String.format("%x", new java.lang.Byte(-4.toByte))).toEqual("fffffffc") + } + + } +} diff --git a/test-suite/src/test/scala/scala/scalajs/testsuite/javalib/SystemTest.scala b/test-suite/src/test/scala/scala/scalajs/testsuite/javalib/SystemTest.scala new file mode 100644 index 0000000..4435e00 --- /dev/null +++ b/test-suite/src/test/scala/scala/scalajs/testsuite/javalib/SystemTest.scala @@ -0,0 +1,118 @@ +/* __ *\ +** ________ ___ / / ___ __ ____ Scala.js Test Suite ** +** / __/ __// _ | / / / _ | __ / // __/ (c) 2013, LAMP/EPFL ** +** __\ \/ /__/ __ |/ /__/ __ |/_// /_\ \ http://scala-js.org/ ** +** /____/\___/_/ |_/____/_/ | |__/ /____/ ** +** |/____/ ** +\* */ +package scala.scalajs.testsuite.javalib + +import language.implicitConversions + +import scala.scalajs.js +import scala.scalajs.js.JSConverters._ + +import org.scalajs.jasminetest.JasmineTest + +object SystemTest extends JasmineTest { + + // Just in here, we allow ourselves to do this + implicit def array2jsArray[T](arr: Array[T]): js.Array[T] = arr.toJSArray + + describe("java.lang.System") { + + it("should respond to `arraycopy`") { + val object0 = Array[Any]("[", "b", "c", "d", "e", "f", "]") + val object1 = Array[Any](() => true, 1, "2", '3', 4.0, true, object0) + + System.arraycopy(object1, 1, object0, 1, 5) + expect(object0.mkString).toEqual("[1234true]") + + val string0 = Array("a", "b", "c", "d", "e", "f") + val string1 = Array("1", "2", "3", "4") + + System.arraycopy(string1, 0, string0, 3, 3) + expect(string0.mkString).toEqual("abc123") + + val ab01Chars = Array("ab".toCharArray, "01".toCharArray) + val chars = new Array[Array[Char]](32) + System.arraycopy(ab01Chars, 0, chars, 0, 2) + for (i <- Seq(0, 2, 4, 8, 16)) { + System.arraycopy(chars, i / 4, chars, i, i) + } + + expect(chars.filter(_ == null).length).toEqual(12) + expect(chars.filter(_ != null).map(_.mkString).mkString). + toEqual("ab01ab0101ab01ab0101ab0101ab01ab0101ab01") + } + + it("should respond to `arraycopy` with range overlaps for the same array") { + val array = new Array[Int](10) + + for (i <- 1 to 6) { + array(i) = i + } + + expect(array).toEqual(Array(0, 1, 2, 3, 4, 5, 6, 0, 0, 0)) + System.arraycopy(array, 0, array, 3, 7) + expect(array).toEqual(Array(0, 1, 2, 0, 1, 2, 3, 4, 5, 6)) + + System.arraycopy(array, 0, array, 1, 0) + expect(array).toEqual(Array(0, 1, 2, 0, 1, 2, 3, 4, 5, 6)) + + System.arraycopy(array, 0, array, 1, 9) + expect(array).toEqual(Array(0, 0, 1, 2, 0, 1, 2, 3, 4, 5)) + + System.arraycopy(array, 1, array, 0, 9) + expect(array).toEqual(Array(0, 1, 2, 0, 1, 2, 3, 4, 5, 5)) + + System.arraycopy(array, 0, array, 0, 10) + expect(array).toEqual(Array(0, 1, 2, 0, 1, 2, 3, 4, 5, 5)) + + val reversed = array.reverse + System.arraycopy(reversed, 5, array, 5, 5) + expect(array).toEqual(Array(0, 1, 2, 0, 1, 1, 0, 2, 1, 0)) + } + + it("should provide identityHashCode") { + /* This test is more restrictive than the spec, but we know our + * implementation will always pass the test. + */ + class HasIDHashCode + + val x1 = new HasIDHashCode + val x2 = new HasIDHashCode + val x1FirstHash = x1.hashCode() + expect(x1.hashCode()).toEqual(x1FirstHash) + expect(x1.hashCode()).not.toEqual(x2.hashCode()) + expect(x1.hashCode()).toEqual(x1FirstHash) + + expect(System.identityHashCode(x1)).toEqual(x1FirstHash) + expect(System.identityHashCode(x2)).toEqual(x2.hashCode()) + } + + it("identityHashCode should by-pass .hashCode()") { + val list1 = List(1, 3, 5) + val list2 = List(1, 3, 5) + expect(list1 == list2).toBeTruthy + expect(list1.hashCode()).toEqual(list2.hashCode()) + expect(System.identityHashCode(list1)).not.toEqual(System.identityHashCode(list2)) + } + + it("identityHashCode(null)") { + expect(System.identityHashCode(null)).toEqual(0) + } + + it("identityHashCode of values implemented as JS primitives") { + expect(System.identityHashCode("foo")).toEqual("foo".hashCode()) + expect(System.identityHashCode("")).toEqual("".hashCode()) + + expect(System.identityHashCode(false)).toEqual(false.hashCode()) + expect(System.identityHashCode(true)).toEqual(true.hashCode()) + + expect(System.identityHashCode(5)).toEqual(5.hashCode()) + expect(System.identityHashCode(789456)).toEqual(789456.hashCode()) + } + + } +} diff --git a/test-suite/src/test/scala/scala/scalajs/testsuite/javalib/ThrowablesTest.scala b/test-suite/src/test/scala/scala/scalajs/testsuite/javalib/ThrowablesTest.scala new file mode 100644 index 0000000..7e53975 --- /dev/null +++ b/test-suite/src/test/scala/scala/scalajs/testsuite/javalib/ThrowablesTest.scala @@ -0,0 +1,90 @@ +/* __ *\ +** ________ ___ / / ___ __ ____ Scala.js Test Suite ** +** / __/ __// _ | / / / _ | __ / // __/ (c) 2013, LAMP/EPFL ** +** __\ \/ /__/ __ |/ /__/ __ |/_// /_\ \ http://scala-js.org/ ** +** /____/\___/_/ |_/____/_/ | |__/ /____/ ** +** |/____/ ** +\* */ +package scala.scalajs.testsuite.javalib + +import org.scalajs.jasminetest.JasmineTest + +object ThrowablesTest extends JasmineTest { + describe("java.lang.Throwables, java.util.Throwables") { + + it("should define all java.lang and java.util Errors/Exceptions") { + new ArithmeticException() + new ArrayIndexOutOfBoundsException() + new ArrayStoreException() + new ClassCastException() + new ClassNotFoundException() + new CloneNotSupportedException() + // Needs an instance of java.lang.Enum. + // import scala.language.existentials + // new EnumConstantNotPresentException(null.asInstanceOf[Class[_ <: Enum[T] forSome { type T <: Enum[T] }]], null) + new Exception() + new IllegalAccessException() + new IllegalArgumentException() + new IllegalMonitorStateException() + new IllegalStateException() + new IllegalThreadStateException() + new IndexOutOfBoundsException() + new InstantiationException() + new InterruptedException() + new NegativeArraySizeException() + new NoSuchFieldException() + new NoSuchMethodException() + new NullPointerException() + new NumberFormatException() + new RuntimeException() + new SecurityException() + new StringIndexOutOfBoundsException() + new TypeNotPresentException(null, null) + new UnsupportedOperationException() + new AbstractMethodError() + new AssertionError() + new ClassCircularityError() + new ClassFormatError() + new Error() + new ExceptionInInitializerError() + new IllegalAccessError() + new IncompatibleClassChangeError() + new InstantiationError() + new InternalError() + new LinkageError() + new NoClassDefFoundError() + new NoSuchFieldError() + new NoSuchMethodError() + new OutOfMemoryError() + new StackOverflowError() + new UnknownError() + new UnsatisfiedLinkError() + new UnsupportedClassVersionError() + new VerifyError() + new VirtualMachineError() {} + + import java.util._ + new ServiceConfigurationError("") + new ConcurrentModificationException() + new DuplicateFormatFlagsException("") + new EmptyStackException() + new FormatFlagsConversionMismatchException("", '\u0000') + new FormatterClosedException() + new IllegalFormatCodePointException(0) + new IllegalFormatConversionException('\u0000', new Object().getClass) + new IllegalFormatFlagsException("") + new IllegalFormatPrecisionException(0) + new IllegalFormatWidthException(0) + new InputMismatchException() + // Needs java.io.IOException. + // new InvalidPropertiesFormatException("") + new MissingFormatArgumentException("") + new MissingFormatWidthException("") + new MissingResourceException(null, null, null) + new NoSuchElementException() + new TooManyListenersException() + new UnknownFormatConversionException("") + new UnknownFormatFlagsException("") + } + } +} diff --git a/test-suite/src/test/scala/scala/scalajs/testsuite/javalib/TimeUnitTest.scala b/test-suite/src/test/scala/scala/scalajs/testsuite/javalib/TimeUnitTest.scala new file mode 100644 index 0000000..79cd8a8 --- /dev/null +++ b/test-suite/src/test/scala/scala/scalajs/testsuite/javalib/TimeUnitTest.scala @@ -0,0 +1,135 @@ +/* __ *\ +** ________ ___ / / ___ __ ____ Scala.js Test Suite ** +** / __/ __// _ | / / / _ | __ / // __/ (c) 2013, LAMP/EPFL ** +** __\ \/ /__/ __ |/ /__/ __ |/_// /_\ \ http://scala-js.org/ ** +** /____/\___/_/ |_/____/_/ | |__/ /____/ ** +** |/____/ ** +\* */ +package scala.scalajs.testsuite.javalib + +import scala.scalajs.js +import org.scalajs.jasminetest.JasmineTest +import java.util.concurrent.TimeUnit + +object TimeUnitTest extends JasmineTest { + + describe("java.util.concurrent.TimeUnit") { + + it("should respond to `toNanos`") { + expect(TimeUnit.NANOSECONDS.toNanos(42L)).toEqual(42L) + expect(TimeUnit.MICROSECONDS.toNanos(42L)).toEqual(42000L) + expect(TimeUnit.MILLISECONDS.toNanos(42L)).toEqual(42000000L) + expect(TimeUnit.SECONDS.toNanos(42L)).toEqual(42000000000L) + expect(TimeUnit.MINUTES.toNanos(42L)).toEqual(2520000000000L) + expect(TimeUnit.HOURS.toNanos(42L)).toEqual(151200000000000L) + expect(TimeUnit.DAYS.toNanos(42L)).toEqual(3628800000000000L) + } + + it("should respond to `toMicros`") { + expect(TimeUnit.NANOSECONDS.toMicros(42L)).toEqual(0L) + expect(TimeUnit.NANOSECONDS.toMicros(42123L)).toEqual(42L) + expect(TimeUnit.MICROSECONDS.toMicros(42L)).toEqual(42L) + expect(TimeUnit.MILLISECONDS.toMicros(42L)).toEqual(42000L) + expect(TimeUnit.SECONDS.toMicros(42L)).toEqual(42000000L) + expect(TimeUnit.MINUTES.toMicros(42L)).toEqual(2520000000L) + expect(TimeUnit.HOURS.toMicros(42L)).toEqual(151200000000L) + expect(TimeUnit.DAYS.toMicros(42L)).toEqual(3628800000000L) + } + + it("should respond to `toMillis`") { + expect(TimeUnit.NANOSECONDS.toMillis(42L)).toEqual(0L) + expect(TimeUnit.NANOSECONDS.toMillis(42000123L)).toEqual(42L) + expect(TimeUnit.MICROSECONDS.toMillis(42L)).toEqual(0L) + expect(TimeUnit.MICROSECONDS.toMillis(42123L)).toEqual(42L) + expect(TimeUnit.MILLISECONDS.toMillis(42L)).toEqual(42L) + expect(TimeUnit.SECONDS.toMillis(42L)).toEqual(42000L) + expect(TimeUnit.MINUTES.toMillis(42L)).toEqual(2520000L) + expect(TimeUnit.HOURS.toMillis(42L)).toEqual(151200000L) + expect(TimeUnit.DAYS.toMillis(42L)).toEqual(3628800000L) + } + + it("should respond to `toSeconds`") { + expect(TimeUnit.NANOSECONDS.toSeconds(42L)).toEqual(0L) + expect(TimeUnit.NANOSECONDS.toSeconds(42000000123L)).toEqual(42L) + expect(TimeUnit.MICROSECONDS.toSeconds(42L)).toEqual(0L) + expect(TimeUnit.MICROSECONDS.toSeconds(42000123L)).toEqual(42L) + expect(TimeUnit.MILLISECONDS.toSeconds(42L)).toEqual(0L) + expect(TimeUnit.MILLISECONDS.toSeconds(42123L)).toEqual(42L) + expect(TimeUnit.SECONDS.toSeconds(42L)).toEqual(42L) + expect(TimeUnit.MINUTES.toSeconds(42L)).toEqual(2520L) + expect(TimeUnit.HOURS.toSeconds(42L)).toEqual(151200L) + expect(TimeUnit.DAYS.toSeconds(42L)).toEqual(3628800L) + } + + it("should respond to `toMinutes`") { + expect(TimeUnit.NANOSECONDS.toMinutes(42L)).toEqual(0L) + expect(TimeUnit.NANOSECONDS.toMinutes(2520000007380L)).toEqual(42L) + expect(TimeUnit.MICROSECONDS.toMinutes(42L)).toEqual(0L) + expect(TimeUnit.MICROSECONDS.toMinutes(2520007380L)).toEqual(42L) + expect(TimeUnit.MILLISECONDS.toMinutes(42L)).toEqual(0L) + expect(TimeUnit.MILLISECONDS.toMinutes(2520738L)).toEqual(42L) + expect(TimeUnit.SECONDS.toMinutes(42L)).toEqual(0L) + expect(TimeUnit.SECONDS.toMinutes(2520L)).toEqual(42L) + expect(TimeUnit.MINUTES.toMinutes(42L)).toEqual(42L) + expect(TimeUnit.HOURS.toMinutes(42L)).toEqual(2520L) + expect(TimeUnit.DAYS.toMinutes(42L)).toEqual(60480L) + } + + it("should respond to `toHours`") { + expect(TimeUnit.NANOSECONDS.toHours(42L)).toEqual(0L) + expect(TimeUnit.NANOSECONDS.toHours(151200000442800L)).toEqual(42L) + expect(TimeUnit.MICROSECONDS.toHours(42L)).toEqual(0L) + expect(TimeUnit.MICROSECONDS.toHours(151200442800L)).toEqual(42L) + expect(TimeUnit.MILLISECONDS.toHours(42L)).toEqual(0L) + expect(TimeUnit.MILLISECONDS.toHours(151244280L)).toEqual(42L) + expect(TimeUnit.SECONDS.toHours(42L)).toEqual(0L) + expect(TimeUnit.SECONDS.toHours(151200L)).toEqual(42L) + expect(TimeUnit.MINUTES.toHours(42L)).toEqual(0L) + expect(TimeUnit.MINUTES.toHours(2520L)).toEqual(42L) + expect(TimeUnit.HOURS.toHours(42L)).toEqual(42L) + expect(TimeUnit.DAYS.toHours(42L)).toEqual(1008L) + } + + it("should respond to `toDays`") { + expect(TimeUnit.NANOSECONDS.toDays(42L)).toEqual(0L) + expect(TimeUnit.NANOSECONDS.toDays(3628800010627200L)).toEqual(42L) + expect(TimeUnit.MICROSECONDS.toDays(42L)).toEqual(0L) + expect(TimeUnit.MICROSECONDS.toDays(3628810627200L)).toEqual(42L) + expect(TimeUnit.MILLISECONDS.toDays(42L)).toEqual(0L) + expect(TimeUnit.MILLISECONDS.toDays(3629862720L)).toEqual(42L) + expect(TimeUnit.SECONDS.toDays(42L)).toEqual(0L) + expect(TimeUnit.SECONDS.toDays(3628800L)).toEqual(42L) + expect(TimeUnit.MINUTES.toDays(42L)).toEqual(0L) + expect(TimeUnit.MINUTES.toDays(60480L)).toEqual(42L) + expect(TimeUnit.HOURS.toDays(42L)).toEqual(1L) + expect(TimeUnit.HOURS.toDays(1008L)).toEqual(42L) + expect(TimeUnit.DAYS.toDays(42L)).toEqual(42L) + } + + it("should respond to `values`") { + val values = TimeUnit.values() + expect(values.length).toEqual(7) + expectTimeUnit(values(0), TimeUnit.NANOSECONDS) + expectTimeUnit(values(1), TimeUnit.MICROSECONDS) + expectTimeUnit(values(2), TimeUnit.MILLISECONDS) + expectTimeUnit(values(3), TimeUnit.SECONDS) + expectTimeUnit(values(4), TimeUnit.MINUTES) + expectTimeUnit(values(5), TimeUnit.HOURS) + expectTimeUnit(values(6), TimeUnit.DAYS) + } + + it("should respond to `valueOf`") { + expectTimeUnit(TimeUnit.valueOf("NANOSECONDS"), TimeUnit.NANOSECONDS) + expectTimeUnit(TimeUnit.valueOf("MICROSECONDS"), TimeUnit.MICROSECONDS) + expectTimeUnit(TimeUnit.valueOf("MILLISECONDS"), TimeUnit.MILLISECONDS) + expectTimeUnit(TimeUnit.valueOf("SECONDS"), TimeUnit.SECONDS) + expectTimeUnit(TimeUnit.valueOf("MINUTES"), TimeUnit.MINUTES) + expectTimeUnit(TimeUnit.valueOf("HOURS"), TimeUnit.HOURS) + expectTimeUnit(TimeUnit.valueOf("DAYS"), TimeUnit.DAYS) + } + + } + + def expectTimeUnit(actual: TimeUnit, expected: TimeUnit): Unit = + expect(actual.asInstanceOf[js.Any]).toEqual(expected.asInstanceOf[js.Any]) +} diff --git a/test-suite/src/test/scala/scala/scalajs/testsuite/javalib/URITest.scala b/test-suite/src/test/scala/scala/scalajs/testsuite/javalib/URITest.scala new file mode 100644 index 0000000..65a049f --- /dev/null +++ b/test-suite/src/test/scala/scala/scalajs/testsuite/javalib/URITest.scala @@ -0,0 +1,312 @@ +/* __ *\ +** ________ ___ / / ___ __ ____ Scala.js Test Suite ** +** / __/ __// _ | / / / _ | __ / // __/ (c) 2013, LAMP/EPFL ** +** __\ \/ /__/ __ |/ /__/ __ |/_// /_\ \ http://scala-js.org/ ** +** /____/\___/_/ |_/____/_/ | |__/ /____/ ** +** |/____/ ** +\* */ +package scala.scalajs.testsuite.javalib + +import scala.scalajs.js +import org.scalajs.jasminetest.JasmineTest + +import java.net.URI + +object URITest extends JasmineTest { + + def expectURI(uri: URI, isAbsolute: Boolean, isOpaque: Boolean)( + authority: String = null, fragment: String = null, + host: String = null, path: String = null, port: Int = -1, + query: String = null, scheme: String = null, userInfo: String = null, + schemeSpecificPart: String = null)(rawAuthority: String = authority, + rawFragment: String = fragment, rawPath: String = path, + rawQuery: String = query, rawUserInfo: String = userInfo, + rawSchemeSpecificPart: String = schemeSpecificPart): Unit = { + + expect(uri.getAuthority()).toBe(authority) + expect(uri.getFragment()).toBe(fragment) + expect(uri.getHost()).toBe(host) + expect(uri.getPath()).toBe(path) + expect(uri.getPort()).toBe(port) + expect(uri.getQuery()).toBe(query) + expect(uri.getRawAuthority()).toBe(rawAuthority) + expect(uri.getRawFragment()).toBe(rawFragment) + expect(uri.getRawPath()).toBe(rawPath) + expect(uri.getRawQuery()).toBe(rawQuery) + expect(uri.getRawSchemeSpecificPart()).toBe(rawSchemeSpecificPart) + expect(uri.getRawUserInfo()).toBe(rawUserInfo) + expect(uri.getScheme()).toBe(scheme) + expect(uri.getSchemeSpecificPart()).toBe(schemeSpecificPart) + expect(uri.getUserInfo()).toBe(userInfo) + expect(uri.isAbsolute()).toBe(isAbsolute) + expect(uri.isOpaque()).toBe(isOpaque) + + } + + describe("java.net.URI") { + + it("should parse vanilla absolute URIs") { + expectURI(new URI("http://java.sun.com/j2se/1.3/"), true, false)( + scheme = "http", + host = "java.sun.com", + path = "/j2se/1.3/", + authority = "java.sun.com", + schemeSpecificPart = "//java.sun.com/j2se/1.3/")() + } + + it("should parse absolute URIs with IPv6") { + val uri = new URI("http://hans@[ffff::0:128.4.5.3]:345/~hans/") + expectURI(uri, true, false)( + scheme = "http", + host = "[ffff::0:128.4.5.3]", + userInfo = "hans", + port = 345, + path = "/~hans/", + authority = "hans@[ffff::0:128.4.5.3]:345", + schemeSpecificPart = "//hans@[ffff::0:128.4.5.3]:345/~hans/" + )() + } + + it("should parse absolute URIs without authority") { + expectURI(new URI("file:/~/calendar"), true, false)( + scheme = "file", + path = "/~/calendar", + schemeSpecificPart = "/~/calendar")() + } + + it("should parse absolute URIs with empty authority") { + expectURI(new URI("file:///~/calendar"), true, false)( + authority = "", + scheme = "file", + path = "/~/calendar", + schemeSpecificPart = "///~/calendar")() + } + + it("should parse opaque URIs") { + expectURI(new URI("mailto:java-net@java.sun.com"), true, true)( + scheme = "mailto", + schemeSpecificPart = "java-net@java.sun.com")() + + expectURI(new URI("news:comp.lang.java"), true, true)( + scheme = "news", + schemeSpecificPart = "comp.lang.java")() + + expectURI(new URI("urn:isbn:096139210x"), true, true)( + scheme = "urn", + schemeSpecificPart = "isbn:096139210x")() + } + + it("should parse relative URIs") { + expectURI(new URI("docs/guide/collections/designfaq.html#28"), false, false)( + path = "docs/guide/collections/designfaq.html", + fragment = "28", + schemeSpecificPart = "docs/guide/collections/designfaq.html#28" + )() + expectURI(new URI("../../../demo/jfc/SwingSet2/src/SwingSet2.java"), false, false)( + path = "../../../demo/jfc/SwingSet2/src/SwingSet2.java", + schemeSpecificPart = "../../../demo/jfc/SwingSet2/src/SwingSet2.java" + )() + } + + it("should parse relative URIs with IPv4") { + expectURI(new URI("//123.5.6.3:45/bar"), false, false)( + authority = "123.5.6.3:45", + host = "123.5.6.3", + port = 45, + path = "/bar", + schemeSpecificPart = "//123.5.6.3:45/bar" + )() + } + + it("should parse relative URIs with registry-based authority") { + expectURI(new URI("//foo:bar"), false, false)( + authority = "foo:bar", + schemeSpecificPart = "//foo:bar" + )() + } + + it("should parse relative URIs with escapes") { + expectURI(new URI("//ma%5dx:secret@example.com:8000/foo"), false, false)( + authority = "ma]x:secret@example.com:8000", + userInfo = "ma]x:secret", + host = "example.com", + port = 8000, + path = "/foo", + schemeSpecificPart = "//ma]x:secret@example.com:8000/foo")( + rawUserInfo = "ma%5dx:secret", + rawAuthority = "ma%5dx:secret@example.com:8000", + rawSchemeSpecificPart = "//ma%5dx:secret@example.com:8000/foo") + } + + it("should parse relative URIs with fragment only") { + expectURI(new URI("#foo"), false, false)( + fragment = "foo", + path = "", + schemeSpecificPart = "#foo" + )() + } + + it("should provide compareTo") { + val x = new URI("http://example.com/asdf%6a") + val y = new URI("http://example.com/asdf%6A") + val z = new URI("http://example.com/asdfj") + val rel = new URI("/foo/bar") + + expect(x.compareTo(y)).toBeGreaterThan(0) + expect(x.compareTo(z)).toBeLessThan(0) + expect(y.compareTo(z)).toBeLessThan(0) + expect(x.compareTo(x)).toBe(0) + expect(y.compareTo(y)).toBe(0) + expect(z.compareTo(z)).toBe(0) + expect(x.compareTo(rel)).toBeGreaterThan(0) + expect(y.compareTo(rel)).toBeGreaterThan(0) + expect(z.compareTo(rel)).toBeGreaterThan(0) + expect(rel.compareTo(rel)).toBe(0) + } + + it("should provide equals") { + val x = new URI("http://example.com/asdf%6a") + val y = new URI("http://example.com/asdf%6A") + val z = new URI("http://example.com/asdfj") + + expect(x == y).toBeTruthy + expect(x == z).toBeFalsy + expect(y == z).toBeFalsy + expect(x == x).toBeTruthy + expect(y == y).toBeTruthy + expect(z == z).toBeTruthy + + expect(new URI("foo:helloWorld%6b%6C") == new URI("foo:helloWorld%6C%6b")) + } + + it("should provide normalize") { + expectURI(new URI("http://example.com/../asef/../../").normalize, true, false)( + scheme = "http", + host = "example.com", + authority = "example.com", + path = "/../../", + schemeSpecificPart = "//example.com/../../")() + expectURI(new URI("http://example.com/../as/./ef/foo/../../").normalize, true, false)( + scheme = "http", + host = "example.com", + authority = "example.com", + path = "/../as/", + schemeSpecificPart = "//example.com/../as/")() + expectURI(new URI("bar/../fo:o/./bar").normalize, false, false)( + path = "./fo:o/bar", + schemeSpecificPart = "./fo:o/bar")() + expectURI(new URI("bar/..//fo:o//./bar").normalize, false, false)( + path = "./fo:o/bar", + schemeSpecificPart = "./fo:o/bar")() + + val x = new URI("http://www.example.com/foo/bar") + expect(x.normalize eq x).toBeTruthy + } + + it("should provide resolve - JavaDoc examples") { + val base = "http://java.sun.com/j2se/1.3/" + val relative1 = "docs/guide/collections/designfaq.html#28" + val resolved1 = + "http://java.sun.com/j2se/1.3/docs/guide/collections/designfaq.html#28" + val relative2 = "../../../demo/jfc/SwingSet2/src/SwingSet2.java" + val resolved2 = + "http://java.sun.com/j2se/1.3/demo/jfc/SwingSet2/src/SwingSet2.java" + + expect(new URI(base).resolve(relative1).toString).toEqual(resolved1) + expect(new URI(resolved1).resolve(relative2).toString).toEqual(resolved2) + } + + it("should provide resolve - RFC2396 examples") { + val base = new URI("http://a/b/c/d;p?q") + def resTest(ref: String, trg: String) = + expect(base.resolve(ref).toString).toEqual(trg) + + // Normal examples + resTest("g:h" , "g:h") + resTest("g" , "http://a/b/c/g") + resTest("./g" , "http://a/b/c/g") + resTest("g/" , "http://a/b/c/g/") + resTest("/g" , "http://a/g") + resTest("//g" , "http://g") + resTest("?y" , "http://a/b/c/?y") + resTest("g?y" , "http://a/b/c/g?y") + resTest("#s" , "http://a/b/c/d;p?q#s") + resTest("g#s" , "http://a/b/c/g#s") + resTest("g?y#s" , "http://a/b/c/g?y#s") + resTest(";x" , "http://a/b/c/;x") + resTest("g;x" , "http://a/b/c/g;x") + resTest("g;x?y#s", "http://a/b/c/g;x?y#s") + resTest("." , "http://a/b/c/") + resTest("./" , "http://a/b/c/") + resTest(".." , "http://a/b/") + resTest("../" , "http://a/b/") + resTest("../g" , "http://a/b/g") + resTest("../.." , "http://a/") + resTest("../../" , "http://a/") + resTest("../../g", "http://a/g") + + // Abnormal examples + resTest("../../../g" , "http://a/../g") + resTest("../../../../g", "http://a/../../g") + resTest("/./g" , "http://a/./g") + resTest("/../g" , "http://a/../g") + resTest("g." , "http://a/b/c/g.") + resTest(".g" , "http://a/b/c/.g") + resTest("g.." , "http://a/b/c/g..") + resTest("..g" , "http://a/b/c/..g") + resTest("./../g" , "http://a/b/g") + resTest("./g/." , "http://a/b/c/g/") + resTest("g/./h" , "http://a/b/c/g/h") + resTest("g/../h" , "http://a/b/c/h") + resTest("g;x=1/./y" , "http://a/b/c/g;x=1/y") + resTest("g;x=1/../y" , "http://a/b/c/y") + resTest("g?y/./x" , "http://a/b/c/g?y/./x") + resTest("g?y/../x" , "http://a/b/c/g?y/../x") + resTest("g#s/./x" , "http://a/b/c/g#s/./x") + resTest("g#s/../x" , "http://a/b/c/g#s/../x") + resTest("http:g" , "http:g") + } + + it("should provide normalize - examples derived from RFC relativize") { + expectURI(new URI("http://a/b/c/..").normalize, true, false)( + scheme = "http", + host = "a", + authority = "a", + path = "/b/", + schemeSpecificPart = "//a/b/")() + + expectURI(new URI("http://a/b/c/.").normalize, true, false)( + scheme = "http", + host = "a", + authority = "a", + path = "/b/c/", + schemeSpecificPart = "//a/b/c/")() + } + + it("should provide relativize") { + val x = new URI("http://f%4Aoo@asdf/a") + val y = new URI("http://fJoo@asdf/a/b/") + val z = new URI("http://f%4aoo@asdf/a/b/") + expect(x.relativize(y) eq y).toBeTruthy + expect(x.relativize(z).toString()).toEqual("b/") + + def relTest(base: String, trg: String, exp: String) = + expect(new URI(base).relativize(new URI(trg)).toString()).toEqual(exp) + + relTest("http://a.ch/a", "http://a.ch/a/b", "b") + relTest("http://a.ch/a/", "http://a.ch/a/b", "b") + relTest("https://a.ch/a", "http://a.ch/a/b", "http://a.ch/a/b") + relTest("/a/b/c", "/a/b/c/d/e", "d/e") + relTest("/a/b/c/", "/a/b/c/d/e", "d/e") + relTest("/a/b/c/", "/a/b/c/foo:e/d", "foo:e/d") // see bug JDK-7037120 + relTest("../a/b", "../a/b/c", "c") + } + + it("should provide hashCode") { + expect(new URI("http://example.com/asdf%6a").hashCode).toEqual( + new URI("http://example.com/asdf%6A").hashCode) + } + + } + +} diff --git a/test-suite/src/test/scala/scala/scalajs/testsuite/javalib/UUIDTest.scala b/test-suite/src/test/scala/scala/scalajs/testsuite/javalib/UUIDTest.scala new file mode 100644 index 0000000..b22fe02 --- /dev/null +++ b/test-suite/src/test/scala/scala/scalajs/testsuite/javalib/UUIDTest.scala @@ -0,0 +1,180 @@ +/* __ *\ +** ________ ___ / / ___ __ ____ Scala.js Test Suite ** +** / __/ __// _ | / / / _ | __ / // __/ (c) 2013, LAMP/EPFL ** +** __\ \/ /__/ __ |/ /__/ __ |/_// /_\ \ http://scala-js.org/ ** +** /____/\___/_/ |_/____/_/ | |__/ /____/ ** +** |/____/ ** +\* */ +package scala.scalajs.testsuite.javalib + +import scala.scalajs.js +import org.scalajs.jasminetest.JasmineTest + +import java.util.UUID + +object UUIDTest extends JasmineTest { + describe("java.util.UUID") { + it("constructor") { + val uuid = new UUID(0xf81d4fae7dec11d0L, 0xa76500a0c91e6bf6L) + expect(uuid.getMostSignificantBits() == 0xf81d4fae7dec11d0L).toBeTruthy + expect(uuid.getLeastSignificantBits() == 0xa76500a0c91e6bf6L).toBeTruthy + expect(uuid.variant()).toEqual(2) + expect(uuid.version()).toEqual(1) + expect(uuid.timestamp() == 0x1d07decf81d4faeL).toBeTruthy + expect(uuid.clockSequence()).toEqual(0x2765) + expect(uuid.node() == 0xA0C91E6BF6L).toBeTruthy + } + + it("getLeastSignificantBits") { + expect(new UUID(0L, 0L).getLeastSignificantBits() == 0L).toBeTruthy + expect(new UUID(0L, Long.MinValue).getLeastSignificantBits() == Long.MinValue).toBeTruthy + expect(new UUID(0L, Long.MaxValue).getLeastSignificantBits() == Long.MaxValue).toBeTruthy + } + + it("getMostSignificantBits") { + expect(new UUID(0L, 0L).getMostSignificantBits() == 0L).toBeTruthy + expect(new UUID(Long.MinValue, 0L).getMostSignificantBits() == Long.MinValue).toBeTruthy + expect(new UUID(Long.MaxValue, 0L).getMostSignificantBits() == Long.MaxValue).toBeTruthy + } + + it("version") { + expect(new UUID(0L, 0L).version()).toEqual(0) + expect(new UUID(0x0000000000001000L, 0L).version()).toEqual(1) + expect(new UUID(0x00000000000f2f00L, 0L).version()).toEqual(2) + } + + it("variant") { + expect(new UUID(0L, 0L).variant()).toEqual(0) + expect(new UUID(0L, 0x7000000000000000L).variant()).toEqual(0) + expect(new UUID(0L, 0x3ff0000000000000L).variant()).toEqual(0) + expect(new UUID(0L, 0x1ff0000000000000L).variant()).toEqual(0) + + expect(new UUID(0L, 0x8000000000000000L).variant()).toEqual(2) + expect(new UUID(0L, 0xb000000000000000L).variant()).toEqual(2) + expect(new UUID(0L, 0xaff0000000000000L).variant()).toEqual(2) + expect(new UUID(0L, 0x9ff0000000000000L).variant()).toEqual(2) + + expect(new UUID(0L, 0xc000000000000000L).variant()).toEqual(6) + expect(new UUID(0L, 0xdf00000000000000L).variant()).toEqual(6) + } + + it("timestamp") { + expect(new UUID(0x0000000000001000L, + 0x8000000000000000L).timestamp() == 0L).toBeTruthy + expect(new UUID(0x7777777755551333L, + 0x8000000000000000L).timestamp() == 0x333555577777777L).toBeTruthy + + expect(() => new UUID(0x0000000000000000L, 0x8000000000000000L).timestamp()).toThrow + expect(() => new UUID(0x0000000000002000L, 0x8000000000000000L).timestamp()).toThrow + } + + it("clockSequence") { + expect(new UUID(0x0000000000001000L, 0x8000000000000000L).clockSequence()).toEqual(0) + expect(new UUID(0x0000000000001000L, 0x8fff000000000000L).clockSequence()).toEqual(0x0fff) + expect(new UUID(0x0000000000001000L, 0xBfff000000000000L).clockSequence()).toEqual(0x3fff) + + expect(() => new UUID(0x0000000000000000L, 0x8000000000000000L).clockSequence()).toThrow + expect(() => new UUID(0x0000000000002000L, 0x8000000000000000L).clockSequence()).toThrow + } + + it("node") { + expect(new UUID(0x0000000000001000L, 0x8000000000000000L).node() == 0L).toBeTruthy + expect(new UUID(0x0000000000001000L, 0x8000ffffffffffffL).node() == 0xffffffffffffL).toBeTruthy + + expect(() => new UUID(0x0000000000000000L, 0x8000000000000000L).node()).toThrow + expect(() => new UUID(0x0000000000002000L, 0x8000000000000000L).node()).toThrow + } + + it("compareTo") { + val uuid0101 = new UUID(1L, 1L) + val uuid0111 = new UUID(1L, 0x100000001L) + val uuid1000 = new UUID(0x100000000L, 0L) + + expect(uuid0101.compareTo(uuid0101)).toEqual(0) + expect(uuid0111.compareTo(uuid0111)).toEqual(0) + expect(uuid1000.compareTo(uuid1000)).toEqual(0) + + expect(uuid0101.compareTo(uuid0111)).toBeLessThan(0) + expect(uuid0101.compareTo(uuid1000)).toBeLessThan(0) + expect(uuid0111.compareTo(uuid1000)).toBeLessThan(0) + + expect(uuid0111.compareTo(uuid0101)).toBeGreaterThan(0) + expect(uuid1000.compareTo(uuid0101)).toBeGreaterThan(0) + expect(uuid1000.compareTo(uuid0111)).toBeGreaterThan(0) + } + + it("hashCode") { + expect(new UUID(0L, 0L).hashCode()).toEqual(0) + expect(new UUID(123L, 123L).hashCode()).toEqual(new UUID(123L, 123L).hashCode()) + } + + it("equals") { + val uuid1 = new UUID(0L, 0L) + expect(uuid1.equals(uuid1)).toBeTruthy + expect(uuid1.equals(null)).toBeFalsy + expect(uuid1.equals("something else")).toBeFalsy + + val uuid2 = new UUID(0L, 0L) + expect(uuid1.equals(uuid2)).toBeTruthy + + val uuid3 = new UUID(0xf81d4fae7dec11d0L, 0xa76500a0c91e6bf6L) + val uuid4 = new UUID(0xf81d4fae7dec11d0L, 0xa76500a0c91e6bf6L) + expect(uuid3.equals(uuid4)).toBeTruthy + expect(uuid3.equals(uuid1)).toBeFalsy + + expect(uuid3.equals(new UUID(0x781d4fae7dec11d0L, 0xa76500a0c91e6bf6L))).toBeFalsy + expect(uuid3.equals(new UUID(0xf81d4fae7dec11d1L, 0xa76500a0c91e6bf6L))).toBeFalsy + expect(uuid3.equals(new UUID(0xf81d4fae7dec11d0L, 0xa76530a0c91e6bf6L))).toBeFalsy + expect(uuid3.equals(new UUID(0xf81d4fae7dec11d0L, 0xa76500a0c91e6cf6L))).toBeFalsy + } + + it("toString") { + expect(new UUID(0xf81d4fae7dec11d0L, + 0xa76500a0c91e6bf6L).toString()).toEqual("f81d4fae-7dec-11d0-a765-00a0c91e6bf6") + expect(new UUID(0x0000000000001000L, + 0x8000000000000000L).toString()).toEqual("00000000-0000-1000-8000-000000000000") + } + + it("randomUUID") { + val uuid = UUID.randomUUID() + expect(uuid.variant()).toEqual(2) + expect(uuid.version()).toEqual(4) + } + + it("fromString") { + val uuid1 = UUID.fromString("f81d4fae-7dec-11d0-a765-00a0c91e6bf6") + expect(uuid1.equals(new UUID(0xf81d4fae7dec11d0L, 0xa76500a0c91e6bf6L))).toBeTruthy + expect(uuid1.getMostSignificantBits() == 0xf81d4fae7dec11d0L).toBeTruthy + expect(uuid1.getLeastSignificantBits() == 0xa76500a0c91e6bf6L).toBeTruthy + expect(uuid1.variant()).toEqual(2) + expect(uuid1.version()).toEqual(1) + expect(uuid1.timestamp() == 130742845922168750L).toBeTruthy + expect(uuid1.clockSequence()).toEqual(10085) + expect(uuid1.node() == 690568981494L).toBeTruthy + + val uuid2 = UUID.fromString("00000000-0000-1000-8000-000000000000") + expect(uuid2.equals(new UUID(0x0000000000001000L, 0x8000000000000000L))) + expect(uuid2.getMostSignificantBits() == 0x0000000000001000L).toBeTruthy + expect(uuid2.getLeastSignificantBits() == 0x8000000000000000L).toBeTruthy + expect(uuid2.variant()).toEqual(2) + expect(uuid2.version()).toEqual(1) + expect(uuid2.timestamp() == 0L).toBeTruthy + expect(uuid2.clockSequence()).toEqual(0) + expect(uuid2.node() == 0L).toBeTruthy + + expect(() => UUID.fromString(null)).toThrow + expect(() => UUID.fromString("")).toThrow + expect(() => UUID.fromString("f81d4fae_7dec-11d0-a765-00a0c91e6bf6")).toThrow + expect(() => UUID.fromString("f81d4fae-7dec_11d0-a765-00a0c91e6bf6")).toThrow + expect(() => UUID.fromString("f81d4fae-7dec-11d0_a765-00a0c91e6bf6")).toThrow + expect(() => UUID.fromString("f81d4fae-7dec-11d0-a765_00a0c91e6bf6")).toThrow + expect(() => UUID.fromString("-7dec-11d0-a765-00a0c91e6bf6")).toThrow + expect(() => UUID.fromString("f81d4fae--11d0-a765-00a0c91e6bf6")).toThrow + expect(() => UUID.fromString("f81d4fae-7dec--a765-00a0c91e6bf6")).toThrow + expect(() => UUID.fromString("f81d4fae-7dec-11d0--00a0c91e6bf6")).toThrow + expect(() => UUID.fromString("f81d4fae-7dec-11d0-a765-")).toThrow + expect(() => UUID.fromString("f81d4fae-7dec-11d0-a765")).toThrow + expect(() => UUID.fromString("f81d4fae-7dZc-11d0-a765-00a0c91e6bf6")).toThrow + } + } +} diff --git a/test-suite/src/test/scala/scala/scalajs/testsuite/jsinterop/ArrayTest.scala b/test-suite/src/test/scala/scala/scalajs/testsuite/jsinterop/ArrayTest.scala new file mode 100644 index 0000000..2ffd6b7 --- /dev/null +++ b/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/test-suite/src/test/scala/scala/scalajs/testsuite/jsinterop/AsyncTest.scala b/test-suite/src/test/scala/scala/scalajs/testsuite/jsinterop/AsyncTest.scala new file mode 100644 index 0000000..e37c89e --- /dev/null +++ b/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/test-suite/src/test/scala/scala/scalajs/testsuite/jsinterop/DictionaryTest.scala b/test-suite/src/test/scala/scala/scalajs/testsuite/jsinterop/DictionaryTest.scala new file mode 100644 index 0000000..8b45395 --- /dev/null +++ b/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/test-suite/src/test/scala/scala/scalajs/testsuite/jsinterop/DynamicTest.scala b/test-suite/src/test/scala/scala/scalajs/testsuite/jsinterop/DynamicTest.scala new file mode 100644 index 0000000..2b6942f --- /dev/null +++ b/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/test-suite/src/test/scala/scala/scalajs/testsuite/jsinterop/ExportsTest.scala b/test-suite/src/test/scala/scala/scalajs/testsuite/jsinterop/ExportsTest.scala new file mode 100644 index 0000000..d577d8d --- /dev/null +++ b/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/test-suite/src/test/scala/scala/scalajs/testsuite/jsinterop/FunctionTest.scala b/test-suite/src/test/scala/scala/scalajs/testsuite/jsinterop/FunctionTest.scala new file mode 100644 index 0000000..4973e64 --- /dev/null +++ b/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/test-suite/src/test/scala/scala/scalajs/testsuite/jsinterop/MiscInteropTest.scala b/test-suite/src/test/scala/scala/scalajs/testsuite/jsinterop/MiscInteropTest.scala new file mode 100644 index 0000000..08211c3 --- /dev/null +++ b/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/test-suite/src/test/scala/scala/scalajs/testsuite/jsinterop/RuntimeLongTest.scala b/test-suite/src/test/scala/scala/scalajs/testsuite/jsinterop/RuntimeLongTest.scala new file mode 100644 index 0000000..589f379 --- /dev/null +++ b/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/test-suite/src/test/scala/scala/scalajs/testsuite/jsinterop/StrangeNamedTests.scala b/test-suite/src/test/scala/scala/scalajs/testsuite/jsinterop/StrangeNamedTests.scala new file mode 100644 index 0000000..846c80b --- /dev/null +++ b/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/test-suite/src/test/scala/scala/scalajs/testsuite/jsinterop/ThisFunctionTest.scala b/test-suite/src/test/scala/scala/scalajs/testsuite/jsinterop/ThisFunctionTest.scala new file mode 100644 index 0000000..4ac9058 --- /dev/null +++ b/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/test-suite/src/test/scala/scala/scalajs/testsuite/jsinterop/UndefOrTest.scala b/test-suite/src/test/scala/scala/scalajs/testsuite/jsinterop/UndefOrTest.scala new file mode 100644 index 0000000..28eae15 --- /dev/null +++ b/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 + } + + } + +} diff --git a/test-suite/src/test/scala/scala/scalajs/testsuite/library/ArrayOpsTest.scala b/test-suite/src/test/scala/scala/scalajs/testsuite/library/ArrayOpsTest.scala new file mode 100644 index 0000000..a1957a5 --- /dev/null +++ b/test-suite/src/test/scala/scala/scalajs/testsuite/library/ArrayOpsTest.scala @@ -0,0 +1,117 @@ +/* __ *\ +** ________ ___ / / ___ __ ____ Scala.js Test Suite ** +** / __/ __// _ | / / / _ | __ / // __/ (c) 2013, LAMP/EPFL ** +** __\ \/ /__/ __ |/ /__/ __ |/_// /_\ \ http://scala-js.org/ ** +** /____/\___/_/ |_/____/_/ | |__/ /____/ ** +** |/____/ ** +\* */ +package scala.scalajs.testsuite.library + +import scala.scalajs.js +import org.scalajs.jasminetest.JasmineTest + +import scala.reflect.ClassTag + +import js.JSConverters._ + +object ArrayOpsTest extends JasmineTest { + + describe("scala.scalajs.js.ArrayOps") { + + // Methods we actually implement + + it("should implement apply") { + val array = js.Array(3,4,5,6,3,4) + val ops: js.ArrayOps[Int] = array + + expect(ops(0)).toEqual(3) + expect(ops(3)).toEqual(6) + + array(0) = 4 + expect(ops(0)).toEqual(4) + } + + it("should implement update") { + val array = js.Array(3,4,5,6,3,4) + val ops: js.ArrayOps[Int] = array + + expect(array(1)).toEqual(4) + ops(1) = 5 + expect(array(1)).toEqual(5) + + ops(5) = 10 + expect(array(5)).toEqual(10) + } + + it("should implement length") { + val array = js.Array(3,4,5,6,3,4) + val ops: js.ArrayOps[Int] = array + + expect(ops.length).toEqual(6) + array.push(1) + expect(ops.length).toEqual(7) + } + + it("should implement seq") { + val array = js.Array(3,4,5,6,3,4) + val ops: js.ArrayOps[Int] = array + val seq = ops.seq + + expect(seq.toList == List(3,4,5,6,3,4)).toBeTruthy + } + + it("should implement reduceLeft") { + val array = js.Array(100, 6, 2, 56, -1) + expect(array.reduceLeft(_ - _)).toEqual(37) + expect(() => js.Array[Int]().reduceLeft(_ + _)).toThrow + } + + it("should implement reduceRight") { + val array = js.Array("hello", "world") + expect(array.reduceRight(_ + ", " + _)).toEqual("hello, world") + expect(() => js.Array[Int]().reduceRight(_ + _)).toThrow + } + + it("should implement ++") { + val left = js.Array("hello", "world") + val right = js.Array("and", "everyone", "else") + expect(left ++ right).toEqual( + js.Array("hello", "world", "and", "everyone", "else")) + + val ints = js.Array(4, 3) + expect(left ++ ints).toEqual(js.Array("hello", "world", 4, 3)) + } + + // Some arbitrary methods to test the builders + + it("should implement collect") { + def ct[A : ClassTag](x: A) = implicitly[ClassTag[A]] + val array = js.Array(3,4,5,6,3,4) + val res = array.collect { + case x if x > 4 => 2*x + } + + expect(ct(res).runtimeClass == classOf[js.Array[Int]]).toBeTruthy + expect(res).toEqual(js.Array(10, 12)) + } + + it("should implement diff") { + val array = js.Array(1,2,1,3,1,10,9) + val diff = array.diff(Seq(1,3,9)) + expect(diff).toEqual(js.Array(2,1,1,10)) + } + + it("should implement toList - #843") { + val array = js.Array(1,2,1,3,1,10,9) + val list = array.toList + expect(list.toJSArray).toEqual(array) + } + + it("should implement to[T] - #843") { + val array = js.Array(1,2,1,3,1,10,9) + val list = array.to[List] + expect(list.toJSArray).toEqual(array) + } + + } +} diff --git a/test-suite/src/test/scala/scala/scalajs/testsuite/library/WrappedArrayTest.scala b/test-suite/src/test/scala/scala/scalajs/testsuite/library/WrappedArrayTest.scala new file mode 100644 index 0000000..e4fed0a --- /dev/null +++ b/test-suite/src/test/scala/scala/scalajs/testsuite/library/WrappedArrayTest.scala @@ -0,0 +1,118 @@ +/* __ *\ +** ________ ___ / / ___ __ ____ Scala.js Test Suite ** +** / __/ __// _ | / / / _ | __ / // __/ (c) 2013, LAMP/EPFL ** +** __\ \/ /__/ __ |/ /__/ __ |/_// /_\ \ http://scala-js.org/ ** +** /____/\___/_/ |_/____/_/ | |__/ /____/ ** +** |/____/ ** +\* */ +package scala.scalajs.testsuite.library + +import scala.scalajs.js +import org.scalajs.jasminetest.JasmineTest + +import scala.collection.mutable + +object WrappedArrayTest extends JasmineTest { + + describe("scala.scalajs.js.WrappedArray") { + + // Methods we actually implement + + it("should implement apply") { + val array = js.Array(3,4,5,6,3,4) + val seq: Seq[Int] = array + + expect(seq(0)).toEqual(3) + expect(seq(3)).toEqual(6) + + array(0) = 4 + expect(seq(0)).toEqual(4) + } + + it("should implement update") { + val array = js.Array(3,4,5,6,3,4) + val seq: mutable.Seq[Int] = array + + expect(array(1)).toEqual(4) + seq(1) = 5 + expect(array(1)).toEqual(5) + + seq(5) = 10 + expect(array(5)).toEqual(10) + } + + it("should implement length") { + val array = js.Array(3,4,5,6,3,4) + val seq: Seq[Int] = array + + expect(seq.length).toEqual(6) + array.push(1) + expect(seq.length).toEqual(7) + } + + it("should implement +=:") { + val array = js.Array(5, 8, 9) + 3 +=: array + expect(array).toEqual(js.Array(3, 5, 8, 9)) + } + + it("should implement ++=:") { + val array = js.Array(5, 8, 9) + js.Array(2, 0) ++=: array + expect(array).toEqual(js.Array(2, 0, 5, 8, 9)) + Seq(-3, -45, 1) ++=: array + expect(array).toEqual(js.Array(-3, -45, 1, 2, 0, 5, 8, 9)) + } + + it("should implement insertAll") { + val array = js.Array(5, 8, 9) + array.insertAll(2, js.Array(2, 0)) + expect(array).toEqual(js.Array(5, 8, 2, 0, 9)) + array.insertAll(1, Seq(-3, -45, 1)) + expect(array).toEqual(js.Array(5, -3, -45, 1, 8, 2, 0, 9)) + } + + it("should implement remove") { + val array = js.Array(5, 8, 2, 0, 9) + expect(array.remove(1)).toEqual(8) + expect(array).toEqual(js.Array(5, 2, 0, 9)) + + array.remove(0, 3) + expect(array).toEqual(js.Array(9)) + } + + // Some arbitrary methods to test the builders + + it("should implement collect") { + // Ascribe to right type here, so we'll actually produce a WrappedArray + val seq: js.WrappedArray[Int] = js.Array(3,4,5,6,3,4) + val res = seq.collect { + case x if x > 4 => 2*x + } + + expect(res.getClass == classOf[js.WrappedArray[Int]]).toBeTruthy + expect(res.toList == List(10,12)).toBeTruthy + expect(res.array).toEqual(js.Array(10,12)) + } + + it("should implement diff") { + val seq: Seq[Int] = js.Array(1,2,1,3,1,10,9) + val diff = seq.diff(Seq(1,3,9)) + expect(diff.toList == List(2,1,1,10)).toBeTruthy + } + + it("should implement toList") { + val seq: Seq[Int] = js.Array(1,2,1,3,1,10,9) + val list = seq.toList + expect(list == List(1,2,1,3,1,10,9)).toBeTruthy + } + + it("should implement to[T]") { + val seq: Seq[Int] = js.Array(1,2,1,3,1,10,9) + val list = seq.to[List] + expect(list == List(1,2,1,3,1,10,9)).toBeTruthy + } + + } + +} diff --git a/test-suite/src/test/scala/scala/scalajs/testsuite/library/WrappedDictionaryTest.scala b/test-suite/src/test/scala/scala/scalajs/testsuite/library/WrappedDictionaryTest.scala new file mode 100644 index 0000000..3b95f55 --- /dev/null +++ b/test-suite/src/test/scala/scala/scalajs/testsuite/library/WrappedDictionaryTest.scala @@ -0,0 +1,106 @@ +/* __ *\ +** ________ ___ / / ___ __ ____ Scala.js Test Suite ** +** / __/ __// _ | / / / _ | __ / // __/ (c) 2013, LAMP/EPFL ** +** __\ \/ /__/ __ |/ /__/ __ |/_// /_\ \ http://scala-js.org/ ** +** /____/\___/_/ |_/____/_/ | |__/ /____/ ** +** |/____/ ** +\* */ +package scala.scalajs.testsuite.library + +import scala.scalajs.js +import org.scalajs.jasminetest.JasmineTest + +import scala.collection.mutable + +import scala.reflect.ClassTag + +object WrappedDictionaryTest extends JasmineTest { + + describe("scala.scalajs.js.WrappedDictionary") { + + // Methods we actually implement + + it("should implement get") { + val map: mutable.Map[String, Any] = + js.Dictionary("a" -> "a", "b" -> 6, "e" -> js.undefined) + expect(map.get("a") == Some("a")).toBeTruthy + expect(map.get("b") == Some(6)).toBeTruthy + expect(map.get("e") == Some(())).toBeTruthy + expect(map.get("f") == None).toBeTruthy + } + + it("should implement += and -=") { + val dict = js.Dictionary[String]() + val map: mutable.Map[String, String] = dict + + expect(js.Object.properties(dict)).toEqual(js.Array()) + + map += "hello" -> "world" + expect(dict("hello")).toEqual("world") + map += "foo" -> "bar" + expect(dict("foo")).toEqual("bar") + map -= "hello" + expect(dict.get("hello").isDefined).toBeFalsy + expect(js.Object.properties(dict)).toEqual(js.Array("foo")) + } + + it("should implement iterator") { + val elems = ('a' to 'e').map(_.toString).zip(1 to 5) + val dict = js.Dictionary[Int]() + val map: mutable.Map[String, Int] = dict + + dict ++= elems + + expect(map.iterator.toList.sorted.sameElements(elems)).toBeTruthy + } + + // Some arbitrary methods to test the builders + + it("should implement map") { + def ct[A : ClassTag](x: A) = implicitly[ClassTag[A]] + val dict = js.Dictionary[Int]() + dict ++= Seq("one" -> 1, "two" -> 2, "three" -> 3) + + val mapChr = dict.map { case (k,v) => k(0) -> v * 2 } + val mapStr = dict.map { case (k,v) => k(0).toString -> v * 2 } + + expect(ct(mapChr).runtimeClass == classOf[js.WrappedDictionary[_]]).toBeFalsy + expect(ct(mapStr).runtimeClass == classOf[js.WrappedDictionary[_]]).toBeTruthy + + expect(mapChr.size).toBe(2) + expect(mapStr.size).toBe(2) + } + + it("should implement withFilter") { + val dict = js.Dictionary[Int]() + val flt = dict.withFilter { case (k,v) => v > 5 || k == "a" } + def size = flt.map(x => x).size + + expect(size).toBe(0) + dict += "a" -> 1 + expect(size).toBe(1) + dict += "b" -> 2 + expect(size).toBe(1) + dict += "c" -> 6 + expect(size).toBe(2) + dict += "b" -> 7 + expect(size).toBe(3) + dict -= "a" + expect(size).toBe(2) + } + + it("should implement toList") { + val dict = js.Dictionary("a" -> "a", "b" -> 6, "e" -> js.undefined) + val list = dict.toList + expect(list.size).toBe(3) + } + + it("should implement to[T]") { + val dict = js.Dictionary("a" -> "a", "b" -> 6, "e" -> js.undefined) + val list = dict.to[List] + expect(list.size).toBe(3) + } + + } + +} diff --git a/test-suite/src/test/scala/scala/scalajs/testsuite/niobuffer/BaseBufferTest.scala b/test-suite/src/test/scala/scala/scalajs/testsuite/niobuffer/BaseBufferTest.scala new file mode 100644 index 0000000..a1f1b71 --- /dev/null +++ b/test-suite/src/test/scala/scala/scalajs/testsuite/niobuffer/BaseBufferTest.scala @@ -0,0 +1,178 @@ +/* __ *\ +** ________ ___ / / ___ __ ____ Scala.js Test Suite ** +** / __/ __// _ | / / / _ | __ / // __/ (c) 2013, LAMP/EPFL ** +** __\ \/ /__/ __ |/ /__/ __ |/_// /_\ \ http://scala-js.org/ ** +** /____/\___/_/ |_/____/_/ | |__/ /____/ ** +** |/____/ ** +\* */ +package scala.scalajs.testsuite.niobuffer + +import org.scalajs.jasminetest.JasmineTest + +import java.nio._ + +abstract class BaseBufferTest extends JasmineTest { + trait BaseFactory { + type BufferType <: Buffer + + val createsReadOnly: Boolean = false + + def allocBuffer(capacity: Int): BufferType + + def allocBuffer(pos: Int, limit: Int, capacity: Int): BufferType = { + val buf = allocBuffer(capacity) + buf.limit(limit).position(pos) + buf + } + } + + type Factory <: BaseFactory + + def commonTests(factory: Factory): Unit = { + import factory._ + + it("allocate") { + val buf = allocBuffer(10) + expect(buf.position).toEqual(0) + expect(buf.limit).toEqual(10) + expect(buf.capacity).toEqual(10) + + expect(allocBuffer(0).capacity).toEqual(0) + + expect(() => allocBuffer(-1)).toThrow + + val buf2 = allocBuffer(1, 5, 9) + expect(buf2.position()).toEqual(1) + expect(buf2.limit()).toEqual(5) + expect(buf2.capacity()).toEqual(9) + } + + it("isReadOnly()") { + val buf = allocBuffer(10) + if (createsReadOnly) + expect(buf.isReadOnly()).toBeTruthy + else + expect(buf.isReadOnly()).toBeFalsy + } + + it("position") { + val buf = allocBuffer(10) + buf.position(3) + expect(buf.position()).toEqual(3) + buf.position(10) + expect(buf.position()).toEqual(10) + buf.position(0) + expect(buf.position()).toEqual(0) + + expect(() => buf.position(-1)).toThrow + expect(() => buf.position(11)).toThrow + expect(buf.position()).toEqual(0) + + val buf2 = allocBuffer(1, 5, 9) + expect(buf2.position()).toEqual(1) + buf2.position(5) + expect(buf2.position()).toEqual(5) + expect(() => buf2.position(6)).toThrow + expect(buf2.position()).toEqual(5) + } + + it("limit") { + val buf = allocBuffer(10) + buf.position(3) + buf.limit(7) + expect(buf.limit()).toEqual(7) + expect(buf.position()).toEqual(3) + expect(() => buf.limit(11)).toThrow + expect(buf.limit()).toEqual(7) + expect(() => buf.limit(-1)).toThrow + expect(buf.limit()).toEqual(7) + expect(buf.position()).toEqual(3) + + buf.position(5) + buf.limit(4) + expect(buf.limit()).toEqual(4) + expect(buf.position()).toEqual(4) + } + + it("mark() and reset()") { + val buf = allocBuffer(10) + + // Initially, the mark should not be set + expect(() => buf.reset()).toThrow + + // Simple test + buf.position(3) + buf.mark() + buf.position(8) + buf.reset() + expect(buf.position()).toEqual(3) + + // reset() should not have cleared the mark + buf.position(5) + buf.reset() + expect(buf.position()).toEqual(3) + + // setting position() below the mark should clear the mark + buf.position(2) + expect(() => buf.reset()).toThrow + } + + it("clear()") { + val buf = allocBuffer(3, 6, 10) + buf.mark() + buf.position(4) + + buf.clear() + expect(buf.position()).toEqual(0) + expect(buf.limit()).toEqual(10) // the capacity + expect(buf.capacity()).toEqual(10) + expect(() => buf.reset()).toThrow + } + + it("flip()") { + val buf = allocBuffer(3, 6, 10) + buf.mark() + buf.position(4) + + buf.flip() + expect(buf.position()).toEqual(0) + expect(buf.limit()).toEqual(4) // old position + expect(buf.capacity()).toEqual(10) + expect(() => buf.reset()).toThrow + } + + it("rewind()") { + val buf = allocBuffer(3, 6, 10) + buf.mark() + buf.position(4) + + buf.rewind() + expect(buf.position()).toEqual(0) + expect(buf.limit()).toEqual(6) // unchanged + expect(buf.capacity()).toEqual(10) + expect(() => buf.reset()).toThrow + } + + it("remaining() and hasRemaining()") { + val buf = allocBuffer(3, 7, 10) + expect(buf.remaining()).toEqual(7-3) + expect(buf.hasRemaining()).toBeTruthy + + buf.position(6) + expect(buf.remaining()).toEqual(7-6) + expect(buf.hasRemaining()).toBeTruthy + + buf.limit(9) + expect(buf.remaining()).toEqual(9-6) + expect(buf.hasRemaining()).toBeTruthy + + buf.limit(2) + expect(buf.remaining()).toEqual(0) + expect(buf.hasRemaining()).toBeFalsy + + buf.position(0) + expect(buf.remaining()).toEqual(2) + expect(buf.hasRemaining()).toBeTruthy + } + } +} diff --git a/test-suite/src/test/scala/scala/scalajs/testsuite/niobuffer/ByteBufferTest.scala b/test-suite/src/test/scala/scala/scalajs/testsuite/niobuffer/ByteBufferTest.scala new file mode 100644 index 0000000..9ec831f --- /dev/null +++ b/test-suite/src/test/scala/scala/scalajs/testsuite/niobuffer/ByteBufferTest.scala @@ -0,0 +1,330 @@ +/* __ *\ +** ________ ___ / / ___ __ ____ Scala.js Test Suite ** +** / __/ __// _ | / / / _ | __ / // __/ (c) 2013, LAMP/EPFL ** +** __\ \/ /__/ __ |/ /__/ __ |/_// /_\ \ http://scala-js.org/ ** +** /____/\___/_/ |_/____/_/ | |__/ /____/ ** +** |/____/ ** +\* */ +package scala.scalajs.testsuite.niobuffer + +import java.nio._ + +import scala.scalajs.js +import js.JSConverters._ + +object ByteBufferTest extends BaseBufferTest { + trait Factory extends BaseFactory { + type BufferType = ByteBuffer + + def withContent(capacity: Int, content: Byte*): ByteBuffer = + withContent(0, capacity, capacity, content: _*) + + def withContent(pos: Int, limit: Int, capacity: Int, + content: Byte*): ByteBuffer = { + val buf = allocBuffer(pos, limit, capacity) + buf.put(content.toArray) + buf.position(pos) + buf + } + } + + def byteRange(start: Int, end: Int): Array[Byte] = + (start until end).map(_.toByte).toArray + + def defineTests(factory: Factory): Unit = { + import factory._ + + commonTests(factory) + + it("absolute get()") { + val buf = withContent(10, byteRange(0, 10): _*) + expect(buf.get(0)).toEqual(0) + expect(buf.position()).toEqual(0) + expect(buf.get(3)).toEqual(3) + expect(buf.position()).toEqual(0) + + expect(() => buf.get(-1)).toThrow + expect(() => buf.get(15)).toThrow + + buf.limit(4) + expect(() => buf.get(5)).toThrow + } + + + if (!createsReadOnly) { + it("absolute put()") { + val buf = allocBuffer(10) + buf.put(5, 42) + expect(buf.position()).toEqual(0) + buf.put(3, 2) + expect(buf.get(3)).toEqual(2) + expect(buf.get(5)).toEqual(42) + expect(buf.get(7)).toEqual(0) + + expect(() => buf.put(-1, 2)).toThrow + expect(() => buf.put(14, 9)).toThrow + + buf.limit(4) + expect(() => buf.put(4, 1)).toThrow + } + } else { + it("absolute put() - read-only") { + val buf = allocBuffer(10) + expect(() => buf.put(2, 1)).toThrow + expect(buf.get(2)).toEqual(0) + expect(buf.position()).toEqual(0) + + expect(() => buf.put(-2, 1)).toThrow + expect(() => buf.put(12, 1)).toThrow + } + } + + it("relative get()") { + val buf = withContent(10, byteRange(0, 10): _*) + expect(buf.get()).toEqual(0) + expect(buf.position()).toEqual(1) + buf.position(3) + expect(buf.get()).toEqual(3) + expect(buf.position()).toEqual(4) + + buf.limit(4) + expect(() => buf.get()).toThrow + } + + if (!createsReadOnly) { + it("relative put()") { + val buf = allocBuffer(10) + buf.put(5.toByte) + expect(buf.position()).toEqual(1) + expect(buf.get(0)).toEqual(5) + + buf.position(3) + buf.put(36.toByte) + expect(buf.position()).toEqual(4) + expect(buf.get(3)).toEqual(36) + + buf.position(10) + expect(() => buf.put(3.toByte)).toThrow + } + } else { + it("relative put() - read-only") { + val buf = allocBuffer(10) + expect(() => buf.put(5.toByte)).toThrow + expect(buf.position()).toEqual(0) + expect(buf.get(0)).toEqual(0) + + buf.position(10) + expect(() => buf.put(3.toByte)).toThrow + } + } + + it("relative bulk get()") { + val buf = withContent(10, byteRange(0, 10): _*) + val a = new Array[Byte](4) + buf.get(a) + expect(a.toJSArray).toEqual(js.Array(0, 1, 2, 3)) + expect(buf.position()).toEqual(4) + + buf.position(6) + buf.get(a, 1, 2) + expect(a.toJSArray).toEqual(js.Array(0, 6, 7, 3)) + expect(buf.position()).toEqual(8) + + expect(() => buf.get(a)).toThrow + expect(buf.position()).toEqual(8) + expect(a.toJSArray).toEqual(js.Array(0, 6, 7, 3)) + } + + if (!createsReadOnly) { + it("relative bulk put()") { + val buf = allocBuffer(10) + buf.put(Array[Byte](6, 7, 12)) + expect((0 to 3).map(buf.get(_)).toJSArray).toEqual(js.Array(6, 7, 12, 0)) + expect(buf.position()).toEqual(3) + + buf.position(2) + buf.put(Array[Byte](44, 55, 66, 77, 88), 2, 2) + expect((0 to 4).map(buf.get(_)).toJSArray).toEqual(js.Array(6, 7, 66, 77, 0)) + expect(buf.position()).toEqual(4) + + expect(() => buf.put(Array.fill[Byte](10)(0))).toThrow + expect(buf.position()).toEqual(4) + expect((0 to 4).map(buf.get(_)).toJSArray).toEqual(js.Array(6, 7, 66, 77, 0)) + } + } else { + it("relative bulk put() - read-only") { + val buf = allocBuffer(10) + expect(() => buf.put(Array[Byte](6, 7, 12))).toThrow + expect(buf.position()).toEqual(0) + expect(buf.get(0)).toEqual(0) + + buf.position(8) + expect(() => buf.put(Array[Byte](6, 7, 12))).toThrow + expect(buf.position()).toEqual(8) + expect(buf.get(8)).toEqual(0) + } + } + + if (!createsReadOnly) { + it("compact()") { + val buf = withContent(10, byteRange(0, 10): _*) + buf.position(6) + buf.mark() + + buf.compact() + expect(buf.position()).toEqual(4) + expect(buf.limit()).toEqual(10) + expect(() => buf.reset()).toThrow + + for (i <- 0 until 4) + expect(buf.get(i)).toEqual(i + 6) + } + } else { + it("compact() - read-only") { + val buf = allocBuffer(10) + expect(() => buf.compact()).toThrow + } + } + + it("slice()" + (if (createsReadOnly) " - read-only" else "")) { + val buf1 = withContent(10, byteRange(0, 10): _*) + buf1.position(3) + buf1.limit(7) + buf1.mark() + val buf2 = buf1.slice() + expect(buf2.position()).toEqual(0) + expect(buf2.limit()).toEqual(4) + expect(buf2.capacity()).toEqual(4) + expect(() => buf2.reset()).toThrow + expect(buf2.get(1)).toEqual(4) + + buf2.position(2) + expect(buf1.position()).toEqual(3) + + if (!createsReadOnly) { + buf2.put(89.toByte) + expect(buf1.get(5)).toEqual(89) + expect(buf2.position()).toEqual(3) + expect(buf1.position()).toEqual(3) + } + + expect(() => buf2.limit(5)).toThrow + expect(buf2.limit()).toEqual(4) + + buf2.limit(3) + expect(buf1.limit()).toEqual(7) + + if (!createsReadOnly) { + buf1.put(3, 23) + expect(buf2.get(0)).toEqual(23) + } + } + + it("duplicate()" + (if (createsReadOnly) " - read-only" else "")) { + val buf1 = withContent(10, byteRange(0, 10): _*) + buf1.position(3) + buf1.limit(7) + buf1.mark() + val buf2 = buf1.duplicate() + expect(buf2.position()).toEqual(3) + expect(buf2.limit()).toEqual(7) + expect(buf2.capacity()).toEqual(10) + expect(buf2.get(4)).toEqual(4) + + buf2.position(4) + expect(buf1.position()).toEqual(3) + expect(buf2.position()).toEqual(4) + + buf2.reset() + expect(buf2.position()).toEqual(3) + buf2.position(4) + + if (!createsReadOnly) { + buf2.put(89.toByte) + expect(buf1.get(4)).toEqual(89) + expect(buf2.position()).toEqual(5) + expect(buf1.position()).toEqual(3) + } + + buf2.limit(5) + expect(buf1.limit()).toEqual(7) + + if (!createsReadOnly) { + buf1.put(6, 23) + buf2.limit(10) + expect(buf2.get(6)).toEqual(23) + } + } + } + + describe("Allocated ByteBuffer") { + defineTests(new Factory { + def allocBuffer(capacity: Int): ByteBuffer = + ByteBuffer.allocate(capacity) + }) + } + + class WrappedByteBufferFactory extends Factory { + def allocBuffer(capacity: Int): ByteBuffer = + ByteBuffer.wrap(new Array[Byte](capacity)) + + override def allocBuffer(pos: Int, limit: Int, capacity: Int): ByteBuffer = + ByteBuffer.wrap(new Array[Byte](capacity), pos, limit-pos) + + override def withContent(pos: Int, limit: Int, capacity: Int, + content: Byte*): ByteBuffer = { + val after = capacity - (pos + content.size) + ByteBuffer.wrap( + (Seq.fill(pos)(0.toByte) ++ content ++ Seq.fill(after)(0.toByte)).toArray, + pos, limit-pos) + } + } + + describe("Wrapped ByteBuffer") { + defineTests(new WrappedByteBufferFactory) + } + + describe("Read-only wrapped ByteBuffer") { + defineTests(new WrappedByteBufferFactory { + override val createsReadOnly = true + + override def allocBuffer(capacity: Int): ByteBuffer = + super.allocBuffer(capacity).asReadOnlyBuffer() + + override def allocBuffer(pos: Int, limit: Int, capacity: Int): ByteBuffer = + super.allocBuffer(pos, limit, capacity).asReadOnlyBuffer() + + override def withContent(pos: Int, limit: Int, capacity: Int, + content: Byte*): ByteBuffer = + super.withContent(pos, limit, capacity, content: _*).asReadOnlyBuffer() + }) + } + + describe("Sliced ByteBuffer") { + defineTests(new Factory { + def allocBuffer(capacity: Int): ByteBuffer = { + if (capacity < 0) + throw new IllegalArgumentException + val buf = ByteBuffer.allocate(capacity+25) + buf.position(17) + buf.limit(17+capacity) + buf.slice() + } + + override def withContent(pos: Int, limit: Int, capacity: Int, + content: Byte*): ByteBuffer = { + if (!(0 <= pos && pos <= limit && limit <= capacity)) + throw new IllegalArgumentException + val buf = ByteBuffer.allocate(capacity+25) + buf.position(9+pos) + buf.put(content.toArray) + buf.position(9) + buf.limit(9+capacity) + val buf2 = buf.slice() + buf2.position(pos) + buf2.limit(limit) + buf2 + } + }) + } +} diff --git a/test-suite/src/test/scala/scala/scalajs/testsuite/niobuffer/CharBufferTest.scala b/test-suite/src/test/scala/scala/scalajs/testsuite/niobuffer/CharBufferTest.scala new file mode 100644 index 0000000..b13c478 --- /dev/null +++ b/test-suite/src/test/scala/scala/scalajs/testsuite/niobuffer/CharBufferTest.scala @@ -0,0 +1,388 @@ +/* __ *\ +** ________ ___ / / ___ __ ____ Scala.js Test Suite ** +** / __/ __// _ | / / / _ | __ / // __/ (c) 2013, LAMP/EPFL ** +** __\ \/ /__/ __ |/ /__/ __ |/_// /_\ \ http://scala-js.org/ ** +** /____/\___/_/ |_/____/_/ | |__/ /____/ ** +** |/____/ ** +\* */ +package scala.scalajs.testsuite.niobuffer + +import java.nio._ + +import scala.scalajs.js +import js.JSConverters._ + +object CharBufferTest extends BaseBufferTest { + trait Factory extends BaseFactory { + type BufferType = CharBuffer + + def withContent(capacity: Int, content: Char*): CharBuffer = + withContent(0, capacity, capacity, content: _*) + + def withContent(pos: Int, limit: Int, capacity: Int, + content: Char*): CharBuffer = { + val buf = allocBuffer(pos, limit, capacity) + buf.put(content.toArray) + buf.position(pos) + buf + } + } + + def zeros(n: Int): String = + "\u0000"*n + + def charRange(start: Int, end: Int): Array[Char] = + (start until end).map(_.toChar).toArray + + def defineTests(factory: Factory): Unit = { + import factory._ + + commonTests(factory) + + it("absolute get()") { + val buf = withContent(10, charRange(0, 10): _*) + expect(buf.get(0)).toEqual(0) + expect(buf.position()).toEqual(0) + expect(buf.get(3)).toEqual(3) + expect(buf.position()).toEqual(0) + + expect(() => buf.get(-1)).toThrow + expect(() => buf.get(15)).toThrow + + buf.limit(4) + expect(() => buf.get(5)).toThrow + } + + + if (!createsReadOnly) { + it("absolute put()") { + val buf = allocBuffer(10) + buf.put(5, 42) + expect(buf.position()).toEqual(0) + buf.put(3, 2) + expect(buf.get(3)).toEqual(2) + expect(buf.get(5)).toEqual(42) + expect(buf.get(7)).toEqual(0) + + expect(() => buf.put(-1, 2)).toThrow + expect(() => buf.put(14, 9)).toThrow + + buf.limit(4) + expect(() => buf.put(4, 1)).toThrow + } + } else { + it("absolute put() - read-only") { + val buf = allocBuffer(10) + expect(() => buf.put(2, 1)).toThrow + expect(buf.get(2)).toEqual(0) + expect(buf.position()).toEqual(0) + + expect(() => buf.put(-2, 1)).toThrow + expect(() => buf.put(12, 1)).toThrow + } + } + + it("relative get()") { + val buf = withContent(10, charRange(0, 10): _*) + expect(buf.get()).toEqual(0) + expect(buf.position()).toEqual(1) + buf.position(3) + expect(buf.get()).toEqual(3) + expect(buf.position()).toEqual(4) + + buf.limit(4) + expect(() => buf.get()).toThrow + } + + if (!createsReadOnly) { + it("relative put()") { + val buf = allocBuffer(10) + buf.put(5.toChar) + expect(buf.position()).toEqual(1) + expect(buf.get(0)).toEqual(5) + + buf.position(3) + buf.put(36.toChar) + expect(buf.position()).toEqual(4) + expect(buf.get(3)).toEqual(36) + + buf.position(10) + expect(() => buf.put(3.toChar)).toThrow + } + } else { + it("relative put() - read-only") { + val buf = allocBuffer(10) + expect(() => buf.put(5.toChar)).toThrow + expect(buf.position()).toEqual(0) + expect(buf.get(0)).toEqual(0) + + buf.position(10) + expect(() => buf.put(3.toChar)).toThrow + } + } + + it("relative bulk get()") { + val buf = withContent(10, charRange(0, 10): _*) + val a = new Array[Char](4) + buf.get(a) + expect(a.map(_.toInt).toJSArray).toEqual(js.Array(0, 1, 2, 3)) + expect(buf.position()).toEqual(4) + + buf.position(6) + buf.get(a, 1, 2) + expect(a.map(_.toInt).toJSArray).toEqual(js.Array(0, 6, 7, 3)) + expect(buf.position()).toEqual(8) + + expect(() => buf.get(a)).toThrow + expect(buf.position()).toEqual(8) + expect(a.map(_.toInt).toJSArray).toEqual(js.Array(0, 6, 7, 3)) + } + + if (!createsReadOnly) { + it("relative bulk put()") { + val buf = allocBuffer(10) + buf.put(Array[Char](6, 7, 12)) + expect((0 to 3).map(buf.get(_).toInt).toJSArray).toEqual(js.Array(6, 7, 12, 0)) + expect(buf.position()).toEqual(3) + + buf.position(2) + buf.put(Array[Char](44, 55, 66, 77, 88), 2, 2) + expect((0 to 4).map(buf.get(_).toInt).toJSArray).toEqual(js.Array(6, 7, 66, 77, 0)) + expect(buf.position()).toEqual(4) + + expect(() => buf.put(Array.fill[Char](10)(0))).toThrow + expect(buf.position()).toEqual(4) + expect((0 to 4).map(buf.get(_).toInt).toJSArray).toEqual(js.Array(6, 7, 66, 77, 0)) + } + } else { + it("relative bulk put() - read-only") { + val buf = allocBuffer(10) + expect(() => buf.put(Array[Char](6, 7, 12))).toThrow + expect(buf.position()).toEqual(0) + expect(buf.get(0)).toEqual(0) + + buf.position(8) + expect(() => buf.put(Array[Char](6, 7, 12))).toThrow + expect(buf.position()).toEqual(8) + expect(buf.get(8)).toEqual(0) + } + } + + if (!createsReadOnly) { + it("compact()") { + val buf = withContent(10, charRange(0, 10): _*) + buf.position(6) + buf.mark() + + buf.compact() + expect(buf.position()).toEqual(4) + expect(buf.limit()).toEqual(10) + expect(() => buf.reset()).toThrow + + for (i <- 0 until 4) + expect(buf.get(i).toInt).toEqual(i + 6) + } + } else { + it("compact() - read-only") { + val buf = allocBuffer(10) + expect(() => buf.compact()).toThrow + } + } + + it("slice()" + (if (createsReadOnly) " - read-only" else "")) { + val buf1 = withContent(10, charRange(0, 10): _*) + buf1.position(3) + buf1.limit(7) + buf1.mark() + val buf2 = buf1.slice() + expect(buf2.position()).toEqual(0) + expect(buf2.limit()).toEqual(4) + expect(buf2.capacity()).toEqual(4) + expect(() => buf2.reset()).toThrow + expect(buf2.get(1)).toEqual(4) + + buf2.position(2) + expect(buf1.position()).toEqual(3) + + if (!createsReadOnly) { + buf2.put(89.toChar) + expect(buf1.get(5)).toEqual(89) + expect(buf2.position()).toEqual(3) + expect(buf1.position()).toEqual(3) + } + + expect(() => buf2.limit(5)).toThrow + expect(buf2.limit()).toEqual(4) + + buf2.limit(3) + expect(buf1.limit()).toEqual(7) + + if (!createsReadOnly) { + buf1.put(3, 23) + expect(buf2.get(0)).toEqual(23) + } + } + + it("duplicate()" + (if (createsReadOnly) " - read-only" else "")) { + val buf1 = withContent(10, charRange(0, 10): _*) + buf1.position(3) + buf1.limit(7) + buf1.mark() + val buf2 = buf1.duplicate() + expect(buf2.position()).toEqual(3) + expect(buf2.limit()).toEqual(7) + expect(buf2.capacity()).toEqual(10) + expect(buf2.get(4)).toEqual(4) + + buf2.position(4) + expect(buf1.position()).toEqual(3) + expect(buf2.position()).toEqual(4) + + buf2.reset() + expect(buf2.position()).toEqual(3) + buf2.position(4) + + if (!createsReadOnly) { + buf2.put(89.toChar) + expect(buf1.get(4)).toEqual(89) + expect(buf2.position()).toEqual(5) + expect(buf1.position()).toEqual(3) + } + + buf2.limit(5) + expect(buf1.limit()).toEqual(7) + + if (!createsReadOnly) { + buf1.put(6, 23) + buf2.limit(10) + expect(buf2.get(6)).toEqual(23) + } + } + } + + describe("Allocated CharBuffer") { + defineTests(new Factory { + def allocBuffer(capacity: Int): CharBuffer = + CharBuffer.allocate(capacity) + }) + } + + class WrappedCharBufferFactory extends Factory { + def allocBuffer(capacity: Int): CharBuffer = + CharBuffer.wrap(new Array[Char](capacity)) + + override def allocBuffer(pos: Int, limit: Int, capacity: Int): CharBuffer = + CharBuffer.wrap(new Array[Char](capacity), pos, limit-pos) + + override def withContent(pos: Int, limit: Int, capacity: Int, + content: Char*): CharBuffer = { + val after = capacity - (pos + content.size) + CharBuffer.wrap( + (Seq.fill(pos)(0.toChar) ++ content ++ Seq.fill(after)(0.toChar)).toArray, + pos, limit-pos) + } + } + + describe("Wrapped CharBuffer") { + defineTests(new WrappedCharBufferFactory) + } + + describe("Read-only wrapped CharBuffer") { + defineTests(new WrappedCharBufferFactory { + override val createsReadOnly = true + + override def allocBuffer(capacity: Int): CharBuffer = + super.allocBuffer(capacity).asReadOnlyBuffer() + + override def allocBuffer(pos: Int, limit: Int, capacity: Int): CharBuffer = + super.allocBuffer(pos, limit, capacity).asReadOnlyBuffer() + + override def withContent(pos: Int, limit: Int, capacity: Int, + content: Char*): CharBuffer = + super.withContent(pos, limit, capacity, content: _*).asReadOnlyBuffer() + }) + } + + describe("CharBuffer wrapping a CharSequence") { + defineTests(new Factory { + override val createsReadOnly = true + + def allocBuffer(capacity: Int): CharBuffer = { + if (capacity < 0) + throw new IllegalArgumentException + CharBuffer.wrap(zeros(capacity)) + } + + override def allocBuffer(pos: Int, limit: Int, capacity: Int): CharBuffer = { + if (capacity < 0) + throw new IllegalArgumentException + CharBuffer.wrap(zeros(capacity), pos, limit-pos) + } + + override def withContent(pos: Int, limit: Int, capacity: Int, + content: Char*): CharBuffer = { + val after = capacity - (pos + content.size) + CharBuffer.wrap( + zeros(pos) + content.mkString + zeros(after), + pos, limit-pos) + } + }) + } + + describe("Sliced CharBuffer") { + defineTests(new Factory { + def allocBuffer(capacity: Int): CharBuffer = { + if (capacity < 0) + throw new IllegalArgumentException + val buf = CharBuffer.allocate(capacity+25) + buf.position(17) + buf.limit(17+capacity) + buf.slice() + } + + override def withContent(pos: Int, limit: Int, capacity: Int, + content: Char*): CharBuffer = { + if (!(0 <= pos && pos <= limit && limit <= capacity)) + throw new IllegalArgumentException + val buf = CharBuffer.allocate(capacity+25) + buf.position(9+pos) + buf.put(content.toArray) + buf.position(9) + buf.limit(9+capacity) + val buf2 = buf.slice() + buf2.position(pos) + buf2.limit(limit) + buf2 + } + }) + } + + describe("Sliced CharBuffer wrapping a CharSequence") { + defineTests(new Factory { + override val createsReadOnly = true + + def allocBuffer(capacity: Int): CharBuffer = { + if (capacity < 0) + throw new IllegalArgumentException + val buf = CharBuffer.wrap(zeros(capacity+25)) + buf.position(17) + buf.limit(17+capacity) + buf.slice() + } + + override def withContent(pos: Int, limit: Int, capacity: Int, + content: Char*): CharBuffer = { + if (!(0 <= pos && pos <= limit && limit <= capacity)) + throw new IllegalArgumentException + val after = (25+capacity) - (9+pos+content.size) + val buf = CharBuffer.wrap(zeros(9+pos) + content.mkString + zeros(after)) + buf.position(9) + buf.limit(9+capacity) + val buf2 = buf.slice() + buf2.position(pos) + buf2.limit(limit) + buf2 + } + }) + } +} diff --git a/test-suite/src/test/scala/scala/scalajs/testsuite/niocharset/BaseCharsetTest.scala b/test-suite/src/test/scala/scala/scalajs/testsuite/niocharset/BaseCharsetTest.scala new file mode 100644 index 0000000..adda838 --- /dev/null +++ b/test-suite/src/test/scala/scala/scalajs/testsuite/niocharset/BaseCharsetTest.scala @@ -0,0 +1,234 @@ +/* __ *\ +** ________ ___ / / ___ __ ____ Scala.js Test Suite ** +** / __/ __// _ | / / / _ | __ / // __/ (c) 2013, LAMP/EPFL ** +** __\ \/ /__/ __ |/ /__/ __ |/_// /_\ \ http://scala-js.org/ ** +** /____/\___/_/ |_/____/_/ | |__/ /____/ ** +** |/____/ ** +\* */ +package scala.scalajs.testsuite.niocharset + +import scala.language.implicitConversions + +import scala.util._ + +import java.nio._ +import java.nio.charset._ + +import scala.scalajs.js +import js.JSConverters._ + +import org.scalajs.jasminetest.JasmineTest + +class BaseCharsetTest(val charset: Charset) extends JasmineTest { + import BaseCharsetTest._ + + protected val AllErrorActions = Seq( + CodingErrorAction.IGNORE, + CodingErrorAction.REPLACE, + CodingErrorAction.REPORT) + + protected val ReportActions = Seq( + CodingErrorAction.REPORT) + + protected def testDecode(in: ByteBuffer)( + outParts: OutPart[CharBuffer]*): Unit = { + + def testOneConfig(malformedAction: CodingErrorAction, + unmappableAction: CodingErrorAction): Unit = { + + val decoder = charset.newDecoder() + decoder.onMalformedInput(malformedAction) + decoder.onUnmappableCharacter(unmappableAction) + + val actualTry = Try { + in.mark() + val buf = + try decoder.decode(in) + finally in.reset() + val actualChars = new Array[Char](buf.remaining()) + buf.get(actualChars) + actualChars + } + + val expectedTry = Try { + val expectedChars = Array.newBuilder[Char] + outParts foreach { + case BufferPart(buf) => + val bufArray = new Array[Char](buf.remaining) + buf.mark() + try buf.get(bufArray) + finally buf.reset() + expectedChars ++= bufArray + case Malformed(len) => + malformedAction match { + case CodingErrorAction.IGNORE => + case CodingErrorAction.REPLACE => + expectedChars ++= decoder.replacement() + case CodingErrorAction.REPORT => + throw new MalformedInputException(len) + } + case Unmappable(len) => + unmappableAction match { + case CodingErrorAction.IGNORE => + case CodingErrorAction.REPLACE => + expectedChars ++= decoder.replacement() + case CodingErrorAction.REPORT => + throw new UnmappableCharacterException(len) + } + } + expectedChars.result() + } + + (actualTry, expectedTry) match { + case (Failure(actualEx: MalformedInputException), + Failure(expectedEx: MalformedInputException)) => + expect(actualEx.getInputLength()).toEqual(expectedEx.getInputLength()) + + case (Failure(actualEx: UnmappableCharacterException), + Failure(expectedEx: UnmappableCharacterException)) => + expect(actualEx.getInputLength()).toEqual(expectedEx.getInputLength()) + + case (Success(actualChars), Success(expectedChars)) => + expect(actualChars.map(_.toInt).toJSArray).toEqual( + expectedChars.map(_.toInt).toJSArray) + + case _ => + // For the error message + expect(actualTry.asInstanceOf[js.Any]).toBe( + expectedTry.asInstanceOf[js.Any]) + } + } + + val hasAnyMalformed = outParts.exists(_.isInstanceOf[Malformed]) + val hasAnyUnmappable = outParts.exists(_.isInstanceOf[Unmappable]) + + for { + malformedAction <- if (hasAnyMalformed) AllErrorActions else ReportActions + unmappableAction <- if (hasAnyUnmappable) AllErrorActions else ReportActions + } { + testOneConfig(malformedAction, unmappableAction) + } + } + + protected def testEncode(in: CharBuffer)( + outParts: OutPart[ByteBuffer]*): Unit = { + + def testOneConfig(malformedAction: CodingErrorAction, + unmappableAction: CodingErrorAction): Unit = { + + val encoder = charset.newEncoder() + encoder.onMalformedInput(malformedAction) + encoder.onUnmappableCharacter(unmappableAction) + + val actualTry = Try { + in.mark() + val buf = + try encoder.encode(in) + finally in.reset() + val actualBytes = new Array[Byte](buf.remaining()) + buf.get(actualBytes) + actualBytes + } + + val expectedTry = Try { + val expectedBytes = Array.newBuilder[Byte] + outParts foreach { + case BufferPart(buf) => + val bufArray = new Array[Byte](buf.remaining) + buf.mark() + try buf.get(bufArray) + finally buf.reset() + expectedBytes ++= bufArray + case Malformed(len) => + malformedAction match { + case CodingErrorAction.IGNORE => + case CodingErrorAction.REPLACE => + expectedBytes ++= encoder.replacement() + case CodingErrorAction.REPORT => + throw new MalformedInputException(len) + } + case Unmappable(len) => + unmappableAction match { + case CodingErrorAction.IGNORE => + case CodingErrorAction.REPLACE => + expectedBytes ++= encoder.replacement() + case CodingErrorAction.REPORT => + throw new UnmappableCharacterException(len) + } + } + expectedBytes.result() + } + + (actualTry, expectedTry) match { + case (Failure(actualEx: MalformedInputException), + Failure(expectedEx: MalformedInputException)) => + expect(actualEx.getInputLength()).toEqual(expectedEx.getInputLength()) + + case (Failure(actualEx: UnmappableCharacterException), + Failure(expectedEx: UnmappableCharacterException)) => + expect(actualEx.getInputLength()).toEqual(expectedEx.getInputLength()) + + case (Success(actualBytes), Success(expectedBytes)) => + expect(actualBytes.toJSArray).toEqual(expectedBytes.toJSArray) + + case _ => + // For the error message + expect(actualTry.asInstanceOf[js.Any]).toBe( + expectedTry.asInstanceOf[js.Any]) + } + } + + val hasAnyMalformed = outParts.exists(_.isInstanceOf[Malformed]) + val hasAnyUnmappable = outParts.exists(_.isInstanceOf[Unmappable]) + + for { + malformedAction <- if (hasAnyMalformed) AllErrorActions else ReportActions + unmappableAction <- if (hasAnyUnmappable) AllErrorActions else ReportActions + } { + testOneConfig(malformedAction, unmappableAction) + } + } +} + +object BaseCharsetTest { + sealed abstract class OutPart[+BufferType <: Buffer] + final case class BufferPart[BufferType <: Buffer](buf: BufferType) extends OutPart[BufferType] + final case class Malformed(length: Int) extends OutPart[Nothing] + final case class Unmappable(length: Int) extends OutPart[Nothing] + + object OutPart { + implicit def fromBuffer[BufferType <: Buffer](buf: BufferType): BufferPart[BufferType] = + BufferPart(buf) + } + + implicit class Interpolators(val sc: StringContext) extends AnyVal { + def bb(args: Any*): ByteBuffer = { + val strings = sc.parts.iterator + val expressions = args.iterator + val buf = Array.newBuilder[Byte] + + def appendStr(s: String): Unit = { + val s1 = s.replace(" ", "") + require(s1.length % 2 == 0) + for (i <- 0 until s1.length by 2) + buf += java.lang.Integer.parseInt(s1.substring(i, i+2), 16).toByte + } + + appendStr(strings.next()) + while (strings.hasNext) { + expressions.next() match { + case b: Byte => buf += b + case bytes: Array[Byte] => buf ++= bytes + case bytes: Seq[_] => + buf ++= bytes.map(_.asInstanceOf[Number].byteValue()) + } + appendStr(strings.next()) + } + + ByteBuffer.wrap(buf.result()) + } + + def cb(args: Any*): CharBuffer = + CharBuffer.wrap(sc.s(args: _*)) + } +} diff --git a/test-suite/src/test/scala/scala/scalajs/testsuite/niocharset/CharsetTest.scala b/test-suite/src/test/scala/scala/scalajs/testsuite/niocharset/CharsetTest.scala new file mode 100644 index 0000000..15b0150 --- /dev/null +++ b/test-suite/src/test/scala/scala/scalajs/testsuite/niocharset/CharsetTest.scala @@ -0,0 +1,74 @@ +/* __ *\ +** ________ ___ / / ___ __ ____ Scala.js Test Suite ** +** / __/ __// _ | / / / _ | __ / // __/ (c) 2013, LAMP/EPFL ** +** __\ \/ /__/ __ |/ /__/ __ |/_// /_\ \ http://scala-js.org/ ** +** /____/\___/_/ |_/____/_/ | |__/ /____/ ** +** |/____/ ** +\* */ +package scala.scalajs.testsuite.niocharset + +import scala.language.implicitConversions + +import java.nio._ +import java.nio.charset._ + +import scala.scalajs.js +import scala.scalajs.niocharset.StandardCharsets._ + +import org.scalajs.jasminetest.JasmineTest + +object CharsetTest extends JasmineTest { + implicit def charsetAsJSAny(charset: Charset): js.Any = + charset.asInstanceOf[js.Any] + + describe("java.nio.charset.Charset") { + it("defaultCharset") { + expect(Charset.defaultCharset()).toBe(UTF_8) + } + + it("forName") { + expect(Charset.forName("ISO-8859-1")).toBe(ISO_8859_1) + expect(Charset.forName("Iso8859-1")).toBe(ISO_8859_1) + expect(Charset.forName("iso_8859_1")).toBe(ISO_8859_1) + expect(Charset.forName("LaTin1")).toBe(ISO_8859_1) + expect(Charset.forName("l1")).toBe(ISO_8859_1) + + expect(Charset.forName("US-ASCII")).toBe(US_ASCII) + expect(Charset.forName("Default")).toBe(US_ASCII) + + expect(Charset.forName("UTF-8")).toBe(UTF_8) + expect(Charset.forName("utf-8")).toBe(UTF_8) + expect(Charset.forName("UtF8")).toBe(UTF_8) + expect(Charset.forName("UTF_8")).toBe(UTF_8) + expect(Charset.forName("UTF-8")).toBe(UTF_8) + + expect(Charset.forName("UTF-16BE")).toBe(UTF_16BE) + expect(Charset.forName("Utf_16BE")).toBe(UTF_16BE) + expect(Charset.forName("UnicodeBigUnmarked")).toBe(UTF_16BE) + + expect(Charset.forName("UTF-16le")).toBe(UTF_16LE) + expect(Charset.forName("Utf_16le")).toBe(UTF_16LE) + expect(Charset.forName("UnicodeLittleUnmarked")).toBe(UTF_16LE) + + expect(Charset.forName("UTF-16")).toBe(UTF_16) + expect(Charset.forName("Utf_16")).toBe(UTF_16) + expect(Charset.forName("unicode")).toBe(UTF_16) + expect(Charset.forName("UnicodeBig")).toBe(UTF_16) + + expect(() => Charset.forName("this-charset-does-not-exist")).toThrow + } + + it("isSupported") { + expect(Charset.isSupported("ISO-8859-1")).toBeTruthy + expect(Charset.isSupported("US-ASCII")).toBeTruthy + expect(Charset.isSupported("Default")).toBeTruthy + expect(Charset.isSupported("utf-8")).toBeTruthy + expect(Charset.isSupported("UnicodeBigUnmarked")).toBeTruthy + expect(Charset.isSupported("Utf_16le")).toBeTruthy + expect(Charset.isSupported("UTF-16")).toBeTruthy + expect(Charset.isSupported("unicode")).toBeTruthy + + expect(Charset.isSupported("this-charset-does-not-exist")).toBeFalsy + } + } +} diff --git a/test-suite/src/test/scala/scala/scalajs/testsuite/niocharset/Latin1Test.scala b/test-suite/src/test/scala/scala/scalajs/testsuite/niocharset/Latin1Test.scala new file mode 100644 index 0000000..f6ddc36 --- /dev/null +++ b/test-suite/src/test/scala/scala/scalajs/testsuite/niocharset/Latin1Test.scala @@ -0,0 +1,91 @@ +/* __ *\ +** ________ ___ / / ___ __ ____ Scala.js Test Suite ** +** / __/ __// _ | / / / _ | __ / // __/ (c) 2013, LAMP/EPFL ** +** __\ \/ /__/ __ |/ /__/ __ |/_// /_\ \ http://scala-js.org/ ** +** /____/\___/_/ |_/____/_/ | |__/ /____/ ** +** |/____/ ** +\* */ +package scala.scalajs.testsuite.niocharset + +import java.nio._ +import java.nio.charset._ + +import scala.scalajs.niocharset.StandardCharsets + +import BaseCharsetTest._ + +object Latin1Test extends BaseCharsetTest(StandardCharsets.ISO_8859_1) { + describe("ISO-8859-1") { + it("decode") { + // Simple tests + + testDecode(bb"48 65 6c 6c 6f")(cb"Hello") + testDecode(bb"42 6f 6e 6a 6f 75 72")(cb"Bonjour") + + testDecode(bb"00 01 0a 10 20")(cb"\u0000\u0001\u000a\u0010 ") + testDecode(bb"7f 7f")(cb"\u007f\u007f") + + testDecode(bb"c8 e5 ec ec ef")(cb"Èåììï") + testDecode(bb"c2 ef ee ea ef f5 f2")(cb"Âïîêïõò") + + testDecode(bb"80 81 8a 90 a0")(cb"\u0080\u0081\u008a\u0090\u00a0") + testDecode(bb"ff ff")(cb"ÿÿ") + } + + it("encode") { + // Simple tests + + testEncode(cb"Hello")(bb"48 65 6c 6c 6f") + testEncode(cb"Bonjour")(bb"42 6f 6e 6a 6f 75 72") + + testEncode(cb"\u0000\u0001\u000a\u0010 ")(bb"00 01 0a 10 20") + testEncode(cb"\u007f\u007f")(bb"7f 7f") + + testEncode(cb"Èåììï")(bb"c8 e5 ec ec ef") + testEncode(cb"Âïîêïõò")(bb"c2 ef ee ea ef f5 f2") + + testEncode(cb"\u0080\u0081\u008a\u0090\u00a0")(bb"80 81 8a 90 a0") + testEncode(cb"ÿÿ")(bb"ff ff") + + // Unmappable characters + + testEncode(cb"\u0100")(Unmappable(1)) + testEncode(cb"\u07ff")(Unmappable(1)) + testEncode(cb"\ue000")(Unmappable(1)) + testEncode(cb"\uffff")(Unmappable(1)) + testEncode(cb"\ud835\udcd7")(Unmappable(2)) + + testEncode(cb"\u0100A")(Unmappable(1), bb"41") + testEncode(cb"\u07ffA")(Unmappable(1), bb"41") + testEncode(cb"\ue000A")(Unmappable(1), bb"41") + testEncode(cb"\uffffA")(Unmappable(1), bb"41") + testEncode(cb"\ud835\udcd7A")(Unmappable(2), bb"41") + + // Single UTF-16 surrogates + testEncode(cb"\ud800")(Malformed(1)) + testEncode(cb"\udaff")(Malformed(1)) + testEncode(cb"\udb80")(Malformed(1)) + testEncode(cb"\udbff")(Malformed(1)) + testEncode(cb"\udc00")(Malformed(1)) + testEncode(cb"\udf80")(Malformed(1)) + testEncode(cb"\udfff")(Malformed(1)) + + // High UTF-16 surrogates not followed by low surrogates + testEncode(cb"\ud800A")(Malformed(1), bb"41") + testEncode(cb"\ud800\ud800")(Malformed(1), Malformed(1)) + testEncode(cb"\ud800\ud835\udcd7")(Malformed(1), Unmappable(2)) + testEncode(cb"\udbffA")(Malformed(1), bb"41") + testEncode(cb"\udbff\udb8f")(Malformed(1), Malformed(1)) + testEncode(cb"\udbff\ud835\udcd7")(Malformed(1), Unmappable(2)) + } + + it("isLegalReplacement") { + val encoder = charset.newEncoder + expect(encoder.isLegalReplacement(Array(0x00.toByte))).toBeTruthy + expect(encoder.isLegalReplacement(Array(0x41.toByte))).toBeTruthy + expect(encoder.isLegalReplacement(Array('?'.toByte))).toBeTruthy + expect(encoder.isLegalReplacement(Array(0x80.toByte))).toBeTruthy + expect(encoder.isLegalReplacement(Array(0xff.toByte))).toBeTruthy + } + } +} diff --git a/test-suite/src/test/scala/scala/scalajs/testsuite/niocharset/USASCIITest.scala b/test-suite/src/test/scala/scala/scalajs/testsuite/niocharset/USASCIITest.scala new file mode 100644 index 0000000..2352d3e --- /dev/null +++ b/test-suite/src/test/scala/scala/scalajs/testsuite/niocharset/USASCIITest.scala @@ -0,0 +1,93 @@ +/* __ *\ +** ________ ___ / / ___ __ ____ Scala.js Test Suite ** +** / __/ __// _ | / / / _ | __ / // __/ (c) 2013, LAMP/EPFL ** +** __\ \/ /__/ __ |/ /__/ __ |/_// /_\ \ http://scala-js.org/ ** +** /____/\___/_/ |_/____/_/ | |__/ /____/ ** +** |/____/ ** +\* */ +package scala.scalajs.testsuite.niocharset + +import java.nio._ +import java.nio.charset._ + +import scala.scalajs.niocharset.StandardCharsets + +import BaseCharsetTest._ + +object USASCIITest extends BaseCharsetTest(StandardCharsets.US_ASCII) { + describe("US-ASCII") { + it("decode") { + // Simple tests + + testDecode(bb"48 65 6c 6c 6f")(cb"Hello") + testDecode(bb"42 6f 6e 6a 6f 75 72")(cb"Bonjour") + + testDecode(bb"00 01 0a 10 20")(cb"\u0000\u0001\u000a\u0010 ") + testDecode(bb"7f 7f")(cb"\u007f\u007f") + + // Bit 7 is ignored, giving the same results as above + + testDecode(bb"c8 e5 ec ec ef")(cb"Hello") + testDecode(bb"c2 ef ee ea ef f5 f2")(cb"Bonjour") + + testDecode(bb"80 81 8a 90 a0")(cb"\u0000\u0001\u000a\u0010 ") + testDecode(bb"ff ff")(cb"\u007f\u007f") + } + + it("encode") { + // Simple tests + + testEncode(cb"Hello")(bb"48 65 6c 6c 6f") + testEncode(cb"Bonjour")(bb"42 6f 6e 6a 6f 75 72") + + testEncode(cb"\u0000\u0001\u000a\u0010 ")(bb"00 01 0a 10 20") + testEncode(cb"\u007f\u007f")(bb"7f 7f") + + // Unmappable characters + + testEncode(cb"é")(Unmappable(1)) + testEncode(cb"\u0080")(Unmappable(1)) + testEncode(cb"\u00ff")(Unmappable(1)) + testEncode(cb"\u0100")(Unmappable(1)) + testEncode(cb"\u07ff")(Unmappable(1)) + testEncode(cb"\ue000")(Unmappable(1)) + testEncode(cb"\uffff")(Unmappable(1)) + testEncode(cb"\ud835\udcd7")(Unmappable(2)) + + testEncode(cb"éA")(Unmappable(1), bb"41") + testEncode(cb"\u0080A")(Unmappable(1), bb"41") + testEncode(cb"\u00ffA")(Unmappable(1), bb"41") + testEncode(cb"\u0100A")(Unmappable(1), bb"41") + testEncode(cb"\u07ffA")(Unmappable(1), bb"41") + testEncode(cb"\ue000A")(Unmappable(1), bb"41") + testEncode(cb"\uffffA")(Unmappable(1), bb"41") + testEncode(cb"\ud835\udcd7A")(Unmappable(2), bb"41") + + // Single UTF-16 surrogates + testEncode(cb"\ud800")(Malformed(1)) + testEncode(cb"\udaff")(Malformed(1)) + testEncode(cb"\udb80")(Malformed(1)) + testEncode(cb"\udbff")(Malformed(1)) + testEncode(cb"\udc00")(Malformed(1)) + testEncode(cb"\udf80")(Malformed(1)) + testEncode(cb"\udfff")(Malformed(1)) + + // High UTF-16 surrogates not followed by low surrogates + testEncode(cb"\ud800A")(Malformed(1), bb"41") + testEncode(cb"\ud800\ud800")(Malformed(1), Malformed(1)) + testEncode(cb"\ud800\ud835\udcd7")(Malformed(1), Unmappable(2)) + testEncode(cb"\udbffA")(Malformed(1), bb"41") + testEncode(cb"\udbff\udb8f")(Malformed(1), Malformed(1)) + testEncode(cb"\udbff\ud835\udcd7")(Malformed(1), Unmappable(2)) + } + + it("isLegalReplacement") { + val encoder = charset.newEncoder + expect(encoder.isLegalReplacement(Array(0x00.toByte))).toBeTruthy + expect(encoder.isLegalReplacement(Array(0x41.toByte))).toBeTruthy + expect(encoder.isLegalReplacement(Array('?'.toByte))).toBeTruthy + expect(encoder.isLegalReplacement(Array(0x80.toByte))).toBeTruthy + expect(encoder.isLegalReplacement(Array(0xff.toByte))).toBeTruthy + } + } +} diff --git a/test-suite/src/test/scala/scala/scalajs/testsuite/niocharset/UTF16Test.scala b/test-suite/src/test/scala/scala/scalajs/testsuite/niocharset/UTF16Test.scala new file mode 100644 index 0000000..85d4eff --- /dev/null +++ b/test-suite/src/test/scala/scala/scalajs/testsuite/niocharset/UTF16Test.scala @@ -0,0 +1,155 @@ +/* __ *\ +** ________ ___ / / ___ __ ____ Scala.js Test Suite ** +** / __/ __// _ | / / / _ | __ / // __/ (c) 2013, LAMP/EPFL ** +** __\ \/ /__/ __ |/ /__/ __ |/_// /_\ \ http://scala-js.org/ ** +** /____/\___/_/ |_/____/_/ | |__/ /____/ ** +** |/____/ ** +\* */ +package scala.scalajs.testsuite.niocharset + +import java.nio._ +import java.nio.charset._ + +import scala.scalajs.niocharset.StandardCharsets + +import BaseCharsetTest._ + +abstract class BaseUTF16Test(charset: Charset) extends BaseCharsetTest(charset) { + describe(charset.name) { + it("decode") { + // ASCII characters + testDecode(bb"0042 006f 006e 006a 006f 0075 0072")(cb"Bonjour") + + // Other characters without surrogate pairs + testDecode(bb"0047 0072 00fc 00df 0020 0047 006f 0074 0074")(cb"Grüß Gott") + testDecode(bb"039a 03b1 03bb 03b7 03bc 03ad 03c1 03b1")(cb"Καλημέρα") + testDecode(bb"0635 0628 0627 062d 0020 0627 0644 062e 064a 0631")(cb"صباح الخير") + testDecode(bb"3053 3093 306b 3061 306f")(cb"こんにちは") + testDecode(bb"0414 043e 0431 0440 044b 0439 0020 0434 0435 043d 044c")(cb"Добрый день") + testDecode(bb"4f60 597d")(cb"你好") + + // 4-byte characters + testDecode(bb"d835 dcd7 d835 dcee d835 dcf5 d835 dcf5 d835 dcf8")( + cb"\ud835\udcd7\ud835\udcee\ud835\udcf5\ud835\udcf5\ud835\udcf8") + + testDecode(bb"")(cb"") + + // Here begin the sequences with at least one error + + // Single UTF-16 surrogates + testDecode(bb"d800")(Malformed(2)) + testDecode(bb"daff")(Malformed(2)) + testDecode(bb"db80")(Malformed(2)) + testDecode(bb"dbff")(Malformed(2)) + testDecode(bb"dc00")(Malformed(2)) + testDecode(bb"df80")(Malformed(2)) + testDecode(bb"dfff")(Malformed(2)) + + // High UTF-16 surrogates not followed by low surrogates + testDecode(bb"d800 0041")(Malformed(2), cb"A") + testDecode(bb"d800 d800")(Malformed(2), Malformed(2)) + testDecode(bb"d800 d835 dcd7")(Malformed(2), cb"\ud835\udcd7") + testDecode(bb"dbff 0041")(Malformed(2), cb"A") + testDecode(bb"dbff db8f")(Malformed(2), Malformed(2)) + testDecode(bb"dbff d835 dcd7")(Malformed(2), cb"\ud835\udcd7") + + // Lonely byte at the end + testDecode(bb"0041 41")(cb"A", Malformed(1)) + } + + it("encode") { + // ASCII characters + testEncode(cb"Bonjour")(bb"0042 006f 006e 006a 006f 0075 0072") + + // Other characters without surrogate pairs + testEncode(cb"Grüß Gott")(bb"0047 0072 00fc 00df 0020 0047 006f 0074 0074") + testEncode(cb"Καλημέρα")(bb"039a 03b1 03bb 03b7 03bc 03ad 03c1 03b1") + testEncode(cb"صباح الخير")(bb"0635 0628 0627 062d 0020 0627 0644 062e 064a 0631") + testEncode(cb"こんにちは")(bb"3053 3093 306b 3061 306f") + testEncode(cb"Добрый день")(bb"0414 043e 0431 0440 044b 0439 0020 0434 0435 043d 044c") + testEncode(cb"你好")(bb"4f60 597d") + + // 4-byte characters + testEncode(cb"\ud835\udcd7\ud835\udcee\ud835\udcf5\ud835\udcf5\ud835\udcf8")( + bb"d835 dcd7 d835 dcee d835 dcf5 d835 dcf5 d835 dcf8") + + testEncode(cb"")(bb"") + + // Here begin the sequences with at least one error + + // Single UTF-16 surrogates + testEncode(cb"\ud800")(Malformed(1)) + testEncode(cb"\udaff")(Malformed(1)) + testEncode(cb"\udb80")(Malformed(1)) + testEncode(cb"\udbff")(Malformed(1)) + testEncode(cb"\udc00")(Malformed(1)) + testEncode(cb"\udf80")(Malformed(1)) + testEncode(cb"\udfff")(Malformed(1)) + + // High UTF-16 surrogates not followed by low surrogates + testEncode(cb"\ud800A")(Malformed(1), bb"0041") + testEncode(cb"\ud800\ud800")(Malformed(1), Malformed(1)) + testEncode(cb"\ud800\ud835\udcd7")(Malformed(1), bb"d835 dcd7") + testEncode(cb"\udbffA")(Malformed(1), bb"0041") + testEncode(cb"\udbff\udb8f")(Malformed(1), Malformed(1)) + testEncode(cb"\udbff\ud835\udcd7")(Malformed(1), bb"d835 dcd7") + } + } +} + +object UTF16BETest extends BaseUTF16Test(StandardCharsets.UTF_16BE) + +object UTF16LETest extends BaseUTF16Test(StandardCharsets.UTF_16LE) { + override protected def testDecode(in: ByteBuffer)( + outParts: OutPart[CharBuffer]*): Unit = { + flipByteBuffer(in) + super.testDecode(in)(outParts: _*) + } + + override protected def testEncode(in: CharBuffer)( + outParts: OutPart[ByteBuffer]*): Unit = { + for (BufferPart(buf) <- outParts) + flipByteBuffer(buf) + super.testEncode(in)(outParts: _*) + } + + /** Flips all pairs of bytes in a byte buffer, except a potential lonely + * last byte. + */ + def flipByteBuffer(buf: ByteBuffer): Unit = { + buf.mark() + while (buf.remaining() >= 2) { + val high = buf.get() + val low = buf.get() + buf.position(buf.position - 2) + buf.put(low) + buf.put(high) + } + buf.reset() + } +} + +object UTF16Test extends BaseUTF16Test(StandardCharsets.UTF_16) { + def BigEndianBOM = ByteBuffer.wrap(Array(0xfe.toByte, 0xff.toByte)) + + override protected def testDecode(in: ByteBuffer)( + outParts: OutPart[CharBuffer]*): Unit = { + // Without BOM, big endian is assumed + super.testDecode(in)(outParts: _*) + + // With BOM, big endian + val inWithBOM = ByteBuffer.allocate(2+in.remaining) + inWithBOM.put(BigEndianBOM).put(in).flip() + super.testDecode(inWithBOM)(outParts: _*) + + // With BOM, little endian + UTF16LETest.flipByteBuffer(inWithBOM) + super.testDecode(inWithBOM)(outParts: _*) + } + + override protected def testEncode(in: CharBuffer)( + outParts: OutPart[ByteBuffer]*): Unit = { + if (in.remaining == 0) super.testEncode(in)(outParts: _*) + else super.testEncode(in)(BufferPart(BigEndianBOM) +: outParts: _*) + } +} diff --git a/test-suite/src/test/scala/scala/scalajs/testsuite/niocharset/UTF8Test.scala b/test-suite/src/test/scala/scala/scalajs/testsuite/niocharset/UTF8Test.scala new file mode 100644 index 0000000..fbb6a9c --- /dev/null +++ b/test-suite/src/test/scala/scala/scalajs/testsuite/niocharset/UTF8Test.scala @@ -0,0 +1,240 @@ +/* __ *\ +** ________ ___ / / ___ __ ____ Scala.js Test Suite ** +** / __/ __// _ | / / / _ | __ / // __/ (c) 2013, LAMP/EPFL ** +** __\ \/ /__/ __ |/ /__/ __ |/_// /_\ \ http://scala-js.org/ ** +** /____/\___/_/ |_/____/_/ | |__/ /____/ ** +** |/____/ ** +\* */ +package scala.scalajs.testsuite.niocharset + +import java.nio._ +import java.nio.charset._ + +import scala.scalajs.niocharset.StandardCharsets + +import BaseCharsetTest._ + +object UTF8Test extends BaseCharsetTest(StandardCharsets.UTF_8) { + describe("UTF-8") { + it("decode") { + def OutSeq(elems: OutPart[CharBuffer]*): Seq[OutPart[CharBuffer]] = + Seq[OutPart[CharBuffer]](elems: _*) + + // 1-byte characters + testDecode(bb"42 6f 6e 6a 6f 75 72")(cb"Bonjour") + + // 2-byte characters + testDecode(bb"47 72 c3 bc c3 9f 20 47 6f 74 74")(cb"Grüß Gott") + testDecode(bb"ce 9a ce b1 ce bb ce b7 ce bc ce ad cf 81 ce b1")(cb"Καλημέρα") + testDecode(bb"d8 b5 d8 a8 d8 a7 d8 ad 20 d8 a7 d9 84 d8 ae d9 8a d8 b1")(cb"صباح الخير") + + // 3-byte characters + testDecode(bb"e3 81 93 e3 82 93 e3 81 ab e3 81 a1 e3 81 af")(cb"こんにちは") + testDecode(bb"d0 94 d0 be d0 b1 d1 80 d1 8b d0 b9 20 d0 b4 d0 b5 d0 bd d1 8c")(cb"Добрый день") + testDecode(bb"e4 bd a0 e5 a5 bd")(cb"你好") + + // 4-byte characters + testDecode(bb"f0 9d 93 97 f0 9d 93 ae f0 9d 93 b5 f0 9d 93 b5 f0 9d 93 b8")( + cb"\ud835\udcd7\ud835\udcee\ud835\udcf5\ud835\udcf5\ud835\udcf8") + + testDecode(bb"")(cb"") + + // First sequence of a certain length + testDecode(bb"00")(cb"\u0000") + testDecode(bb"c2 80")(cb"\u0080") + testDecode(bb"e0 a0 80")(cb"\u0800") + testDecode(bb"f0 90 80 80")(cb"\ud800\udc00") + + // Last sequence of a certain length + testDecode(bb"7f")(cb"\u007f") + testDecode(bb"df bf")(cb"\u07ff") + testDecode(bb"ef bf bf")(cb"\uffff") + testDecode(bb"f4 8f bf bf")(cb"\udbff\udfff") + + // Other boundary conditions + testDecode(bb"ed 9f bf")(cb"\ud7ff") + testDecode(bb"ee 80 80")(cb"\ue000") + testDecode(bb"ef bf bd")(cb"\ufffd") + + // Here begin the sequences with at least one error + + // Code point too big + testDecode(bb"f4 90 80 80")(Malformed(4)) + testDecode(bb"41 f4 90 80 80 42")(cb"A", Malformed(4), cb"B") + + // Unexpected continuation bytes (each is reported separately) + testDecode(bb"80")(Malformed(1)) + testDecode(bb"bf")(Malformed(1)) + testDecode(bb"80 80")(Malformed(1), Malformed(1)) + testDecode(bb"80 80 80")(Malformed(1), Malformed(1), Malformed(1)) + testDecode(bb"80 80 80 80")(Malformed(1), Malformed(1), Malformed(1), Malformed(1)) + testDecode(bb"80 80 80 80 80")(Malformed(1), Malformed(1), Malformed(1), Malformed(1), Malformed(1)) + testDecode(bb"41 80 80 42 80 43")(cb"A", Malformed(1), Malformed(1), cb"B", Malformed(1), cb"C") + + // Lonely start characters, separated by spaces + /* We add 2 spaces at the end so that the last 4-byte start does not + * swallow the last space as an underflow. */ + testDecode(bb"${(0xc0 to 0xf4).flatMap(c => Seq(c, 32)) ++ Seq[Byte](32, 32)}")( + (0xc0 to 0xf4).flatMap(i => OutSeq(Malformed(1), cb" ")) ++ OutSeq(cb" "): _*) + // Now we let it swallow the last space + testDecode(bb"${Seq[Byte](32) ++ (0xc0 to 0xf4).flatMap(c => Seq(c, 32))}")( + (0xc0 to 0xf4).flatMap(i => OutSeq(cb" ", Malformed(1))): _*) + + // Sequences with some continuation bytes missing + testDecode(bb"c2")(Malformed(1)) + testDecode(bb"e0")(Malformed(1)) + testDecode(bb"e0 a0")(Malformed(2)) + testDecode(bb"f0")(Malformed(1)) + testDecode(bb"f0 90")(Malformed(2)) + testDecode(bb"f0 90 80")(Malformed(3)) + // and all of them concatenated + testDecode(bb"c2 e0 e0 a0 f0 f0 90 f0 90 80")( + Seq(1, 1, 2, 1, 2, 3).map(Malformed(_)): _*) + // and with normal sequences interspersed + testDecode(bb"c2 41 e0 41 e0 a0 41 f0 41 f0 90 41 f0 90 80 41")( + Seq(1, 1, 2, 1, 2, 3).flatMap(l => Seq[OutPart[CharBuffer]](Malformed(l), cb"A")): _*) + + // Impossible bytes + testDecode(bb"fe")(Malformed(1)) + testDecode(bb"ff")(Malformed(1)) + testDecode(bb"fe fe ff ff")(Malformed(1), Malformed(1), Malformed(1), Malformed(1)) + // Old 5-byte and 6-byte starts + testDecode(bb"f8 80 80 80 af")( + Malformed(1), Malformed(1), Malformed(1), Malformed(1), Malformed(1)) + testDecode(bb"fc 80 80 80 80 af")( + Malformed(1), Malformed(1), Malformed(1), Malformed(1), Malformed(1), Malformed(1)) + + // Overlong sequences (encoded with more bytes than necessary) + // Overlong '/' + testDecode(bb"c0 af")(Malformed(2)) + testDecode(bb"e0 80 af")(Malformed(3)) + testDecode(bb"f0 80 80 af")(Malformed(4)) + // Maximum overlong sequences + testDecode(bb"c1 bf")(Malformed(2)) + testDecode(bb"e0 9f bf")(Malformed(3)) + testDecode(bb"f0 8f bf bf")(Malformed(4)) + // Overlong NUL + testDecode(bb"c0 80")(Malformed(2)) + testDecode(bb"e0 80 80")(Malformed(3)) + testDecode(bb"f0 80 80 80")(Malformed(4)) + + // Single UTF-16 surrogates + testDecode(bb"ed a0 80")(Malformed(3)) + testDecode(bb"ed ad bf")(Malformed(3)) + testDecode(bb"ed ae 80")(Malformed(3)) + testDecode(bb"ed af bf")(Malformed(3)) + testDecode(bb"ed b0 80")(Malformed(3)) + testDecode(bb"ed be 80")(Malformed(3)) + testDecode(bb"ed bf bf")(Malformed(3)) + + // Paired UTF-16 surrogates + testDecode(bb"ed a0 80 ed b0 80")(Malformed(3), Malformed(3)) + testDecode(bb"ed a0 80 ed bf bf")(Malformed(3), Malformed(3)) + testDecode(bb"ed ad bf ed b0 80")(Malformed(3), Malformed(3)) + testDecode(bb"ed ad bf ed bf bf")(Malformed(3), Malformed(3)) + testDecode(bb"ed ae 80 ed b0 80")(Malformed(3), Malformed(3)) + testDecode(bb"ed ae 80 ed bf bf")(Malformed(3), Malformed(3)) + testDecode(bb"ed af bf ed b0 80")(Malformed(3), Malformed(3)) + testDecode(bb"ed af bf ed bf bf")(Malformed(3), Malformed(3)) + } + + it("encode") { + def OutSeq(elems: OutPart[ByteBuffer]*): Seq[OutPart[ByteBuffer]] = + Seq[OutPart[ByteBuffer]](elems: _*) + + // 1-byte characters + testEncode(cb"Bonjour")(bb"42 6f 6e 6a 6f 75 72") + + // 2-byte characters + testEncode(cb"Grüß Gott")(bb"47 72 c3 bc c3 9f 20 47 6f 74 74") + testEncode(cb"Καλημέρα")(bb"ce 9a ce b1 ce bb ce b7 ce bc ce ad cf 81 ce b1") + testEncode(cb"صباح الخير")(bb"d8 b5 d8 a8 d8 a7 d8 ad 20 d8 a7 d9 84 d8 ae d9 8a d8 b1") + + // 3-byte characters + testEncode(cb"こんにちは")(bb"e3 81 93 e3 82 93 e3 81 ab e3 81 a1 e3 81 af") + testEncode(cb"Добрый день")(bb"d0 94 d0 be d0 b1 d1 80 d1 8b d0 b9 20 d0 b4 d0 b5 d0 bd d1 8c") + testEncode(cb"你好")(bb"e4 bd a0 e5 a5 bd") + + // 4-byte characters + testEncode(cb"\ud835\udcd7\ud835\udcee\ud835\udcf5\ud835\udcf5\ud835\udcf8")( + bb"f0 9d 93 97 f0 9d 93 ae f0 9d 93 b5 f0 9d 93 b5 f0 9d 93 b8") + + testEncode(cb"")(bb"") + + // First sequence of a certain length + testEncode(cb"\u0000")(bb"00") + testEncode(cb"\u0080")(bb"c2 80") + testEncode(cb"\u0800")(bb"e0 a0 80") + testEncode(cb"\ud800\udc00")(bb"f0 90 80 80") + + // Last sequence of a certain length + testEncode(cb"\u007f")(bb"7f") + testEncode(cb"\u07ff")(bb"df bf") + testEncode(cb"\uffff")(bb"ef bf bf") + testEncode(cb"\udbff\udfff")(bb"f4 8f bf bf") + + // Other boundary conditions + testEncode(cb"\ud7ff")(bb"ed 9f bf") + testEncode(cb"\ue000")(bb"ee 80 80") + testEncode(cb"\ufffd")(bb"ef bf bd") + + // Here begin the sequences with at least one error + + // Single UTF-16 surrogates + testEncode(cb"\ud800")(Malformed(1)) + testEncode(cb"\udaff")(Malformed(1)) + testEncode(cb"\udb80")(Malformed(1)) + testEncode(cb"\udbff")(Malformed(1)) + testEncode(cb"\udc00")(Malformed(1)) + testEncode(cb"\udf80")(Malformed(1)) + testEncode(cb"\udfff")(Malformed(1)) + + // High UTF-16 surrogates not followed by low surrogates + testEncode(cb"\ud800A")(Malformed(1), bb"41") + testEncode(cb"\ud800\ud800")(Malformed(1), Malformed(1)) + testEncode(cb"\ud800\ud835\udcd7")(Malformed(1), bb"f0 9d 93 97") + testEncode(cb"\udbffA")(Malformed(1), bb"41") + testEncode(cb"\udbff\udb8f")(Malformed(1), Malformed(1)) + testEncode(cb"\udbff\ud835\udcd7")(Malformed(1), bb"f0 9d 93 97") + } + + it("isLegalReplacement") { + val encoder = charset.newEncoder + + // The good ones + + expect(encoder.isLegalReplacement(Array(0x00.toByte))).toBeTruthy + expect(encoder.isLegalReplacement(Array(0x41.toByte))).toBeTruthy + expect(encoder.isLegalReplacement(Array('?'.toByte))).toBeTruthy + expect(encoder.isLegalReplacement(Array(0x7f.toByte))).toBeTruthy + + expect(encoder.isLegalReplacement( + Array(0xc2.toByte, 0x80.toByte))).toBeTruthy + expect(encoder.isLegalReplacement( + Array(0xdf.toByte, 0xbf.toByte))).toBeTruthy + + expect(encoder.isLegalReplacement( + Array(0xe0.toByte, 0xa0.toByte, 0x80.toByte))).toBeTruthy + expect(encoder.isLegalReplacement( + Array(0xef.toByte, 0xbf.toByte, 0xbf.toByte))).toBeTruthy + + expect(encoder.isLegalReplacement( + Array(0xf0.toByte, 0x90.toByte, 0x80.toByte, 0x80.toByte))).toBeTruthy + expect(encoder.isLegalReplacement( + Array(0xf4.toByte, 0x8f.toByte, 0xbf.toByte, 0xbf.toByte))).toBeTruthy + + // The bad ones + + expect(encoder.isLegalReplacement(Array(0x80.toByte))).toBeFalsy + expect(encoder.isLegalReplacement(Array(0xbf.toByte))).toBeFalsy + expect(encoder.isLegalReplacement(Array(0xc2.toByte))).toBeFalsy + expect(encoder.isLegalReplacement(Array(0xdf.toByte))).toBeFalsy + expect(encoder.isLegalReplacement(Array(0xe0.toByte))).toBeFalsy + expect(encoder.isLegalReplacement(Array(0xef.toByte))).toBeFalsy + expect(encoder.isLegalReplacement(Array(0xf4.toByte))).toBeFalsy + + expect(encoder.isLegalReplacement( + Array(0xe0.toByte, 0x80.toByte))).toBeFalsy + } + } +} diff --git a/test-suite/src/test/scala/scala/scalajs/testsuite/scalalib/EnumerationTest.scala b/test-suite/src/test/scala/scala/scalajs/testsuite/scalalib/EnumerationTest.scala new file mode 100644 index 0000000..f5b17d9 --- /dev/null +++ b/test-suite/src/test/scala/scala/scalajs/testsuite/scalalib/EnumerationTest.scala @@ -0,0 +1,95 @@ +/* __ *\ +** ________ ___ / / ___ __ ____ Scala.js Test Suite ** +** / __/ __// _ | / / / _ | __ / // __/ (c) 2013, LAMP/EPFL ** +** __\ \/ /__/ __ |/ /__/ __ |/_// /_\ \ http://scala-js.org/ ** +** /____/\___/_/ |_/____/_/ | |__/ /____/ ** +** |/____/ ** +\* */ +package scala.scalajs.testsuite.scalalib + +import org.scalajs.jasminetest.JasmineTest + +object EnumerationTest extends JasmineTest { + + describe("scala.Enumeration") { + + it("should use explicit naming for enumerated values - #38") { + object HelpLevel extends Enumeration { + type HelpLevel = Value + val None = Value("None") + val Basic = Value("Basic") + val Medium = Value("Medium") + val Full = Value("Full") + } + + val h = HelpLevel.None + + expect(h.toString).toEqual("None") + } + + it("should allow implicit naming for values") { + object HelpLevel extends Enumeration { + type HelpLevel = Value + val None, Basic, Medium, Full = Value + val Special = Value(100) + val / = Value + } + + val h = HelpLevel.Medium + expect(h.toString).toEqual("Medium") + expect(HelpLevel.Special.toString).toEqual("Special") + expect(HelpLevel./.toString).toEqual("$div") + } + + it("should give a pseudo toString to unnamed values") { + object Test extends Enumeration { + private val nullStr: String = null + val A = Value(nullStr) // Circumvent compiler replacement and warning + } + + expect(Test.A.toString.startsWith( + "<Unknown name for enum field #0 of class ")).toBeTruthy + } + + it("should give a graceful error message upon name based query when unnamed fields are present") { + object Test extends Enumeration { + private val nullStr: String = null + val A = Value(nullStr) // Circumvent compiler replacement and warning + } + + expect(() => Test.withName("A")).toThrow + expect { + try { Test.withName("A"); ??? } + catch { case e: NoSuchElementException => e.getMessage } + } toContain { + """Couldn't find enum field with name A. + |However, there were the following unnamed fields:""".stripMargin + } + } + + it("should respond to `toString`") { + expect(FooBarEnum.toString).toEqual("FooBarEnum") + } + + it("should respond to `values`") { + expect(FooBarEnum.values.toString).toEqual( + "FooBarEnum.ValueSet(A, B, C, D, E, F)") + } + + it("should allow setting nextName") { + object Test extends Enumeration { + nextName = Iterator("x","y","z") + val a,b,c = Value + } + + expect(Test.values.mkString("|")).toEqual("x|y|z") + } + + } + + /** Object is here due to issues with Enumeration.toString inside closures */ + object FooBarEnum extends Enumeration { + val A,B,C,D,E,F = Value + } + +} diff --git a/test-suite/src/test/scala/scala/scalajs/testsuite/scalalib/RangesTest.scala b/test-suite/src/test/scala/scala/scalajs/testsuite/scalalib/RangesTest.scala new file mode 100644 index 0000000..511e183 --- /dev/null +++ b/test-suite/src/test/scala/scala/scalajs/testsuite/scalalib/RangesTest.scala @@ -0,0 +1,27 @@ +/* __ *\ +** ________ ___ / / ___ __ ____ Scala.js Test Suite ** +** / __/ __// _ | / / / _ | __ / // __/ (c) 2013, LAMP/EPFL ** +** __\ \/ /__/ __ |/ /__/ __ |/_// /_\ \ http://scala-js.org/ ** +** /____/\___/_/ |_/____/_/ | |__/ /____/ ** +** |/____/ ** +\* */ +package scala.scalajs.testsuite.scalalib + +import org.scalajs.jasminetest.JasmineTest + +object RangesTest extends JasmineTest { + + describe("Collection ranges") { + + it("Iterable.range should not emit dce warnings - #650") { + Iterable.range(1, 10) + } + + it("Iterable.range and simple range should be equal") { + // Mostly to exercise more methods of ranges for dce warnings + expect(Iterable.range(0, 10).toList == (0 until 10).toList).toBeTruthy + } + + } + +} diff --git a/test-suite/src/test/scala/scala/scalajs/testsuite/scalalib/SymbolTest.scala b/test-suite/src/test/scala/scala/scalajs/testsuite/scalalib/SymbolTest.scala new file mode 100644 index 0000000..3612629 --- /dev/null +++ b/test-suite/src/test/scala/scala/scalajs/testsuite/scalalib/SymbolTest.scala @@ -0,0 +1,63 @@ +/* __ *\ +** ________ ___ / / ___ __ ____ Scala.js Test Suite ** +** / __/ __// _ | / / / _ | __ / // __/ (c) 2013, LAMP/EPFL ** +** __\ \/ /__/ __ |/ /__/ __ |/_// /_\ \ http://scala-js.org/ ** +** /____/\___/_/ |_/____/_/ | |__/ /____/ ** +** |/____/ ** +\* */ +package scala.scalajs.testsuite.scalalib + +import scala.scalajs.js +import org.scalajs.jasminetest.JasmineTest + +object SymbolTest extends JasmineTest { + + describe("scala.Symbol") { + + it("should ensure unique identity") { + def expectEqual(sym1: Symbol, sym2: Symbol): Unit = { + expect(sym1 eq sym2).toBeTruthy + expect(sym1 == sym2).toBeTruthy + expect(sym1.equals(sym2)).toBeTruthy + expect(sym1.## == sym2.##).toBeTruthy + } + + expectEqual('ScalaJS, Symbol("ScalaJS")) + expectEqual('$, Symbol("$")) + expectEqual('-, Symbol("-")) + + val `42` = Symbol("42") + val map = Map[Symbol, js.Any](Symbol("ScalaJS") -> "Scala.js", '$ -> 1.2, `42` -> 42) + expect(map('ScalaJS)).toEqual("Scala.js") + expect(map(Symbol("$"))).toEqual(1.2) + expect(map(Symbol("42"))).toEqual(42) + expect(map(`42`)).toEqual(42) + } + + it("should support `name`") { + val scalajs = 'ScalaJS + + expect(scalajs.name).toEqual("ScalaJS") + expect(Symbol("$").name).toEqual("$") + expect('$$.name).toEqual("$$") + expect('-.name).toEqual("-") + expect('*.name).toEqual("*") + expect(Symbol("'").name).toEqual("'") + expect(Symbol("\"").name).toEqual("\"") + } + + it("should support `toString`") { + val scalajs = 'ScalaJS + + expect(scalajs.toString).toEqual("'ScalaJS") + expect(Symbol("$").toString).toEqual("'$") + expect('$$.toString).toEqual("'$$") + expect('-.toString).toEqual("'-") + expect('*.toString).toEqual("'*") + expect(Symbol("'").toString).toEqual("''") + expect(Symbol("\"").toString).toEqual("'\"") + } + + } + +} diff --git a/test-suite/src/test/scala/scala/scalajs/testsuite/typedarray/ArrayBufferInputStreamTest.scala b/test-suite/src/test/scala/scala/scalajs/testsuite/typedarray/ArrayBufferInputStreamTest.scala new file mode 100644 index 0000000..7c49d0c --- /dev/null +++ b/test-suite/src/test/scala/scala/scalajs/testsuite/typedarray/ArrayBufferInputStreamTest.scala @@ -0,0 +1,36 @@ +/* __ *\ +** ________ ___ / / ___ __ ____ Scala.js Test Suite ** +** / __/ __// _ | / / / _ | __ / // __/ (c) 2013, LAMP/EPFL ** +** __\ \/ /__/ __ |/ /__/ __ |/_// /_\ \ http://scala-js.org/ ** +** /____/\___/_/ |_/____/_/ | |__/ /____/ ** +** |/____/ ** +\* */ +package scala.scalajs.testsuite.typedarray + +import scala.scalajs.testsuite.javalib.CommonStreamsTests + +import scala.scalajs.js.typedarray._ + +import org.scalajs.jasminetest.JasmineTest + +/** Tests for our implementation of java.io._ stream classes */ +object ArrayBufferInputStreamTest extends JasmineTest with CommonStreamsTests { + + when("typedarray"). + describe("scala.scalajs.js.typedarray.ArrayBufferInputStream") { + byteArrayInputStreamLikeTests(seq => new ArrayBufferInputStream( + new Int8Array(seq).buffer)) + } + + when("typedarray"). + describe("scala.scalajs.js.typedarray.ArrayBufferInputStream - with offset") { + byteArrayInputStreamLikeTests { seq => + val off = 100 + val data = new Int8Array(seq.size + off) + data.set(seq, off) + + new ArrayBufferInputStream(data.buffer, off, seq.size) + } + } + +} diff --git a/test-suite/src/test/scala/scala/scalajs/testsuite/typedarray/ArrayBufferTest.scala b/test-suite/src/test/scala/scala/scalajs/testsuite/typedarray/ArrayBufferTest.scala new file mode 100644 index 0000000..9e64c7f --- /dev/null +++ b/test-suite/src/test/scala/scala/scalajs/testsuite/typedarray/ArrayBufferTest.scala @@ -0,0 +1,39 @@ +/* __ *\ +** ________ ___ / / ___ __ ____ Scala.js Test Suite ** +** / __/ __// _ | / / / _ | __ / // __/ (c) 2013, LAMP/EPFL ** +** __\ \/ /__/ __ |/ /__/ __ |/_// /_\ \ http://scala-js.org/ ** +** /____/\___/_/ |_/____/_/ | |__/ /____/ ** +** |/____/ ** +\* */ +package scala.scalajs.testsuite.typedarray + +import org.scalajs.jasminetest.JasmineTest + +import scala.scalajs.js.typedarray._ + +object ArrayBufferTest extends JasmineTest { + + when("typedarry"). + describe("ArrayBuffer") { + + it("should provide a length constructor") { + val x = new ArrayBuffer(100) + expect(x.isInstanceOf[ArrayBuffer]).toBeTruthy + expect(x.byteLength).toBe(100) + } + + it("should provide `slice` with one argument") { + val x = new ArrayBuffer(100) + val y = x.slice(10) + expect(y.byteLength).toBe(90) + } + + it("should provide `slice` with two arguments") { + val x = new ArrayBuffer(100) + val y = x.slice(10, 20) + expect(y.byteLength).toBe(10) + } + + } + +} diff --git a/test-suite/src/test/scala/scala/scalajs/testsuite/typedarray/ArraysTest.scala b/test-suite/src/test/scala/scala/scalajs/testsuite/typedarray/ArraysTest.scala new file mode 100644 index 0000000..1976f3f --- /dev/null +++ b/test-suite/src/test/scala/scala/scalajs/testsuite/typedarray/ArraysTest.scala @@ -0,0 +1,45 @@ +/* __ *\ +** ________ ___ / / ___ __ ____ Scala.js Test Suite ** +** / __/ __// _ | / / / _ | __ / // __/ (c) 2013, LAMP/EPFL ** +** __\ \/ /__/ __ |/ /__/ __ |/_// /_\ \ http://scala-js.org/ ** +** /____/\___/_/ |_/____/_/ | |__/ /____/ ** +** |/____/ ** +\* */ +package scala.scalajs.testsuite.typedarray + +import scala.scalajs.js.typedarray._ +import scala.scalajs.js.JSConverters._ + +import scala.reflect._ + +import org.scalajs.jasminetest.JasmineTest + +import scala.scalajs.testsuite.javalib + +object ArraysTest extends javalib.ArraysTest { + + override def Array[T : ClassTag](v: T*): scala.Array[T] = classTag[T] match { + case ClassTag.Byte => + new Int8Array(v.asInstanceOf[Seq[Byte]].toJSArray) + .toArray.asInstanceOf[scala.Array[T]] + case ClassTag.Short => + new Int16Array(v.asInstanceOf[Seq[Short]].toJSArray) + .toArray.asInstanceOf[scala.Array[T]] + case ClassTag.Int => + new Int32Array(v.asInstanceOf[Seq[Int]].toJSArray) + .toArray.asInstanceOf[scala.Array[T]] + case ClassTag.Float => + new Float32Array(v.asInstanceOf[Seq[Float]].toJSArray) + .toArray.asInstanceOf[scala.Array[T]] + case ClassTag.Double => + new Float64Array(v.asInstanceOf[Seq[Double]].toJSArray) + .toArray.asInstanceOf[scala.Array[T]] + case _ => scala.Array(v: _*) + } + + override def testBody(suite: => Unit) = { + when("typedarray"). + describe("java.util.Arrays backed with TypedArrays")(suite) + } + +} diff --git a/test-suite/src/test/scala/scala/scalajs/testsuite/typedarray/DataViewTest.scala b/test-suite/src/test/scala/scala/scalajs/testsuite/typedarray/DataViewTest.scala new file mode 100644 index 0000000..76c5639 --- /dev/null +++ b/test-suite/src/test/scala/scala/scalajs/testsuite/typedarray/DataViewTest.scala @@ -0,0 +1,275 @@ +/* __ *\ +** ________ ___ / / ___ __ ____ Scala.js Test Suite ** +** / __/ __// _ | / / / _ | __ / // __/ (c) 2013, LAMP/EPFL ** +** __\ \/ /__/ __ |/ /__/ __ |/_// /_\ \ http://scala-js.org/ ** +** /____/\___/_/ |_/____/_/ | |__/ /____/ ** +** |/____/ ** +\* */ +package scala.scalajs.testsuite.typedarray + +import org.scalajs.jasminetest.JasmineTest + +import scala.scalajs.js.typedarray._ + +object DataViewTest extends JasmineTest { + + when("typedarray"). + describe("DataView") { + + it("should provide an ArrayBuffer only constructor") { + val buf = new ArrayBuffer(10) + val view = new DataView(buf) + expect(view.isInstanceOf[DataView]).toBeTruthy + expect(view.byteLength).toBe(10) + expect(view.byteOffset).toBe(0) + expect(view.getInt8(0)).toBe(0) + } + + it("should provide an ArrayBuffer and offset constructor") { + val buf = new ArrayBuffer(10) + val view = new DataView(buf, 2) + expect(view.isInstanceOf[DataView]).toBeTruthy + expect(view.byteLength).toBe(8) + expect(view.byteOffset).toBe(2) + expect(view.getInt8(0)).toBe(0) + } + + it("should provide an ArrayBuffer, offset and length constructor") { + val buf = new ArrayBuffer(10) + val view = new DataView(buf, 3, 2) + expect(view.isInstanceOf[DataView]).toBeTruthy + expect(view.byteLength).toBe(2) + expect(view.byteOffset).toBe(3) + expect(view.getInt8(0)).toBe(0) + } + + it("should provide `getInt8`") { + val view = new DataView(new ArrayBuffer(4)) + + view.setInt8(0, 1) + view.setInt8(1, 127) + view.setInt8(3, -50) + + expect(view.getInt8(0)).toBe(1) + expect(view.getInt8(1)).toBe(127) + expect(view.getInt8(2)).toBe(0) + expect(view.getInt8(3)).toBe(-50) + } + + it("should provide `getUint8`") { + val view = new DataView(new ArrayBuffer(4)) + + view.setInt8(0, 1) + view.setInt8(1, -127) + + expect(view.getUint8(0)).toBe(1) + expect(view.getUint8(1)).toBe(129) + expect(view.getUint8(2)).toBe(0) + } + + it("should provide `getInt16`") { + val view = new DataView(new ArrayBuffer(4)) + + view.setUint8(0, 0x01) + view.setUint8(1, 0xFF) + view.setUint8(2, 0xB3) + view.setUint8(3, 0x30) + + expect(view.getInt16(0)).toBe(0x01FF) + expect(view.getInt16(0, true)).toBe(-255) + expect(view.getInt16(1)).toBe(-77) + expect(view.getInt16(2, true)).toBe(0x30B3) + } + + it("should provide `getUint16`") { + val view = new DataView(new ArrayBuffer(4)) + + view.setUint8(0, 0x01) + view.setUint8(1, 0xFF) + view.setUint8(2, 0xB3) + view.setUint8(3, 0x30) + + expect(view.getUint16(0)).toBe(0x01FF) + expect(view.getUint16(0, true)).toBe(0xFF01) + expect(view.getUint16(1)).toBe(0xFFB3) + expect(view.getUint16(2, true)).toBe(0x30B3) + } + + it("should provide `getInt32`") { + val view = new DataView(new ArrayBuffer(5)) + + view.setUint8(0, 0x01) + view.setUint8(1, 0xFF) + view.setUint8(2, 0xB3) + view.setUint8(3, 0x30) + view.setUint8(4, 0x1A) + + expect(view.getInt32(0)).toBe(0x01FFB330) + expect(view.getInt32(0, true)).toBe(0x30B3FF01) + expect(view.getInt32(1)).toBe(0xFFB3301A) // is negative since Int + expect(view.getInt32(1, true)).toBe(0x1A30B3FF) + } + + it("should provide `getUint32`") { + val view = new DataView(new ArrayBuffer(5)) + + view.setUint8(0, 0x01) + view.setUint8(1, 0xFF) + view.setUint8(2, 0xB3) + view.setUint8(3, 0x30) + view.setUint8(4, 0x1A) + + expect(view.getUint32(0)).toBe(0x01FFB330) + expect(view.getUint32(0, true)).toBe(0x30B3FF01) + expect(view.getUint32(1)).toBe(0xFFB3301AL.toDouble) + expect(view.getUint32(1, true)).toBe(0x1A30B3FF) + } + + it("should provide `getFloat32`") { + val view = new DataView(new ArrayBuffer(5)) + + view.setFloat32(0, 0.1f) + + expect(view.getFloat32(0)).toBeCloseTo(0.1, 7) + expect(view.getFloat32(1)).not.toBeCloseTo(0.1, 7) + expect(view.getFloat32(0, true)).not.toBeCloseTo(0.1, 7) + expect(view.getFloat32(1, true)).not.toBeCloseTo(0.1, 7) + } + + it("should provide `getFloat64`") { + val view = new DataView(new ArrayBuffer(9)) + + view.setFloat64(0, 0.5) + + expect(view.getFloat64(0)).toBe(0.5) + expect(view.getFloat64(1)).not.toBe(0.5) + expect(view.getFloat64(0, true)).not.toBe(0.5) + expect(view.getFloat64(1, true)).not.toBe(0.5) + } + + it("should provide `setInt8`") { + val view = new DataView(new ArrayBuffer(4)) + + view.setInt8(0, 1) + view.setInt8(1, 127) + view.setInt8(2, -20) + view.setInt8(3, -50) + + expect(view.getUint8(0)).toBe(0x01) + expect(view.getUint8(1)).toBe(0x7F) + expect(view.getUint8(2)).toBe(0xEC) + expect(view.getUint8(3)).toBe(0xCE) + } + + it("should provide `setUint8`") { + val view = new DataView(new ArrayBuffer(4)) + + view.setUint8(0, 0x01) + view.setUint8(1, 0xFC) + view.setUint8(2, 0x4D) + view.setUint8(3, 0x8C) + + expect(view.getInt8(0)).toBe(1) + expect(view.getInt8(1)).toBe(-4) + expect(view.getInt8(2)).toBe(0x4D) + expect(view.getInt8(3)).toBe(-116) + } + + it("should provide `setInt16`") { + val view = new DataView(new ArrayBuffer(4)) + + view.setInt16(0, 0x7F3B, true) + view.setInt16(2, -1) + + expect(view.getUint8(0)).toBe(0x3B) + expect(view.getUint8(1)).toBe(0x7F) + expect(view.getUint8(2)).toBe(0xFF) + expect(view.getUint8(3)).toBe(0xFF) + } + + it("should provide `setUint16`") { + val view = new DataView(new ArrayBuffer(4)) + + view.setUint16(0, 0x7F3B, true) + view.setUint16(2, 0xFCBA) + + expect(view.getUint8(0)).toBe(0x3B) + expect(view.getUint8(1)).toBe(0x7F) + expect(view.getUint8(2)).toBe(0xFC) + expect(view.getUint8(3)).toBe(0xBA) + + view.setUint16(1, 0x03BC) + + expect(view.getUint8(0)).toBe(0x3B) + expect(view.getUint8(1)).toBe(0x03) + expect(view.getUint8(2)).toBe(0xBC) + expect(view.getUint8(3)).toBe(0xBA) + } + + it("should provide `setInt32`") { + val view = new DataView(new ArrayBuffer(8)) + + view.setInt32(0, 0x7F3B8342, true) + view.setInt32(3, 0xFCBA1020) + + expect(view.getUint8(0)).toBe(0x42) + expect(view.getUint8(1)).toBe(0x83) + expect(view.getUint8(2)).toBe(0x3B) + expect(view.getUint8(3)).toBe(0xFC) + expect(view.getUint8(4)).toBe(0xBA) + expect(view.getUint8(5)).toBe(0x10) + expect(view.getUint8(6)).toBe(0x20) + expect(view.getUint8(7)).toBe(0x00) + } + + it("should provide `setUint32`") { + val view = new DataView(new ArrayBuffer(8)) + + view.setUint32(0, 0x7F3B8342, true) + view.setUint32(3, 0xFCBA1020L.toDouble) + + expect(view.getUint8(0)).toBe(0x42) + expect(view.getUint8(1)).toBe(0x83) + expect(view.getUint8(2)).toBe(0x3B) + expect(view.getUint8(3)).toBe(0xFC) + expect(view.getUint8(4)).toBe(0xBA) + expect(view.getUint8(5)).toBe(0x10) + expect(view.getUint8(6)).toBe(0x20) + expect(view.getUint8(7)).toBe(0x00) + } + + it("should provide `setFloat32`") { + val view = new DataView(new ArrayBuffer(5)) + + view.setFloat32(0, 0.1f) + view.setFloat32(1, 0.4f) + + expect(view.getFloat32(1)).toBeCloseTo(0.4, 7) + expect(view.getFloat32(0)).not.toBeCloseTo(0.1, 7) + + view.setFloat32(0, 0.1f, true) + view.setFloat32(1, 0.4f, true) + + expect(view.getFloat32(0, true)).not.toBeCloseTo(0.1, 7) + expect(view.getFloat32(1, true)).toBeCloseTo(0.4, 7) + } + + it("should provide `getFloat64`") { + val view = new DataView(new ArrayBuffer(9)) + + view.setFloat64(0, 0.5) + view.setFloat64(1, 0.6) + + expect(view.getFloat64(0)).not.toBe(0.5) + expect(view.getFloat64(1)).toBe(0.6) + + view.setFloat64(0, 0.5, true) + view.setFloat64(1, 0.6, true) + + expect(view.getFloat64(0, true)).not.toBe(0.5) + expect(view.getFloat64(1, true)).toBe(0.6) + } + + } + +} diff --git a/test-suite/src/test/scala/scala/scalajs/testsuite/typedarray/TypedArrayConversionTest.scala b/test-suite/src/test/scala/scala/scalajs/testsuite/typedarray/TypedArrayConversionTest.scala new file mode 100644 index 0000000..dc9a056 --- /dev/null +++ b/test-suite/src/test/scala/scala/scalajs/testsuite/typedarray/TypedArrayConversionTest.scala @@ -0,0 +1,197 @@ +/* __ *\ +** ________ ___ / / ___ __ ____ Scala.js Test Suite ** +** / __/ __// _ | / / / _ | __ / // __/ (c) 2013, LAMP/EPFL ** +** __\ \/ /__/ __ |/ /__/ __ |/_// /_\ \ http://scala-js.org/ ** +** /____/\___/_/ |_/____/_/ | |__/ /____/ ** +** |/____/ ** +\* */ +package scala.scalajs.testsuite.typedarray + +import org.scalajs.jasminetest.JasmineTest + +import scala.scalajs.js +import js.typedarray._ + +object TypedArrayConversionTest extends JasmineTest { + + when("typedarray"). + describe("TypedArray to scala.Array conversions") { + + def data(factor: Double) = js.Array(-1,1,2,3,4,5,6,7,8).map((_: Int) * factor) + def sum(factor: Double) = (8 * 9 / 2 - 1) * factor + + it("should convert an Int8Array to a scala.Array[Byte]") { + val x = new Int8Array(data(1)) + val y = x.toArray + + expect(y.getClass == classOf[scala.Array[Byte]]).toBeTruthy + expect(y.sum).toEqual(sum(1)) + + // Ensure its a copy + x(0) = 0 + expect(y.sum).toEqual(sum(1)) + } + + it("should convert an Int16Array to a scala.Array[Short]") { + val x = new Int16Array(data(100)) + val y = x.toArray + + expect(y.getClass == classOf[scala.Array[Short]]).toBeTruthy + expect(y.sum).toEqual(sum(100)) + + // Ensure its a copy + x(0) = 0 + expect(y.sum).toEqual(sum(100)) + } + + it("should convert an Uint16Array to a scala.Array[Char]") { + val data = js.Array((1 to 6).map(_ * 10000): _*) + val sum = (6*7/2*10000).toChar + + val x = new Uint16Array(data) + val y = x.toArray + + expect(y.getClass == classOf[scala.Array[Char]]).toBeTruthy + expect(y.sum).toEqual(sum) + + // Ensure its a copy + x(0) = 0 + expect(y.sum).toEqual(sum) + } + + it("should convert an Int32Array to a scala.Array[Int]") { + val x = new Int32Array(data(10000)) + val y = x.toArray + + expect(y.getClass == classOf[scala.Array[Int]]).toBeTruthy + expect(y.sum).toEqual(sum(10000)) + + // Ensure its a copy + x(0) = 0 + expect(y.sum).toEqual(sum(10000)) + } + + it("should convert a Float32Array to a scala.Array[Float]") { + val x = new Float32Array(data(0.2)) + val y = x.toArray + + expect(y.getClass == classOf[scala.Array[Float]]).toBeTruthy + expect(y.sum).toBeCloseTo(sum(0.2), 6) + + // Ensure its a copy + x(0) = 0 + expect(y.sum).toBeCloseTo(sum(0.2), 6) + } + + it("should convert a Float64Array to a scala.Array[Double]") { + val x = new Float64Array(data(0.2)) + val y = x.toArray + + expect(y.getClass == classOf[scala.Array[Double]]).toBeTruthy + expect(y.sum).toEqual(sum(0.2)) + + // Ensure its a copy + x(0) = 0 + expect(y.sum).toEqual(sum(0.2)) + } + + } + + when("typedarray"). + describe("scala.Array to TypedArray conversions") { + + it("should convert a scala.Array[Byte] to an Int8Array") { + val x = (Byte.MinValue to Byte.MaxValue).map(_.toByte).toArray + val y = x.toTypedArray + + expect(y.isInstanceOf[Int8Array]).toBeTruthy + expect(y.length).toBe(x.length) + + for (i <- 0 until y.length) + expect(y(i)).toBe(x(i)) + + // Ensure its a copy + x(0) = 0 + expect(y(0)).toBe(Byte.MinValue) + } + + it("should convert a scala.Array[Short] to an Int16Array") { + val x = ((Short.MinValue to (Short.MinValue + 1000)) ++ + ((Short.MaxValue - 1000) to Short.MaxValue)).map(_.toShort).toArray + val y = x.toTypedArray + + expect(y.isInstanceOf[Int16Array]).toBeTruthy + expect(y.length).toBe(x.length) + + for (i <- 0 until y.length) + expect(y(i)).toBe(x(i)) + + // Ensure its a copy + x(0) = 0 + expect(y(0)).toBe(Short.MinValue) + } + + it("should convert a scala.Array[Char] to an Uint16Array") { + val x = ((Char.MaxValue - 1000) to Char.MaxValue).map(_.toChar).toArray + val y = x.toTypedArray + + expect(y.isInstanceOf[Uint16Array]).toBeTruthy + expect(y.length).toBe(x.length) + + for (i <- 0 until y.length) + expect(y(i)).toBe(x(i).toInt) + + // Ensure its a copy + x(0) = 0 + expect(y(0)).toBe(Char.MaxValue - 1000) + } + + it("should convert a scala.Array[Int] to an Int32Array") { + val x = ((Int.MinValue to (Int.MinValue + 1000)) ++ + ((Int.MaxValue - 1000) to Int.MaxValue)).toArray + val y = x.toTypedArray + + expect(y.isInstanceOf[Int32Array]).toBeTruthy + expect(y.length).toBe(x.length) + + for (i <- 0 until y.length) + expect(y(i)).toBe(x(i)) + + // Ensure its a copy + x(0) = 0 + expect(y(0)).toBe(Int.MinValue) + } + + it("should convert a scala.Array[Float] to a Float32Array") { + val x = Array[Float](1.0f, 2.0f, -2.3f, 5.3f) + val y = x.toTypedArray + + expect(y.isInstanceOf[Float32Array]).toBeTruthy + expect(y.length).toBe(x.length) + + for (i <- 0 until y.length) + expect(y(i)).toBe(x(i)) + + // Ensure its a copy + x(0) = 0 + expect(y(0)).toBe(1.0f) + } + + it("should convert a scala.Array[Double] to a Float64Array") { + val x = Array[Double](1.0, 2.0, -2.3, 5.3) + val y = x.toTypedArray + + expect(y.isInstanceOf[Float64Array]).toBeTruthy + expect(y.length).toBe(x.length) + + for (i <- 0 until y.length) + expect(y(i)).toBe(x(i)) + + // Ensure its a copy + x(0) = 0 + expect(y(0)).toBe(1.0) + } + + } + +} diff --git a/test-suite/src/test/scala/scala/scalajs/testsuite/typedarray/TypedArrayTest.scala b/test-suite/src/test/scala/scala/scalajs/testsuite/typedarray/TypedArrayTest.scala new file mode 100644 index 0000000..1dfbbd4 --- /dev/null +++ b/test-suite/src/test/scala/scala/scalajs/testsuite/typedarray/TypedArrayTest.scala @@ -0,0 +1,332 @@ +/* __ *\ +** ________ ___ / / ___ __ ____ Scala.js Test Suite ** +** / __/ __// _ | / / / _ | __ / // __/ (c) 2013, LAMP/EPFL ** +** __\ \/ /__/ __ |/ /__/ __ |/_// /_\ \ http://scala-js.org/ ** +** /____/\___/_/ |_/____/_/ | |__/ /____/ ** +** |/____/ ** +\* */ +package scala.scalajs.testsuite.typedarray + +import org.scalajs.jasminetest.JasmineTest +import org.scalajs.jasmine.JasmineExpectation + +import scala.scalajs.js +import js.typedarray._ + +/** Shallow test for TypedArrays. Basically just tests that the method exist and + * return something which could be a right result. It is probably sufficient to + * test whether a runtime supports TypedArrays. + */ +object TypedArrayTest extends JasmineTest { + + /** Generalized tests for all TypedArrays */ + def tests[V, T <: TypedArray[V, T]](name: String, + bytesPerElement: => Int, + lenCtor: Int => T, + tarrCtor: TypedArray[_, _] => T, + arrCtor: js.Array[_] => T, + bufCtor1: (ArrayBuffer) => T, + bufCtor2: (ArrayBuffer, Int) => T, + bufCtor3: (ArrayBuffer, Int, Int) => T, + hasType: Any => Boolean, + expectV: V => JasmineExpectation, + intToV: Int => V + ) = { + + when("typedarray"). + describe(name) { + + it(s"should allow constructing a new $name with length") { + val x = lenCtor(10) + expect(hasType(x)).toBeTruthy + expect(x.length).toBe(10) + } + + it(s"should allow constructing a new $name from an Int8Array") { + val x = tarrCtor(new Float32Array(js.Array(3, 7))) + expect(hasType(x)).toBeTruthy + expect(x.length).toBe(2) + + expectV(x(0)).toEqual(3) + expectV(x(1)).toEqual(7) + } + + it(s"should allow constructing a new $name from a js.Array") { + val x = arrCtor(js.Array(5,6,7)) + expect(hasType(x)).toBeTruthy + expect(x.length).toBe(3) + + expectV(x(0)).toEqual(5) + expectV(x(1)).toEqual(6) + expectV(x(2)).toEqual(7) + } + + it(s"should allow constructing a new $name from an ArrayBuffer (1 arg)") { + val buf = arrCtor(js.Array(5, 6, 7, 8)).buffer + val x = bufCtor1(buf) + expect(hasType(x)).toBeTruthy + expect(x.length).toBe(4) + + expectV(x(0)).toEqual(5) + expectV(x(1)).toEqual(6) + expectV(x(2)).toEqual(7) + expectV(x(3)).toEqual(8) + } + + it(s"should allow constructing a new $name from an ArrayBuffer (2 arg)") { + val buf = arrCtor(js.Array(5, 6, 7, 8)).buffer + val x = bufCtor2(buf, bytesPerElement) + expect(hasType(x)).toBeTruthy + expect(x.length).toBe(3) + + expectV(x(0)).toEqual(6) + expectV(x(1)).toEqual(7) + expectV(x(2)).toEqual(8) + } + + it(s"should allow constructing a new $name from an ArrayBuffer (3 arg)") { + val buf = arrCtor(js.Array(5, 6, 7, 8)).buffer + val x = bufCtor3(buf, bytesPerElement, 2) + expect(hasType(x)).toBeTruthy + expect(x.length).toBe(2) + + expectV(x(0)).toEqual(6) + expectV(x(1)).toEqual(7) + } + + it("should allow retrieving the length") { + val x = lenCtor(100) + expect(x.length).toBe(100) + } + + it("should allow retrieving an element") { + val x = arrCtor(js.Array(5)) + expectV(x(0)).toBe(5) + } + + it("should allow setting an element") { + val x = lenCtor(2) + + x(0) = intToV(5) + x(1) = intToV(10) + + expectV(x(0)).toBe(5) + expectV(x(1)).toBe(10) + } + + it("should provide `get`") { + val x = arrCtor(js.Array(10)) + expectV(x.get(0)).toBe(10) + } + + it("should provide `set` for a single element") { + val x = lenCtor(10) + x.set(0, intToV(5)) + x.set(1, intToV(6)) + + expectV(x(0)).toBe(5) + expectV(x(1)).toBe(6) + expectV(x(2)).toBe(0) + } + + it("should provide `set` for a js.Array with one arguments") { + val x = lenCtor(10) + x.set(js.Array(5,6,7)) + expectV(x(0)).toBe(5) + expectV(x(1)).toBe(6) + expectV(x(2)).toBe(7) + expectV(x(3)).toBe(0) + expectV(x(4)).toBe(0) + expectV(x(5)).toBe(0) + } + + it("should provide `set` for a js.Array with two arguments") { + val x = lenCtor(10) + x.set(js.Array(5,6,7), 2) + expectV(x(0)).toBe(0) + expectV(x(1)).toBe(0) + expectV(x(2)).toBe(5) + expectV(x(3)).toBe(6) + expectV(x(4)).toBe(7) + expectV(x(5)).toBe(0) + } + + it("should provide `set` for a TypedArray with one argument") { + val x = lenCtor(10) + x.set(new Int8Array(js.Array(5,6,7))) + expectV(x(0)).toBe(5) + expectV(x(1)).toBe(6) + expectV(x(2)).toBe(7) + expectV(x(3)).toBe(0) + expectV(x(4)).toBe(0) + expectV(x(5)).toBe(0) + } + + it("should provide `set` for a TypedArray with two arguments") { + val x = lenCtor(10) + x.set(new Int8Array(js.Array(5,6,7)), 2) + expectV(x(0)).toBe(0) + expectV(x(1)).toBe(0) + expectV(x(2)).toBe(5) + expectV(x(3)).toBe(6) + expectV(x(4)).toBe(7) + expectV(x(5)).toBe(0) + } + + it("should provide `subarray` with one argument") { + val x = arrCtor(js.Array(1,2,3,4,5,6,7,8,9)) + val y = x.subarray(2) + + expect(y.length).toBe(7) + expectV(y(0)).toBe(3) + + x(2) = intToV(100) + + expectV(y(0)).toBe(100) + } + + it("should provide `subarray` with two arguments") { + val x = arrCtor(js.Array(1,2,3,4,5,6,7,8,9)) + val y = x.subarray(2, 4) + + expect(y.length).toBe(2) + expectV(y(0)).toBe(3) + + x(2) = intToV(100) + + expectV(y(0)).toBe(100) + } + + it("should provide `buffer`") { + val x = arrCtor(js.Array(1,2,3,4,5,6,7,8,9)) + val y = bufCtor3(x.buffer, 0, 2) + + expect(x.buffer eq y.buffer).toBeTruthy + } + + it("should provide `byteLength`") { + val x = arrCtor(js.Array(0 until bytesPerElement * 4: _*)) + val y = bufCtor3(x.buffer, bytesPerElement, 3) + + expect(y.byteLength).toBe(3 * bytesPerElement) + } + + it("should provide `byteOffset`") { + val x = arrCtor(js.Array(0 until bytesPerElement * 4: _*)) + val y = bufCtor3(x.buffer, bytesPerElement, 3) + + expect(y.byteOffset).toBe(bytesPerElement) + } + + } + } + + tests("Int8Array", + Int8Array.BYTES_PER_ELEMENT, + len => new Int8Array(len), + tarr => new Int8Array(tarr), + arr => new Int8Array(arr), + buf => new Int8Array(buf), + (buf, start) => new Int8Array(buf, start), + (buf, start, end) => new Int8Array(buf, start, end), + _.isInstanceOf[Int8Array], + expect (_: Byte), + _.toByte) + + tests("Uint8Array", + Uint8Array.BYTES_PER_ELEMENT, + len => new Uint8Array(len), + tarr => new Uint8Array(tarr), + arr => new Uint8Array(arr), + buf => new Uint8Array(buf), + (buf, start) => new Uint8Array(buf, start), + (buf, start, end) => new Uint8Array(buf, start, end), + _.isInstanceOf[Uint8Array], + expect (_: Short), + _.toShort) + + tests("Uint8ClampedArray", + Uint8ClampedArray.BYTES_PER_ELEMENT, + len => new Uint8ClampedArray(len), + tarr => new Uint8ClampedArray(tarr), + arr => new Uint8ClampedArray(arr), + buf => new Uint8ClampedArray(buf), + (buf, start) => new Uint8ClampedArray(buf, start), + (buf, start, end) => new Uint8ClampedArray(buf, start, end), + _.isInstanceOf[Uint8ClampedArray], + expect (_: Int), + _.toInt) + + tests("Int16Array", + Int16Array.BYTES_PER_ELEMENT, + len => new Int16Array(len), + tarr => new Int16Array(tarr), + arr => new Int16Array(arr), + buf => new Int16Array(buf), + (buf, start) => new Int16Array(buf, start), + (buf, start, end) => new Int16Array(buf, start, end), + _.isInstanceOf[Int16Array], + expect (_: Short), + _.toShort) + + tests("Uint16Array", + Uint16Array.BYTES_PER_ELEMENT, + len => new Uint16Array(len), + tarr => new Uint16Array(tarr), + arr => new Uint16Array(arr), + buf => new Uint16Array(buf), + (buf, start) => new Uint16Array(buf, start), + (buf, start, end) => new Uint16Array(buf, start, end), + _.isInstanceOf[Uint16Array], + expect (_: Int), + _.toInt) + + tests("Int32Array", + Int32Array.BYTES_PER_ELEMENT, + len => new Int32Array(len), + tarr => new Int32Array(tarr), + arr => new Int32Array(arr), + buf => new Int32Array(buf), + (buf, start) => new Int32Array(buf, start), + (buf, start, end) => new Int32Array(buf, start, end), + _.isInstanceOf[Int32Array], + expect (_: Int), + _.toInt) + + tests("Uint32Array", + Uint32Array.BYTES_PER_ELEMENT, + len => new Uint32Array(len), + tarr => new Uint32Array(tarr), + arr => new Uint32Array(arr), + buf => new Uint32Array(buf), + (buf, start) => new Uint32Array(buf, start), + (buf, start, end) => new Uint32Array(buf, start, end), + _.isInstanceOf[Uint32Array], + expect (_: Double), + _.toDouble) + + tests("Float32Array", + Float32Array.BYTES_PER_ELEMENT, + len => new Float32Array(len), + tarr => new Float32Array(tarr), + arr => new Float32Array(arr), + buf => new Float32Array(buf), + (buf, start) => new Float32Array(buf, start), + (buf, start, end) => new Float32Array(buf, start, end), + _.isInstanceOf[Float32Array], + expect (_: Float), + _.toFloat) + + tests("Float64Array", + Float64Array.BYTES_PER_ELEMENT, + len => new Float64Array(len), + tarr => new Float64Array(tarr), + arr => new Float64Array(arr), + buf => new Float64Array(buf), + (buf, start) => new Float64Array(buf, start), + (buf, start, end) => new Float64Array(buf, start, end), + _.isInstanceOf[Float64Array], + expect (_: Double), + _.toDouble) + +} diff --git a/test-suite/src/test/scala/scala/scalajs/testsuite/utils/JSUtils.scala b/test-suite/src/test/scala/scala/scalajs/testsuite/utils/JSUtils.scala new file mode 100644 index 0000000..4b2ac62 --- /dev/null +++ b/test-suite/src/test/scala/scala/scalajs/testsuite/utils/JSUtils.scala @@ -0,0 +1,26 @@ +package scala.scalajs.testsuite.utils + +import scala.scalajs.js +import js.annotation.JSExport + +@JSExport("JSUtils") +object JSUtils { + /* We use java.lang.Character explicitly, because this class is used by + * tests that check that Chars are actually boxed by the compiler. + * If we rely on the compiler doing the job in here, we might have false + * positives just because the value was never boxed, and never unboxed. + */ + + @JSExport + def isChar(c: Any): Boolean = c.isInstanceOf[java.lang.Character] + + @JSExport + def stringToChar(s: String): java.lang.Character = { + assert(s.length == 1, "makeChar() requires a string of length 1") + new java.lang.Character(s.charAt(0)) + } + + @JSExport + def charToString(c: Any): String = + c.asInstanceOf[java.lang.Character].toString() +} diff --git a/test-suite/src/test/scala/scala/scalajs/testsuite/utils/TestDetector.scala b/test-suite/src/test/scala/scala/scalajs/testsuite/utils/TestDetector.scala new file mode 100644 index 0000000..ad67a95 --- /dev/null +++ b/test-suite/src/test/scala/scala/scalajs/testsuite/utils/TestDetector.scala @@ -0,0 +1,33 @@ +package scala.scalajs.testsuite.utils + +import scala.scalajs.js +import js.annotation.JSExport +import js.JSConverters._ + +/** An ad-hoc but centralized way to detect tests in this test suite */ +@JSExport("scalajs.TestDetector") +object TestDetector { + + private final val basePackage = "scala.scalajs.testsuite" + + def detectTestNames(): List[String] = detectTestsInternal().map(_._2).toList + + @JSExport + def loadDetectedTests(): Unit = detectTestsInternal().foreach(_._1()) + + private def detectTestsInternal() = { + val parts = basePackage.split('.') + val base = parts.foldLeft(js.Dynamic.global)(_.selectDynamic(_)) + + // We make sure to use only exported modules (not classes) by checking + // .prototype of the exporters. + for { + pName <- js.Object.properties(base) + testName <- js.Object.properties(base.selectDynamic(pName)) + test = base.selectDynamic(pName).selectDynamic(testName) + if js.Object.getPrototypeOf(test.prototype.asInstanceOf[js.Object]) eq + js.Object.asInstanceOf[js.Dynamic].prototype + } yield (test, s"$basePackage.$pName.$testName") + } + +} |