]> Dogcows Code - chaz/sbt-tap/blob - src/main/scala/SbtTapReporting.scala
update tap protocol version to 13
[chaz/sbt-tap] / src / main / scala / SbtTapReporting.scala
1 import java.io.{PrintWriter, StringWriter, File, FileWriter}
2 import sbt._
3 import org.scalatools.testing.{Event => TEvent, Result => TResult}
4
5 import java.util.concurrent.atomic.AtomicInteger
6
7 object SbtTapReporting extends Plugin {
8 def apply() = new SbtTapListener
9 }
10
11 /**
12 * Listens to sbt test listener events and writes them to a tap compatible file. Results for all groups
13 * go to a single file although it might be desirable to generate one tap file per group.
14 * <p>
15 * sbt runs tests in parallel and the protocol does not seem to provide a way to match a group to a test event. It
16 * does look line one thread calls startGroup/testEvent/endGroup sequentially and using thread local to keep
17 * the current active group might be one way to go.
18 */
19 class SbtTapListener extends TestsListener {
20 var testId = new AtomicInteger(0)
21 var fileWriter: FileWriter = _
22
23 override def doInit = {
24 val filename = scala.util.Properties.envOrElse("SBT_TAP_OUTPUT", "test-results/test.tap")
25 val file = new File(filename)
26 new File(file.getParent).mkdirs
27 fileWriter = new FileWriter(file)
28 writeTap("TAP", "version", 13)
29 }
30
31 def startGroup(name: String) =
32 writeTapDiag("start", name)
33
34 def endGroup(name: String, result: TestResult.Value) =
35 writeTapDiag("end", name, "with result", result.toString.toLowerCase)
36
37 def endGroup(name: String, t: Throwable) = {
38 writeTapDiag("end", name)
39 writeTapDiag(stackTraceForError(t))
40 }
41
42 def testEvent(event: TestEvent) = {
43 event.detail.foreach { e: TEvent =>
44 val description = e.testName.replaceAll("#", "%23")
45 e.result match {
46 case TResult.Success =>
47 writeTap("ok", testId.incrementAndGet, "-", description)
48 case TResult.Skipped =>
49 writeTap("ok", testId.incrementAndGet, "-", description, "# SKIP")
50 case TResult.Error | TResult.Failure =>
51 writeTap("not ok", testId.incrementAndGet, "-", description)
52 // TODO: It would be nice if we could report the exact line in the test where this happened.
53 writeTapDiag(stackTraceForError(e.error))
54 }
55 }
56 }
57
58 override def doComplete(finalResult: TestResult.Value) = {
59 writeTap("1.." + testId.get)
60 fileWriter.close
61 }
62
63 private def writeTap(s: Any*) = {
64 fileWriter.write(s.mkString("", " ", "\n"))
65 fileWriter.flush
66 }
67
68 private def writeTapDiag(s: Any*) =
69 writeTap("#", s.mkString("", " ", "\n").trim.replaceAll("\\n", "\n# "))
70
71 private def stackTraceForError(t: Throwable): String = {
72 val sw = new StringWriter
73 val printWriter = new PrintWriter(sw)
74 t.printStackTrace(printWriter)
75 sw.toString
76 }
77 }
This page took 0.039315 seconds and 4 git commands to generate.