Skip to content

Commit 5383153

Browse files
committed
Regex hell
1 parent bbe5111 commit 5383153

File tree

1 file changed

+29
-9
lines changed

1 file changed

+29
-9
lines changed

src/main/scala/zio/intellij/testsupport/ZTestFrameworkConsoleProperties.scala

+29-9
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,9 @@ import com.intellij.util.ReflectionUtil
99
import jetbrains.buildServer.messages.serviceMessages._
1010
import org.jetbrains.plugins.scala.testingSupport.test.{AbstractTestRunConfiguration, ScalaTestFrameworkConsoleProperties}
1111

12+
import java.io.PrintStream
13+
import scala.util.control.NoStackTrace
14+
1215
private[zio] class ZTestFrameworkConsoleProperties(configuration: AbstractTestRunConfiguration, executor: Executor)
1316
extends ScalaTestFrameworkConsoleProperties(configuration, "ZIO Test", executor)
1417
with SMCustomMessagesParsing {
@@ -26,6 +29,7 @@ private[zio] class ZTestFrameworkConsoleProperties(configuration: AbstractTestRu
2629
// All this is needed to emit a custom TestFailedEvent that contains the expected and actual values extracted from
2730
// the output of a ZIO Test. This allows displaying a clickable hyperlink to see the differences in IDEA's built-in
2831
// diff viewer, because it assumes a JUnit-style failure reporting ("Expected:", "Actual:") which ZIO Test doesn't do.
32+
// Unfortunately, the visitor is both private and not overridable, so we have to resort to reflection to get to it.
2933
private lazy val underlyingTestVisitor = ReflectionUtil
3034
.findFieldInHierarchy(classOf[OutputToGeneralTestEventsConverter], _.getName == "myServiceMessageVisitor")
3135
.get(self)
@@ -38,20 +42,36 @@ private[zio] class ZTestFrameworkConsoleProperties(configuration: AbstractTestRu
3842

3943
}
4044

41-
// Copied from [[com.intellij.execution.testframework.sm.runner.OutputToGeneralTestEventsConverter#MyServiceMessageVisitor]]
4245
private class ZTestVisitor(underlying: ServiceMessageVisitor) extends DefaultServiceMessageVisitor {
46+
private val regexFromHell =
47+
raw"\[1m.\[34m([\s\S]*).\[0m.\[0m.*\[31mwas not equal to.*\[1m.\[34m([\s\S]*?).\[0m.\[0m".r
48+
4349
override def visitTestFailed(testFailed: TestFailed): Unit = {
4450
val details = testFailed.getStacktrace
51+
val tf = regexFromHell
52+
.findFirstMatchIn(details)
53+
.map { m =>
54+
val expected = unescapeAnsi(m.group(1)).trim
55+
val actual = unescapeAnsi(m.group(2)).trim
56+
val ex = new Throwable with NoStackTrace {
57+
override def printStackTrace(s: PrintStream): Unit =
58+
s.println(details)
59+
60+
override def toString: String = testFailed.getFailureMessage
61+
}
62+
new TestFailed(testFailed.getTestName, ex, actual, expected)
63+
}
64+
.getOrElse {
65+
testFailed
66+
}
67+
68+
underlying.visitTestFailed(tf)
69+
}
4570

71+
private def unescapeAnsi(s: String): String = {
4672
val builder = new StringBuilder()
47-
new AnsiEscapeDecoder().escapeText(details.trim, ProcessOutputTypes.STDOUT, (text, _) => builder.append(text))
48-
val plain = builder.result()
49-
println(plain)
50-
51-
52-
53-
underlying.visitTestFailed(testFailed)
54-
73+
new AnsiEscapeDecoder().escapeText(s, ProcessOutputTypes.STDOUT, (text, _) => builder.append(text))
74+
builder.result()
5575
}
5676

5777
override def visitTestSuiteStarted(testSuiteStarted: TestSuiteStarted): Unit =

0 commit comments

Comments
 (0)