]> Dogcows Code - chaz/sbt-tap/blob - src/main/scala/SbtTapReporting.scala
097157a520359f862faee08c7ba748c7597908b4
[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 new File("test-results").mkdirs()
25
26 fileWriter = new FileWriter(
27 scala.util.Properties.envOrElse("SBT_TAP_OUTPUT", "test-results/test.tap")
28 )
29 }
30
31 def startGroup(name: String) {
32 writeTapFields("#", "start", name)
33 }
34
35 def endGroup(name: String, result: TestResult.Value) {
36 writeTapFields("#", "end", name, "with result", result.toString.toLowerCase)
37 }
38
39 def endGroup(name: String, t: Throwable) {
40 writeTapFields("#", "end", name)
41 }
42
43 def testEvent(event: TestEvent) {
44 event.detail.foreach { e: TEvent =>
45 e.result match {
46 case TResult.Success => writeTapFields("ok", testId.incrementAndGet(), "-", e.testName())
47 case TResult.Error | TResult.Failure =>
48 writeTapFields("not ok", testId.incrementAndGet(), "-", e.testName())
49 // According to the TAP spec, as long as there is any kind of whitespace, this output should belong to the
50 // the test that failed and it should get displayed in the UI.
51 // TODO:It would be nice if we could report the exact line in the test where this happened.
52 writeTapFields(" ", stackTraceForError(e.error()))
53 case TResult.Skipped =>
54 // it doesn't look like this framework distinguishes between pending and ignored.
55 writeTapFields("ok", testId.incrementAndGet(), e.testName(), "#", "skip", e.testName())
56 }
57 }
58 }
59
60 override def doComplete(finalResult: TestResult.Value) {
61 writeTapFields("1.." + testId.get)
62 fileWriter.close()
63 }
64
65 private def writeTapFields(s: Any*) {
66 fileWriter.write(s.mkString("", " ", "\n"))
67 fileWriter.flush()
68 }
69
70 private def stackTraceForError(t: Throwable): String = {
71 val sw = new StringWriter()
72 val printWriter = new PrintWriter(sw)
73 t.printStackTrace(printWriter)
74 sw.toString
75 }
76 }
This page took 0.035387 seconds and 3 git commands to generate.