-
Notifications
You must be signed in to change notification settings - Fork 12
/
wrap_caller_test.go
113 lines (89 loc) · 2.43 KB
/
wrap_caller_test.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
package errtrace_test
import (
"errors"
"runtime"
"strings"
"testing"
"braces.dev/errtrace"
)
var safe = false
// Note: Though test tables could DRY up the below tests, they're intentionally
// kept as functions calling other simple functions to test how inlining impacts
// use of `GetCaller`.
func TestGetCallerWrap_ErrorsNew(t *testing.T) {
err := callErrorsNew()
wantErr(t, err, "callErrorsNew")
}
func callErrorsNew() error {
return errorsNew("wrap errors.New")
}
func errorsNew(msg string) error {
caller := errtrace.GetCaller()
return caller.Wrap(errors.New(msg))
}
func TestGetCallerWrap_WrapExisting(t *testing.T) {
err := callWrapExisting()
wantErr(t, err, "callWrapExisting")
}
func callWrapExisting() error {
return wrapExisting()
}
var errFoo = errors.New("foo")
func wrapExisting() error {
return errtrace.GetCaller().Wrap(errFoo)
}
func TestGetCallerWrap_PassCaller(t *testing.T) {
err := callPassCaller()
wantErr(t, err, "callPassCaller")
}
func callPassCaller() error {
return passCaller()
}
func passCaller() error {
return passCallerInner(errtrace.GetCaller())
}
func passCallerInner(caller errtrace.Caller) error {
return caller.Wrap(errFoo)
}
func TestGetCallerWrap_RetCaller(t *testing.T) {
err := callRetCaller()
wantFn := "callRetCaller"
if !safe {
// If the function calling pc.GetCaller is inlined, there's no stack frame
// so the assembly implementation can skip the correct caller.
// Callers of GetCaller using `go:noinline` avoid this (as recommended in the docs).
// Inlining is not consistent, hence we check the frame in !safe mode.
f, _, _ := errtrace.UnwrapFrame(err)
if !strings.HasSuffix(f.Function, wantFn) {
wantFn = "TestGetCallerWrap_RetCaller"
}
}
wantErr(t, err, wantFn)
}
func callRetCaller() error {
return retCaller().Wrap(errFoo)
}
func retCaller() errtrace.Caller {
return errtrace.GetCaller()
}
func TestGetCallerWrap_RetCallerNoInline(t *testing.T) {
err := callRetCallerNoInline()
wantErr(t, err, "callRetCallerNoInline")
}
func callRetCallerNoInline() error {
return retCallerNoInline().Wrap(errFoo)
}
//go:noinline
func retCallerNoInline() errtrace.Caller {
return errtrace.GetCaller()
}
func wantErr(t testing.TB, err error, fn string) runtime.Frame {
if err == nil {
t.Fatalf("expected err")
}
f, _, _ := errtrace.UnwrapFrame(err)
if !strings.HasSuffix(f.Function, "."+fn) {
t.Errorf("expected caller to be %v, got %v", fn, f.Function)
}
return f
}