cats.scalatest.StackDepthHelpers.scala Maven / Gradle / Ivy
package cats.scalatest
import org.scalatest.exceptions.{ StackDepthException, StackDepthExceptionHelper }
/**
* Helper functions taken from ScalaTest's StackDepthExceptionHelper (version 2.2.4).
* Bill Venners suggested lifting them instead of monkey patching to use them as he might break them soon.
*/
private[scalatest] object StackDepthHelpers {
def getStackDepth(stackTrace: Array[StackTraceElement], fileName: String, methodName: String, adjustment: Int = 0): Int = {
val stackTraceList = stackTrace.toList
val fileNameIsDesiredList: List[Boolean] =
for (element <- stackTraceList) yield element.getFileName == fileName // such as "Checkers.scala"
val methodNameIsDesiredList: List[Boolean] =
for (element <- stackTraceList) yield element.getMethodName == methodName // such as "check"
// For element 0, the previous file name was not desired, because there is no previous
// one, so you start with false. For element 1, it depends on whether element 0 of the stack trace
// had the desired file name, and so forth.
val previousFileNameIsDesiredList: List[Boolean] = false :: (fileNameIsDesiredList.dropRight(1))
// Zip these two related lists together. They now have two boolean values together, when both
// are true, that's a stack trace element that should be included in the stack depth.
val zipped1 = methodNameIsDesiredList zip previousFileNameIsDesiredList
val methodNameAndPreviousFileNameAreDesiredList: List[Boolean] =
for ((methodNameIsDesired, previousFileNameIsDesired) <- zipped1) yield methodNameIsDesired && previousFileNameIsDesired
// Zip the two lists together, that when one or the other is true is an include.
val zipped2 = fileNameIsDesiredList zip methodNameAndPreviousFileNameAreDesiredList
val includeInStackDepthList: List[Boolean] =
for ((fileNameIsDesired, methodNameAndPreviousFileNameAreDesired) <- zipped2) yield fileNameIsDesired || methodNameAndPreviousFileNameAreDesired
val includeDepth = includeInStackDepthList.takeWhile(include => include).length
val depth = if (includeDepth == 0 && stackTrace(0).getFileName != fileName && stackTrace(0).getMethodName != methodName)
stackTraceList.takeWhile(st => st.getFileName != fileName || st.getMethodName != methodName).length
else
includeDepth
depth + adjustment
}
def getStackDepthFun(fileName: String, methodName: String, adjustment: Int = 0): (StackDepthException => Int) = { sde =>
getStackDepth(sde.getStackTrace, fileName, methodName, adjustment)
}
}