65 lines
1.7 KiB
Go
65 lines
1.7 KiB
Go
|
// +build go1.7
|
||
|
|
||
|
package is
|
||
|
|
||
|
import (
|
||
|
"regexp"
|
||
|
"runtime"
|
||
|
)
|
||
|
|
||
|
// Helper marks the calling function as a test helper function.
|
||
|
// When printing file and line information, that function will be skipped.
|
||
|
//
|
||
|
// Available with Go 1.7 and later.
|
||
|
func (is *I) Helper() {
|
||
|
is.helpers[callerName(1)] = struct{}{}
|
||
|
}
|
||
|
|
||
|
// callerName gives the function name (qualified with a package path)
|
||
|
// for the caller after skip frames (where 0 means the current function).
|
||
|
func callerName(skip int) string {
|
||
|
// Make room for the skip PC.
|
||
|
var pc [1]uintptr
|
||
|
n := runtime.Callers(skip+2, pc[:]) // skip + runtime.Callers + callerName
|
||
|
if n == 0 {
|
||
|
panic("is: zero callers found")
|
||
|
}
|
||
|
frames := runtime.CallersFrames(pc[:n])
|
||
|
frame, _ := frames.Next()
|
||
|
return frame.Function
|
||
|
}
|
||
|
|
||
|
// The maximum number of stack frames to go through when skipping helper functions for
|
||
|
// the purpose of decorating log messages.
|
||
|
const maxStackLen = 50
|
||
|
|
||
|
var reIsSourceFile = regexp.MustCompile(`is(-1.7)?\.go$`)
|
||
|
|
||
|
func (is *I) callerinfo() (path string, line int, ok bool) {
|
||
|
var pc [maxStackLen]uintptr
|
||
|
// Skip two extra frames to account for this function
|
||
|
// and runtime.Callers itself.
|
||
|
n := runtime.Callers(2, pc[:])
|
||
|
if n == 0 {
|
||
|
panic("is: zero callers found")
|
||
|
}
|
||
|
frames := runtime.CallersFrames(pc[:n])
|
||
|
var firstFrame, frame runtime.Frame
|
||
|
for more := true; more; {
|
||
|
frame, more = frames.Next()
|
||
|
if reIsSourceFile.MatchString(frame.File) {
|
||
|
continue
|
||
|
}
|
||
|
if firstFrame.PC == 0 {
|
||
|
firstFrame = frame
|
||
|
}
|
||
|
if _, ok := is.helpers[frame.Function]; ok {
|
||
|
// Frame is inside a helper function.
|
||
|
continue
|
||
|
}
|
||
|
return frame.File, frame.Line, true
|
||
|
}
|
||
|
// If no "non-helper" frame is found, the first non is frame is returned.
|
||
|
return firstFrame.File, firstFrame.Line, true
|
||
|
}
|