summaryrefslogtreecommitdiff
path: root/contrib/bsp/src/mill/contrib/bsp/BspTestReporter.scala
diff options
context:
space:
mode:
Diffstat (limited to 'contrib/bsp/src/mill/contrib/bsp/BspTestReporter.scala')
-rw-r--r--contrib/bsp/src/mill/contrib/bsp/BspTestReporter.scala117
1 files changed, 117 insertions, 0 deletions
diff --git a/contrib/bsp/src/mill/contrib/bsp/BspTestReporter.scala b/contrib/bsp/src/mill/contrib/bsp/BspTestReporter.scala
new file mode 100644
index 00000000..b49c0b7c
--- /dev/null
+++ b/contrib/bsp/src/mill/contrib/bsp/BspTestReporter.scala
@@ -0,0 +1,117 @@
+package mill.contrib.bsp
+
+import java.io.{PrintWriter, StringWriter}
+
+import ch.epfl.scala.bsp4j._
+import mill.api.TestReporter
+import sbt.testing._
+
+
+/**
+ * Context class for BSP, specialized for sending `task-start` and
+ * `task-finish` notifications for every test being ran.
+ *
+ * @param client The client to send notifications to
+ * @param targetId The targetId of the BSP target for which
+ * the test request is being processed
+ * @param taskId The unique taskId associated with the
+ * test task that will trigger this reporter
+ * to log testing events.
+ * @param arguments compilation arguments as part of the BSP context,
+ * in case special arguments need to be passed to
+ * the compiler before running the test task.
+ */
+class BspTestReporter(client: BuildClient,
+ targetId: BuildTargetIdentifier,
+ taskId: TaskId,
+ arguments: Seq[String]) extends TestReporter {
+
+ var passed = 0
+ var failed = 0
+ var cancelled = 0
+ var ignored = 0
+ var skipped = 0
+ var totalTime: Long = 0
+
+ override def logStart(event: Event): Unit = {
+ val taskStartParams = new TaskStartParams(taskId)
+ taskStartParams.setEventTime(System.currentTimeMillis())
+ taskStartParams.setDataKind(TaskDataKind.TEST_START)
+ taskStartParams.setData(new TestStart(getDisplayName(event)))
+ taskStartParams.setMessage("Starting running: " + getDisplayName(event))
+ client.onBuildTaskStart(taskStartParams)
+ }
+
+ // Compute the display name of the test / test suite
+ // to which the given event relates
+ private[this] def getDisplayName(e: Event): String = {
+ e.selector() match {
+ case s: NestedSuiteSelector => s.suiteId()
+ case s: NestedTestSelector => s.suiteId() + "." + s.testName()
+ case s: SuiteSelector => s.toString
+ case s: TestSelector => s.testName()
+ case s: TestWildcardSelector => s.testWildcard()
+ }
+ }
+
+ override def logFinish(event: Event): Unit = {
+ totalTime += event.duration()
+ val taskFinishParams = new TaskFinishParams(taskId,
+ event.status() match {
+ case sbt.testing.Status.Canceled => StatusCode.CANCELLED
+ case sbt.testing.Status.Error => StatusCode.ERROR
+ case default => StatusCode.OK
+ })
+ val status = event.status match {
+ case sbt.testing.Status.Success =>
+ passed += 1
+ TestStatus.PASSED
+ case sbt.testing.Status.Canceled =>
+ cancelled += 1
+ TestStatus.CANCELLED
+ case sbt.testing.Status.Error =>
+ failed += 1
+ TestStatus.FAILED
+ case sbt.testing.Status.Failure =>
+ failed += 1
+ TestStatus.FAILED
+ case sbt.testing.Status.Ignored =>
+ ignored += 1
+ TestStatus.IGNORED
+ case sbt.testing.Status.Skipped =>
+ skipped += 1
+ TestStatus.SKIPPED
+ case sbt.testing.Status.Pending =>
+ skipped += 1
+ TestStatus.SKIPPED //TODO: what to do here
+ }
+
+ taskFinishParams.setDataKind(TaskDataKind.TEST_FINISH)
+ taskFinishParams.setData({
+ val testFinish = new TestFinish(getDisplayName(event), status)
+ if (event.throwable.isDefined)
+ testFinish.setMessage(throwableToString(event.throwable().get()))
+ testFinish
+ })
+ taskFinishParams.setEventTime(System.currentTimeMillis())
+ client.onBuildTaskFinish(taskFinishParams)
+ }
+
+ private def throwableToString(t: Throwable): String = {
+ val sw = new StringWriter
+ val pw = new PrintWriter(sw)
+ t.printStackTrace(pw)
+ sw.toString
+ }
+
+ // Compute the test report data structure that will go into
+ // the task finish notification after all tests are ran.
+ def getTestReport: TestReport = {
+ val report = new TestReport(targetId, passed, failed, ignored, cancelled, skipped)
+ report.setTime(totalTime)
+ report
+ }
+
+}
+
+case class TestException(stackTrace: String, message: String, exClass: String)