approvals / go-approval-tests

Apache License 2.0
86 stars 22 forks source link

bug: use CallerFrames to find the filename instead of traversing program counter #40

Open karngyan opened 2 years ago

karngyan commented 2 years ago

Regarding findFileName

Go runtime docs discourage traversing PC or FuncForPC on any returned PCs as they can't account for inlining or return program counter adjustment.

This sometimes returns the wrong file name.

Something like this would be a better alternative:

func findFileName() (*string, error) {
    pc := make([]uintptr, 100)
    count := runtime.Callers(0, pc)
    frames := runtime.CallersFrames(pc[:count])
    var lastFrame *runtime.Frame
    var testFrame *runtime.Frame

    for {
        frame, more := frames.Next()
        if !more {
            break
        }

        if isTestRunnerFrame(&frame) {
            testFrame = &frame
            break
        }
        lastFrame = &frame
    }

    if !isTestRunnerFrame(testFrame) {
        return nil, fmt.Errorf("approvals: could not find the test method")
    }

    return &lastFrame.File, nil
}

func isTestRunnerFrame(f *runtime.Frame) bool {
    return f != nil && f.Function == "testing.tRunner" || f.Function == "testing.runExample"
}

What do you think?