diff options
Diffstat (limited to 'examples/scala-js/test-bridge/src/main/scala/scala/scalajs/testbridge')
5 files changed, 221 insertions, 0 deletions
diff --git a/examples/scala-js/test-bridge/src/main/scala/scala/scalajs/testbridge/Test.scala b/examples/scala-js/test-bridge/src/main/scala/scala/scalajs/testbridge/Test.scala new file mode 100644 index 0000000..05d3077 --- /dev/null +++ b/examples/scala-js/test-bridge/src/main/scala/scala/scalajs/testbridge/Test.scala @@ -0,0 +1,17 @@ +/* __ *\ +** ________ ___ / / ___ __ ____ Scala.js API ** +** / __/ __// _ | / / / _ | __ / // __/ (c) 2013, LAMP/EPFL ** +** __\ \/ /__/ __ |/ /__/ __ |/_// /_\ \ http://scala-js.org/ ** +** /____/\___/_/ |_/____/_/ | |__/ /____/ ** +** |/____/ ** +\* */ + + +package scala.scalajs.testbridge + +import scala.scalajs.js +import js.annotation.JSExportDescendentObjects + +/** Marker trait for Scala.js tests */ +@JSExportDescendentObjects +trait Test diff --git a/examples/scala-js/test-bridge/src/main/scala/scala/scalajs/testbridge/TestFramework.scala b/examples/scala-js/test-bridge/src/main/scala/scala/scalajs/testbridge/TestFramework.scala new file mode 100644 index 0000000..f855cf6 --- /dev/null +++ b/examples/scala-js/test-bridge/src/main/scala/scala/scalajs/testbridge/TestFramework.scala @@ -0,0 +1,36 @@ +/* __ *\ +** ________ ___ / / ___ __ ____ Scala.js API ** +** / __/ __// _ | / / / _ | __ / // __/ (c) 2013, LAMP/EPFL ** +** __\ \/ /__/ __ |/ /__/ __ |/_// /_\ \ http://scala-js.org/ ** +** /____/\___/_/ |_/____/_/ | |__/ /____/ ** +** |/____/ ** +\* */ + + +package scala.scalajs.testbridge + +import scala.scalajs.js +import js.annotation.{ JSExportDescendentObjects, JSExport } + +/** This trait should be sub classed (as object) by a concrete test framework + * + * It will receive a call to runTest for each object on the classpath + * extending Test + */ +@JSExportDescendentObjects +trait TestFramework { + @JSExport + final def safeRunTest(testOutput: TestOutput, args: js.Array[String])( + test: js.Function0[Test]): Unit = { + try { + runTest(testOutput, args)(test) + } catch { + case e: Throwable => + testOutput.error(s"Test framework ${getClass.getName} failed:") + testOutput.error(e.getMessage, e.getStackTrace) + } + } + + def runTest(testOutput: TestOutput, args: js.Array[String])( + test: js.Function0[Test]): Unit +} diff --git a/examples/scala-js/test-bridge/src/main/scala/scala/scalajs/testbridge/TestOutput.scala b/examples/scala-js/test-bridge/src/main/scala/scala/scalajs/testbridge/TestOutput.scala new file mode 100644 index 0000000..5f3b8b6 --- /dev/null +++ b/examples/scala-js/test-bridge/src/main/scala/scala/scalajs/testbridge/TestOutput.scala @@ -0,0 +1,34 @@ +/* __ *\ +** ________ ___ / / ___ __ ____ Scala.js API ** +** / __/ __// _ | / / / _ | __ / // __/ (c) 2013, LAMP/EPFL ** +** __\ \/ /__/ __ |/ /__/ __ |/_// /_\ \ http://scala-js.org/ ** +** /____/\___/_/ |_/____/_/ | |__/ /____/ ** +** |/____/ ** +\* */ + + +package scala.scalajs.testbridge + +trait TestOutput { + + type Color + + val errorColor: Color + val successColor: Color + val infoColor: Color + + def color(message: String, color: Color): String + + def error(message: String, stack: Array[StackTraceElement]): Unit + def error(message: String): Unit + def failure(message: String, stack: Array[StackTraceElement]): Unit + def failure(message: String): Unit + def succeeded(message: String): Unit + def skipped(message: String): Unit + def pending(message: String): Unit + def ignored(message: String): Unit + def canceled(message: String): Unit + + def log: TestOutputLog + +} diff --git a/examples/scala-js/test-bridge/src/main/scala/scala/scalajs/testbridge/TestOutputLog.scala b/examples/scala-js/test-bridge/src/main/scala/scala/scalajs/testbridge/TestOutputLog.scala new file mode 100644 index 0000000..3369592 --- /dev/null +++ b/examples/scala-js/test-bridge/src/main/scala/scala/scalajs/testbridge/TestOutputLog.scala @@ -0,0 +1,16 @@ +/* __ *\ +** ________ ___ / / ___ __ ____ Scala.js API ** +** / __/ __// _ | / / / _ | __ / // __/ (c) 2013, LAMP/EPFL ** +** __\ \/ /__/ __ |/ /__/ __ |/_// /_\ \ http://scala-js.org/ ** +** /____/\___/_/ |_/____/_/ | |__/ /____/ ** +** |/____/ ** +\* */ + + +package scala.scalajs.testbridge + +trait TestOutputLog { + def info(message: String): Unit + def warn(message: String): Unit + def error(message: String): Unit +} diff --git a/examples/scala-js/test-bridge/src/main/scala/scala/scalajs/testbridge/internal/ConsoleTestOutput.scala b/examples/scala-js/test-bridge/src/main/scala/scala/scalajs/testbridge/internal/ConsoleTestOutput.scala new file mode 100644 index 0000000..c89a32e --- /dev/null +++ b/examples/scala-js/test-bridge/src/main/scala/scala/scalajs/testbridge/internal/ConsoleTestOutput.scala @@ -0,0 +1,118 @@ +package scala.scalajs.testbridge.internal + +import scala.scalajs.js +import scala.scalajs.js.annotation.JSExport + +import scala.scalajs.testbridge._ + +import scala.scalajs.runtime.StackTrace.ColumnStackTraceElement + +/** Implementation of TestOutput. + * + * Attention: This class monkey-patches console.log. Make sure it is loaded + * before any output. It also should always be paired with a + * [[scala.scalajs.sbtplugin.testing.TestOutputConsole]] on the JVM side. + */ +@JSExport +protected object ConsoleTestOutput extends TestOutput { + + /** monkey-patches console.log when class is loaded */ + private val savedConsoleLog: js.Function1[String, Unit] = { + import js.Dynamic.{ global => g } + + val console = g.console + val savedLog = console.log + + val patch = (new MonkeyPatchConsole).asInstanceOf[js.Dynamic] + + // Need to write updateDynamic explicitly here. Since 2.10.x + // chokes on this ("erroneous or inaccessible type") + console.updateDynamic("log")(patch.log.bind(patch)) + + savedLog.bind(console).asInstanceOf[js.Function1[String, Unit]] + } + + type Color = String + + val errorColor = "\u001b[31m" + val successColor = "\u001b[32m" + val infoColor = "\u001b[34m" + + private val reset = "\u001b[0m" + + def color(message: String, color: String): String = + message.split('\n').mkString(color, reset + '\n' + color, reset) + + def error(message: String, + stack: Array[StackTraceElement]): Unit = { + sendTrace(stack) + send("error", message) + } + + def error(message: String): Unit = + error(message, Array.empty) + + def failure(message: String, + stack: Array[StackTraceElement]): Unit = { + sendTrace(stack) + send("failure", message) + } + + def failure(message: String): Unit = + failure(message, Array.empty) + + def succeeded(message: String): Unit = + send("succeeded", message) + + def skipped(message: String): Unit = + send("skipped", message) + + def pending(message: String): Unit = + send("pending", message) + + def ignored(message: String): Unit = + send("ignored", message) + + def canceled(message: String): Unit = + send("canceled", message) + + val log = + new TestOutputLog { + def info(message: String): Unit = send("info", message) + def warn(message: String): Unit = send("warn", message) + def error(message: String): Unit = send("error-log", message) + } + + private def send(fct: String, msg: String) = { + val escaped = msg + .replace("\\", "\\\\") + .replace("\n", "\\n") + .replace("\r", "\\r") + savedConsoleLog(fct + "|" + escaped) + } + + private def sendTrace(stack: Array[StackTraceElement]) = for { + el <- stack + } send("trace", serializeStackElem(el)) + + private def serializeStackElem(e: StackTraceElement) = { + + val flds = List( + e.getClassName, + e.getMethodName, + e.getFileName, + e.getLineNumber.toString, + e.getColumnNumber.toString) + + flds.mkString("|") + } + + /** used to monkey-patch console (only log will be used) + * we can't write a simple lambda, because we need varargs + */ + private class MonkeyPatchConsole { + @JSExport + def log(msg: js.Any*): Unit = send("console-log", msg.mkString(" ")) + } + +} |