wrapper.go 2.0 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980
  1. // Package ginkgowrapper wraps Ginkgo Fail and Skip functions to panic
  2. // with structured data instead of a constant string.
  3. package ginkgowrapper
  4. import (
  5. "bufio"
  6. "bytes"
  7. "regexp"
  8. "runtime"
  9. "runtime/debug"
  10. "strings"
  11. "github.com/onsi/ginkgo"
  12. )
  13. // FailurePanic is the value that will be panicked from Fail.
  14. type FailurePanic struct {
  15. Message string // The failure message passed to Fail
  16. Filename string // The filename that is the source of the failure
  17. Line int // The line number of the filename that is the source of the failure
  18. FullStackTrace string // A full stack trace starting at the source of the failure
  19. }
  20. // String makes FailurePanic look like the old Ginkgo panic when printed.
  21. func (FailurePanic) String() string { return ginkgo.GINKGO_PANIC }
  22. // Fail wraps ginkgo.Fail so that it panics with more useful
  23. // information about the failure. This function will panic with a
  24. // FailurePanic.
  25. func Fail(message string, callerSkip ...int) {
  26. skip := 1
  27. if len(callerSkip) > 0 {
  28. skip += callerSkip[0]
  29. }
  30. _, file, line, _ := runtime.Caller(skip)
  31. fp := FailurePanic{
  32. Message: message,
  33. Filename: file,
  34. Line: line,
  35. FullStackTrace: pruneStack(skip),
  36. }
  37. defer func() {
  38. e := recover()
  39. if e != nil {
  40. panic(fp)
  41. }
  42. }()
  43. ginkgo.Fail(message, skip)
  44. }
  45. // ginkgo adds a lot of test running infrastructure to the stack, so
  46. // we filter those out
  47. var stackSkipPattern = regexp.MustCompile(`onsi/ginkgo`)
  48. func pruneStack(skip int) string {
  49. skip += 2 // one for pruneStack and one for debug.Stack
  50. stack := debug.Stack()
  51. scanner := bufio.NewScanner(bytes.NewBuffer(stack))
  52. var prunedStack []string
  53. // skip the top of the stack
  54. for i := 0; i < 2*skip+1; i++ {
  55. scanner.Scan()
  56. }
  57. for scanner.Scan() {
  58. if stackSkipPattern.Match(scanner.Bytes()) {
  59. scanner.Scan() // these come in pairs
  60. } else {
  61. prunedStack = append(prunedStack, scanner.Text())
  62. scanner.Scan() // these come in pairs
  63. prunedStack = append(prunedStack, scanner.Text())
  64. }
  65. }
  66. return strings.Join(prunedStack, "\n")
  67. }